| @@ -233,7 +233,19 @@ public: | |||||
| static Vst::UnitID getUnitID (const AudioProcessorParameterGroup* group) | static Vst::UnitID getUnitID (const AudioProcessorParameterGroup* group) | ||||
| { | { | ||||
| return group == nullptr ? Vst::kRootUnitId : group->getID().hashCode(); | |||||
| if (group == nullptr || group->getParent() == nullptr) | |||||
| return Vst::kRootUnitId; | |||||
| // From the VST3 docs: | |||||
| // Up to 2^31 parameters can be exported with id range [0, 2147483648] | |||||
| // (the range [2147483649, 429496729] is reserved for host application). | |||||
| auto unitID = group->getID().hashCode() & 0x7fffffff; | |||||
| // If you hit this assertion then your group ID is hashing to a value | |||||
| // reserved by the VST3 SDK. Use a different group ID. | |||||
| jassert (unitID != Vst::kRootUnitId); | |||||
| return unitID; | |||||
| } | } | ||||
| int getNumParameters() const noexcept { return vstParamIDs.size(); } | int getNumParameters() const noexcept { return vstParamIDs.size(); } | ||||
| @@ -263,6 +275,21 @@ private: | |||||
| { | { | ||||
| parameterGroups = audioProcessor->getParameterTree().getSubgroups (true); | parameterGroups = audioProcessor->getParameterTree().getSubgroups (true); | ||||
| #if JUCE_DEBUG | |||||
| auto allGroups = parameterGroups; | |||||
| allGroups.add (&audioProcessor->getParameterTree()); | |||||
| std::unordered_set<Vst::UnitID> unitIDs; | |||||
| for (auto* group : allGroups) | |||||
| { | |||||
| auto insertResult = unitIDs.insert (getUnitID (group)); | |||||
| // If you hit this assertion then either a group ID is not unique or | |||||
| // you are very unlucky and a hashed group ID is not unique | |||||
| jassert (insertResult.second); | |||||
| } | |||||
| #endif | |||||
| #if JUCE_FORCE_USE_LEGACY_PARAM_IDS | #if JUCE_FORCE_USE_LEGACY_PARAM_IDS | ||||
| const bool forceLegacyParamIDs = true; | const bool forceLegacyParamIDs = true; | ||||
| #else | #else | ||||
| @@ -443,6 +443,24 @@ void AudioProcessor::checkForDuplicateParamID (AudioProcessorParameter* param) | |||||
| #endif | #endif | ||||
| } | } | ||||
| void AudioProcessor::checkForDuplicateGroupIDs (const AudioProcessorParameterGroup& newGroup) | |||||
| { | |||||
| ignoreUnused (newGroup); | |||||
| #if JUCE_DEBUG | |||||
| auto groups = newGroup.getSubgroups (true); | |||||
| groups.add (&newGroup); | |||||
| for (auto* group : groups) | |||||
| { | |||||
| auto insertResult = groupIDs.insert (group->getID()); | |||||
| // If you hit this assertion then a group ID is not unique | |||||
| jassert (insertResult.second); | |||||
| } | |||||
| #endif | |||||
| } | |||||
| const Array<AudioProcessorParameter*>& AudioProcessor::getParameters() const { return flatParameterList; } | const Array<AudioProcessorParameter*>& AudioProcessor::getParameters() const { return flatParameterList; } | ||||
| const AudioProcessorParameterGroup& AudioProcessor::getParameterTree() const { return parameterTree; } | const AudioProcessorParameterGroup& AudioProcessor::getParameterTree() const { return parameterTree; } | ||||
| @@ -461,6 +479,7 @@ void AudioProcessor::addParameter (AudioProcessorParameter* param) | |||||
| void AudioProcessor::addParameterGroup (std::unique_ptr<AudioProcessorParameterGroup> group) | void AudioProcessor::addParameterGroup (std::unique_ptr<AudioProcessorParameterGroup> group) | ||||
| { | { | ||||
| jassert (group != nullptr); | jassert (group != nullptr); | ||||
| checkForDuplicateGroupIDs (*group); | |||||
| auto oldSize = flatParameterList.size(); | auto oldSize = flatParameterList.size(); | ||||
| flatParameterList.addArray (group->getParameters (true)); | flatParameterList.addArray (group->getParameters (true)); | ||||
| @@ -481,9 +500,12 @@ void AudioProcessor::setParameterTree (AudioProcessorParameterGroup&& newTree) | |||||
| { | { | ||||
| #if JUCE_DEBUG | #if JUCE_DEBUG | ||||
| paramIDs.clear(); | paramIDs.clear(); | ||||
| groupIDs.clear(); | |||||
| #endif | #endif | ||||
| parameterTree = std::move (newTree); | parameterTree = std::move (newTree); | ||||
| checkForDuplicateGroupIDs (parameterTree); | |||||
| flatParameterList = parameterTree.getParameters (true); | flatParameterList = parameterTree.getParameters (true); | ||||
| for (int i = 0; i < flatParameterList.size(); ++i) | for (int i = 0; i < flatParameterList.size(); ++i) | ||||
| @@ -1487,10 +1487,11 @@ private: | |||||
| #endif | #endif | ||||
| bool textRecursionCheck = false; | bool textRecursionCheck = false; | ||||
| std::unordered_set<String> paramIDs; | |||||
| std::unordered_set<String> paramIDs, groupIDs; | |||||
| #endif | #endif | ||||
| void checkForDuplicateParamID (AudioProcessorParameter*); | void checkForDuplicateParamID (AudioProcessorParameter*); | ||||
| void checkForDuplicateGroupIDs (const AudioProcessorParameterGroup&); | |||||
| AudioProcessorListener* getListenerLocked (int) const noexcept; | AudioProcessorListener* getListenerLocked (int) const noexcept; | ||||
| void updateSpeakerFormatStrings(); | void updateSpeakerFormatStrings(); | ||||