Program change bug in JUCE VST3 wrapper (v5.0.2)?

Hi all,

I think there’s a little bug in the JUCE VST3 wrapper that causes erratic behaviour when handling presets.

In line 461 of juce_VST3_Wrapper.cpp, we convert the (integer) program number to a floating point representation [0, 1]:

setParamNormalized (paramPreset, static_castVst::ParamValue (pluginInstance->getCurrentProgram()) / static_castVst::ParamValue (numPrograms - 1));

Then in line 1891, we do the inverse, taking the float [0,1] and mapping it back to an integer program number:
const int numPrograms = pluginInstance->getNumPrograms();
const int programValue = roundToInt (value * numPrograms);

This mapping seems to cause the wrong integer program number as we divide by (numPrograms-1) but multiply by (numPrograms) instead of (numPrograms-1). Shouldn’t this be symmetric?

I have seen cases where Cubase reads the program number and writes it back again a little later (and has the intermediate float representation) whenever an ‘updateHostDisplay()’ is called, randomly changing presets due to the above.

btw the scaling issue is present in both the master as well as the develop branch.

Furthermore, if I change it to const int programValue = roundToInt(value * (numPrograms-1)), the erratic program switching issues related to VST3 presets disappear and everything seems to work as expected.

Could you guys please confirm that scaling by (numPrograms-1) is indeed the intended behavior?

Thank you for reporting this bug. This is now fixed on the develop branch with commit 4b4b171.

Awesome, thanks Fabian!

Reviving this topic because I want to ask @djb: how does your plug-in obtain notification that Cubase has set that parameter / changed program?

Is setCurrentProgram() called?

We basically rely on a call to AudioProcessor::setCurrentProgram(int index). Following that call, we do a couple of things (but that is quite specific to how we handle a bank of programs and their states):

  1. All current parameter values are read from the array of AudioProcessorParameters in the plugin, and stored in our plugin program bank state;
  2. We change the program index of the plugin program bank state;
  3. We re-instate all AudioProcessorParameter values from the newly selected program.

Thank you for your answer, my problem is that setCurrentProgram() seems to be never called at all.

Can you please tell what steps you take in Cubase to make it happen in your plug-in?

I’m not an expert of Cubase, what I have tried is to put a MIDI program change along the path of the plug-in, but that did not seem to have any effect.

I have not seen any issues with that function not being called… That said, we’re not using plugins that accept midi so there could be a difference there.

Does it get called in other hosts? If not, perhaps the setCurrentProgram() is not overridden correctly?

Cheers,
Jeroen

Thanks, I fear that my question is much more basic that that.

Provided that adding a MIDI Program Change is not the right way to trigger a call to setCurrentProgram()
what actions should I do in my Cubase to expect it to be called instead?

As I said, I’m not much an expert with this program/preset system of Cubase so I don’t even know where to look.

SetCurrentProgram will AFAIK get called when a user selects one of the presets of the plugin from within the host program (assuming you have multiple programs in your plugin).

For MIDI program changes, you probably need to process the incoming midi stream and detect a midi program change, and do whatever needs to be done? Just guessing here as I don’t have experience with that.

That’d be soo easy if it were just like that, and it was, until VST3 has been introduced.
In VST3, Steinberg decided that dealing with MIDI was basically a prerogative of the DAW rather than the plug-in, and for example a VST3 plug-in now obtains the actions of MIDI CC messages only via automated parameters.

the JUCE wrapper does a good job at picking those up and translating them back into MIDI messages, that are piped through the processBlock() callback exactly like it happens for all other formats, but unfortunately Program Changes require yet another such bodge which has not been (fully) developed into JUCE (yet?)

It’s to assess how much work is yet to be done, and possibly do it myself, that I’m now playing with this stuff: it seems that a way to obtain program changes from VST3 hosts is to tap into this Program feature, but so far I have not been able to even expose those programs to be visible in Cubase, even in the most simple of the implementations:

int Vst3pcTestAudioProcessor::getNumPrograms()
{
    return 128;
}

int Vst3pcTestAudioProcessor::getCurrentProgram()
{
    return m_currentProgram;
}

void Vst3pcTestAudioProcessor::setCurrentProgram (int index)
{
    m_currentProgram = index;
}

const String Vst3pcTestAudioProcessor::getProgramName (int index)
{
    return String (index);
}

void Vst3pcTestAudioProcessor::changeProgramName (int index, const String& newName)
{
    DBG (newName);
}

My intention with the above code is to expose 128 such programs in my AudioProcessor, each having a name made simply of a string containing its number, and to store the index of the currently selected program in the m_currentProgram member variable.

The plug-in is derived directly from the default plug-in project created by Projucer. I would have expected the Program names to be listed in the green area shown in the picture below, but that remains empty.

Am I even looking in the right place?