diff --git a/modules/juce_audio_processors/format_types/juce_VST3Common.h b/modules/juce_audio_processors/format_types/juce_VST3Common.h index 482de6c714..bd30abc726 100644 --- a/modules/juce_audio_processors/format_types/juce_VST3Common.h +++ b/modules/juce_audio_processors/format_types/juce_VST3Common.h @@ -1040,24 +1040,18 @@ public: } } - static void hostToPluginEventList (Steinberg::Vst::IEventList& result, MidiBuffer& midiBuffer, - Steinberg::Vst::IParameterChanges* parameterChanges, - const StoredMidiMapping& midiMapping) - { - toEventList (result, - midiBuffer, - parameterChanges, - &midiMapping, - EventConversionKind::hostToPlugin); + template + static void hostToPluginEventList (Steinberg::Vst::IEventList& result, + MidiBuffer& midiBuffer, + StoredMidiMapping& mapping, + Callback&& callback) + { + toEventList (result, midiBuffer, &mapping, callback); } static void pluginToHostEventList (Steinberg::Vst::IEventList& result, MidiBuffer& midiBuffer) { - toEventList (result, - midiBuffer, - nullptr, - nullptr, - EventConversionKind::pluginToHost); + toEventList (result, midiBuffer, nullptr, [] (auto&&...) {}); } private: @@ -1073,48 +1067,70 @@ private: pluginToHost }; - static void toEventList (Steinberg::Vst::IEventList& result, MidiBuffer& midiBuffer, - Steinberg::Vst::IParameterChanges* parameterChanges, - const StoredMidiMapping* midiMapping, - EventConversionKind kind) + template + static bool sendMappedParameter (const MidiMessage& msg, + StoredMidiMapping* midiMapping, + Callback&& callback) { - enum { maxNumEvents = 2048 }; // Steinberg's Host Checker states that no more than 2048 events are allowed at once - int numEvents = 0; + if (midiMapping == nullptr) + return false; - for (const auto metadata : midiBuffer) - { - if (++numEvents > maxNumEvents) - break; + const auto controlEvent = toVst3ControlEvent (msg); + + if (! controlEvent.hasValue()) + return false; - auto msg = metadata.getMessage(); + const auto controlParamID = midiMapping->getMapping (createSafeChannel (msg.getChannel()), + controlEvent->controllerNumber); - if (midiMapping != nullptr && parameterChanges != nullptr) - { - Vst3MidiControlEvent controlEvent; + if (controlParamID != Steinberg::Vst::kNoParamId) + callback (controlParamID, controlEvent->paramValue); - if (toVst3ControlEvent (msg, controlEvent)) - { - const auto controlParamID = midiMapping->getMapping (createSafeChannel (msg.getChannel()), - controlEvent.controllerNumber); + return true; + } - if (controlParamID != Steinberg::Vst::kNoParamId) - { - Steinberg::int32 ignore; + template + static void processMidiMessage (Steinberg::Vst::IEventList& result, + const MidiMessageMetadata metadata, + StoredMidiMapping* midiMapping, + Callback&& callback) + { + const auto msg = metadata.getMessage(); - if (auto* queue = parameterChanges->addParameterData (controlParamID, ignore)) - queue->addPoint (metadata.samplePosition, controlEvent.paramValue, ignore); - } + if (sendMappedParameter (msg, midiMapping, std::forward (callback))) + return; - continue; - } - } + const auto kind = midiMapping != nullptr ? EventConversionKind::hostToPlugin + : EventConversionKind::pluginToHost; - if (auto maybeEvent = createVstEvent (msg, metadata.data, kind)) - { - maybeEvent->busIndex = 0; - maybeEvent->sampleOffset = metadata.samplePosition; - result.addEvent (*maybeEvent); - } + auto maybeEvent = createVstEvent (msg, metadata.data, kind); + + if (! maybeEvent.hasValue()) + return; + + maybeEvent->busIndex = 0; + maybeEvent->sampleOffset = metadata.samplePosition; + result.addEvent (*maybeEvent); + } + + /* If mapping is non-null, the conversion is assumed to be host-to-plugin, or otherwise + plugin-to-host. + */ + template + static void toEventList (Steinberg::Vst::IEventList& result, + MidiBuffer& midiBuffer, + StoredMidiMapping* midiMapping, + Callback&& callback) + { + enum { maxNumEvents = 2048 }; // Steinberg's Host Checker states that no more than 2048 events are allowed at once + int numEvents = 0; + + for (const auto metadata : midiBuffer) + { + if (++numEvents > maxNumEvents) + break; + + processMidiMessage (result, metadata, midiMapping, std::forward (callback)); } } @@ -1361,28 +1377,18 @@ private: Steinberg::Vst::ParamValue paramValue; }; - static bool toVst3ControlEvent (const MidiMessage& msg, Vst3MidiControlEvent& result) + static Optional toVst3ControlEvent (const MidiMessage& msg) { if (msg.isController()) - { - result = { (Steinberg::Vst::CtrlNumber) msg.getControllerNumber(), msg.getControllerValue() / 127.0}; - return true; - } + return Vst3MidiControlEvent { (Steinberg::Vst::CtrlNumber) msg.getControllerNumber(), msg.getControllerValue() / 127.0 }; if (msg.isPitchWheel()) - { - result = { Steinberg::Vst::kPitchBend, msg.getPitchWheelValue() / 16383.0}; - return true; - } + return Vst3MidiControlEvent { Steinberg::Vst::kPitchBend, msg.getPitchWheelValue() / 16383.0}; if (msg.isChannelPressure()) - { - result = { Steinberg::Vst::kAfterTouch, msg.getChannelPressureValue() / 127.0}; - return true; - } + return Vst3MidiControlEvent { Steinberg::Vst::kAfterTouch, msg.getChannelPressureValue() / 127.0}; - result.controllerNumber = -1; - return false; + return {}; } JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MidiEventList) diff --git a/modules/juce_audio_processors/format_types/juce_VST3PluginFormat.cpp b/modules/juce_audio_processors/format_types/juce_VST3PluginFormat.cpp index 16f10392f4..15c512d072 100644 --- a/modules/juce_audio_processors/format_types/juce_VST3PluginFormat.cpp +++ b/modules/juce_audio_processors/format_types/juce_VST3PluginFormat.cpp @@ -2082,18 +2082,6 @@ public: void setValue (float newValue) override { pluginInstance.cachedParamValues.set (vstParamIndex, newValue); - pluginInstance.parameterDispatcher.push (vstParamIndex, newValue); - } - - /* If the editor set the value, there's no need to notify it that the parameter - value changed. Instead, we set the cachedValue (which will be read by the - processor during the next processBlock) and notify listeners that the parameter - has changed. - */ - void setValueFromEditor (float newValue) - { - pluginInstance.cachedParamValues.set (vstParamIndex, newValue); - sendValueChangedMessageToListeners (newValue); } /* If we're syncing the editor to the processor, the processor won't need to @@ -2559,6 +2547,11 @@ public: inputParameterChanges->set (cachedParamValues.getParamID (index), value); }); + inputParameterChanges->forEach ([&] (Steinberg::int32 index, float value) + { + parameterDispatcher.push (index, value); + }); + processor->process (data); outputParameterChanges->forEach ([&] (Steinberg::int32 index, float value) @@ -3024,7 +3017,9 @@ private: { Steinberg::MemoryStream stream; - if (object->getState (&stream) == kResultTrue) + const auto result = object->getState (&stream); + + if (result == kResultTrue) { MemoryBlock info (stream.getData(), (size_t) stream.getSize()); head.createNewChildElement (identifier)->addTextElement (info.toBase64Encoding()); @@ -3322,8 +3317,12 @@ private: { MidiEventList::hostToPluginEventList (*midiInputs, midiBuffer, - destination.inputParameterChanges, - storedMidiMapping); + storedMidiMapping, + [this] (const auto controlID, const auto paramValue) + { + if (auto* param = this->getParameterForID (controlID)) + param->setValueNotifyingHost ((float) paramValue); + }); } destination.inputEvents = midiInputs; @@ -3468,7 +3467,7 @@ tresult VST3HostContext::performEdit (Vst::ParamID paramID, Vst::ParamValue valu if (auto* param = plugin->getParameterForID (paramID)) { - param->setValueFromEditor ((float) valueNormalised); + param->setValueNotifyingHost ((float) valueNormalised); // did the plug-in already update the parameter internally if (plugin->editController->getParamNormalized (paramID) != (float) valueNormalised)