| @@ -81,12 +81,6 @@ using namespace Steinberg; | |||
| extern JUCE_API void setNativeHostWindowSizeVST (void* window, Component*, int newWidth, int newHeight, bool isNSView); | |||
| #endif | |||
| enum | |||
| { | |||
| kJuceVST3BypassParamID = 0x62797073, // 'byps' | |||
| kMidiControllerMappingsStartID = 0x6d636d00 // 'mdm*' | |||
| }; | |||
| //============================================================================== | |||
| class JuceAudioProcessor : public FUnknown | |||
| { | |||
| @@ -197,6 +191,13 @@ public: | |||
| } | |||
| //============================================================================== | |||
| enum InternalParameters | |||
| { | |||
| paramPreset = 0x70727374, // 'prst' | |||
| paramBypass = 0x62797073, // 'byps' | |||
| paramMidiControllerOffset = 0x6d636d00 // 'mdm*' | |||
| }; | |||
| struct Param : public Vst::Parameter | |||
| { | |||
| Param (AudioProcessor& p, int index, Vst::ParamID paramID) : owner (p), paramIndex (index) | |||
| @@ -350,6 +351,79 @@ public: | |||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (BypassParam) | |||
| }; | |||
| //============================================================================== | |||
| struct ProgramChangeParameter : public Vst::Parameter | |||
| { | |||
| ProgramChangeParameter (AudioProcessor& p) : owner (p) | |||
| { | |||
| jassert (owner.getNumPrograms() > 1); | |||
| info.id = paramPreset; | |||
| toString128 (info.title, "Program"); | |||
| toString128 (info.shortTitle, "Program"); | |||
| toString128 (info.units, ""); | |||
| info.stepCount = owner.getNumPrograms() - 1; | |||
| info.defaultNormalizedValue = static_cast<Vst::ParamValue> (owner.getCurrentProgram()) / static_cast<Vst::ParamValue> (info.stepCount); | |||
| info.unitId = Vst::kRootUnitId; | |||
| info.flags = Vst::ParameterInfo::kIsProgramChange | Vst::ParameterInfo::kCanAutomate; | |||
| } | |||
| virtual ~ProgramChangeParameter() {} | |||
| bool setNormalized (Vst::ParamValue v) override | |||
| { | |||
| Vst::ParamValue program = v * info.stepCount; | |||
| if (! isPositiveAndBelow ((int) program, owner.getNumPrograms())) | |||
| return false; | |||
| if (valueNormalized != v) | |||
| { | |||
| valueNormalized = v; | |||
| changed(); | |||
| return true; | |||
| } | |||
| return false; | |||
| } | |||
| void toString (Vst::ParamValue value, Vst::String128 result) const override | |||
| { | |||
| Vst::ParamValue program = value * info.stepCount; | |||
| toString128 (result, owner.getProgramName ((int) program)); | |||
| } | |||
| bool fromString (const Vst::TChar* text, Vst::ParamValue& outValueNormalized) const override | |||
| { | |||
| const String paramValueString (getStringFromVstTChars (text)); | |||
| const int n = owner.getNumPrograms(); | |||
| for (int i = 0; i < n; ++i) | |||
| { | |||
| if (paramValueString == owner.getProgramName (i)) | |||
| { | |||
| outValueNormalized = static_cast<Vst::ParamValue> (i) / info.stepCount; | |||
| return true; | |||
| } | |||
| } | |||
| return false; | |||
| } | |||
| static String getStringFromVstTChars (const Vst::TChar* text) | |||
| { | |||
| return juce::String (juce::CharPointer_UTF16 (reinterpret_cast<const juce::CharPointer_UTF16::CharType*> (text))); | |||
| } | |||
| Vst::ParamValue toPlain (Vst::ParamValue v) const override { return v * info.stepCount; } | |||
| Vst::ParamValue toNormalized (Vst::ParamValue v) const override { return v / info.stepCount; } | |||
| private: | |||
| AudioProcessor& owner; | |||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ProgramChangeParameter) | |||
| }; | |||
| //============================================================================== | |||
| tresult PLUGIN_API setComponentState (IBStream* stream) override | |||
| { | |||
| @@ -362,6 +436,10 @@ public: | |||
| setParamNormalized (getVSTParamIDForIndex (i), (double) pluginInstance->getParameter (i)); | |||
| setParamNormalized (bypassParamID, audioProcessor->isBypassed ? 1.0f : 0.0f); | |||
| const int numPrograms = pluginInstance->getNumPrograms(); | |||
| if (numPrograms > 1) | |||
| setParamNormalized (paramPreset, static_cast<Vst::ParamValue> (pluginInstance->getCurrentProgram()) / static_cast<Vst::ParamValue> (numPrograms - 1)); | |||
| } | |||
| return Vst::EditController::setComponentState (stream); | |||
| @@ -459,6 +537,13 @@ public: | |||
| void audioProcessorChanged (AudioProcessor*) override | |||
| { | |||
| if (AudioProcessor* pluginInstance = getPluginInstance()) | |||
| { | |||
| if (pluginInstance->getNumPrograms() > 1) | |||
| EditController::setParamNormalized (paramPreset, static_cast<Vst::ParamValue> (pluginInstance->getCurrentProgram()) | |||
| / static_cast<Vst::ParamValue> (pluginInstance->getNumPrograms() - 1)); | |||
| } | |||
| if (componentHandler != nullptr) | |||
| componentHandler->restartComponent (Vst::kLatencyChanged | Vst::kParamValuesChanged); | |||
| } | |||
| @@ -531,12 +616,15 @@ private: | |||
| parameters.addParameter (new Param (*pluginInstance, i, vstParamID)); | |||
| } | |||
| bypassParamID = static_cast<Vst::ParamID> (usingManagedParameter ? kJuceVST3BypassParamID : numParameters); | |||
| bypassParamID = static_cast<Vst::ParamID> (usingManagedParameter ? paramBypass : numParameters); | |||
| parameters.addParameter (new BypassParam (*pluginInstance, bypassParamID)); | |||
| if (pluginInstance->getNumPrograms() > 1) | |||
| parameters.addParameter (new ProgramChangeParameter (*pluginInstance)); | |||
| } | |||
| #if JUCE_VST3_EMULATE_MIDI_CC_WITH_PARAMETERS | |||
| parameterToMidiControllerOffset = static_cast<Vst::ParamID> (usingManagedParameter ? kMidiControllerMappingsStartID | |||
| parameterToMidiControllerOffset = static_cast<Vst::ParamID> (usingManagedParameter ? paramMidiControllerOffset | |||
| : parameters.getParameterCount()); | |||
| initialiseMidiControllerMappings (); | |||
| @@ -1357,7 +1445,7 @@ public: | |||
| { | |||
| if (listIndex == 0) | |||
| { | |||
| info.id = paramPreset; | |||
| info.id = JuceVST3EditController::paramPreset; | |||
| info.programCount = (Steinberg::int32) getPluginInstance().getNumPrograms(); | |||
| toString128 (info.name, TRANS("Factory Presets")); | |||
| @@ -1372,7 +1460,7 @@ public: | |||
| tresult PLUGIN_API getProgramName (Vst::ProgramListID listId, Steinberg::int32 programIndex, Vst::String128 name) override | |||
| { | |||
| if (listId == paramPreset | |||
| if (listId == JuceVST3EditController::paramPreset | |||
| && isPositiveAndBelow ((int) programIndex, getPluginInstance().getNumPrograms())) | |||
| { | |||
| toString128 (name, getPluginInstance().getProgramName ((int) programIndex)); | |||
| @@ -1722,6 +1810,15 @@ public: | |||
| else if (juceVST3EditController->isMidiControllerParamID (vstParamID)) | |||
| addParameterChangeToMidiBuffer (offsetSamples, vstParamID, value); | |||
| #endif | |||
| else if (vstParamID == JuceVST3EditController::paramPreset) | |||
| { | |||
| const int numPrograms = pluginInstance->getNumPrograms(); | |||
| const int programValue = static_cast<int> (std::round (value * static_cast<Vst::ParamValue> (numPrograms))); | |||
| if (numPrograms > 1 && isPositiveAndBelow (programValue, numPrograms) | |||
| && programValue != pluginInstance->getCurrentProgram()) | |||
| pluginInstance->setCurrentProgram (programValue); | |||
| } | |||
| else | |||
| { | |||
| const int index = getJuceIndexForVSTParamID (vstParamID); | |||
| @@ -1972,12 +2069,6 @@ private: | |||
| return AudioBusPointerHelper<FloatType>::impl (data); | |||
| } | |||
| //============================================================================== | |||
| enum InternalParameters | |||
| { | |||
| paramPreset = 'prst' | |||
| }; | |||
| void preparePlugin (double sampleRate, int bufferSize) | |||
| { | |||
| AudioProcessor& p = getPluginInstance(); | |||
| @@ -1996,7 +2087,7 @@ private: | |||
| const int numParameters = pluginInstance->getNumParameters(); | |||
| usingManagedParameter = (pluginInstance->getParameters().size() == numParameters); | |||
| vstBypassParameterId = static_cast<Vst::ParamID> (usingManagedParameter ? kJuceVST3BypassParamID : numParameters); | |||
| vstBypassParameterId = static_cast<Vst::ParamID> (usingManagedParameter ? JuceVST3EditController::paramBypass : numParameters); | |||
| for (int i = 0; i < numParameters; ++i) | |||
| { | |||