Changing a parameter value when another is changed?

Hello. I have been trying to make a VST3 controller plugin of sorts and I have come up against a strange issue. Let me explain…

I have some buttons in my GUI, that allow me to switch between different “patches”, but this is not really important beyond them changing a parameter in the APVTS called ToggleState. Now the idea is that you can slave another instance of the plugin to this ToggleState parameter. So this parameter being updated in the host is critical to this ability. At least, using this method of doing things.

Now… additionally I have implemented some boolean parameters in the APVTS which when changed, should change the ToggleState parameter. So that I can midi learn these parameters in the host (REAPER).

And now here is the issue. If I click the buttons in the GUI, the ‘setValueNotifyingHost’ method seems to work correctly, however… if just the boolean parameters change when I press buttons on my midi controller using midi learn, the ToggleState value is not updated. But the exact same code is executing in the audio processors ‘parameterChanged’ method since it calls a method called ‘toggle’ which handles this behaviour - the same as what the editor calls when a button is pressed.

Really confused about this if I am honest. Any help would be appreciated.

Thanks.

I will just point out that I have implemented a way of solving the immediate problem with midi. I just found it odd that I could change the value through the GUI, but not with the ‘parameterChanged’ method. This also just moves the problem, since other parameters still are not being updated for the same reason. Gah so frustrating. Yes, any help or explanation would be great. I am trying to make it so that when I switch between patches using a midi controller, parameters will be updated for parameter modulation in the host.

SOLVED! It is because I wasn’t calling it from the message thread. Used ‘juce::MessageManager::callAsync’ to call the ‘toggle’ method from a lambda. :).

Forget my edits, problem fixed. Sorry.

I add this fyi, in case you find problems later on. What you see is likely caused by this in the VST3 wrapper:


inParameterChangedCallback is thread-local, so if you set a parameter in the change callback of another one, the host won’t know. Additionally, Cubase and Nuendo ignore parameter changes sent from non-message threads. A warning in the VST docs underlies all this:

Audio units have a concept for this (metaparameters), VST doesn’t. Your solution works because it defers the change. It has another issue though: callAsync allocates, which is generally a bad idea on the audio thread. Here eyalamir gives a timer-based solution to a similar problem. In my experience, the deferred solutions mostly work, until you do something silly like reading both parameters at the same time, or recording one while reading the other. Still, given the format explicitly forbids this, you could always find a host (or a future version of it) that complains in uglier manners.

2 Likes

Thanks for the information. When I started I wasn’t aware that this method also can be called from the audio thread and also that you should not do these meta parameters in VST3. I migrated most of our plugins from VST2 to the VST3 format. Meta parameters always worked in the past with AU, AAX, and VST2.

We already removed this in the code and solved it on the UI. Unfortunately, this is a requirement a lot of plugins have.
Yes, we have solutions like lock-free queues and timers. But this increases the complexity of the code and makes debugging harder. Also, you always have to think about the offline rendering case where you should not use timers.

I wanted to write some comments about the VST3 format, but I better leave it :slight_smile: I have a lot of hope for the new CLAP plugin format. I see a lot of advantages.

Aha! Now that does make sense. Thank you for your clear and concise reply. I will look into this now. :D.