I run numeric tests on my JUCE-based plugin host using various plugins. The tests normally produce identical results on every run. After a JUCE upgrade I started seeing test failures from a certain vendor’s VST3 plugins. One or two samples are off, but exactly which ones is non-deterministic, varying from run to run. It only occurs after setting parameters. I suspect some kind of indeterminancy in when parameter changes take effect.
I found the change in behavior was introduced in commit 0d96a8b, “Workaround for VST-3 plug-ins which do not change their parameter values internally when the user changes them in the custom UI”.
Can someone tell me more about this change, and how deterministic behavior might be restored? I’m not launching the custom UIs, just making a sequence of processBlock() and setParameter() calls.
Hmmm I think the commit is correct. In fact, strictly speaking, any plug-in which strictly conforms to the VST3 SDK needs those lines.
This is because the VST3 edit controller and the VST3 audio processor keep a completely separate set of parameter values. It’s the responsibility of the host to pass on any parameter changes that were done in the editor to the plug-in so that the editor and the plug-in parameters are synced. This is why those lines are needed.
Have a look at the again example in the VST3 SDK (
VST3 SDK/public.sdk/samples/vst/again/source): put a breakpoint at
void AGainEditorView::valueChanged in
againeditor.cpp. This is the slider’s listeners callback. You will see that a change in slider does not pass the value change to the again’s audio processor. It only updates it’s own copy of the gain parameter and then informs the host (via
performEdit) that the value has been changed.
If you put another breakpoint in the loop where parameter event changes are retrieved from the
tresult PLUGIN_API AGain::process (ProcessData& data) in
again.cpp) then you will see that the host passes on the
performEdit change to the audioprocessor via the param queues. This is exactly what the commit does.
Now the problem is that many VST3s out there use some kind of wrapper library (like JUCE) which does not have this separation between the editor and the audio processor. This means that the editor will have already changed the single copy of the gain parameter - and the process function will just change it again. This is - I think - mostly ok as this double change can only happen if the user changes a parameter via the plug-ins editor (for example with the mouse) - which is bound to be inaccurate anyway. The recorded automation data will only receive the changes from the editor (so only once) and when playing back automation data we only use the parameter updates that the audio processor gets.