Super specific and nasty VST3-Ableton bug - Progress achieved

I’m encountering a highly specific and unusual bug that’s been eluding me for days. Despite my extensive experience in development, this issue is a first for me. The problem occurs exclusively within the Ableton Live environment, affecting both VST3 on macOS and Windows platforms. Here’s a detailed breakdown:

  • Environment: The issue is observed in Ableton Live, specifically with VST3 plugins. It affects both Ableton Live 11 and 12, across macOS and Windows.
  • Bug Description: The core of the problem lies in handling meta parameters. I have designed a meta parameter that adjusts the values of other parameters internally, without these changes being reported to the host (Ableton Live). This mechanism works flawlessly in all DAWs except for Ableton Live VST3.
  • Trigger Condition: The bug manifests when I initiate a ‘begin change gesture’ on a parameter (referred to as a slave) that was previously modified by the meta parameter (referred to as the master), without the host being notified of this change. Following this action, JuceVST3Component::processParameterChanges() is unexpectedly called. This method then executes setValueAndNotifyIfChanged(), which erroneously applies the value from the last automation event to the parameter. This results in the parameter’s value reverting to its last reported state, rather than maintaining the new value set by the meta parameter.
  • Additional Observation: This issue occurs immediately after the closure of the JUCE_VST3_EMULATE_MIDI_CC_WITH_PARAMETERS block, which may or may not be related to the problem.

Further Oddities Noted:

  1. This problem was not present in JUCE version 7.0.5.
  2. The issue is specifically tied to parameters that are slaves to a meta parameter. Interestingly, when parameters are adjusted through preset changes (which also aren’t reported to the host), this bug does not occur. In such cases, initiating a ‘beginGesture’ does not lead to the parameter value being reset to its previously reported value.
  3. Despite numerous attempts, I am unable to replicate this issue in a new simplified JUCE project despite my best efforts to replicate all the conditions i can think of. In that project “processParameterChanges” is not registering changes in the slave parameters and numParamsChanged is 0 when i send the begin gesture - unlike my original project.

I am using the last develop tip.

I’m at my wit’s end trying to diagnose and resolve this peculiar bug. If anyone has insights or suggestions on potential areas to investigate or solutions, your expertise would be greatly appreciated. The specificity of the issue to Ableton Live’s handling of VST3 plugins and its absence in earlier versions of JUCE suggests a complex interaction at play. Your thoughts and guidance on tackling this would be invaluable.

1 Like

last week I reported a bug in Ableton Lives parameter handling. It is more straightforward (any old parameter) but it feels like it might be related:

--------------------------------------- Ableton Support #2890650 -----------------------------

I am a plugin developer.
My plugins GUI is experiencing jitter when I am moving controls.
I placed logging diagnostic code in my plugin.
I observed that while I am dragging a control on the GUI that Ableton Live will occasionally call my plugins setParamNormalized() method with an out-of-date parameter value.

for example, as I dragged a knob my plugin called performEdit() to notify the DAW with the following values…

param 0.310000 => DAW
param 0.315000 => DAW
param 0.320000 => DAW
param 0.325000 => DAW

at that point Ableton calls back into my plugin with:

setParamNormalized(51, 0.315000)

note that this is NOT the most up-to-date value of this parameter. It is the value the plugin sent 2 iterations earlier. This causes the control to ‘jitter’ as it jumps backward to an earlier value. This is very irritating behavior.

The DAW is not meant to echo parameter updates back to the Editor (GUI).

Additional information: I notice that Ableton sends these updates to the GUI at the same time it is updating the processor on the real-time thread with the same value.

1 Like

OK. I got it to not work :crazy_face:!
I mean - to the bug is now manifested in the following project:

with the amazing help of @eyalamir

This is a project to show a bug that specifically happens in Ableton Live (11 and 12) on VST3 - Windows AND Mac. On the latest develop tip of JUCE.

The bug is as follows:

  1. A meta parameter (we will call it MasterParam) moves a slave paremeter (or several) we will call it “SlaveParam” - but does not report the change to the host.
  2. The slave param sends a beging gesture change to the host
  3. the host then sets the SlaveParam to the previously reported value - overriding its un-reported parameter

