Any best practices for patch switching?


#1

Hello, fellow JUCErs,

How do you usually implement glitch-safe, lock-free switch between patches of your instruments and effects?

The lock-free problem is, that switching between patches containing different content requires you to delete objects and create new ones. This can be solved if we anticipate any possible size of the content to be loaded, but that doesn’t really yield good results, since the difference could be significant - in my current case could measure in GB’s of unused allocated memory, so that’s not really an option for me. So a better solution seems to be to allocate on a different thread and when ready to switch to the new content.

But here comes the glitch part - hard switch doesn’t produce pleasant sonic results. But to fade into it, I need to basically have 2 instances of my entire plugin and on each such general change to gradually switch between them.

Or I could fully silence it, free & allocate on the same thread and gradually unmute - even if locks occur, the plugin will be silent… Nope, that couldn’t be it, because everything else on the audio thread will be late and everything that isn’t muted will glitch/clip.

So, naturally I thought - this is a pretty basic problem and most likely a lot of people in the JUCE community has tackled it before.

How do you guys do this in synths, samplers (and any other type of instruments) or effects?

Cheers,
Nikolay


#2

Keep it simple :slight_smile: I’m using AudioProcessors SuspendProcessing to switch patches that takes some time. You can fade out the current playing sounds a few milliseconds (don’t accept any new Notes while fading out). After that you can set suspendProcessing and load all the new sounds in a separate thread without affecting anything. Disable suspendProcessing when all new sounds are ready to play.


#3

I use a system where patch changes basically work like the user doing all the changes in a row. The plugin doesn’t really know the difference between a parameter change and a patch change, it’s just a whole lot of changes in a short amount of time. Making all parameter changes sound pleasant and not glitch then also makes sure patch changes sound smooth.

One thing to note for future reference is that there are a number of hosts out there that really don’t like any parameter change notifications when they initiate preset changes. Some just get confused, but others crash while most have no issues with it. For the problematic ones I make sure not to call notifyHostOfParameterChange() during preset switches.


#4

This is reasonable when you don’t load content (a synth for example). But when the difference between 2 patches is GB(s) of memory - I have to do this on another thread, because I can’t pre-allocate so much memory. How do you transition between 2 patches of a sampler for example? I can’t think of a way to smoothly fade between the samples - I’d have to create a second sampler instance (again on a new thread) and when loaded to fade the old one out and fade the new one in, simultaneously. For these cases, I think Patrick’s solution is the way to go.

I am interested, though, on synths there still might be some artefacts that can occur when quickly changing most (all) parameters at once - have you had to deal with this?


#5

I do have stuff with samples. I have a manager class keeping track of all samples, the presets just use references. If a preset switch happens, samples are kept in memory and marked for unload. Once they are no longer played back, they are unloaded. Samples marked for unload are doing a quick fadeout once no longer referenced by the preset. Usually only a few samples are still playing back on a switch, so while this uses more memory than a muted switch, I think it’s still reasonable. This was already needed before doing the preset switch system because otherwise a sample cannot be unloaded without clicks while it is playing back.

I’ve had some troubles with preset changes and interdependent parameters with my system, however sorting these out has also lead to a cleaner design. If the design was prefect, this would never be an issue and I admit I had to use workarounds for extreme cases.


#6

If you’re thinking about loading GB:s worth of samples at once, think again. Do you really need that much samples for the next second or so? If it’s a sampled instrument, there’s most probably a start and an end to the sample and why would you need to load the end before you even have started playing the start?

If building a sampler, you could just preload the first say tenth of a second of each note/sample/sound. If you organize the notes in an Array then you just do array.swap() (which virtually takes no time at all) for swapping instruments/patches.

Load the rest of the sample first when that note have started to play and you won’t have to set aside memory for notes that never will be played!

After the Array swap, all new key downs or note on’s use the new sound and when all notes of the old patch have gone to meet their note off or decayed into inaudibiliy, you can throw that old patch on the waste bin/destructor.

You need no fade, process suspension or any stuff like that, just an atomic array switch!


#7

Correct, about the sampler example. I am actually building something else right now. But I have built a sampler and I do only pre-load small portion of the overall patch’s audio resources.

As for the solution to the patch-switching problem: to switch all at once, without fading out, you have to wait for all of the notes to end… which doesn’t seem like a good idea - let’s say you have played a note with a sustain pedal down and you switch a preset, then (if I understood correctly) you have to wait that (20 sec) sustain to end before you can trigger another note (you probably disable the ability to trigger new notes, otherwise this could take even longer and you don’t want the musician to scratch their head - “Did I press that preset-switch?”), or you need to lift you foot of the pedal. Also what do you do if someone has pressed a chord of notes and switches between presets? I think you would want to keep that chord running, wouldn’t you?


#8

This is how it works. Say you have a… church organ patch loaded. Each note corresponds to one sample. No velocity layers, round robins or stuff like that in this example. You store the adress of each sample in a note Array with 128 positions, one for each note. In reality you probably have sampled at the most each third note or so and do some repitching later, so many of the notes in the note Array points to the sampe sample and the first and last positions are probably nullptr:s while your organ haven’t a range of 128 notes, but let’s keep it simple now…

You press mid C. The sample in noteArray[60] (or more precisely just the address of it) are put in another array, lets call it the voice array (it could be a circular buffer or whatever you think is appropriate.) From this voice array, the samples are read for subseq adsr-handling, repitching etc and finally put in the AudioBuffer in processBlock().

You press another key, E, and the sample address in noteArray[64] is copied to the voiceArray, which now contains two voices, C and E and finally you add noteArray[67] to the voiceArray. Now the C major chord will be heard as long as you keep your fingers down. Note that all sample access is through the voiceArray, which is iterated in each processBlock call so each note/voice is getting its due handling.

Now you long for a rockier sound and switch to the Rock organ patch. Your synth loads it in another noteArray (or just the first handful of samples for each key as outlined above). And swaps the church organ array for the rock organ array.

What happens? Nothing. The C-chord of the church organ is still being played and will still be heard as long as you keep the three keys down. Remember the samples is not read from the noteArray, but from the voiceArray whose samples are still valid as nothing has yet gone to the destructor.

Now lift the C-key and the synth engine will start the decay/release handling of that voice in voiceArray position 0. The last thing this voice does after it’s decayed below some threshold level is removing itself from the voice array.

If you now press the C-key once again, the newly loaded rock organ patch will be copied from the noteArray to the next free entry in the voiceArray and subsequently start to play. At this moment one rock organ voice/sample and three church organ voices/samples are being played (the C of the church organ is still sounding in it’s decay phase and will continue to do so the next five, ten seconds or so depending on the church size.

When at some point in the future you lift your fingers from the E and G keys and wait til they have duely faded out and removed themselves from the voiceArray, none of the church organ samples are any longer in use and the whole church organ patch can be fed to the destructor. (use ref counting or whatever feels appropriate).

Hope this better explains why you need neither fade nor silence when switching patches.