Hi,
So, I’m kinda stumped on this one and any leads would be greatly appreciated. I’m having trouble with getting my plugin working in FL Studio. I’m pretty new to dsp and juce in general, but I’m making a pretty simple plugin with stereoswap, delays and couple of filters (one LowPass and one HighPass).
Everything is nice and good when testing in REAPER or juce’s AudioPluginHost, but FL studio makes the filters pop like crazy. The popping goes away when ticking on “use fixed buffer size”, so this issue seems to be related to the variable block sizes FL Studio gives for some reason.
I’m using dsp filters with ProcessDuplicators (dsp::ProcessorDuplicator<dsp::IIR::Filter<float>, dsp::IIR::Coefficients<float>> lowPassFilter;
) and simply setting their states every processBlock like this
lowPassFilter.state = *dsp::IIR::COefficients<float>::makeFirstOrderLowPass(sampleRate, lowPassFreq);
and then using process on the audio buffer. I thought this implementation should be independent of block size, but I seem to be missing something.
So, I’ve read several forum posts, mainly this one, and tried to make the buffer size constant on my own by using a circular AudioBuffer.
I save the desiredBlockSize given in prepareToPlay(), then in processBlock I keep filling the circular buffer until I have enough, then move that amount of buffers to the output buffer and do my processing in processBlockInternal. avbsBuffer is of type CircularAudioBuffer, which you can see below in its entirety. It just has an AudioBuffer and an AbstractFifo to keep track of writes and reads.
void JucePluginAppAudioProcessor::processBlock(AudioBuffer<float> &buffer, MidiBuffer &midiMessages)
{
avbsBuffer.addSamples(buffer);
if (avbsBuffer.getSize() >= desiredBlockSize)
{
avbsBuffer.popSamples(desiredBlockSize, buffer);
processBlockInternal(buffer, midiMessages);
}
else
{
// fill buffer wth zeros
buffer.applyGain(0);
}
}
The CircularAudioBuffer class in its entirety looks like this
class CircularAudioBuffer
{
public:
CircularAudioBuffer(int numChannels, int maxNumSamples): internalBuf(numChannels, maxNumSamples * 2),
fifo(maxNumSamples*2)
{}
void addSamples(AudioBuffer<float>& buf);
void popSamples(int numSamples, AudioBuffer<float>& bufToOverwrite);
int getSize() { return fifo.getNumReady() }
void setSize(int numChannels, int numSamples)
{
fifo.setTotalSize(numSamples*2);
fifo.reset();
internalBuf.setSize(numChannels, numSamples * 2);
internalBuf.clear();
}
void clear()
{
fifo.reset();
internalBuf.clear();
}
private:
AudioBuffer<float> internalBuf;
AbstractFifo fifo;
};
In the addSamples and popSamples methods I just copy over the samples using AbstractFifo to keep track of all operations.
void CircularAudioBuffer::addSamples(AudioBuffer<float> &buf)
{
int start1, size1, start2, size2;
int numSamples = buf.getNumSamples();
fifo.prepareToWrite(numSamples, start1, size1, start2, size2);
if (size1 > 0)
{
for (int c = 0; c < buf.getNumChannels(); ++c)
{
internalBuf.copyFrom(c, 0, buf.getReadPointer(c) + start1, size1);
}
}
if (size2 > 0)
{
for (int c = 0; c < buf.getNumChannels(); ++c)
{
internalBuf.copyFrom(c, size1, buf.getReadPointer(c) + start2, size2);
}
}
fifo.finishedWrite(size1+size2);
}
void CircularAudioBuffer::popSamples(int numSamples, AudioBuffer<float> &bufToOverwrite)
{
int start1, size1, start2, size2;
fifo.prepareToRead (numSamples, start1, size1, start2, size2);
if (size1 > 0)
{
for (int c = 0; c < bufToOverwrite.getNumChannels(); ++c)
{
bufToOverwrite.copyFrom(c, 0, internalBuf.getReadPointer(c) + start1, size1);
}
}
if (size2 > 0)
{
for (int c = 0; c < bufToOverwrite.getNumChannels(); ++c)
{
bufToOverwrite.copyFrom(c, size1, internalBuf.getReadPointer(c) + start2, size2);
}
}
fifo.finishedRead (size1 + size2);
}
With this implementation though the audio is heavily distorted even on “normal” hosts.
I really can’t seem to grasp what the problem is here, but that could also be because I’ve misunderstood something fundamental. Any and all help is greatly appreciated!