This only happens when there are 65 parameters or more in the plug-in. not on vst2 or au.

The theory is that this has to do with
JUCE_VST3_EMULATE_MIDI_CC_WITH_PARAMETERS

2 Likes

Perhaps it’s worthwhile doing a git bisect to figure out at which point it went from working → broken?

Thanks for providing some sample code to test out. I tried out the example project on both JUCE 8 and 7.0.5, but I get the same behaviour in both cases. Can you confirm that you see the desired behaviour in the example project with JUCE 7.0.5?

Looking at the code, I’m not sure that I’d expect this to work in the way that you described. For background, see this section of the VST3 docs. In particular:

No automated parameter must influence another automated parameter!

If you want your macro parameter to influence other parameters, then it must not be automatable. You can make the parameter non-automatable using AudioParameterFloatAttributes::withAutomatable (false).

Additiionally, changes to other parameters should be signalled to the host somehow when they are changed (normally with setValueNotifyingHost). If you fail to do this, then the host and the plugin will get out-of-sync, and the host may display the wrong parameter value to the user. So, in your example, your non-macro parameter should be updated with beginGesture, endGesture, and setValueNotifyingHost when the macro slider is moved.

I’m not sure exactly why the behaviour changes when the plugin has more than 64 parameters. However, I believe that Live’s behaviour could be considered conformant to the VST3 spec in both cases.

In the VST3 architecture, the ‘editor’ and ‘audio processor’ are allowed to be two competely separate components, and for this reason, if the plugin’s editor informs the host that a parameter has changed, then the host needs to forward this change on to the processor, so that the processor can update itself accordingly. It looks like, when there are more than 64 parameters, Live will send the processor what it believes to be the current parameter value in response to a call to beginChangeGesture. When there are fewer parameters, it doesn’t do this. I think either approach is fine. Normally, on beginChangeGesture, the processor’s parameter value will already match the host’s parameter value. Therefore, if the host chooses to forward the value, it will have no effect (the processor’s parameter is already at that value), and if the host chooses not to forward the value, that will also have no effect (again, the processor’s parameter already has the correct value).

Based on all of that, I think that the plugin code should be updated as follows:

  • Mark the meta parameter non-automatable
  • Whenever any parameter is changed, notify the host so that the plugin and host models are consistent
1 Like

void MetaBugAudioProcessorEditor::sliderValueChanged (Slider* slider)
{
if (slider == &metaSlaveSlider)
{
audioProcessor.metaSlaveParam->setValueNotifyingHost(slider->getValue());
}
else if (slider == &metaMasterSlider)
{

    audioProcessor.metaMasterParam->*setValueNotifyingHost*(slider->getValue());
    audioProcessor.metaSlaveParam->setValue(audioProcessor.metaMasterParam->getValue());
}

}
void MetaBugAudioProcessorEditor::sliderDragStarted (Slider* slider)
{
if (slider == &metaSlaveSlider)
{
audioProcessor.metaSlaveParam->beginChangeGesture();
}
else if (slider == &metaMasterSlider)
{
audioProcessor.metaMasterParam->beginChangeGesture();
}
}
void MetaBugAudioProcessorEditor::sliderDragEnded (Slider* slider)
{
if (slider == &metaSlaveSlider)
{
audioProcessor.metaSlaveParam->endChangeGesture();
}
else if (slider == &metaMasterSlider)
{
audioProcessor.metaMasterParam->endChangeGesture();
}
}

Assaf, is the repo code updated based on reuk suggestions? It appears it has the setValueNotifyingHost, beginChangeGesture, endChangeGesture implemented, can you confirm?

Hi, curious if you heard from Ableton on this or made any progress on this? I’m working on my own VST3 implementation and I think I am encountering the same behavior.

I haven’t heard anything.

A related thread: Jumpy/inconsistent parameter value changes when using ParameterAttachment on VST3 - #11 by JeffMcClintock

1 Like