Allocation and locks in Synthesiser::findVoiceToSteal

    // this is a list of voices we can steal, sorted by how long they've been running
    Array<SynthesiserVoice*> usableVoices;
    usableVoices.ensureStorageAllocated (voices.size());

and

    /** Increases the array's internal storage to hold a minimum number of elements.

        Calling this before adding a large known number of elements means that
        the array won't have to keep dynamically resizing itself as the elements
        are added, and it'll therefore be more efficient.
    */
    void ensureStorageAllocated (int minNumElements)
    {
        const ScopedLockType lock (getLock());
        values.ensureAllocatedSize (minNumElements);
    }

This both locks and allocates.
This is called from processBlock too.
I’m not sure what other options are usable here, since voices.size() is not known at compile time…

Iterrate through the voices and determine which one you want to instantly stop, then return it. Alternatively you can just use it as a method to stop a voice and then return a spare one, allocated as a set of voices to use only when youve ran out. But you should also stop it so you dont run out or return nullptr etc.

juce::Array takes a CriticalSection type as a template parameter; its default is a DummyCriticalSection which does nothing when locked.

Personally I would keep track of active voices with an std::atomic.

The worst lock is actually in Synthesiser::processNextBlock.
(And similar in MPESynthesiser).

Ideally, that would have been a SpinLock or something that doesn’t involve a system call. Or even better - no lock at all. :slight_smile:

1 Like