Question for the JUCE team - hash generation of parameters and internal defines

Hi JUCE team,

I have found this abandoned (1 year old) thread:

Can you confirm if this is a problem?

Also, I’m trying to add support for program changes in the same way that control changes are supported in VST3 (This is what Arne actually recommends: MIDI Program Change - VST 3 SDK - Steinberg Forums)

However I don’t understand under which criteria the following numbers are chosen in juce_VST3_Wrapper.cpp:

enum InternalParameters
    {
        paramPreset               = 0x70727374, // 'prst'
        paramMidiControllerOffset = 0x6d636d00, // 'mdm*'
        paramMidiProgramChangeOffset = ??????????, // ?????'
        paramBypass               = 0x62797073  // 'byps'
    };

Should it say ‘mcm*’ instead of ‘mdm*’?

To which value do you recommend me to set paramMidiProgramChangeOffset?
Would paramMidiProgramChangeOffset = 0x70676d00, // ‘pgm*’ make sense?

Thank you very much in advance

Not definitively. However, I don’t recall any reports of developers encountering VST3 parameter ID collisions. Even if there were a collision, this would trigger an assertion, so as long as the developer tested with a debugger before shipping, they’d be able to work around the issue (change the JUCE param ID). Therefore, I suspect this is unlikely to cause problems in practice.

I’m not sure how these were chosen. Changing them seems risky, though!

If I’ve understood correctly, you’re trying to add multiple program-change parameters to the plugin, one for each ‘unit’. At the moment, a JUCE VST3 has a single unit, with its program parameter set to paramPreset. It might make sense to just add the unit number to paramPreset in order to get the program parameter ID for that unit, i.e. unit 0 → paramPreset + 0, unit 1 → paramPreset + 1 etc.

Thank you for your reply reuk.

I’ve taken a deeper look at those InternalParameters. I think they can create conflicts without triggering asserts.

Here’s the breakdown (everything happens in juce_VST3_Wrapper.cpp):

Those InternalParameters hexadecimal numbers are a hash of the ASCII characters written in the comments (so it should read “mcm” instead of “mdm”, I guess it’s a typo). They are used as ParamID of some internal Vst::parameters added by JUCE as an interface to the mad design of VST3 (Bypass, Program changes (aka presets), and CC). All of this takes place in JuceVST3EditController::installAudioProcessor().

However previously JuceAudioProcessor::setupParameters() creates the ParamID of Vst::parameters for the plugin actual normal parameters. Those ParamID numbers are created as a hash of the parameter names. This is done in JuceAudioProcessor::generateVSTParamIDForParam() (called when forceLegacyParamIDs==false).

If you take a look at JuceAudioProcessor::setupParameters(), nothing checks for clashes in the Vst::parameters ParamID’s. I’ve tested it setting InternalParameters to the generateVSTParamIDForParam() value of one of my plugin parameters and this latter parameter simply got overwritten without any asserts.

To be fair, the name of the plugin parameters would have to be crazily long to clash with the values of InternalParameters but I think that it’s still a possibility and I haven’t looked at parameter groups which also may create conflicts. Additionally if you later changed the implementation of generateVSTParamIDForParam() for whatever reason, those conflicts would give you a good nightmare, so it looks risky to leave the code as it is.

If each unit is attached to a particular MIDI channel, it looks like this would imply modifying those internal parameters that handle the input CC MIDI. I have moved this discussion to VST3, Programs and MIDI Program Changes - #3 by Qfactor which has a more suitable title. I’m running out of steam right now but I’ve documented everything that I have found.

This still needs fixing otherwise you’re stuck testing out each and every type of plugin: VSTv2, VSTv3, AAXv2, AUv2, AUv3, and Clap for possible collisions every time you change or add a parameter.

The better approach would be for each type of plugin to publish which are reserved hashes to a central store, then, when a new instance of the plugin is created, no matter the plugin type, the check can be done once, not 6 times.