construct reference-counted objects on the GUI thread (or background thread) and add them to a release pool, then use a FIFO to pass them to the audio thread where they get used. the audio thread needs a member variable of the type being passed around, which will get updated.
This pattern prevents allocations/deallocations on the audio thread, while still allowing the exchange of objects between the gui and audio thread.
struct PluginProcessor : AudioProcessor
{
DataObject::ptr dataObj = new DataObject();
Fifo<DataObject::Ptr, 50> dataObjectFifo;
void processBlock(buffer)
{
DataObject::ptr t; //nullptr by default
while( dataObjectFifo.pull(t) ) { ; }
if( t != nullptr )
dataObject = t;
dataObject->process(buffer); //or whatever processing you need done
}
};
struct GUI : Editor
{
GUI(PluginProcessor& proc) : processor(proc) { ... }
ReleasePool<DataObject::Ptr> releasePool;
PluginProcessor& processor;
void mouseUp(...) //perhaps mouseUp events is where you create new DataObjects
{
DataObject::Ptr obj = new DataObject( ... );
releasePool.add(obj); //keeps it alive
processor.dataObjectFifo.push(obj);
}
}
the DataObject might look like this:
struct DataObject : juce::ReferenceCountedObject
{
using Ptr = juce::ReferenceCountedObjectPtr<DataObject>;
std::array<float, 100> arbitraryData;
float value1 = 0.f;
int value2 = 0;
double value3 = 0.0;
juce::AudioBuffer<float> buffer;
};
No allocation/deallocation happens on the audio thread.
Usage is the only thing that happens.
I discuss this idea further here: