Timur Doumler Talks on C++ Audio (Sharing data across threads)

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:

2 Likes