Super weird bug, what to do? [SOLVED]

I have a project that is rather complex already, so I don’t want to post all the code.

I have a console app… main() that creates a class AudioApp on the stack that holds the AudioDeviceManager an AudioSource and an AudioSourcePlayer

The AudioSource does a lot of funky stuff hosting other AudioSources and a MixerAudioSource to bring it all together.

I’m having a problem with a variable that sometimes gets correctly initialised at startup, or doesn’t.

NOTE: this bug sometimes shows up, sometimes doesn’t - at run time, not between compiles!!!

Here’s the freakiest part…

This is my main() code:

int main (int argc, char* argv[])
{

	AudioApp arif;

	while (true)
	{
		// float input;
		std::cout << "enter value: ";
		//std::cin >> input;
                //arif.outputSource.triggerFireChange(input);
	}

    return 0;
}

If I (also) comment out the single std::cout << "enter value: "; line, the bug dissappears completely, and the app works every time!

Swapping the std::cout for DBG() gives me the same problem.

i.e. if my while loop does little (the float declaration doesn’t trigger the bug), the bug will not occur.

Can you give me any advice on what to do!?

Maybe the AudioApp object is “large” and is right at the border of what fits on the stack. Try allocating it on the heap?

1 Like

AudioApp* arif = new AudioApp; ?

auto arif = std::make_unique<AudioApp>();

Lol are you doing it like that just to wind me up?

Well, it could be done like this too :

std::unique_ptr<AudioApp> arif{new AudioApp};

Okay, I just tried

auto arif = std::make_unique<AudioApp>(); and AudioApp* arif = new AudioApp;

Both, with std::cout included mean that the bug appears 100% of the time

On the stack, AudioApp arif; (as before) and the bug appears roughly 1/3 of the time! :woozy_face:

You still have that float input; line in your code? Is something in the code using that variable? Because that doesn’t initialize the input variable to zero. You always have to initialize your primitive variables explicitly in C++.

Is doing outputSource.triggerFireChange(input); thread safe?

Well it’s all commented out, so doesn’t matter anyway, for now.

My main as is (with bug) is just a declaration of AudioApp, and an infinite loop with stdd::cout << "enter value: "; Nothing else.

Interesting you mentioned thread because I just got into learning about threads, in order to have a timed event that occurs outside of getNextAudioBlock() But even with it commented out it appears to make no difference to the bug.

Some explanation about what the bug actually is might help?
If it’s a crash, providing the stack trace is probably the best way to narrow it down.
Does the crash stack trace change between runs?

Maybe I should tell you that the bug appears to occur somewhere inside my custom SmoothedValue class. It has worked perfectly up until now, but only now I am running 2 instances of the class - I don’t see how that affects anything.

Anyway, here is my personal parameter smoothing that I think sounds lovely: (the bug appears to be that sometimes startValue doesn’t seem to be passed in)

// A class to glide between values
// Using a one pole lowpass filter
//
// Taken from the OpeFrameworks Audio Tutorial youtube video: 
// https://www.youtube.com/watch?v=BdJRSqgEqPQ
// Which in turn, got it from RackFX

// more of current input (input * b) less of old input (z* a) = more higher freuqncy
// less of current input (input *b)  and more of old input (z * a) = less high frequency

// When using Glide: *= the variable you want to use for example: signal *= Glide.process(0);
// where 0 is the target value;
// Then call init() repeatedly to change value as in PD [line~] object

#define TWO_PI 6.28318530717958647693


class Glide
{
private:
	float a; // coefficient (scalar value) (cut off frequency)
	float b; // coefficient (scalar value) (cut off frequency)
	float z; // previous input
public:

	Glide() : z(0.0f) {}

	void init(float startValue, float glideTimeMS, int sampleRate)
	{
		z = startValue;
		// set coefficients
		a = exp(-TWO_PI / (glideTimeMS * 0.001f * sampleRate));
		b = 1.0f - a;
	}

	inline float process(float targetValue)
	{
		z = (targetValue * b) + (z * a);
		return z;
	}
};

I can just guess your class’s process method gets a chance to be executed before the init method has been executed. The code would then use the uninitialized a and b members of your class and that could lead to all kinds of weird behavior.

Yeah, nope, not that :slight_smile: I am however calling init() in the constructor of the class that uses it, is that a bad idea maybe?

Do you have a valid samplerate available during that other constructor? Also, are you sure the audio isn’t already running before you call your smoother’s init method?

Ah wow! It might be that, I’ll have a play. In the meantime, I’m gonna dump the whole class on ya :stuck_out_tongue: (it’s not too big though) in case you want to look for yourself.

class FireBus : public AudioSource
{ // output bus that owns all the fire sources and manages their parameters.
private:
    float sampleRate;

    MixerAudioSource fireMixer;

    float fireSize = 0.9f; // a variable to hold and manage the current size of the fire
    float fireSizeTarget = 1.0f;

    Hissing hissing;
    Roaring flames;
    Crackling crackling;

    RandomWalk fireSizeModulator;
    Glide fsmSmoother;

public:
    FireBus()
    {
        fireMixer.addInputSource(&hissing, false);
        fireMixer.addInputSource(&flames, false);
        fireMixer.addInputSource(&crackling, false);

        //init parameters
        fireSizeModulator.setRange(-0.0f, 1.0f);
        fireSizeModulator.setStepSize(0.01f);
        fsmSmoother.init(fireSize,1000,sampleRate);
    }

    float getFireSize() {return fireSize;}

    void triggerFireChange(float value)
    {
        fireSizeTarget = value;
        fsmSmoother.init(value,1000,sampleRate);
    }

    void setFireSize(float value)
    {
        hissing.setSize(value);
        flames.setSize(value);
        crackling.setSize(value);
    }

    void prepareToPlay(int samplesPerBlockExpected, double rate) override
    {
        sampleRate = rate;

        fireMixer.prepareToPlay(samplesPerBlockExpected, sampleRate);
    }

    void releaseResources() override
    {}

    void getNextAudioBlock(const AudioSourceChannelInfo& bufferToFill) override
    {
        // interpolate the FireSizeModulator Random walk
        float interpolateFire = fireSize *= fsmSmoother.process(0);
        setFireSize(interpolateFire);

        // process Fire
        fireMixer.getNextAudioBlock(bufferToFill);
    }
};

Yeah, the smoother’s init is going to get a junk value for the samplerate when called from the constructor. Probably best to move the smoother init call into prepareToPlay.

High priority advice : start initializing your variables properly.

1 Like

Yes it was that!! Xenakios.freeBeer++;

Just confirmed! Moving the init call inside prepare to play (so that there is a sampleRate) fixes that.

I’m going to have to look elsewhere in the code now where I am also using sampleRate to see if I might be doing it wrong there too (and just getting lucky).

I absolutely heed your advice. In the case such as this where I need sampleRate, as a principle, should I have my own init class that gets called from within prepareToPlay, because evidently the constructor is not sufficient in such a case.

For initing a samplerate class member you can probably get away by initially setting it to :

0.0f, because that almost certainly leads to a blatant bug that you will immediately notice

or preferably 44100.0f, because that’s a typical value for it. The call to prepareToPlay or a similar method can set the right value later anyway.

I usually set the samplerate to 0 and put jassert(samplerate > 0) in the functions that use it :wink: Also if a class uses some variables I can only set during prepareToPlay I add a function to the class, for example prepare(const double samplerate) - this way I protect myself from forgetting :wink: