Suggestion for synth class - removing voices

Hi everyone,

I’m implementing a custom rewrite of the Synthesiser class and one of the features I wanted for my application is the ability for the user to dynamically update the number of voices on the fly. Obviously, continuity of sound while doing this isn’t always possible or a priority, but I did come up with a little function so that if you’re removing voices, it first removes voices that are currently silent. I thought this might be a handy feature to include in the Synthesiser class, or possibly this might be useful to someone else out there ¯_(ツ)_/¯

Here’s the top-level function in my plugin processor:

void AudioProcessor::updateNumVoices(const int newNumVoices)
{
	if(const int currentVoices = synth.getNumVoices(); currentVoices != newNumVoices)
	{
		if(newNumVoices > currentVoices) 
		{
			const int voicesToAdd = newNumVoices - currentVoices;
			for(int i = 0; i < voicesToAdd; ++i)
				synth.addVoice(new SynthesiserVoice);
		}
		else
		{
			synth.removeNumVoices(currentVoices - newNumVoices); // this is a custom function I added to the synth class, see below...
		}
	}
};

and here’s the removeNumVoices() function, which goes inside the synthesiser class:

void Synthesiser::removeNumVoices(const int voicesToRemove)
{
	const ScopedLock sl (lock);
	
	int voicesRemoved = 0;
	while(voicesRemoved < voicesToRemove)
	{
		int indexToRemove = -1;
		for(auto* voice : voices)
		{
			if(! voice->isVoiceActive())
			{
				indexToRemove = voices.indexOf(voice);
				break;
			}
		}
		
		if(indexToRemove > -1)
			voices.remove(indexToRemove);
		else
			voices.remove(0);
		
		++voicesRemoved;
	}
};

1 Like

It’s not a bad idea – but is it really necessary to remove voices?

Your synth voice shouldn’t really take any CPU overhead if it’s not running – so imo, you would just add your max number of voices, and then handle your voice stealing / current num voices logic in layer above at the midi handling level.

Perhaps the JUCE synth doesn’t allow you set a max number of active voices which would be another issue and I could see why this might be helpful, but you’d definitely want the processor to be grabbing that same lock so it doesn’t attempt to play a voice after you delete it.

imo some sensible locks are okay in the audio land if you’re well aware of them – but others would say it’s bad practice.

1 Like

would having extra voices not playing use extra RAM?

or is there not really any performance advantage at all to removing voices that aren’t being used?

what I’m thinking about is, say I want my plugin to be able to do 12 voices of polyphony for people who need it… but if a producer knows that they will only use 4 voices in a project, I don’t want to take up any extra computer resources for voices that are basically dormant…

hmm not unless you’re allocating wave tables or have samples in the voice or something

1 Like

I see. Okay, well, writing this function was at least a nice little exercise for me :slightly_smiling_face:

It’s not bad! I’ve had some very very memory heavy synth voices where this would have been the way to go in retrospect

1 Like

That’s what I was thinking of… I’m not sure if my current project’s individual voices will end up being memory heavy enough to justify this, but I’ll hang on to this code in case i ever need it!