| @@ -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) | |||
| }; | |||