Programs-Parameter doing wired stuff

For me this looks like a bug in JUCE.
I tried to connect my own presetsystem with the inhouse presets of vst3 and au. So that presets can be triggered from the daw and that the name of the plugin is the preset name. If I load the plugin in DAWs like Logic or FL-studio and use their preset system evrything works fine.

But if I try it by using the program-parameter at the end of the plugins parameters, wired stuff happens, wrong presets are trigged or in same case it even crashes the plugin.

While searching for the error I found that it seems that the program-parameter is sending wrong values.

Here my testingcode for the program functions:

int currentPreset = 0;

int DuckAudioProcessor::getNumPrograms(){
    return 5;
}
int DuckAudioProcessor::getCurrentProgram(){
    return currentPreset;
}
void DuckAudioProcessor::setCurrentProgram (int index){
    DBG("setProg");
    DBG(index);
    currentPreset = index;
}

If I now move the slider I get the following values:
1 2 4
moving back to start gives a 0
so it jumps immediately to 4 from to and for the last position it dosen’t give a value at all.

Which version of JUCE are you using? I fixed an issue to do with program parameter normalisation here:

If you’re seeing the issue on develop, please provide the set of steps you are following to trigger the issue. In particular, we will need to know the plugin format you’re using, the host, and ideally the operating system too. We’ll also need to know how you’re updating the program parameter, e.g. from a control in the host, or from a control in your plugin.

I use 6.1.2 Master branche on Mac OS 11.6.
I tried it in Ableton, GarageBand, FLStudio and AudioPluginHost. GarageBand (AU) and FLStudio(AU and VST3) had now issues, as I could trigger it from the DAWs menu.
In Ableton (VST3) and AudioPluginHost (VST3) I updated withe programs-parameter in the parameterlist (not from the gui)

I tried your fixe, but it still skips numbers.

Thanks, I can reproduce the issue.

This should now be fixed on develop:

Tried it and so far it seems to work as expected :+1:

I just came across this because a user reported that one of our plugins loads the wrong preset on program changes. It seems like the issue is not fixed, here is what happens:

Ableton 12 → Midi Clip with PGM Change message → Plugin

My plugin reports 256 presets. In the JUCE VST3 wrapper info.stepCount is set in the constructor of the ProgramChangeParameter: JUCE/modules/juce_audio_plugin_client/juce_audio_plugin_client_VST3.cpp at 501c07674e1ad693085a7e7c398f205c2677f5da Ā· juce-framework/JUCE Ā· GitHub

Now when Ableton sends a Program Change message it gets denormalised using info.stepCount in the function here: JUCE/modules/juce_audio_plugin_client/juce_audio_plugin_client_VST3.cpp at 501c07674e1ad693085a7e7c398f205c2677f5da Ā· juce-framework/JUCE Ā· GitHub

But the normalised value I’m getting seems to be normalised using the Standard Program Change range (0-127). So finally when setCurrentProgram() gets called in my processor I end up with a Program multiplied by 2.

Who’s to blame? Either Ableton sends the wrong normalised value (but according to the standard MIDI Program Change messages are 0-127) or JUCE handles it wrong?
BTW in Reaper everything works fine but Reaper seems to check for the number of programs and normalises based on that number.

I’m curious how you think that a range from 0-127 (so 128 discrete values) can be mapped to 256 values without any gaps. Can you show us the math?

Look at the code snippets I linked above, it happens in the denormalise function, which is here to exact:

And info.stepCount is set here:

let’s say you normalise a value of 1 using 128 programs → 1/128.
Now you denormalise using 256 programs → 1/128 * 256 = 256/128 = 2.

So it looks like either the value is not correctly normalised (using 128 programs) because Ableton doesn’t check how many programs a plugin has and just uses the MIDI standard - or JUCE doesn’t correctly denormalise it in this case. In any case it doesn’t work as expected :wink:

So you expect a value that can only be between 0 and 127 to map to a new range of 0 to 255 without gaps?

Can you create me a simple map from 0-3 (to keep it simple) that maps to 0-7?

What you ask is impossible.

I think you are getting me totally wrong here: I’m asking for either Ableton to correctly normalise the value or JUCE to correctly denormalise it. I’m not expecting it to work this way. Yes, at the moment there are gaps because it is not correct.

The only thing I can do to fix this is returning 128 in getNumPrograms() (and handle the presets accordingly). But there is nothing about that in the JUCE documentation and everyone who is overriding getNumPrograms() and returning anything else than 128 will get bit by this!

There is no mathematical solution to this. There is no way to fix reality with code. You can’t map 0-127 to 0-255 without having gaps. It’s impossible.

You claim it’s because Ableton or JUCE don’t convert values correctly, so I’m asking you again how a formula can map something from one discrete range to a larger discrete range without having gaps?

Weā€˜ve all been on the same page from the start here: mapping 0-127 to 0-255 without gaps simply isn’t mathematically possible. My question was never about ā€œfixingā€ that, but about who is doing what: is Ableton sending a value normalised to 128 while JUCE assumes numPrograms, or is JUCE’s VST3 wrapper making an incorrect assumption about how the host normalises program changes? In other words, I’m trying to figure out whether this is a JUCE-side issue or simply undefined behaviour that every host handles differently.

I have a feeling itā€˜s the latter and in this case this should be documented so others donā€˜t end up in a discussion here.

Maybe the JUCE team should add an assertion to prevent this confusion if the number of programs reported by a plugin exceeds 128.

This thread here was actually helpful:

Thanks for the clarification and for the pointers — understood.
I can see this thread is tightly scoped around a specific JUCE/VST3 behaviour, and my broader line of questioning sits outside that boundary. I didn’t intend to derail the discussion.
I’ll step back here and keep any follow-up exploration framed in a more appropriate context elsewhere. Appreciate the time and input.

1 Like