Currently hash codes for plugin parameters are not generated correctly to guarantee to be unique (up to the limit of what a Uint32 can store). It does take a little more work to so it “properly” so it won’t break, but it is possible. Here is an example of how it is currently done if you don’t use legacy indices - too bad if you’re unlucky right?:
static AudioUnitParameterID generateAUParameterID (const AudioProcessorParameter& param)
{
...
AudioUnitParameterID paramHash = static_cast<AudioUnitParameterID> (juceParamID.hashCode());
...
}
void JuceAU::addParameters()
{
...
for (auto* param : juceParameters)
{
const AudioUnitParameterID auParamID = generateAUParameterID (*param);
// Consider yourself very unlucky if you hit this assertion. The hash codes of your
// parameter ids are not unique.
jassert (paramMap.find (static_cast<int32> (auParamID)) == paramMap.end());
auParamIDs.add (auParamID);
paramMap.emplace (static_cast<int32> (auParamID), param);
Globals()->SetParameter (auParamID, param->getValue());
}
...
}
Here is a possible solution:
- When parameters are added there needs to be some way to keep track of when, eg the version hint, so each time new groups of parameters are added this version hint gets incremented so it is numerically larger to indicate newer. The version hint could just be the date the parameters were added eg 20230526.
- Once all parameters are added in the order you want them to appear in the DAW, then the hashes can be generated.
- All parameters get sorted first by version / date then alphabetically (they have to have a unique name as well, so this will produce a fixed ordering of the parameters)
- Hashes are generated using that order, and stored into each parameter.
- If a later parameter has a hash which clashes with an earlier one, a new hash needs to be generated for that parameter, eg by adding 1 until the hash is unique, then that hash is stored.
- If parameters are removed, they still need to be added to the list with fixed name and version / date, but an additional flag is needed to disable the parameter, so it does not appear anywhere else, but since a fixed ordering and hash resolution is required for the entire life of the plugin the parameter still needs to be added in the first place.
I’m in the middle of going a release which has to use legacy indices, so this isn’t currently an issue for me, and I’m happy to write the code to make this happen.
I want to also point out that “Consider yourself very unlucky if you hit this assertion. The hash codes of your parameter ids are not unique.” doesn’t reflect the reality of the situation. It is blaming the plugin author for choosing parameter ids that don’t hash uniquely, instead of taking responsibility for the choices made by the programmer that actually wrote the code that doesn’t always work and instead just asserts when there is a problem.
What would be useful in the comment is something like: “This code doesn’t work properly in all situations because a single hash like this isn’t guaranteed to be unique. It needs to be fixed in the future. Sorry if your plugin breaks because of it, it’s not your fault, but this code has now made it your problem.”