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.
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 (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.
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.
I usually set the samplerate to 0 and put jassert(samplerate > 0) in the functions that use it 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