Plugin Outputting Constant Value of 1

I’m having trouble figuring out why my Ugen is only outputting a constant value of 1. Any insight would be greatly appreciated!

LFSRNoise Plugin Gist

LFSRNoise.hpp

// LFSRNoise.hpp
// m josiah sytsma

#pragma once

#include "SC_PlugIn.hpp"
#include <stdint.h>

class LFSRNoise : public SCUnit {
    enum Inputs { FREQ, FB_POS };
    
    uint16_t mVal;       //value
    uint16_t mFreqMul;   //constant for multiplying freq
    const unsigned int MAX_POS = 15;
    const unsigned int MIN_POS = 0;
    
    // Calc function
    void next_a(int nSamples);
    void next_k(int nSamples);
    
    //step through lfsr process
    float progressSeq(float frequency);
    
    //get output value
    float calcOutVal();

    // State variables
    float m_frequency_past{0.f};
public:
    LFSRNoise();
};

LFSRNoise.cpp

// LFSRNoise.cpp

#include "SC_PlugIn.hpp"
#include "LFSRNoise.hpp"
#include "jsUtils.h"

static InterfaceTable *ft;

LFSRNoise::LFSRNoise() {
    // set the calculation function.
    if (isAudioRateIn(FREQ)) {
        set_calc_function<LFSRNoise,&LFSRNoise::next_a>();
    } else {
        set_calc_function<LFSRNoise,&LFSRNoise::next_k>();
    }

    // 2. initialize the unit generator state variables.
    // initialize a constant for multiplying the frequency
    this->mFreqMul  = sampleDur();
    this->mVal      = -1;

    // 3. calculate one sample of output.
    if (isAudioRateIn(0)) {
        next_a(1);
    } else {
        next_k(1);
    }
}

float LFSRNoise::progressSeq(float frequency) {
    size_t increment    = static_cast<size_t>(frequency / sampleRate());
    uint16_t val        = this->mVal;
    unsigned int pos    = in0(FB_POS);
    
    if (pos > this->MAX_POS) {
        pos = this->MAX_POS;
    }
    else if (pos < this->MIN_POS) {
        pos = this->MIN_POS;
    };
    
    for (int i = 0; i < increment; i++) {
        unsigned int x = jsUtils::getBit(val, 0)^jsUtils::getBit(val, 1);
        val >>= 1;
        val = jsUtils::setBit(val, pos, x);
    };
    
    if (val == 0) {
        val = -1;
    };
    
    this->mVal = val;
    
    return calcOutVal();
}

void LFSRNoise::next_a(int nSamples) {
    
    //pointer to output buffer
    float *outbuf = out(0);
    
    //pointer to input buffer
    const float *frequency = in(FREQ);
    
    for (int i = 0; i < nSamples; ++i) {
        outbuf[i] = progressSeq(frequency[i]);
    }
}

float LFSRNoise::calcOutVal()
{
    if (jsUtils::getBit(this->mVal, 0) == 1) {
        return 1.f;
    }
    else {
        return -1.f;
    };
}

void LFSRNoise::next_k(int nSamples) {
    const float frequencyParam = in(FREQ)[0];
    SlopeSignal<float> slopedFrequency =
    makeSlope(frequencyParam, m_frequency_past);
    float *outbuf = out(0);
    
    for (int i = 0; i < nSamples; ++i) {
        const float freq = slopedFrequency.consume();
        
        outbuf[i] = progressSeq(freq);
    }
    
    m_frequency_past = slopedFrequency.value;
}

PluginLoad(LFSRNoise) {
    // Plugin magic
    ft = inTable;
    registerUnit<LFSRNoise>(ft, "LFSRNoise", false);
}

There are many C++ errors in this code. I believe it is this one that causes the issue…

You are casting an uint16_t to a bool implicitly, what do you want that to do? In c++ you should follow the type system and avoid the implicit casts c has.

Further, you are taking the bitwise ‘and’ of some number and 1, this is the equivalent to asking if the number is odd - you should just do this the normal way with mod, the compiler knows what it’s doing.

So I believe your code will produce the value 1 when mVal is odd.

Have you checked your bit-shifting can produce even values given all states and given the initial state?

I wasn’t thinking about mod, I was just thinking of the LSB, but you’re right. I caught a few of the issues, like a weird static cast to the wrong type. I’m pretty new to C++ as I’m sure you can tell, so I’m trying to get some practice in by making plugins for SC and VCV.

What I thought would happen is it would give -1 while mVal’s LSB is 0 or 1 if it’s 1.

I added a conditional statement to reset mVal to -1 if it gets to 0, but I don’t think it will. I could be wrong. I don’t know how to do the math to figure it out. I have a separate code to just print LFSR states and it gives this as a small sample given a feedback position of bit 15.

I think the problem might be I’m not really sure how the frequency argument should work. MySaw2 and Mads’s RampUpGen approached frequency in two different ways that I wasn’t totally sure how to implement. Again, not great with math.

