I have a plugin with a spectrum analyser… the spectrum runs on its own thread and asks for a FIFO from the audio processor ~50 times a second.
In my audio processor I have the following code to add to the FIFO:
void processBlock(AudioBuffer<float>& buffer, MidiBuffer& midiMessages)
{
// get number of samples, channel data, etc...
// ...
for (int i = 0; i < numSamples; i++)
{
float mono = 0.5f * (leftChannel[i] + rightChannel[i]);
// fifo is a std::vector and private member of the processor class
fifo.push_back(mono);
}
}
Also in the processor:
// size parameter is the number of samples/bins the FFT (in the Spectrum class) requires
std::vector<float> getFIFO(int size)
{
if (fifo.size() < size)
// not enough samples in fifo yet... return empty vector
return {};
// calculate the difference in size between the fifo size and the required size
int difference = fifo.size() - size;
// rotate the vector so the most recent <size> samples are at the front
std::rotate(fifo.begin(), fifo.begin() + difference, fifo.end());
// resize the vector to the required size
fifo.resize(size); // [1]
return fifo; // [2]
}
The above method is called repeatedly by the Spectrum class which then processes the FIFO to produce frequency bins etc.
However, using this method an issue can arise where, during the execution of getFIFO
, more samples are added to the FIFO after resizing it, and before returning it (between points [1] and [2]) because the audio thread is still running in the background…
To solve this issue I simply took a copy of the current FIFO at the start of getFIFO
, like so:
// size parameter is the number of samples/bins the FFT (in the Spectrum class) requires
std::vector<float> getFIFO(int size)
{
// get a copy of the fifo vector
std::vector<float> fifoCopy = fifo;
if (fifoCopy.size() < size)
// not enough samples in fifo yet... return empty vector
return {};
// calculate the difference in size between the fifo size and the required size
int difference = fifoCopy.size() - size;
// rotate the vector so the most recent <size> samples are at the front
std::rotate(fifoCopy.begin(), fifoCopy.begin() + difference, fifoCopy.end());
// resize the vector to the required size
fifoCopy.resize(size); // [1]
return fifoCopy; // [2]
}
This does solve the issue and guarantees that the returned vector always has the correct size. However I feel there may be a better, more JUCE-y way of achieving this. Would anyone be able to suggest a better method?