From da8150bb58f28b33c025b98d07d2d994efd75b60 Mon Sep 17 00:00:00 2001 From: reuk Date: Thu, 7 Aug 2025 17:07:57 +0100 Subject: [PATCH] AudioProcessorParameter: Break dependency cycle with AudioProcessor --- .../juce_LegacyAudioParameter.cpp | 16 ++++++-- .../processors/juce_AudioProcessor.cpp | 31 ++++++++++++-- .../processors/juce_AudioProcessor.h | 27 +++++++++++++ .../processors/juce_AudioProcessorEditor.h | 1 + .../juce_AudioProcessorParameter.cpp | 40 +++++++------------ .../processors/juce_AudioProcessorParameter.h | 16 ++++---- 6 files changed, 91 insertions(+), 40 deletions(-) diff --git a/modules/juce_audio_processors/format_types/juce_LegacyAudioParameter.cpp b/modules/juce_audio_processors/format_types/juce_LegacyAudioParameter.cpp index 33a8751968..2225dfeea0 100644 --- a/modules/juce_audio_processors/format_types/juce_LegacyAudioParameter.cpp +++ b/modules/juce_audio_processors/format_types/juce_LegacyAudioParameter.cpp @@ -40,10 +40,12 @@ JUCE_BEGIN_IGNORE_DEPRECATION_WARNINGS class LegacyAudioParameter final : public HostedAudioProcessorParameter { public: - LegacyAudioParameter (AudioProcessor& audioProcessorToUse, int audioParameterIndex) + LegacyAudioParameter (AudioProcessorParameter::Listener& listener, + AudioProcessor& audioProcessorToUse, + int audioParameterIndex) + : processor (&audioProcessorToUse) { - processor = &audioProcessorToUse; - + setOwner (&listener); setParameterIndex (audioParameterIndex); jassert (getParameterIndex() < processor->getNumParameters()); } @@ -118,6 +120,9 @@ public: return {}; } + +private: + AudioProcessor* processor = nullptr; }; //============================================================================== @@ -135,6 +140,7 @@ public: { clear(); + forwarder = AudioProcessor::ParameterChangeForwarder { &audioProcessor }; legacyParamIDs = forceLegacyParamIDs; auto numParameters = audioProcessor.getNumParameters(); @@ -147,7 +153,7 @@ public: if (usingManagedParameters) return audioProcessor.getParameters()[i]; - auto newParam = std::make_unique (audioProcessor, i); + auto newParam = std::make_unique (forwarder, audioProcessor, i); auto* result = newParam.get(); ownedGroup.addChild (std::move (newParam)); @@ -163,6 +169,7 @@ public: void clear() { + forwarder = AudioProcessor::ParameterChangeForwarder { nullptr }; ownedGroup = AudioProcessorParameterGroup(); params.clear(); } @@ -211,6 +218,7 @@ private: const AudioProcessorParameterGroup* processorGroup = nullptr; AudioProcessorParameterGroup ownedGroup; Array params; + AudioProcessor::ParameterChangeForwarder forwarder { nullptr }; bool legacyParamIDs = false, usingManagedParameters = false; }; diff --git a/modules/juce_audio_processors/processors/juce_AudioProcessor.cpp b/modules/juce_audio_processors/processors/juce_AudioProcessor.cpp index 989abed023..26fdf35837 100644 --- a/modules/juce_audio_processors/processors/juce_AudioProcessor.cpp +++ b/modules/juce_audio_processors/processors/juce_AudioProcessor.cpp @@ -521,7 +521,7 @@ void AudioProcessor::addParameter (AudioProcessorParameter* param) jassert (param != nullptr); parameterTree.addChild (std::unique_ptr (param)); - param->processor = this; + param->setOwner (¶meterListener); param->setParameterIndex (flatParameterList.size()); flatParameterList.add (param); @@ -539,7 +539,7 @@ void AudioProcessor::addParameterGroup (std::unique_ptrprocessor = this; + p->setOwner (¶meterListener); p->setParameterIndex (i); validateParameter (p); @@ -566,7 +566,7 @@ void AudioProcessor::setParameterTree (AudioProcessorParameterGroup&& newTree) for (int i = 0; i < flatParameterList.size(); ++i) { auto p = flatParameterList.getUnchecked (i); - p->processor = this; + p->setOwner (¶meterListener); p->setParameterIndex (i); validateParameter (p); @@ -1423,6 +1423,31 @@ AudioProcessorParameter* AudioProcessor::getParamChecked (int index) const bool AudioProcessor::canAddBus ([[maybe_unused]] bool isInput) const { return false; } bool AudioProcessor::canRemoveBus ([[maybe_unused]] bool isInput) const { return false; } +//============================================================================== +void AudioProcessor::ParameterChangeForwarder::parameterValueChanged (int index, float value) +{ + if (owner == nullptr) + return; + + for (int i = owner->listeners.size(); --i >= 0;) + if (auto* l = owner->listeners[i]) + l->audioProcessorParameterChanged (owner, index, value); +} + +void AudioProcessor::ParameterChangeForwarder::parameterGestureChanged (int index, bool begin) +{ + if (owner == nullptr) + return; + + const auto callback = begin + ? &AudioProcessorListener::audioProcessorParameterChangeGestureBegin + : &AudioProcessorListener::audioProcessorParameterChangeGestureEnd; + + for (int i = owner->listeners.size(); --i >= 0;) + if (auto* l = owner->listeners[i]) + (l->*callback) (owner, index); +} + JUCE_END_IGNORE_DEPRECATION_WARNINGS } // namespace juce diff --git a/modules/juce_audio_processors/processors/juce_AudioProcessor.h b/modules/juce_audio_processors/processors/juce_AudioProcessor.h index c9a86be43c..cd57916c37 100644 --- a/modules/juce_audio_processors/processors/juce_AudioProcessor.h +++ b/modules/juce_audio_processors/processors/juce_AudioProcessor.h @@ -1516,6 +1516,31 @@ public: [[deprecated]] virtual bool isOutputChannelStereoPair (int index) const; /** @endcond */ + /** @internal + Used to convert new-style per-parameter callbacks into old-style processor-change + callbacks. + This type will be removed in the future! + */ + class ParameterChangeForwarder : public AudioProcessorParameter::Listener + { + public: + explicit ParameterChangeForwarder (AudioProcessor* o) : owner (o) {} + + ParameterChangeForwarder (const ParameterChangeForwarder& other) : owner (other.owner) {} + + ParameterChangeForwarder& operator= (const ParameterChangeForwarder& other) + { + owner = other.owner; + return *this; + } + + void parameterValueChanged (int, float) override; + void parameterGestureChanged (int, bool) override; + + private: + AudioProcessor* owner = nullptr; + }; + private: //============================================================================== struct InOutChannelPair @@ -1588,6 +1613,8 @@ private: AudioProcessorParameterGroup parameterTree; Array flatParameterList; + ParameterChangeForwarder parameterListener { this }; + AudioProcessorParameter* getParamChecked (int) const; #if JUCE_DEBUG diff --git a/modules/juce_audio_processors/processors/juce_AudioProcessorEditor.h b/modules/juce_audio_processors/processors/juce_AudioProcessorEditor.h index 85f52cd264..e194b0ef6c 100644 --- a/modules/juce_audio_processors/processors/juce_AudioProcessorEditor.h +++ b/modules/juce_audio_processors/processors/juce_AudioProcessorEditor.h @@ -36,6 +36,7 @@ namespace juce { class AudioProcessorEditorListener; +class AudioProcessor; //============================================================================== /** diff --git a/modules/juce_audio_processors/processors/juce_AudioProcessorParameter.cpp b/modules/juce_audio_processors/processors/juce_AudioProcessorParameter.cpp index 7aec22456f..1221281a0a 100644 --- a/modules/juce_audio_processors/processors/juce_AudioProcessorParameter.cpp +++ b/modules/juce_audio_processors/processors/juce_AudioProcessorParameter.cpp @@ -50,6 +50,12 @@ void AudioProcessorParameter::setParameterIndex (int index) noexcept parameterIndex = index; } +void AudioProcessorParameter::setOwner (Listener* listenerIn) noexcept +{ + jassert (finalListener == nullptr); + finalListener = listenerIn; +} + void AudioProcessorParameter::setValueNotifyingHost (float newValue) { setValue (newValue); @@ -59,7 +65,7 @@ void AudioProcessorParameter::setValueNotifyingHost (float newValue) void AudioProcessorParameter::beginChangeGesture() { // This method can't be used until the parameter has been attached to a processor! - jassert (processor != nullptr && parameterIndex >= 0); + jassert (parameterIndex >= 0); #if JUCE_DEBUG && ! JUCE_DISABLE_AUDIOPROCESSOR_BEGIN_END_GESTURE_CHECKING // This means you've called beginChangeGesture twice in succession without @@ -75,20 +81,14 @@ void AudioProcessorParameter::beginChangeGesture() if (auto* l = listeners[i]) l->parameterGestureChanged (getParameterIndex(), true); - if (processor != nullptr && parameterIndex >= 0) - { - // audioProcessorParameterChangeGestureBegin callbacks will shortly be deprecated and - // this code will be removed. - for (int i = processor->listeners.size(); --i >= 0;) - if (auto* l = processor->listeners[i]) - l->audioProcessorParameterChangeGestureBegin (processor, getParameterIndex()); - } + if (finalListener != nullptr) + finalListener->parameterGestureChanged (getParameterIndex(), true); } void AudioProcessorParameter::endChangeGesture() { // This method can't be used until the parameter has been attached to a processor! - jassert (processor != nullptr && parameterIndex >= 0); + jassert (parameterIndex >= 0); #if JUCE_DEBUG && ! JUCE_DISABLE_AUDIOPROCESSOR_BEGIN_END_GESTURE_CHECKING // This means you've called endChangeGesture without having previously @@ -104,14 +104,8 @@ void AudioProcessorParameter::endChangeGesture() if (auto* l = listeners[i]) l->parameterGestureChanged (getParameterIndex(), false); - if (processor != nullptr && parameterIndex >= 0) - { - // audioProcessorParameterChangeGestureEnd callbacks will shortly be deprecated and - // this code will be removed. - for (int i = processor->listeners.size(); --i >= 0;) - if (auto* l = processor->listeners[i]) - l->audioProcessorParameterChangeGestureEnd (processor, getParameterIndex()); - } + if (finalListener != nullptr) + finalListener->parameterGestureChanged (getParameterIndex(), false); } void AudioProcessorParameter::sendValueChangedMessageToListeners (float newValue) @@ -122,14 +116,8 @@ void AudioProcessorParameter::sendValueChangedMessageToListeners (float newValue if (auto* l = listeners [i]) l->parameterValueChanged (getParameterIndex(), newValue); - if (processor != nullptr && parameterIndex >= 0) - { - // audioProcessorParameterChanged callbacks will shortly be deprecated and - // this code will be removed. - for (int i = processor->listeners.size(); --i >= 0;) - if (auto* l = processor->listeners[i]) - l->audioProcessorParameterChanged (processor, getParameterIndex(), newValue); - } + if (finalListener != nullptr) + finalListener->parameterValueChanged (getParameterIndex(), newValue); } bool AudioProcessorParameter::isOrientationInverted() const { return false; } diff --git a/modules/juce_audio_processors/processors/juce_AudioProcessorParameter.h b/modules/juce_audio_processors/processors/juce_AudioProcessorParameter.h index 0c0ddaaeec..4790d0a271 100644 --- a/modules/juce_audio_processors/processors/juce_AudioProcessorParameter.h +++ b/modules/juce_audio_processors/processors/juce_AudioProcessorParameter.h @@ -35,8 +35,6 @@ namespace juce { -class AudioProcessor; - //============================================================================== /** An abstract base class for parameter objects that can be added to an AudioProcessor. @@ -264,9 +262,9 @@ public: /** @internal This should only be called by the owner of the parameter after it has been added to - a processor. Do not call this function; changing parameter indices *will* break things! + a processor. Do not call this function; changing the parameter index *will* break things! */ - void setParameterIndex (int index) noexcept; + void setParameterIndex (int) noexcept; //============================================================================== /** Returns the current value of the parameter as a String. @@ -338,6 +336,12 @@ public: virtual void parameterGestureChanged (int parameterIndex, bool gestureIsStarting) = 0; }; + /** @internal + This should only be called by the owner of the parameter after it has been added to + a processor. Do not call this function; changing the owner *will* break things! + */ + void setOwner (Listener* listener) noexcept; + /** Registers a listener to receive events when the parameter's state changes. If the listener is already registered, this will not register it again. @@ -355,9 +359,6 @@ public: /** @internal */ void sendValueChangedMessageToListeners (float newValue); - /** @internal */ - AudioProcessor* processor = nullptr; - /** Returns the default number of steps for a parameter. NOTE! This method is deprecated! It's recommended that you use @@ -373,6 +374,7 @@ private: int version = 0; CriticalSection listenerLock; Array listeners; + Listener* finalListener = nullptr; mutable StringArray valueStrings; #if JUCE_DEBUG