11111111111111111111111111111111 4294967295
01111111111111110111111111111111 2147450879
00111111111111110011111111111111 1073692671
00011111111111110001111111111111 536813567
00001111111111110000111111111111 268374015
00000111111111110000011111111111 134154239
00000011111111110000001111111111 67044351
00000001111111110000000111111111 33489407
00000000111111110000000011111111 16711935
00000000011111110000000001111111 8323199
00000000001111110000000000111111 4128831
00000000000111110000000000011111 2031647
00000000000011110000000000001111 983055
00000000000001110000000000000111 458759
00000000000000110000000000000011 196611
00000000000000010000000000000001 65537
00000000000000001000000000000000 32768
00000000000000000100000000000000 16384
00000000000000000010000000000000 8192
00000000000000000001000000000000 4096
00000000000000000000100000000000 2048
00000000000000000000010000000000 1024
00000000000000000000001000000000 512
00000000000000000000000100000000 256
00000000000000000000000010000000 128
00000000000000000000000001000000 64
00000000000000000000000000100000 32
00000000000000000000000000010000 16
00000000000000000000000000001000 8
00000000000000000000000000000100 4
00000000000000000000000000000010 2
00000000000000001000000000000001 32769
00000000000000001100000000000000 49152
00000000000000000110000000000000 24576
00000000000000000011000000000000 12288
00000000000000000001100000000000 6144
00000000000000000000110000000000 3072
00000000000000000000011000000000 1536
00000000000000000000001100000000 768
00000000000000000000000110000000 384
00000000000000000000000011000000 192
00000000000000000000000001100000 96
00000000000000000000000000110000 48
00000000000000000000000000011000 24
00000000000000000000000000001100 12
00000000000000000000000000000110 6
00000000000000001000000000000011 32771
00000000000000000100000000000001 16385
00000000000000001010000000000000 40960
00000000000000000101000000000000 20480
00000000000000000010100000000000 10240
00000000000000000001010000000000 5120
00000000000000000000101000000000 2560
00000000000000000000010100000000 1280
00000000000000000000001010000000 640
00000000000000000000000101000000 320
00000000000000000000000010100000 160
00000000000000000000000001010000 80
00000000000000000000000000101000 40
00000000000000000000000000010100 20
00000000000000000000000000001010 10
00000000000000001000000000000101 32773
00000000000000001100000000000010 49154
00000000000000001110000000000001 57345
00000000000000001111000000000000 61440
00000000000000000111100000000000 30720
00000000000000000011110000000000 15360
00000000000000000001111000000000 7680
00000000000000000000111100000000 3840
00000000000000000000011110000000 1920
00000000000000000000001111000000 960
00000000000000000000000111100000 480
00000000000000000000000011110000 240
00000000000000000000000001111000 120
00000000000000000000000000111100 60
00000000000000000000000000011110 30
00000000000000001000000000001111 32783
00000000000000000100000000000111 16391
00000000000000000010000000000011 8195
00000000000000000001000000000001 4097
00000000000000001000100000000000 34816
00000000000000000100010000000000 17408
00000000000000000010001000000000 8704
00000000000000000001000100000000 4352
00000000000000000000100010000000 2176
00000000000000000000010001000000 1088
00000000000000000000001000100000 544
00000000000000000000000100010000 272
00000000000000000000000010001000 136
00000000000000000000000001000100 68
00000000000000000000000000100010 34
00000000000000001000000000010001 32785
00000000000000001100000000001000 49160
00000000000000000110000000000100 24580
00000000000000000011000000000010 12290
00000000000000001001100000000001 38913
00000000000000001100110000000000 52224
00000000000000000110011000000000 26112
00000000000000000011001100000000 13056
00000000000000000001100110000000 6528
00000000000000000000110011000000 3264
00000000000000000000011001100000 1632
00000000000000000000001100110000 816
00000000000000000000000110011000 408
00000000000000000000000011001100 204
00000000000000000000000001100110 102
00000000000000001000000000110011 32819
00000000000000000100000000011001 16409
00000000000000001010000000001100 40972
00000000000000000101000000000110 20486
00000000000000001010100000000011 43011
00000000000000000101010000000001 21505
00000000000000001010101000000000 43520
00000000000000000101010100000000 21760
00000000000000000010101010000000 10880
00000000000000000001010101000000 5440
00000000000000000000101010100000 2720
00000000000000000000010101010000 1360
00000000000000000000001010101000 680
00000000000000000000000101010100 340
00000000000000000000000010101010 170
00000000000000001000000001010101 32853
00000000000000001100000000101010 49194
00000000000000001110000000010101 57365
00000000000000001111000000001010 61450
00000000000000001111100000000101 63493
00000000000000001111110000000010 64514
00000000000000001111111000000001 65025
Program ended with exit code: 0

Is that large code snippet the values of mVal? If so, it looks like it should work now? Perhaps replace add the logic to switch on odd and check that works to?

That’s 2^16 - 1. You can use the numerical limits in c++ to write this much nicer.

This line too has an issue…

size_t increment = static_cast<size_t>(frequency / sampleRate());

Unless frequency is larger than the sample rate, it will always be 0 … Or perhaps it will be 1 if it’s greater than fs/2… I can’t remember, point being, don’t use a cast to change a value, instead use round, floor or ceil.

This isn’t necessary…
uint16_t val = this->mVal

I get what your thinking, let’s not do the pointer deference everytime we look at mVal … but the compiler knows this and will fix it for you given that ints fit in the register, you can just write mVal directly everywhere. You don’t need the ‘this->’ either.

This branch is currently impossible as min pos is 0 and ‘pos’ is a uint.

else if (pos < this->MIN_POS) 

Ok I’m starting to see where some of the issues are, thanks for your help! I think I’m going to have to step back through this a little more carefully and try some other less flexible designs first to build out from there

Here it is not necessary because the variable is an integer. However, if it were a float you would indeed need to copy it to the stack, otherwise the compiler must assume that it may alias one of the output samples and reload it from memory on every iteration!

Usually, you can rely on optimizing compilers to do the right thing, but there are still cases where they lack information and need some hand holding.

Oft, nice catch! I find those sought of aliasing issues really difficult to spot.