Hi guys i´m quite new to JUCE and i´m trying to add a modulator to my synthesiser voice, I extended the synthesiser voice class and I made a custom class that looks something like this
class LFOModulator
{
public:
LFOModulator();
void retrigger();
void advance(double sampleRate);
double getValue();
private:
double lfoBuffer[2048];
double phase;
const long double PI = 3.141592653589793238L;
JUCE_LEAK_DETECTOR(LFOModulator)
};
Now i´m trying to call the advance function for every sample that the synthesiser voice processes from the synthesiser voice which I made a dummy for at the moment to see why its crashing, right now it does this.
void LFOModulator::advance(double sampleRate){
}
The strange thing is that it doesnt crash instantly but it slowly grinds to a halt causing audio dropouts first. Is there internal blocking in calling member object functions, or is there something else going wrong here. I know that the error is in the function call because removing the call removes the crash.
for a start, you probably should just return a double from your advance function rather than making a separate getValue() function.
Secondly, you shouldn't be feeding the samplerate into your advance function. Check it once per process block at most, not every single sample. Samplerate is not something that usually ever even changes. Checking on every sample is a total waste.
I know that the error is in the function call because removing the call removes the crash.
I have a sneeking suspicion that you are declaring your LFOModulator object inside the synth process loop (which would be wrong). Can you share the rest of the code?
void SamplerAudioProcessor::initialiseSynth()
{
const int numVoices = 8;
//Voicing
for (int i = numVoices; --i >= 0;){
synth.addVoice(new GranularVoice(LFOModulator(*lfo1RateParam)));
}
}
class GranularVoice : public SamplerVoice
{
public:
GranularVoice(LFOModulator lfoModulator1);
~GranularVoice();
bool canPlaySound(SynthesiserSound*) override;
void startNote(int midiNoteNumber, float velocity, SynthesiserSound*, int pitchWheel) override;
void stopNote(float velocity, bool allowTailOff) override;
void pitchWheelMoved(int newValue) override;
void controllerMoved(int controllerNumber, int newValue) override;
void renderNextBlock(AudioSampleBuffer&, int startSample, int numSamples) override;
private:
//Envelope
bool isInAttack, isInRelease;
float velocityGain, envelopeLevel, attackDelta, releaseDelta;
int attackSamples, decaySamples, releaseSamples;
//Grain phasor
double grainPhasorDelta; //Same for all grains (synchronous)
double grainPhasorPhases[8];
//Voiced Modulators
double scanPosition;
LFOModulator& lfoModulator1; //this has too much overhead on audio rate modulation ??
//SAH per note
int noteTransposition;
int totalTransposition;
//SAH per grain
double pitchRatio;
double readPositions[10];
JUCE_LEAK_DETECTOR(GranularVoice)
};
By the way right now I am not even using the get value function yet only the advance just to see why its crashing
void GranularVoice::renderNextBlock(AudioSampleBuffer& outputBuffer, int startSample, int numSamples)
{
if (const GranularSound* const playingSound = static_cast <GranularSound*> (getCurrentlyPlayingSound().get()))
{
const float* const sourceL = playingSound->sourceBuffer->getReadPointer(0);
const float* const sourceR = playingSound->sourceBuffer->getNumChannels() > 1
? playingSound->sourceBuffer->getReadPointer(1) : nullptr;
//Get output write pointers. The pointer address is incremented in the while loop.
float* outputL = outputBuffer.getWritePointer(0, startSample);
float* outputR = outputBuffer.getNumChannels() > 1 ? outputBuffer.getWritePointer(1, startSample) : nullptr;
grainsL *= (envelopeLevel*envelopeLevel);
grainsR *= (envelopeLevel*envelopeLevel);
scanPosition += (playingSound->scanSpeed-0.5f)*10.0f; //-5 to 5
lfoModulator1.advance(getSampleRate());
if (isInAttack)
{
envelopeLevel += attackDelta;
if (envelopeLevel >= 1.0f)
{
envelopeLevel = 1.0f;
isInAttack = false;
}
}
else if (isInRelease)
{
envelopeLevel += releaseDelta;
if (envelopeLevel <= 0.0f)
{
stopNote(0.0f, false);
break; //Exit while loop when release is done (no need to write more into the output buffer)
}
}
This runs fine when i remove the lfo1modulator.advance line which I think is strange since there is no actual code inside that function it does absolutely nothing except for being called. Is it really just the passing of the samplerate that causes this crash (I just had this right now because I didnt think of a proper way to set the modulator sample rates yet) ? Does memory allocation cause blocking when a value gets copied in a function call ? I know that passing the sample rate here is stupid I'm just trying to figure out the limitations of the audio thread. I would like to have audio rate modulations for some granular parameters thats why I'm looking into this.
Ok i did another test to simplify things even more, now i have an advance function without any arguments and still nothing in the body and it still crashes. Maybe its in the way i referenced to the LFOModulator object? I cant seem to find out how a void function with absolutely no content can grind down the process loop.
You declare your lfoModulator1 as reference, so can you make sure, that this reference is actually referencing an instance? Otherwise your advance is called in the nirvana, hence the crash...
LFOModulator& lfoModulator1;
Removing the ampersand will call at least the default constructor, and advance can be called.
I was just browsing your code, not actually debugging, so I could be wrong...
In the top part of the code I posted it shows that for every voice I pass a new instance of LFOModulator into the constructor. If I'm correct this should stay in the same address on the heap right?
Ive been looking trough the synthesiservoice class and it shows that they reference the playingSound with a referenceCountedObjectPointer, since accesing the sound parameters and functions seem to cause no trouble, but when I call something from my LFOModulator it seems to be really slow (I'm geussing)?
Omg sorry guys for asking these questions I think i figured out what the problem was, it had something to do with using directSound driver in the juce plugin host that caused problems. Seems to be running fine on windows audio driver now and in ableton aswell, sorry.