1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-01-10 23:44:24 +00:00

VST3 Client: Include VST2 ID in set of compatible classes when JUCE_VST3_CAN_REPLACE_VST2 is set

With this change in place:
- The compatible VST2 ID will be included in the list of compatible
  classes in the moduleinfo.json.
- getCompatibleParameterIds() will be called with the ID of the
  commpatible VST2 plugin.
This commit is contained in:
reuk 2025-05-19 20:41:36 +01:00
parent dae152ee99
commit 5d11fa5045
No known key found for this signature in database

View file

@ -643,39 +643,61 @@ public:
compatibleParameterIdMap = {};
compatibleParameterIdMap[currentPluginId] = paramMap;
if (const auto* ext = audioProcessor->getVST3ClientExtensions())
auto* ext = audioProcessor->getVST3ClientExtensions();
// If there are no extensions, we assume that no adjustments should be made to the mapping.
if (ext == nullptr)
return;
for (const auto& compatibleClass : getAllCompatibleClasses (*audioProcessor))
{
for (auto& compatibleClass : ext->getCompatibleClasses())
auto& parameterIdMap = compatibleParameterIdMap[compatibleClass];
for (auto [oldParamId, newParamId] : ext->getCompatibleParameterIds (compatibleClass))
{
auto& parameterIdMap = compatibleParameterIdMap[compatibleClass];
auto* parameter = getParameter (newParamId);
parameterIdMap[oldParamId] = parameter;
for (auto [oldParamId, newParamId] : ext->getCompatibleParameterIds (compatibleClass))
{
auto* parameter = getParameter (newParamId);
parameterIdMap[oldParamId] = parameter;
// This means a parameter ID returned by getCompatibleParameterIds()
// does not match any parameters declared in the plugin. All IDs must
// match an existing parameter, or return an empty string to indicate
// there is no parameter to map to.
jassert (parameter != nullptr || newParamId.isEmpty());
// This means a parameter ID returned by getCompatibleParameterIds()
// does not match any parameters declared in the plugin. All IDs must
// match an existing parameter, or return an empty string to indicate
// there is no parameter to map to.
jassert (parameter != nullptr || newParamId.isEmpty());
// This means getCompatibleParameterIds() returned a parameter mapping
// that will hide a parameter in the current plugin! If this is due to
// an ID collision between plugin versions, you may be able to determine
// the mapping to report based on setStateInformation(). If you've
// already done this you can safely ignore this warning. If there is no
// way to determine the difference between the two plugin versions in
// setStateInformation() the best course of action is to remove the
// problematic parameter from the mapping.
jassert (compatibleClass != currentPluginId
|| getParamForVSTParamID (oldParamId) == nullptr
|| parameter == getParamForVSTParamID (oldParamId));
}
// This means getCompatibleParameterIds() returned a parameter mapping
// that will hide a parameter in the current plugin! If this is due to
// an ID collision between plugin versions, you may be able to determine
// the mapping to report based on setStateInformation(). If you've
// already done this you can safely ignore this warning. If there is no
// way to determine the difference between the two plugin versions in
// setStateInformation() the best course of action is to remove the
// problematic parameter from the mapping.
jassert (compatibleClass != currentPluginId
|| getParamForVSTParamID (oldParamId) == nullptr
|| parameter == getParamForVSTParamID (oldParamId));
}
}
}
/* Includes all compatible classes declared in the client extensions, along with
our own ID in the case that JUCE_VST3_CAN_REPLACE_VST2 is set.
*/
static std::vector<VST3ClientExtensions::InterfaceId> getAllCompatibleClasses (AudioProcessor& processor)
{
auto result = std::invoke ([&]
{
if (auto* ext = processor.getVST3ClientExtensions())
return ext->getCompatibleClasses();
return std::vector<VST3ClientExtensions::InterfaceId>{};
});
#if JUCE_VST3_CAN_REPLACE_VST2
result.push_back (getInterfaceId (VST3InterfaceType::component));
#endif
return result;
}
//==============================================================================
inline static const FUID iid = toSteinbergUID (getInterfaceId (VST3InterfaceType::processor));
@ -1160,8 +1182,18 @@ public:
}
const auto* parameter = iter->second;
newParamID = parameter != nullptr ? audioProcessor->getVSTParamIDForIndex (parameter->getParameterIndex())
: 0xffffffff;
if (parameter == nullptr)
{
// There's a null entry in the map of compatible parameters.
// This implies a problem with the implementation of getCompatibleParameterIds - one of
// the IDs in the returned map doesn't refer to any parameter in the current plugin.
jassertfalse;
return kResultFalse;
}
// We found a compatible parameter in the map.
newParamID = audioProcessor->getVSTParamIDForIndex (parameter->getParameterIndex());
return kResultTrue;
}
@ -1221,6 +1253,8 @@ public:
// As an IEditController member, the host should only call this from the message thread.
assertHostMessageThread();
auto restartFlags = toUnderlyingType (Vst::kParamValuesChanged);
if (audioProcessor != nullptr)
{
auto* pluginInstance = getPluginInstance();
@ -1239,11 +1273,15 @@ public:
setParamNormalized (vstParamId, paramValue);
}
audioProcessor->updateParameterMapping();
if (! JuceAudioProcessor::getAllCompatibleClasses (*pluginInstance).empty())
{
restartFlags |= Vst::kParamIDMappingChanged;
audioProcessor->updateParameterMapping();
}
}
if (auto* handler = getComponentHandler())
handler->restartComponent (Vst::kParamValuesChanged | Vst::kParamIDMappingChanged);
handler->restartComponent (restartFlags);
return kResultOk;
}
@ -2947,14 +2985,7 @@ public:
//==============================================================================
bool shouldTryToLoadVst2State()
{
#if JUCE_VST3_CAN_REPLACE_VST2
return true;
#else
if (auto extensions = pluginInstance->getVST3ClientExtensions())
return ! extensions->getCompatibleClasses().empty();
return false;
#endif
return ! JuceAudioProcessor::getAllCompatibleClasses (*pluginInstance).empty();
}
bool shouldWriteStateWithVst2Compatibility()
@ -4120,29 +4151,30 @@ public:
const ScopedJuceInitialiser_GUI libraryInitialiser;
auto filter = createPluginFilterOfType (AudioProcessor::WrapperType::wrapperType_VST3);
auto* extensions = filter->getVST3ClientExtensions();
const auto compatibilityObjects = [&]
const auto compatibilityObjects = std::invoke ([&]
{
if (extensions == nullptr || extensions->getCompatibleClasses().empty())
const auto compatibleClasses = JuceAudioProcessor::getAllCompatibleClasses (*filter);
if (compatibleClasses.empty())
return Array<var>();
DynamicObject::Ptr object { new DynamicObject };
// New iid is the ID of our Audio Effect class
object->setProperty ("New", String (VST3::UID (JuceVST3Component::iid).toString()));
object->setProperty ("Old", [&]
object->setProperty ("Old", std::invoke ([&]
{
Array<var> oldArray;
for (const auto& uid : extensions->getCompatibleClasses())
for (const auto& uid : compatibleClasses)
oldArray.add (String::toHexString (uid.data(), (int) uid.size(), 0));
return oldArray;
}());
}));
return Array<var> { object.get() };
}();
});
MemoryOutputStream memory;
JSON::writeToStream (memory, var { compatibilityObjects });