From 9b1d596dd5bf7ecfded26cebf86be929f4f0ba5e Mon Sep 17 00:00:00 2001 From: jules Date: Mon, 13 Oct 2014 16:19:15 +0100 Subject: [PATCH] Added new base-class AudioProcessorParameter, and modified the AudioProcessor class to manage a list of these as a cleaner way of handling its parameters. --- .../juce_audio_processors.h | 1 + .../processors/juce_AudioProcessor.cpp | 166 ++++++++++++++++-- .../processors/juce_AudioProcessor.h | 23 ++- .../processors/juce_AudioProcessorParameter.h | 143 +++++++++++++++ 4 files changed, 310 insertions(+), 23 deletions(-) create mode 100644 modules/juce_audio_processors/processors/juce_AudioProcessorParameter.h diff --git a/modules/juce_audio_processors/juce_audio_processors.h b/modules/juce_audio_processors/juce_audio_processors.h index 3854d2af55..2811656805 100644 --- a/modules/juce_audio_processors/juce_audio_processors.h +++ b/modules/juce_audio_processors/juce_audio_processors.h @@ -76,6 +76,7 @@ class AudioProcessor; #include "processors/juce_AudioPlayHead.h" #include "processors/juce_AudioProcessorEditor.h" #include "processors/juce_AudioProcessorListener.h" +#include "processors/juce_AudioProcessorParameter.h" #include "processors/juce_AudioProcessor.h" #include "processors/juce_PluginDescription.h" #include "processors/juce_AudioPluginInstance.h" diff --git a/modules/juce_audio_processors/processors/juce_AudioProcessor.cpp b/modules/juce_audio_processors/processors/juce_AudioProcessor.cpp index 42f1c4dbc5..cdb192d0b9 100644 --- a/modules/juce_audio_processors/processors/juce_AudioProcessor.cpp +++ b/modules/juce_audio_processors/processors/juce_AudioProcessor.cpp @@ -118,20 +118,6 @@ void AudioProcessor::setParameterNotifyingHost (const int parameterIndex, sendParamChangeMessageToListeners (parameterIndex, newValue); } -String AudioProcessor::getParameterName (int parameterIndex, int maximumStringLength) -{ - return getParameterName (parameterIndex).substring (0, maximumStringLength); -} - -String AudioProcessor::getParameterText (int parameterIndex, int maximumStringLength) -{ - return getParameterText (parameterIndex).substring (0, maximumStringLength); -} - -int AudioProcessor::getDefaultNumParameterSteps() noexcept { return 0x7fffffff; } -int AudioProcessor::getParameterNumSteps (int /*parameterIndex*/) { return getDefaultNumParameterSteps(); } -float AudioProcessor::getParameterDefaultValue (int /*parameterIndex*/) { return 0.0f; } - AudioProcessorListener* AudioProcessor::getListenerLocked (const int index) const noexcept { const ScopedLock sl (listenerLock); @@ -202,10 +188,129 @@ void AudioProcessor::updateHostDisplay() l->audioProcessorChanged (this); } -String AudioProcessor::getParameterLabel (int) const { return String(); } -bool AudioProcessor::isParameterOrientationInverted (int) const { return false; } -bool AudioProcessor::isParameterAutomatable (int) const { return true; } -bool AudioProcessor::isMetaParameter (int) const { return false; } +const OwnedArray& AudioProcessor::getParameters() const noexcept +{ + return managedParameters; +} + +int AudioProcessor::getNumParameters() +{ + return managedParameters.size(); +} + +float AudioProcessor::getParameter (int index) +{ + if (AudioProcessorParameter* p = getParamChecked (index)) + return p->getValue(); + + return 0; +} + +void AudioProcessor::setParameter (int index, float newValue) +{ + if (AudioProcessorParameter* p = getParamChecked (index)) + p->setValue (newValue); +} + +float AudioProcessor::getParameterDefaultValue (int index) +{ + if (AudioProcessorParameter* p = managedParameters[index]) + return p->getDefaultValue(); + + return 0; +} + +const String AudioProcessor::getParameterName (int index) +{ + if (AudioProcessorParameter* p = getParamChecked (index)) + return p->getName (512); + + return String(); +} + +String AudioProcessor::getParameterName (int index, int maximumStringLength) +{ + if (AudioProcessorParameter* p = managedParameters[index]) + return p->getName (maximumStringLength); + + return getParameterName (index).substring (0, maximumStringLength); +} + +const String AudioProcessor::getParameterText (int index) +{ + return getParameterText (index, 1024); +} + +String AudioProcessor::getParameterText (int index, int maximumStringLength) +{ + if (AudioProcessorParameter* p = managedParameters[index]) + return p->getText (p->getValue(), maximumStringLength); + + return getParameterText (index).substring (0, maximumStringLength); +} + +int AudioProcessor::getParameterNumSteps (int index) +{ + if (AudioProcessorParameter* p = managedParameters[index]) + return p->getNumSteps(); + + return AudioProcessor::getDefaultNumParameterSteps(); +} + +int AudioProcessor::getDefaultNumParameterSteps() noexcept +{ + return 0x7fffffff; +} + +String AudioProcessor::getParameterLabel (int index) const +{ + if (AudioProcessorParameter* p = managedParameters[index]) + return p->getLabel(); + + return String(); +} + +bool AudioProcessor::isParameterAutomatable (int index) const +{ + if (AudioProcessorParameter* p = managedParameters[index]) + return p->isAutomatable(); + + return true; +} + +bool AudioProcessor::isParameterOrientationInverted (int index) const +{ + if (AudioProcessorParameter* p = managedParameters[index]) + return p->isOrientationInverted(); + + return false; +} + +bool AudioProcessor::isMetaParameter (int index) const +{ + if (AudioProcessorParameter* p = managedParameters[index]) + return p->isMetaParameter(); + + return false; +} + +AudioProcessorParameter* AudioProcessor::getParamChecked (int index) const noexcept +{ + AudioProcessorParameter* p = managedParameters[index]; + + // If you hit this, then you're either trying to access parameters that are out-of-range, + // or you're not using addParameter and the managed parameter list, but have failed + // to override some essential virtual methods and implement them appropriately. + jassert (p != nullptr); + return p; +} + +void AudioProcessor::addParameter (AudioProcessorParameter* p) +{ + p->processor = this; + p->parameterIndex = managedParameters.size(); + managedParameters.add (p); +} void AudioProcessor::suspendProcessing (const bool shouldBeSuspended) { @@ -296,6 +401,31 @@ XmlElement* AudioProcessor::getXmlFromBinary (const void* data, const int sizeIn void AudioProcessorListener::audioProcessorParameterChangeGestureBegin (AudioProcessor*, int) {} void AudioProcessorListener::audioProcessorParameterChangeGestureEnd (AudioProcessor*, int) {} +//============================================================================== +AudioProcessorParameter::AudioProcessorParameter() noexcept + : processor (nullptr), parameterIndex (-1) +{} + +AudioProcessorParameter::~AudioProcessorParameter() {} + +void AudioProcessorParameter::setValueNotifyingHost (float newValue) +{ + // This method can't be used until the parameter has been attached to a processor! + jassert (processor != nullptr && parameterIndex >= 0); + + return processor->setParameterNotifyingHost (parameterIndex, newValue); +} + +bool AudioProcessorParameter::isOrientationInverted() const { return false; } +bool AudioProcessorParameter::isAutomatable() const { return true; } +bool AudioProcessorParameter::isMetaParameter() const { return false; } +int AudioProcessorParameter::getNumSteps() const { return AudioProcessor::getDefaultNumParameterSteps(); } + +String AudioProcessorParameter::getText (float value, int /*maximumStringLength*/) const +{ + return String (value, 2); +} + //============================================================================== bool AudioPlayHead::CurrentPositionInfo::operator== (const CurrentPositionInfo& other) const noexcept { diff --git a/modules/juce_audio_processors/processors/juce_AudioProcessor.h b/modules/juce_audio_processors/processors/juce_AudioProcessor.h index 33cd4e57c4..aaae9ef172 100644 --- a/modules/juce_audio_processors/processors/juce_AudioProcessor.h +++ b/modules/juce_audio_processors/processors/juce_AudioProcessor.h @@ -377,10 +377,10 @@ public: /** This must return the correct value immediately after the object has been created, and mustn't change the number of parameters later. */ - virtual int getNumParameters() = 0; + virtual int getNumParameters(); /** Returns the name of a particular parameter. */ - virtual const String getParameterName (int parameterIndex) = 0; + virtual const String getParameterName (int parameterIndex); /** Called by the host to find out the value of one of the filter's parameters. @@ -390,10 +390,10 @@ public: It's also likely to be called by non-UI threads, so the code in here should be thread-aware. */ - virtual float getParameter (int parameterIndex) = 0; + virtual float getParameter (int parameterIndex); /** Returns the value of a parameter as a text string. */ - virtual const String getParameterText (int parameterIndex) = 0; + virtual const String getParameterText (int parameterIndex); /** Returns the name of a parameter as a text string with a preferred maximum length. If you want to provide customised short versions of your parameter names that @@ -455,7 +455,7 @@ public: The value passed will be between 0 and 1.0. */ - virtual void setParameter (int parameterIndex, float newValue) = 0; + virtual void setParameter (int parameterIndex, float newValue); /** Your filter can call this when it needs to change one of its parameters. @@ -507,6 +507,16 @@ public: */ void updateHostDisplay(); + //============================================================================== + /** Adds a parameter to the list. + The parameter object will be managed and deleted automatically by the list + when no longer needed. + */ + void addParameter (AudioProcessorParameter*); + + /** Returns the current list of parameters. */ + const OwnedArray& getParameters() const noexcept; + //============================================================================== /** Returns the number of preset programs the filter supports. @@ -663,6 +673,9 @@ private: CriticalSection callbackLock, listenerLock; String inputSpeakerArrangement, outputSpeakerArrangement; + OwnedArray managedParameters; + AudioProcessorParameter* getParamChecked (int) const noexcept; + #if JUCE_DEBUG BigInteger changingParams; #endif diff --git a/modules/juce_audio_processors/processors/juce_AudioProcessorParameter.h b/modules/juce_audio_processors/processors/juce_AudioProcessorParameter.h new file mode 100644 index 0000000000..8b7e87f9d6 --- /dev/null +++ b/modules/juce_audio_processors/processors/juce_AudioProcessorParameter.h @@ -0,0 +1,143 @@ +/* + ============================================================================== + + This file is part of the JUCE library. + Copyright (c) 2013 - Raw Material Software Ltd. + + Permission is granted to use this software under the terms of either: + a) the GPL v2 (or any later version) + b) the Affero GPL v3 + + Details of these licenses can be found at: www.gnu.org/licenses + + JUCE is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + ------------------------------------------------------------------------------ + + To release a closed-source product which uses JUCE, commercial licenses are + available: visit www.juce.com for more information. + + ============================================================================== +*/ + +#ifndef JUCE_AUDIOPROCESSORPARAMETER_H_INCLUDED +#define JUCE_AUDIOPROCESSORPARAMETER_H_INCLUDED + + +//============================================================================== +/** An abstract base class for parameter objects that can be added to an + AudioProcessor. + + @see AudioProcessor::addParameter +*/ +class JUCE_API AudioProcessorParameter +{ +public: + AudioProcessorParameter() noexcept; + + /** Destructor. */ + virtual ~AudioProcessorParameter(); + + /** Called by the host to find out the value of this parameter. + + Hosts will expect the value returned to be between 0 and 1.0. + + This could be called quite frequently, so try to make your code efficient. + It's also likely to be called by non-UI threads, so the code in here should + be thread-aware. + */ + virtual float getValue() const = 0; + + /** The host will call this method to change the value of one of the filter's parameters. + + The host may call this at any time, including during the audio processing + callback, so the filter has to process this very fast and avoid blocking. + + If you want to set the value of a parameter internally, e.g. from your + editor component, then don't call this directly - instead, use the + setValueNotifyingHost() method, which will also send a message to + the host telling it about the change. If the message isn't sent, the host + won't be able to automate your parameters properly. + + The value passed will be between 0 and 1.0. + */ + virtual void setValue (float newValue) = 0; + + /** Your filter can call this when it needs to change one of its parameters. + + This could happen when the editor or some other internal operation changes + a parameter. This method will call the setParameter() method to change the + value, and will then send a message to the host telling it about the change. + + Note that to make sure the host correctly handles automation, you should call + the beginParameterChangeGesture() and endParameterChangeGesture() methods to + tell the host when the user has started and stopped changing the parameter. + */ + void setValueNotifyingHost (float newValue); + + /** This should return the default value for this parameter. */ + virtual float getDefaultValue() const = 0; + + /** Returns the name to display for this parameter, which should be made + to fit within the given string length. + */ + virtual String getName (int maximumStringLength) const = 0; + + /** Some parameters may be able to return a label string for + their units. For example "Hz" or "%". + */ + virtual String getLabel() const = 0; + + /** Returns the number of discrete interval steps that this parameter's range + should be quantised into. + + If you want a continuous range of values, don't override this method, and allow + the default implementation to return AudioProcessor::getDefaultNumParameterSteps(). + If your parameter is boolean, then you may want to make this return 2. + The value that is returned may or may not be used, depending on the host. + */ + virtual int getNumSteps() const; + + /** Returns a textual version of the supplied parameter value. + The default implementation just returns the floating point value + as a string, but this could do anything you need for a custom type + of value. + */ + virtual String getText (float value, int /*maximumStringLength*/) const; + + /** Should parse a string and return the appropriate value for it. */ + virtual float getValueForText (const String& text) const = 0; + + /** This can be overridden to tell the host that this parameter operates in the + reverse direction. + (Not all plugin formats or hosts will actually use this information). + */ + virtual bool isOrientationInverted() const; + + /** Returns true if the host can automate this parameter. + By default, this returns true. + */ + virtual bool isAutomatable() const; + + /** Should return true if this parameter is a "meta" parameter. + A meta-parameter is a parameter that changes other params. It is used + by some hosts (e.g. AudioUnit hosts). + By default this returns false. + */ + virtual bool isMetaParameter() const; + + /** Returns the index of this parameter in its parent processor's parameter list. */ + int getParameterIndex() const noexcept { return parameterIndex; } + +private: + friend class AudioProcessor; + AudioProcessor* processor; + int parameterIndex; + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioProcessorParameter) +}; + + +#endif // JUCE_AUDIOPROCESSORPARAMETER_H_INCLUDED