Realtime deallocation question for SamplerPluginDemo

Hi there,

In another thread there is a brief exchange about this but the thread grew too long I didn’t want to slide it with a long question.

The part that interested me is the FIFO solution to swap the resource on the audio thread which results in the non-realtime thread deallocating it upon overwriting it. Someone asks if the Sampler Plugin Demo uses a FIFO solution suggested by @reuk, to which he replies that it uses an “incoming and outgoing buffer”.

The queue is a lock-free circular buffer. Adding an item to the queue only happens on the main thread. When adding an item, you overwrite the object that used to occupy that position in the buffer, which frees that object. When removing an item from the queue, you do a swap, so after the swap, the ‘reader’ owns the item that was at that queue position, and that queue position is occupied by the reader’s last state.

Question 1: I can see the the incoming but cannot see the outgoing buffer or anything that handles deallocation. Does this demo actually not handle deallocation? To avoid verbosity for a simple demo app or something?

class SetSampleCommand
{
public:
...
    void operator() (SamplerAudioProcessor& proc)
    {
        // Realtime thread.
        proc.readerFactory = std::move (readerFactory);
        auto sound = proc.samplerSound;
        sound->setSample (std::move (sample)); // See MPESamplerSound::setSample
...
class MPESamplerSound final
{
public:
    void setSample (std::unique_ptr<Sample> value)
    {
        // Realtime thread.
        sample = std::move (value); // Deallocation if sample != nullptr before this assign.
        setLoopPointsInSeconds (loopPoints);
    }
...
private:
    std::unique_ptr<Sample> sample; // Sample holds an audio buffer to Huge File.

Another part that interested me is Timur questioning the usage of a FIFO (for another solution) if only one object is being passed at a time.

You are only sharing the last object that was written on the GUI thread with the audio thread. Why don’t you atomically publish that one value to the audio thread? A FIFO is needed if you have a sequence of objects that are being pumped from one thread to another, but in this case there is no sequence, just a single object that is periodically updated.

Question 2: FIFO of size 1 does sound like overkill, but what’s the alternative if atomic<shared_ptr> is not lock free?

Question 3: Anyone know of any example implementations of this FIFO solution? I know it looks simple enough to just go in and do it, I’m just curious how others are doing it and if they ran into any edge cases they needed to handle.

​​

I implemented a version here: AudioFilePlayer/Source/PluginProcessor.h at master · matkatmusic/AudioFilePlayer · GitHub

1 Like

is there a way to do this without eyeballing the release pool fifo size and timer interval to avoid fifo push rejection? if we’re going lock free except for some rare case how is that better than using a mutex? unless i’m missing something here.

In my case at least I would only need to add auto release pool strategies if I wanted samples to continue playing upon reloading. Although I can’t think of a real world app that has this feature let alone implemented it lock-free.