Weird discontinuity with waveform when making a synthesiser plugin

Hi, I have started developing an FM synth and I’ve decided to use the MPESynthesiser class since it looks to be a bit nicer/future proof than the Synthesiser class. One thing I do to debug is to use audacity to record the sounds I make, then see what the wave form looks like. However a strange thing is happening. Whenever I start a new voice there is an audible click that can be seen here as this discontinuity in the waveform. It’s as though the voice starts playing, then something interrupts for an indeterminate amount of time. The number of samples that it takes for this discontinuity to happen is variable. I can assure you that my code is solid and I am not allocating memory when a new voice is made or anything like that. I assume it is a quirk of JUCE.
Anyone had this before or know how to fix it?
Thanks

Are you respecting the startSample parameter of renderNextBlock() ?

1 Like

inside renderNextBlock() my loop looks like this:

for (int i = startSample; i < numSamples; i++){
~CODE~
}

How many iterations does this loop do when startSample is 10 and numSamples is 5?

1 Like

that is an excellent question, but to my knowledge, numSamples is gonna be the block size, no?
Before I had it as

for (int i = 0; i < numSamples; i++){
~CODE~
}

But it behaved exactly the same.
How would you do it?

No, numSamples is not the same as the getNumSamples of the passed in AudioBuffer.

From the documentation :

“Only the region of the buffer between startSample and (startSample + numSamples) should be altered by this method.”

1 Like

So are you saying my loops should look like this?

for (int i = 0; i < startSamples + numSamples; i++){
~CODE~
}

That’s not right. How the loop likes would depend on how you are actually accessing the buffer locations.

For example it could be like :

auto bufferpointers = buffer.getArrayOfWritePointers();
for (int i=0;i<numSamples;++i)
{
  bufferpointers[0][startSample+i] += thesynthvoiceaudio;
}

Or :

auto bufferpointers = buffer.getArrayOfWritePointers();
for (int i=startSample;i<startSample+numSamples;++i)
{
  bufferpointers[0][i] += thesynthvoiceaudio;
}

Or :

auto bufferpointer = buffer.getWritePointer(0,startSample);
for (int i=0;i<numSamples;++i)
{
  bufferpointer[i] += thesynthvoiceaudio;
}

Among some other possibilities.

Here is what my whole renderNextSubBlock() looks like:

void Voice::renderNextBlock(juce::AudioBuffer<float>& outputBuffer, int startSample, int numSamples)
{
    for (int i = startSample; i < startSample + numSamples; i++)
    {
        float currentSample = 0;
        iterate([&](unsigned o)
            {
                currentSample += osc[o].process() * velocity;
            });
        for (auto c = 0; c < outputBuffer.getNumChannels(); c++)
        {
            outputBuffer.addSample(c, i, currentSample);
        }
    }
}

I have altered the loops to say go from startSample to startSamples + numSamples, this has removed the weird error that causes the wave to start, stop then restart. So now the wave looks like this:

image

I think I can pick it up from here, this seems like its just a problem with making sure my phase is 0 when I start a new voice. Thanks for your help

EDIT* the function iterate() just iterates through a vector of oscillators if it wasn’t clear.