mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-10 23:44:24 +00:00
VST3: Fixed an AudioProcessorParameterGroup bug
This commit is contained in:
parent
7c45ad695c
commit
17be524798
1 changed files with 249 additions and 106 deletions
|
|
@ -89,7 +89,7 @@ using namespace Steinberg;
|
|||
#endif
|
||||
|
||||
//==============================================================================
|
||||
class JuceAudioProcessor : public FUnknown
|
||||
class JuceAudioProcessor : public Vst::IUnitInfo
|
||||
{
|
||||
public:
|
||||
JuceAudioProcessor (AudioProcessor* source) noexcept
|
||||
|
|
@ -105,6 +105,99 @@ public:
|
|||
JUCE_DECLARE_VST3_COM_QUERY_METHODS
|
||||
JUCE_DECLARE_VST3_COM_REF_METHODS
|
||||
|
||||
//==============================================================================
|
||||
enum InternalParameters
|
||||
{
|
||||
paramPreset = 0x70727374, // 'prst'
|
||||
paramMidiControllerOffset = 0x6d636d00, // 'mdm*'
|
||||
paramBypass = 0x62797073 // 'byps'
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
Steinberg::int32 PLUGIN_API getUnitCount() override
|
||||
{
|
||||
return parameterGroups.size() + 1;
|
||||
}
|
||||
|
||||
tresult PLUGIN_API getUnitInfo (Steinberg::int32 unitIndex, Vst::UnitInfo& info) override
|
||||
{
|
||||
if (unitIndex == 0)
|
||||
{
|
||||
info.id = Vst::kRootUnitId;
|
||||
info.parentUnitId = Vst::kNoParentUnitId;
|
||||
info.programListId = Vst::kNoProgramListId;
|
||||
|
||||
toString128 (info.name, TRANS("Root Unit"));
|
||||
|
||||
return kResultTrue;
|
||||
}
|
||||
|
||||
if (auto* group = parameterGroups[unitIndex - 1])
|
||||
{
|
||||
info.id = JuceAudioProcessor::getUnitID (group);
|
||||
info.parentUnitId = JuceAudioProcessor::getUnitID (group->getParent());
|
||||
info.programListId = Vst::kNoProgramListId;
|
||||
|
||||
toString128 (info.name, group->getName());
|
||||
|
||||
return kResultTrue;
|
||||
}
|
||||
|
||||
return kResultFalse;
|
||||
}
|
||||
|
||||
Steinberg::int32 PLUGIN_API getProgramListCount() override
|
||||
{
|
||||
if (audioProcessor->getNumPrograms() > 0)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
tresult PLUGIN_API getProgramListInfo (Steinberg::int32 listIndex, Vst::ProgramListInfo& info) override
|
||||
{
|
||||
if (listIndex == 0)
|
||||
{
|
||||
info.id = paramPreset;
|
||||
info.programCount = (Steinberg::int32) audioProcessor->getNumPrograms();
|
||||
|
||||
toString128 (info.name, TRANS("Factory Presets"));
|
||||
|
||||
return kResultTrue;
|
||||
}
|
||||
|
||||
jassertfalse;
|
||||
zerostruct (info);
|
||||
return kResultFalse;
|
||||
}
|
||||
|
||||
tresult PLUGIN_API getProgramName (Vst::ProgramListID listId, Steinberg::int32 programIndex, Vst::String128 name) override
|
||||
{
|
||||
if (listId == paramPreset
|
||||
&& isPositiveAndBelow ((int) programIndex, audioProcessor->getNumPrograms()))
|
||||
{
|
||||
toString128 (name, audioProcessor->getProgramName ((int) programIndex));
|
||||
return kResultTrue;
|
||||
}
|
||||
|
||||
jassertfalse;
|
||||
toString128 (name, juce::String());
|
||||
return kResultFalse;
|
||||
}
|
||||
|
||||
tresult PLUGIN_API getProgramInfo (Vst::ProgramListID, Steinberg::int32, Vst::CString, Vst::String128) override { return kNotImplemented; }
|
||||
tresult PLUGIN_API hasProgramPitchNames (Vst::ProgramListID, Steinberg::int32) override { return kNotImplemented; }
|
||||
tresult PLUGIN_API getProgramPitchName (Vst::ProgramListID, Steinberg::int32, Steinberg::int16, Vst::String128) override { return kNotImplemented; }
|
||||
tresult PLUGIN_API selectUnit (Vst::UnitID) override { return kNotImplemented; }
|
||||
tresult PLUGIN_API setUnitProgramData (Steinberg::int32, Steinberg::int32, IBStream*) override { return kNotImplemented; }
|
||||
Vst::UnitID PLUGIN_API getSelectedUnit() override { return Vst::kRootUnitId; }
|
||||
|
||||
tresult PLUGIN_API getUnitByBus (Vst::MediaType, Vst::BusDirection, Steinberg::int32, Steinberg::int32, Vst::UnitID& unitId) override
|
||||
{
|
||||
zerostruct (unitId);
|
||||
return kNotImplemented;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
inline Vst::ParamID getVSTParamIDForIndex (int paramIndex) const noexcept
|
||||
{
|
||||
|
|
@ -140,11 +233,6 @@ public:
|
|||
bool bypassIsRegularParameter = false;
|
||||
|
||||
private:
|
||||
enum InternalParameters
|
||||
{
|
||||
paramBypass = 0x62797073 // 'byps'
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
bool isBypassPartOfRegularParemeters() const
|
||||
{
|
||||
|
|
@ -160,6 +248,8 @@ private:
|
|||
|
||||
void setupParameters()
|
||||
{
|
||||
parameterGroups = audioProcessor->getParameterTree().getSubgroups (true);
|
||||
|
||||
#if JUCE_FORCE_USE_LEGACY_PARAM_IDS
|
||||
const bool forceLegacyParamIDs = true;
|
||||
#else
|
||||
|
|
@ -235,6 +325,7 @@ private:
|
|||
LegacyAudioParametersWrapper juceParameters;
|
||||
HashMap<int32, AudioProcessorParameter*> paramMap;
|
||||
std::unique_ptr<AudioProcessorParameter> ownedBypassParameter;
|
||||
Array<const AudioProcessorParameterGroup*> parameterGroups;
|
||||
|
||||
JuceAudioProcessor() = delete;
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (JuceAudioProcessor)
|
||||
|
|
@ -247,6 +338,7 @@ static ThreadLocalValue<bool> inParameterChangedCallback;
|
|||
//==============================================================================
|
||||
class JuceVST3EditController : public Vst::EditController,
|
||||
public Vst::IMidiMapping,
|
||||
public Vst::IUnitInfo,
|
||||
public Vst::ChannelContext::IInfoListener,
|
||||
public AudioProcessorListener,
|
||||
private AudioProcessorParameter::Listener
|
||||
|
|
@ -281,6 +373,7 @@ public:
|
|||
TEST_FOR_AND_RETURN_IF_VALID (targetIID, Vst::IEditController2)
|
||||
TEST_FOR_AND_RETURN_IF_VALID (targetIID, Vst::IConnectionPoint)
|
||||
TEST_FOR_AND_RETURN_IF_VALID (targetIID, Vst::IMidiMapping)
|
||||
TEST_FOR_AND_RETURN_IF_VALID (targetIID, Vst::IUnitInfo)
|
||||
TEST_FOR_AND_RETURN_IF_VALID (targetIID, Vst::ChannelContext::IInfoListener)
|
||||
TEST_FOR_COMMON_BASE_AND_RETURN_IF_VALID (targetIID, IPluginBase, Vst::IEditController)
|
||||
TEST_FOR_COMMON_BASE_AND_RETURN_IF_VALID (targetIID, IDependent, Vst::IEditController)
|
||||
|
|
@ -325,12 +418,6 @@ public:
|
|||
}
|
||||
|
||||
//==============================================================================
|
||||
enum InternalParameters
|
||||
{
|
||||
paramPreset = 0x70727374, // 'prst'
|
||||
paramMidiControllerOffset = 0x6d636d00 // 'mdm*'
|
||||
};
|
||||
|
||||
struct Param : public Vst::Parameter
|
||||
{
|
||||
Param (JuceVST3EditController& editController, AudioProcessorParameter& p,
|
||||
|
|
@ -440,7 +527,7 @@ public:
|
|||
{
|
||||
jassert (owner.getNumPrograms() > 1);
|
||||
|
||||
info.id = paramPreset;
|
||||
info.id = JuceAudioProcessor::paramPreset;
|
||||
toString128 (info.title, "Program");
|
||||
toString128 (info.shortTitle, "Program");
|
||||
toString128 (info.units, "");
|
||||
|
|
@ -553,8 +640,8 @@ public:
|
|||
auto numPrograms = pluginInstance->getNumPrograms();
|
||||
|
||||
if (numPrograms > 1)
|
||||
setParamNormalized (paramPreset, static_cast<Vst::ParamValue> (pluginInstance->getCurrentProgram())
|
||||
/ static_cast<Vst::ParamValue> (numPrograms - 1));
|
||||
setParamNormalized (JuceAudioProcessor::paramPreset, static_cast<Vst::ParamValue> (pluginInstance->getCurrentProgram())
|
||||
/ static_cast<Vst::ParamValue> (numPrograms - 1));
|
||||
}
|
||||
|
||||
if (auto* handler = getComponentHandler())
|
||||
|
|
@ -626,6 +713,133 @@ public:
|
|||
static_cast<Vst::ParamID> (numElementsInArray (parameterToMidiController))));
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
Steinberg::int32 PLUGIN_API getUnitCount() override
|
||||
{
|
||||
if (audioProcessor != nullptr)
|
||||
return audioProcessor->getUnitCount();
|
||||
|
||||
jassertfalse;
|
||||
return 1;
|
||||
}
|
||||
|
||||
tresult PLUGIN_API getUnitInfo (Steinberg::int32 unitIndex, Vst::UnitInfo& info) override
|
||||
{
|
||||
if (audioProcessor != nullptr)
|
||||
return audioProcessor->getUnitInfo (unitIndex, info);
|
||||
|
||||
if (unitIndex == 0)
|
||||
{
|
||||
info.id = Vst::kRootUnitId;
|
||||
info.parentUnitId = Vst::kNoParentUnitId;
|
||||
info.programListId = Vst::kNoProgramListId;
|
||||
|
||||
toString128 (info.name, TRANS("Root Unit"));
|
||||
|
||||
return kResultTrue;
|
||||
}
|
||||
|
||||
jassertfalse;
|
||||
zerostruct (info);
|
||||
return kResultFalse;
|
||||
}
|
||||
|
||||
Steinberg::int32 PLUGIN_API getProgramListCount() override
|
||||
{
|
||||
if (audioProcessor != nullptr)
|
||||
return audioProcessor->getProgramListCount();
|
||||
|
||||
jassertfalse;
|
||||
return 0;
|
||||
}
|
||||
|
||||
tresult PLUGIN_API getProgramListInfo (Steinberg::int32 listIndex, Vst::ProgramListInfo& info) override
|
||||
{
|
||||
if (audioProcessor != nullptr)
|
||||
return audioProcessor->getProgramListInfo (listIndex, info);
|
||||
|
||||
jassertfalse;
|
||||
zerostruct (info);
|
||||
return kResultFalse;
|
||||
}
|
||||
|
||||
tresult PLUGIN_API getProgramName (Vst::ProgramListID listId, Steinberg::int32 programIndex, Vst::String128 name) override
|
||||
{
|
||||
if (audioProcessor != nullptr)
|
||||
return audioProcessor->getProgramName (listId, programIndex, name);
|
||||
|
||||
jassertfalse;
|
||||
toString128 (name, juce::String());
|
||||
return kResultFalse;
|
||||
}
|
||||
|
||||
tresult PLUGIN_API getProgramInfo (Vst::ProgramListID listId, Steinberg::int32 programIndex,
|
||||
Vst::CString attributeId, Vst::String128 attributeValue) override
|
||||
{
|
||||
if (audioProcessor != nullptr)
|
||||
return audioProcessor->getProgramInfo (listId, programIndex, attributeId, attributeValue);
|
||||
|
||||
jassertfalse;
|
||||
return kResultFalse;
|
||||
}
|
||||
|
||||
tresult PLUGIN_API hasProgramPitchNames (Vst::ProgramListID listId, Steinberg::int32 programIndex) override
|
||||
{
|
||||
if (audioProcessor != nullptr)
|
||||
return audioProcessor->hasProgramPitchNames (listId, programIndex);
|
||||
|
||||
jassertfalse;
|
||||
return kResultFalse;
|
||||
}
|
||||
|
||||
tresult PLUGIN_API getProgramPitchName (Vst::ProgramListID listId, Steinberg::int32 programIndex,
|
||||
Steinberg::int16 midiPitch, Vst::String128 name) override
|
||||
{
|
||||
if (audioProcessor != nullptr)
|
||||
return audioProcessor->getProgramPitchName (listId, programIndex, midiPitch, name);
|
||||
|
||||
jassertfalse;
|
||||
return kResultFalse;
|
||||
}
|
||||
|
||||
tresult PLUGIN_API selectUnit (Vst::UnitID unitId) override
|
||||
{
|
||||
if (audioProcessor != nullptr)
|
||||
return audioProcessor->selectUnit (unitId);
|
||||
|
||||
jassertfalse;
|
||||
return kResultFalse;
|
||||
}
|
||||
|
||||
tresult PLUGIN_API setUnitProgramData (Steinberg::int32 listOrUnitId, Steinberg::int32 programIndex,
|
||||
Steinberg::IBStream* data) override
|
||||
{
|
||||
if (audioProcessor != nullptr)
|
||||
return audioProcessor->setUnitProgramData (listOrUnitId, programIndex, data);
|
||||
|
||||
jassertfalse;
|
||||
return kResultFalse;
|
||||
}
|
||||
|
||||
Vst::UnitID PLUGIN_API getSelectedUnit() override
|
||||
{
|
||||
if (audioProcessor != nullptr)
|
||||
return audioProcessor->getSelectedUnit();
|
||||
|
||||
jassertfalse;
|
||||
return kResultFalse;
|
||||
}
|
||||
|
||||
tresult PLUGIN_API getUnitByBus (Vst::MediaType type, Vst::BusDirection dir, Steinberg::int32 busIndex,
|
||||
Steinberg::int32 channel, Vst::UnitID& unitId) override
|
||||
{
|
||||
if (audioProcessor != nullptr)
|
||||
return audioProcessor->getUnitByBus (type, dir, busIndex, channel, unitId);
|
||||
|
||||
jassertfalse;
|
||||
return kResultFalse;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
IPlugView* PLUGIN_API createView (const char* name) override
|
||||
{
|
||||
|
|
@ -669,8 +883,8 @@ public:
|
|||
if (auto* pluginInstance = getPluginInstance())
|
||||
{
|
||||
if (pluginInstance->getNumPrograms() > 1)
|
||||
EditController::setParamNormalized (paramPreset, static_cast<Vst::ParamValue> (pluginInstance->getCurrentProgram())
|
||||
/ static_cast<Vst::ParamValue> (pluginInstance->getNumPrograms() - 1));
|
||||
EditController::setParamNormalized (JuceAudioProcessor::paramPreset, static_cast<Vst::ParamValue> (pluginInstance->getCurrentProgram())
|
||||
/ static_cast<Vst::ParamValue> (pluginInstance->getNumPrograms() - 1));
|
||||
}
|
||||
|
||||
if (componentHandler != nullptr)
|
||||
|
|
@ -758,7 +972,7 @@ private:
|
|||
}
|
||||
|
||||
#if JUCE_VST3_EMULATE_MIDI_CC_WITH_PARAMETERS
|
||||
parameterToMidiControllerOffset = static_cast<Vst::ParamID> (audioProcessor->isUsingManagedParameters() ? paramMidiControllerOffset
|
||||
parameterToMidiControllerOffset = static_cast<Vst::ParamID> (audioProcessor->isUsingManagedParameters() ? JuceAudioProcessor::paramMidiControllerOffset
|
||||
: parameters.getParameterCount());
|
||||
|
||||
initialiseMidiControllerMappings();
|
||||
|
|
@ -1349,8 +1563,6 @@ public:
|
|||
// and not AudioChannelSet::discreteChannels (2) etc.
|
||||
jassert (checkBusFormatsAreNotDiscrete());
|
||||
|
||||
parameterGroups = pluginInstance->parameterTree.getSubgroups (true);
|
||||
|
||||
comPluginInstance = new JuceAudioProcessor (pluginInstance);
|
||||
|
||||
zerostruct (processContext);
|
||||
|
|
@ -1844,89 +2056,22 @@ public:
|
|||
}
|
||||
|
||||
//==============================================================================
|
||||
Steinberg::int32 PLUGIN_API getUnitCount() override
|
||||
{
|
||||
return parameterGroups.size() + 1;
|
||||
}
|
||||
|
||||
tresult PLUGIN_API getUnitInfo (Steinberg::int32 unitIndex, Vst::UnitInfo& info) override
|
||||
{
|
||||
if (unitIndex == 0)
|
||||
{
|
||||
info.id = Vst::kRootUnitId;
|
||||
info.parentUnitId = Vst::kNoParentUnitId;
|
||||
info.programListId = Vst::kNoProgramListId;
|
||||
|
||||
toString128 (info.name, TRANS("Root Unit"));
|
||||
|
||||
return kResultTrue;
|
||||
}
|
||||
|
||||
if (auto* group = parameterGroups[unitIndex - 1])
|
||||
{
|
||||
info.id = JuceAudioProcessor::getUnitID (group);
|
||||
info.parentUnitId = JuceAudioProcessor::getUnitID (group->getParent());
|
||||
info.programListId = Vst::kNoProgramListId;
|
||||
|
||||
toString128 (info.name, group->getName());
|
||||
|
||||
return kResultTrue;
|
||||
}
|
||||
|
||||
return kResultFalse;
|
||||
}
|
||||
|
||||
Steinberg::int32 PLUGIN_API getProgramListCount() override
|
||||
{
|
||||
if (getPluginInstance().getNumPrograms() > 0)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
tresult PLUGIN_API getProgramListInfo (Steinberg::int32 listIndex, Vst::ProgramListInfo& info) override
|
||||
{
|
||||
if (listIndex == 0)
|
||||
{
|
||||
info.id = JuceVST3EditController::paramPreset;
|
||||
info.programCount = (Steinberg::int32) getPluginInstance().getNumPrograms();
|
||||
|
||||
toString128 (info.name, TRANS("Factory Presets"));
|
||||
|
||||
return kResultTrue;
|
||||
}
|
||||
|
||||
jassertfalse;
|
||||
zerostruct (info);
|
||||
return kResultFalse;
|
||||
}
|
||||
|
||||
tresult PLUGIN_API getProgramName (Vst::ProgramListID listId, Steinberg::int32 programIndex, Vst::String128 name) override
|
||||
{
|
||||
if (listId == JuceVST3EditController::paramPreset
|
||||
&& isPositiveAndBelow ((int) programIndex, getPluginInstance().getNumPrograms()))
|
||||
{
|
||||
toString128 (name, getPluginInstance().getProgramName ((int) programIndex));
|
||||
return kResultTrue;
|
||||
}
|
||||
|
||||
jassertfalse;
|
||||
toString128 (name, juce::String());
|
||||
return kResultFalse;
|
||||
}
|
||||
|
||||
tresult PLUGIN_API getProgramInfo (Vst::ProgramListID, Steinberg::int32, Vst::CString, Vst::String128) override { return kNotImplemented; }
|
||||
tresult PLUGIN_API hasProgramPitchNames (Vst::ProgramListID, Steinberg::int32) override { return kNotImplemented; }
|
||||
tresult PLUGIN_API getProgramPitchName (Vst::ProgramListID, Steinberg::int32, Steinberg::int16, Vst::String128) override { return kNotImplemented; }
|
||||
tresult PLUGIN_API selectUnit (Vst::UnitID) override { return kNotImplemented; }
|
||||
tresult PLUGIN_API setUnitProgramData (Steinberg::int32, Steinberg::int32, IBStream*) override { return kNotImplemented; }
|
||||
Vst::UnitID PLUGIN_API getSelectedUnit() override { return Vst::kRootUnitId; }
|
||||
|
||||
tresult PLUGIN_API getUnitByBus (Vst::MediaType, Vst::BusDirection, Steinberg::int32, Steinberg::int32, Vst::UnitID& unitId) override
|
||||
{
|
||||
zerostruct (unitId);
|
||||
return kNotImplemented;
|
||||
}
|
||||
Steinberg::int32 PLUGIN_API getUnitCount() override { return comPluginInstance->getUnitCount(); }
|
||||
tresult PLUGIN_API getUnitInfo (Steinberg::int32 unitIndex, Vst::UnitInfo& info) override { return comPluginInstance->getUnitInfo (unitIndex, info); }
|
||||
Steinberg::int32 PLUGIN_API getProgramListCount() override { return comPluginInstance->getProgramListCount(); }
|
||||
tresult PLUGIN_API getProgramListInfo (Steinberg::int32 listIndex, Vst::ProgramListInfo& info) override { return comPluginInstance->getProgramListInfo (listIndex, info); }
|
||||
tresult PLUGIN_API getProgramName (Vst::ProgramListID listId, Steinberg::int32 programIndex, Vst::String128 name) override { return comPluginInstance->getProgramName (listId, programIndex, name); }
|
||||
tresult PLUGIN_API getProgramInfo (Vst::ProgramListID listId, Steinberg::int32 programIndex,
|
||||
Vst::CString attributeId, Vst::String128 attributeValue) override { return comPluginInstance->getProgramInfo (listId, programIndex, attributeId, attributeValue); }
|
||||
tresult PLUGIN_API hasProgramPitchNames (Vst::ProgramListID listId, Steinberg::int32 programIndex) override { return comPluginInstance->hasProgramPitchNames (listId, programIndex); }
|
||||
tresult PLUGIN_API getProgramPitchName (Vst::ProgramListID listId, Steinberg::int32 programIndex,
|
||||
Steinberg::int16 midiPitch, Vst::String128 name) override { return comPluginInstance->getProgramPitchName (listId, programIndex, midiPitch, name); }
|
||||
tresult PLUGIN_API selectUnit (Vst::UnitID unitId) override { return comPluginInstance->selectUnit (unitId); }
|
||||
tresult PLUGIN_API setUnitProgramData (Steinberg::int32 listOrUnitId, Steinberg::int32 programIndex,
|
||||
Steinberg::IBStream* data) override { return comPluginInstance->setUnitProgramData (listOrUnitId, programIndex, data); }
|
||||
Vst::UnitID PLUGIN_API getSelectedUnit() override { return comPluginInstance->getSelectedUnit(); }
|
||||
tresult PLUGIN_API getUnitByBus (Vst::MediaType type, Vst::BusDirection dir, Steinberg::int32 busIndex,
|
||||
Steinberg::int32 channel, Vst::UnitID& unitId) override { return comPluginInstance->getUnitByBus (type, dir, busIndex, channel, unitId); }
|
||||
|
||||
//==============================================================================
|
||||
bool getCurrentPosition (CurrentPositionInfo& info) override
|
||||
|
|
@ -2262,7 +2407,7 @@ public:
|
|||
{
|
||||
auto vstParamID = paramQueue->getParameterId();
|
||||
|
||||
if (vstParamID == JuceVST3EditController::paramPreset)
|
||||
if (vstParamID == JuceAudioProcessor::paramPreset)
|
||||
{
|
||||
auto numPrograms = pluginInstance->getNumPrograms();
|
||||
auto programValue = roundToInt (value * (jmax (0, numPrograms - 1)));
|
||||
|
|
@ -2622,8 +2767,6 @@ private:
|
|||
ScopedJuceInitialiser_GUI libraryInitialiser;
|
||||
static const char* kJucePrivateDataIdentifier;
|
||||
|
||||
Array<const AudioProcessorParameterGroup*> parameterGroups;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (JuceVST3Component)
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue