| @@ -1,6 +1,34 @@ | |||||
| JUCE breaking changes | JUCE breaking changes | ||||
| ===================== | ===================== | ||||
| develop | |||||
| ======= | |||||
| Change | |||||
| ------ | |||||
| Constructors of AudioParameterBool, AudioParameterChoice, AudioParameterFloat, | |||||
| AudioParameterInt, and AudioProcessorParameterWithID have been deprecated and | |||||
| replaced with new constructors taking an 'Attributes' argument. | |||||
| Possible Issues | |||||
| --------------- | |||||
| The compiler may issue a deprecation warning upon encountering usages of the | |||||
| old constructors. | |||||
| Workaround | |||||
| ---------- | |||||
| Update code to pass an 'Attributes' instance instead. Example usages of the new | |||||
| constructors are given in the constructor documentation, and in the plugin | |||||
| example projects. | |||||
| Rationale | |||||
| --------- | |||||
| Parameter types have many different properties. Setting a non-default property | |||||
| using the old constructors required explicitly setting other normally-defaulted | |||||
| properties, which was redundant. The new Attributes types allow non-default | |||||
| properties to be set in isolation. | |||||
| Version 6.1.6 | Version 6.1.6 | ||||
| ============= | ============= | ||||
| @@ -1601,7 +1601,7 @@ namespace AAXClasses | |||||
| if (bypassParameter == nullptr) | if (bypassParameter == nullptr) | ||||
| { | { | ||||
| ownedBypassParameter.reset (new AudioParameterBool (cDefaultMasterBypassID, "Master Bypass", false, {}, {}, {})); | |||||
| ownedBypassParameter.reset (new AudioParameterBool (cDefaultMasterBypassID, "Master Bypass", false)); | |||||
| bypassParameter = ownedBypassParameter.get(); | bypassParameter = ownedBypassParameter.get(); | ||||
| } | } | ||||
| @@ -526,7 +526,7 @@ private: | |||||
| if (bypassParameter == nullptr) | if (bypassParameter == nullptr) | ||||
| { | { | ||||
| vst3WrapperProvidedBypassParam = true; | vst3WrapperProvidedBypassParam = true; | ||||
| ownedBypassParameter.reset (new AudioParameterBool ("byps", "Bypass", false, {}, {}, {})); | |||||
| ownedBypassParameter.reset (new AudioParameterBool ("byps", "Bypass", false)); | |||||
| bypassParameter = ownedBypassParameter.get(); | bypassParameter = ownedBypassParameter.get(); | ||||
| } | } | ||||
| @@ -26,49 +26,36 @@ | |||||
| namespace juce | namespace juce | ||||
| { | { | ||||
| AudioParameterBool::AudioParameterBool (const String& idToUse, | |||||
| AudioParameterBool::AudioParameterBool (const ParameterID& idToUse, | |||||
| const String& nameToUse, | const String& nameToUse, | ||||
| bool def, | bool def, | ||||
| const String& labelToUse, | |||||
| std::function<String (bool, int)> stringFromBool, | |||||
| std::function<bool (const String&)> boolFromString, | |||||
| int versionHintToUse) | |||||
| : RangedAudioParameter (idToUse, nameToUse, labelToUse, Category::genericParameter, versionHintToUse), | |||||
| value (def ? 1.0f : 0.0f), | |||||
| defaultValue (value), | |||||
| stringFromBoolFunction (stringFromBool), | |||||
| boolFromStringFunction (boolFromString) | |||||
| const AudioParameterBoolAttributes& attributes) | |||||
| : RangedAudioParameter (idToUse, nameToUse, attributes.getAudioProcessorParameterWithIDAttributes()), | |||||
| value (def ? 1.0f : 0.0f), | |||||
| valueDefault (def), | |||||
| stringFromBoolFunction (attributes.getStringFromValueFunction() != nullptr | |||||
| ? attributes.getStringFromValueFunction() | |||||
| : [] (bool v, int) { return v ? TRANS("On") : TRANS("Off"); }), | |||||
| boolFromStringFunction (attributes.getValueFromStringFunction() != nullptr | |||||
| ? attributes.getValueFromStringFunction() | |||||
| : [] (const String& text) | |||||
| { | |||||
| static const StringArray onStrings { TRANS ("on"), TRANS ("yes"), TRANS ("true") }; | |||||
| static const StringArray offStrings { TRANS ("off"), TRANS ("no"), TRANS ("false") }; | |||||
| String lowercaseText (text.toLowerCase()); | |||||
| for (auto& testText : onStrings) | |||||
| if (lowercaseText == testText) | |||||
| return true; | |||||
| for (auto& testText : offStrings) | |||||
| if (lowercaseText == testText) | |||||
| return false; | |||||
| return text.getIntValue() != 0; | |||||
| }) | |||||
| { | { | ||||
| if (stringFromBoolFunction == nullptr) | |||||
| stringFromBoolFunction = [] (bool v, int) { return v ? TRANS("On") : TRANS("Off"); }; | |||||
| if (boolFromStringFunction == nullptr) | |||||
| { | |||||
| StringArray onStrings; | |||||
| onStrings.add (TRANS("on")); | |||||
| onStrings.add (TRANS("yes")); | |||||
| onStrings.add (TRANS("true")); | |||||
| StringArray offStrings; | |||||
| offStrings.add (TRANS("off")); | |||||
| offStrings.add (TRANS("no")); | |||||
| offStrings.add (TRANS("false")); | |||||
| boolFromStringFunction = [onStrings, offStrings] (const String& text) | |||||
| { | |||||
| String lowercaseText (text.toLowerCase()); | |||||
| for (auto& testText : onStrings) | |||||
| if (lowercaseText == testText) | |||||
| return true; | |||||
| for (auto& testText : offStrings) | |||||
| if (lowercaseText == testText) | |||||
| return false; | |||||
| return text.getIntValue() != 0; | |||||
| }; | |||||
| } | |||||
| } | } | ||||
| AudioParameterBool::~AudioParameterBool() | AudioParameterBool::~AudioParameterBool() | ||||
| @@ -81,7 +68,7 @@ AudioParameterBool::~AudioParameterBool() | |||||
| float AudioParameterBool::getValue() const { return value; } | float AudioParameterBool::getValue() const { return value; } | ||||
| void AudioParameterBool::setValue (float newValue) { value = newValue; valueChanged (get()); } | void AudioParameterBool::setValue (float newValue) { value = newValue; valueChanged (get()); } | ||||
| float AudioParameterBool::getDefaultValue() const { return defaultValue; } | |||||
| float AudioParameterBool::getDefaultValue() const { return valueDefault; } | |||||
| int AudioParameterBool::getNumSteps() const { return 2; } | int AudioParameterBool::getNumSteps() const { return 2; } | ||||
| bool AudioParameterBool::isDiscrete() const { return true; } | bool AudioParameterBool::isDiscrete() const { return true; } | ||||
| bool AudioParameterBool::isBoolean() const { return true; } | bool AudioParameterBool::isBoolean() const { return true; } | ||||
| @@ -26,6 +26,13 @@ | |||||
| namespace juce | namespace juce | ||||
| { | { | ||||
| /** Properties of an AudioParameterBool. | |||||
| @see AudioParameterBool(), RangedAudioParameterAttributes() | |||||
| */ | |||||
| class AudioParameterBoolAttributes : public RangedAudioParameterAttributes<AudioParameterBoolAttributes, bool> {}; | |||||
| //============================================================================== | |||||
| /** | /** | ||||
| Provides a class of AudioProcessorParameter that can be used as a boolean value. | Provides a class of AudioProcessorParameter that can be used as a boolean value. | ||||
| @@ -36,6 +43,28 @@ namespace juce | |||||
| class JUCE_API AudioParameterBool : public RangedAudioParameter | class JUCE_API AudioParameterBool : public RangedAudioParameter | ||||
| { | { | ||||
| public: | public: | ||||
| /** Creates a AudioParameterBool with the specified parameters. | |||||
| Note that the attributes argument is optional and only needs to be | |||||
| supplied if you want to change options from their default values. | |||||
| Example usage: | |||||
| @code | |||||
| auto attributes = AudioParameterBoolAttributes().withStringFromValueFunction ([] (auto x, auto) { return x ? "On" : "Off"; }) | |||||
| .withLabel ("enabled"); | |||||
| auto param = std::make_unique<AudioParameterBool> ("paramID", "Parameter Name", false, attributes); | |||||
| @endcode | |||||
| @param parameterID The parameter ID to use | |||||
| @param parameterName The parameter name to use | |||||
| @param defaultValue The default value | |||||
| @param attributes Optional characteristics | |||||
| */ | |||||
| AudioParameterBool (const ParameterID& parameterID, | |||||
| const String& parameterName, | |||||
| bool defaultValue, | |||||
| const AudioParameterBoolAttributes& attributes = {}); | |||||
| /** Creates a AudioParameterBool with the specified parameters. | /** Creates a AudioParameterBool with the specified parameters. | ||||
| @param parameterID The parameter ID to use | @param parameterID The parameter ID to use | ||||
| @@ -48,13 +77,22 @@ public: | |||||
| @param boolFromString An optional lambda function that parses a string and | @param boolFromString An optional lambda function that parses a string and | ||||
| converts it into a bool value. Some hosts use this | converts it into a bool value. Some hosts use this | ||||
| to allow users to type in parameter values. | to allow users to type in parameter values. | ||||
| @param versionHint See AudioProcessorParameter::getVersionHint() | |||||
| */ | */ | ||||
| AudioParameterBool (const String& parameterID, const String& parameterName, bool defaultValue, | |||||
| const String& parameterLabel = String(), | |||||
| [[deprecated ("Prefer the signature taking an Attributes argument")]] | |||||
| AudioParameterBool (const ParameterID& parameterID, | |||||
| const String& parameterName, | |||||
| bool defaultValue, | |||||
| const String& parameterLabel, | |||||
| std::function<String (bool value, int maximumStringLength)> stringFromBool = nullptr, | std::function<String (bool value, int maximumStringLength)> stringFromBool = nullptr, | ||||
| std::function<bool (const String& text)> boolFromString = nullptr, | |||||
| int versionHint = 0); | |||||
| std::function<bool (const String& text)> boolFromString = nullptr) | |||||
| : AudioParameterBool (parameterID, | |||||
| parameterName, | |||||
| defaultValue, | |||||
| AudioParameterBoolAttributes().withLabel (parameterLabel) | |||||
| .withStringFromValueFunction (std::move (stringFromBool)) | |||||
| .withValueFromStringFunction (std::move (boolFromString))) | |||||
| { | |||||
| } | |||||
| /** Destructor. */ | /** Destructor. */ | ||||
| ~AudioParameterBool() override; | ~AudioParameterBool() override; | ||||
| @@ -90,7 +128,7 @@ private: | |||||
| const NormalisableRange<float> range { 0.0f, 1.0f, 1.0f }; | const NormalisableRange<float> range { 0.0f, 1.0f, 1.0f }; | ||||
| std::atomic<float> value; | std::atomic<float> value; | ||||
| const float defaultValue; | |||||
| const float valueDefault; | |||||
| std::function<String (bool, int)> stringFromBoolFunction; | std::function<String (bool, int)> stringFromBoolFunction; | ||||
| std::function<bool (const String&)> boolFromStringFunction; | std::function<bool (const String&)> boolFromStringFunction; | ||||
| @@ -26,12 +26,12 @@ | |||||
| namespace juce | namespace juce | ||||
| { | { | ||||
| AudioParameterChoice::AudioParameterChoice (const String& idToUse, const String& nameToUse, | |||||
| const StringArray& c, int def, const String& labelToUse, | |||||
| std::function<String (int, int)> stringFromIndex, | |||||
| std::function<int (const String&)> indexFromString, | |||||
| int versionHintToUse) | |||||
| : RangedAudioParameter (idToUse, nameToUse, labelToUse, Category::genericParameter, versionHintToUse), | |||||
| AudioParameterChoice::AudioParameterChoice (const ParameterID& idToUse, | |||||
| const String& nameToUse, | |||||
| const StringArray& c, | |||||
| int def, | |||||
| const AudioParameterChoiceAttributes& attributes) | |||||
| : RangedAudioParameter (idToUse, nameToUse, attributes.getAudioProcessorParameterWithIDAttributes()), | |||||
| choices (c), | choices (c), | ||||
| range ([this] | range ([this] | ||||
| { | { | ||||
| @@ -44,16 +44,14 @@ AudioParameterChoice::AudioParameterChoice (const String& idToUse, const String& | |||||
| }()), | }()), | ||||
| value ((float) def), | value ((float) def), | ||||
| defaultValue (convertTo0to1 ((float) def)), | defaultValue (convertTo0to1 ((float) def)), | ||||
| stringFromIndexFunction (stringFromIndex), | |||||
| indexFromStringFunction (indexFromString) | |||||
| stringFromIndexFunction (attributes.getStringFromValueFunction() != nullptr | |||||
| ? attributes.getStringFromValueFunction() | |||||
| : [this] (int index, int) { return choices [index]; }), | |||||
| indexFromStringFunction (attributes.getValueFromStringFunction() != nullptr | |||||
| ? attributes.getValueFromStringFunction() | |||||
| : [this] (const String& text) { return choices.indexOf (text); }) | |||||
| { | { | ||||
| jassert (choices.size() > 1); // you must supply an actual set of items to choose from! | jassert (choices.size() > 1); // you must supply an actual set of items to choose from! | ||||
| if (stringFromIndexFunction == nullptr) | |||||
| stringFromIndexFunction = [this] (int index, int) { return choices [index]; }; | |||||
| if (indexFromStringFunction == nullptr) | |||||
| indexFromStringFunction = [this] (const String& text) { return choices.indexOf (text); }; | |||||
| } | } | ||||
| AudioParameterChoice::~AudioParameterChoice() | AudioParameterChoice::~AudioParameterChoice() | ||||
| @@ -26,6 +26,13 @@ | |||||
| namespace juce | namespace juce | ||||
| { | { | ||||
| /** Properties of an AudioParameterChoice. | |||||
| @see AudioParameterChoice(), RangedAudioParameterAttributes() | |||||
| */ | |||||
| class AudioParameterChoiceAttributes : public RangedAudioParameterAttributes<AudioParameterChoiceAttributes, int> {}; | |||||
| //============================================================================== | |||||
| /** | /** | ||||
| Provides a class of AudioProcessorParameter that can be used to select | Provides a class of AudioProcessorParameter that can be used to select | ||||
| an indexed, named choice from a list. | an indexed, named choice from a list. | ||||
| @@ -39,10 +46,33 @@ class JUCE_API AudioParameterChoice : public RangedAudioParameter | |||||
| public: | public: | ||||
| /** Creates a AudioParameterChoice with the specified parameters. | /** Creates a AudioParameterChoice with the specified parameters. | ||||
| Note that the attributes argument is optional and only needs to be | |||||
| supplied if you want to change options from their default values. | |||||
| Example usage: | |||||
| @code | |||||
| auto attributes = AudioParameterChoiceAttributes().withLabel ("selected"); | |||||
| auto param = std::make_unique<AudioParameterChoice> ("paramID", "Parameter Name", StringArray { "a", "b", "c" }, 0, attributes); | |||||
| @endcode | |||||
| @param parameterID The parameter ID to use | @param parameterID The parameter ID to use | ||||
| @param parameterName The parameter name to use | @param parameterName The parameter name to use | ||||
| @param choices The set of choices to use | @param choices The set of choices to use | ||||
| @param defaultItemIndex The index of the default choice | @param defaultItemIndex The index of the default choice | ||||
| @param attributes Optional characteristics | |||||
| */ | |||||
| AudioParameterChoice (const ParameterID& parameterID, | |||||
| const String& parameterName, | |||||
| const StringArray& choices, | |||||
| int defaultItemIndex, | |||||
| const AudioParameterChoiceAttributes& attributes = {}); | |||||
| /** Creates a AudioParameterChoice with the specified parameters. | |||||
| @param parameterID The parameter ID to use | |||||
| @param parameterName The parameter name to use | |||||
| @param choicesToUse The set of choices to use | |||||
| @param defaultItemIndex The index of the default choice | |||||
| @param parameterLabel An optional label for the parameter's value | @param parameterLabel An optional label for the parameter's value | ||||
| @param stringFromIndex An optional lambda function that converts a choice | @param stringFromIndex An optional lambda function that converts a choice | ||||
| index to a string with a maximum length. This may | index to a string with a maximum length. This may | ||||
| @@ -50,15 +80,24 @@ public: | |||||
| @param indexFromString An optional lambda function that parses a string and | @param indexFromString An optional lambda function that parses a string and | ||||
| converts it into a choice index. Some hosts use this | converts it into a choice index. Some hosts use this | ||||
| to allow users to type in parameter values. | to allow users to type in parameter values. | ||||
| @param versionHint See AudioProcessorParameter::getVersionHint() | |||||
| */ | */ | ||||
| AudioParameterChoice (const String& parameterID, const String& parameterName, | |||||
| const StringArray& choices, | |||||
| [[deprecated ("Prefer the signature taking an Attributes argument")]] | |||||
| AudioParameterChoice (const ParameterID& parameterID, | |||||
| const String& parameterName, | |||||
| const StringArray& choicesToUse, | |||||
| int defaultItemIndex, | int defaultItemIndex, | ||||
| const String& parameterLabel = String(), | |||||
| const String& parameterLabel, | |||||
| std::function<String (int index, int maximumStringLength)> stringFromIndex = nullptr, | std::function<String (int index, int maximumStringLength)> stringFromIndex = nullptr, | ||||
| std::function<int (const String& text)> indexFromString = nullptr, | |||||
| int versionHint = 0); | |||||
| std::function<int (const String& text)> indexFromString = nullptr) | |||||
| : AudioParameterChoice (parameterID, | |||||
| parameterName, | |||||
| choicesToUse, | |||||
| defaultItemIndex, | |||||
| AudioParameterChoiceAttributes().withLabel (parameterLabel) | |||||
| .withStringFromValueFunction (std::move (stringFromIndex)) | |||||
| .withValueFromStringFunction (std::move (indexFromString))) | |||||
| { | |||||
| } | |||||
| /** Destructor. */ | /** Destructor. */ | ||||
| ~AudioParameterChoice() override; | ~AudioParameterChoice() override; | ||||
| @@ -26,16 +26,17 @@ | |||||
| namespace juce | namespace juce | ||||
| { | { | ||||
| AudioParameterFloat::AudioParameterFloat (const String& idToUse, const String& nameToUse, | |||||
| NormalisableRange<float> r, float def, | |||||
| const String& labelToUse, Category categoryToUse, | |||||
| std::function<String (float, int)> stringFromValue, | |||||
| std::function<float (const String&)> valueFromString, | |||||
| int versionHintToUse) | |||||
| : RangedAudioParameter (idToUse, nameToUse, labelToUse, categoryToUse, versionHintToUse), | |||||
| range (r), value (def), defaultValue (def), | |||||
| stringFromValueFunction (stringFromValue), | |||||
| valueFromStringFunction (valueFromString) | |||||
| AudioParameterFloat::AudioParameterFloat (const ParameterID& idToUse, | |||||
| const String& nameToUse, | |||||
| NormalisableRange<float> r, | |||||
| float def, | |||||
| const AudioParameterFloatAttributes& attributes) | |||||
| : RangedAudioParameter (idToUse, nameToUse, attributes.getAudioProcessorParameterWithIDAttributes()), | |||||
| range (r), | |||||
| value (def), | |||||
| valueDefault (def), | |||||
| stringFromValueFunction (attributes.getStringFromValueFunction()), | |||||
| valueFromStringFunction (attributes.getValueFromStringFunction()) | |||||
| { | { | ||||
| if (stringFromValueFunction == nullptr) | if (stringFromValueFunction == nullptr) | ||||
| { | { | ||||
| @@ -71,7 +72,7 @@ AudioParameterFloat::AudioParameterFloat (const String& idToUse, const String& n | |||||
| valueFromStringFunction = [] (const String& text) { return text.getFloatValue(); }; | valueFromStringFunction = [] (const String& text) { return text.getFloatValue(); }; | ||||
| } | } | ||||
| AudioParameterFloat::AudioParameterFloat (String pid, String nm, float minValue, float maxValue, float def) | |||||
| AudioParameterFloat::AudioParameterFloat (const ParameterID& pid, const String& nm, float minValue, float maxValue, float def) | |||||
| : AudioParameterFloat (pid, nm, { minValue, maxValue, 0.01f }, def) | : AudioParameterFloat (pid, nm, { minValue, maxValue, 0.01f }, def) | ||||
| { | { | ||||
| } | } | ||||
| @@ -86,7 +87,7 @@ AudioParameterFloat::~AudioParameterFloat() | |||||
| float AudioParameterFloat::getValue() const { return convertTo0to1 (value); } | float AudioParameterFloat::getValue() const { return convertTo0to1 (value); } | ||||
| void AudioParameterFloat::setValue (float newValue) { value = convertFrom0to1 (newValue); valueChanged (get()); } | void AudioParameterFloat::setValue (float newValue) { value = convertFrom0to1 (newValue); valueChanged (get()); } | ||||
| float AudioParameterFloat::getDefaultValue() const { return convertTo0to1 (defaultValue); } | |||||
| float AudioParameterFloat::getDefaultValue() const { return convertTo0to1 (valueDefault); } | |||||
| int AudioParameterFloat::getNumSteps() const { return AudioProcessorParameterWithID::getNumSteps(); } | int AudioParameterFloat::getNumSteps() const { return AudioProcessorParameterWithID::getNumSteps(); } | ||||
| String AudioParameterFloat::getText (float v, int length) const { return stringFromValueFunction (convertFrom0to1 (v), length); } | String AudioParameterFloat::getText (float v, int length) const { return stringFromValueFunction (convertFrom0to1 (v), length); } | ||||
| float AudioParameterFloat::getValueForText (const String& text) const { return convertTo0to1 (valueFromStringFunction (text)); } | float AudioParameterFloat::getValueForText (const String& text) const { return convertTo0to1 (valueFromStringFunction (text)); } | ||||
| @@ -26,6 +26,13 @@ | |||||
| namespace juce | namespace juce | ||||
| { | { | ||||
| /** Properties of an AudioParameterFloat. | |||||
| @see AudioParameterFloat(), RangedAudioParameterAttributes() | |||||
| */ | |||||
| class AudioParameterFloatAttributes : public RangedAudioParameterAttributes<AudioParameterFloatAttributes, float> {}; | |||||
| //============================================================================== | |||||
| /** | /** | ||||
| A subclass of AudioProcessorParameter that provides an easy way to create a | A subclass of AudioProcessorParameter that provides an easy way to create a | ||||
| parameter which maps onto a given NormalisableRange. | parameter which maps onto a given NormalisableRange. | ||||
| @@ -37,6 +44,30 @@ namespace juce | |||||
| class JUCE_API AudioParameterFloat : public RangedAudioParameter | class JUCE_API AudioParameterFloat : public RangedAudioParameter | ||||
| { | { | ||||
| public: | public: | ||||
| /** Creates a AudioParameterFloat with the specified parameters. | |||||
| Note that the attributes argument is optional and only needs to be | |||||
| supplied if you want to change options from their default values. | |||||
| Example usage: | |||||
| @code | |||||
| auto attributes = AudioParameterFloatAttributes().withStringFromValueFunction ([] (auto x, auto) { return String (x * 100); }) | |||||
| .withLabel ("%"); | |||||
| auto param = std::make_unique<AudioParameterFloat> ("paramID", "Parameter Name", NormalisableRange<float>(), 0.5f, attributes); | |||||
| @endcode | |||||
| @param parameterID The parameter ID to use | |||||
| @param parameterName The parameter name to use | |||||
| @param normalisableRange The NormalisableRange to use | |||||
| @param defaultValue The non-normalised default value | |||||
| @param attributes Optional characteristics | |||||
| */ | |||||
| AudioParameterFloat (const ParameterID& parameterID, | |||||
| const String& parameterName, | |||||
| NormalisableRange<float> normalisableRange, | |||||
| float defaultValue, | |||||
| const AudioParameterFloatAttributes& attributes = {}); | |||||
| /** Creates a AudioParameterFloat with the specified parameters. | /** Creates a AudioParameterFloat with the specified parameters. | ||||
| @param parameterID The parameter ID to use | @param parameterID The parameter ID to use | ||||
| @@ -51,25 +82,34 @@ public: | |||||
| @param valueFromString An optional lambda function that parses a string and | @param valueFromString An optional lambda function that parses a string and | ||||
| converts it into a non-normalised value. Some hosts use | converts it into a non-normalised value. Some hosts use | ||||
| this to allow users to type in parameter values. | this to allow users to type in parameter values. | ||||
| @param versionHint See AudioProcessorParameter::getVersionHint() | |||||
| */ | */ | ||||
| AudioParameterFloat (const String& parameterID, | |||||
| [[deprecated ("Prefer the signature taking an Attributes argument")]] | |||||
| AudioParameterFloat (const ParameterID& parameterID, | |||||
| const String& parameterName, | const String& parameterName, | ||||
| NormalisableRange<float> normalisableRange, | NormalisableRange<float> normalisableRange, | ||||
| float defaultValue, | float defaultValue, | ||||
| const String& parameterLabel = String(), | |||||
| const String& parameterLabel, | |||||
| Category parameterCategory = AudioProcessorParameter::genericParameter, | Category parameterCategory = AudioProcessorParameter::genericParameter, | ||||
| std::function<String (float value, int maximumStringLength)> stringFromValue = nullptr, | std::function<String (float value, int maximumStringLength)> stringFromValue = nullptr, | ||||
| std::function<float (const String& text)> valueFromString = nullptr, | |||||
| int versionHint = 0); | |||||
| std::function<float (const String& text)> valueFromString = nullptr) | |||||
| : AudioParameterFloat (parameterID, | |||||
| parameterName, | |||||
| std::move (normalisableRange), | |||||
| defaultValue, | |||||
| AudioParameterFloatAttributes().withLabel (parameterLabel) | |||||
| .withCategory (parameterCategory) | |||||
| .withStringFromValueFunction (std::move (stringFromValue)) | |||||
| .withValueFromStringFunction (std::move (valueFromString))) | |||||
| { | |||||
| } | |||||
| /** Creates a AudioParameterFloat with an ID, name, and range. | /** Creates a AudioParameterFloat with an ID, name, and range. | ||||
| On creation, its value is set to the default value. | On creation, its value is set to the default value. | ||||
| For control over skew factors, you can use the other | For control over skew factors, you can use the other | ||||
| constructor and provide a NormalisableRange. | constructor and provide a NormalisableRange. | ||||
| */ | */ | ||||
| AudioParameterFloat (String parameterID, | |||||
| String parameterName, | |||||
| AudioParameterFloat (const ParameterID& parameterID, | |||||
| const String& parameterName, | |||||
| float minValue, | float minValue, | ||||
| float maxValue, | float maxValue, | ||||
| float defaultValue); | float defaultValue); | ||||
| @@ -108,7 +148,7 @@ private: | |||||
| float getValueForText (const String&) const override; | float getValueForText (const String&) const override; | ||||
| std::atomic<float> value; | std::atomic<float> value; | ||||
| const float defaultValue; | |||||
| const float valueDefault; | |||||
| std::function<String (float, int)> stringFromValueFunction; | std::function<String (float, int)> stringFromValueFunction; | ||||
| std::function<float (const String&)> valueFromStringFunction; | std::function<float (const String&)> valueFromStringFunction; | ||||
| @@ -26,34 +26,29 @@ | |||||
| namespace juce | namespace juce | ||||
| { | { | ||||
| AudioParameterInt::AudioParameterInt (const String& idToUse, const String& nameToUse, | |||||
| AudioParameterInt::AudioParameterInt (const ParameterID& idToUse, const String& nameToUse, | |||||
| int minValue, int maxValue, int def, | int minValue, int maxValue, int def, | ||||
| const String& labelToUse, | |||||
| std::function<String (int, int)> stringFromInt, | |||||
| std::function<int (const String&)> intFromString, | |||||
| int versionHintToUse) | |||||
| : RangedAudioParameter (idToUse, nameToUse, labelToUse, Category::genericParameter, versionHintToUse), | |||||
| range ([minValue, maxValue] | |||||
| { | |||||
| NormalisableRange<float> rangeWithInterval { (float) minValue, (float) maxValue, | |||||
| [] (float start, float end, float v) { return jlimit (start, end, v * (end - start) + start); }, | |||||
| [] (float start, float end, float v) { return jlimit (0.0f, 1.0f, (v - start) / (end - start)); }, | |||||
| [] (float start, float end, float v) { return (float) roundToInt (juce::jlimit (start, end, v)); } }; | |||||
| rangeWithInterval.interval = 1.0f; | |||||
| return rangeWithInterval; | |||||
| }()), | |||||
| value ((float) def), | |||||
| defaultValue (convertTo0to1 ((float) def)), | |||||
| stringFromIntFunction (stringFromInt), | |||||
| intFromStringFunction (intFromString) | |||||
| const AudioParameterIntAttributes& attributes) | |||||
| : RangedAudioParameter (idToUse, nameToUse, attributes.getAudioProcessorParameterWithIDAttributes()), | |||||
| range ([minValue, maxValue] | |||||
| { | |||||
| NormalisableRange<float> rangeWithInterval { (float) minValue, (float) maxValue, | |||||
| [] (float start, float end, float v) { return jlimit (start, end, v * (end - start) + start); }, | |||||
| [] (float start, float end, float v) { return jlimit (0.0f, 1.0f, (v - start) / (end - start)); }, | |||||
| [] (float start, float end, float v) { return (float) roundToInt (juce::jlimit (start, end, v)); } }; | |||||
| rangeWithInterval.interval = 1.0f; | |||||
| return rangeWithInterval; | |||||
| }()), | |||||
| value ((float) def), | |||||
| defaultValue (convertTo0to1 ((float) def)), | |||||
| stringFromIntFunction (attributes.getStringFromValueFunction() != nullptr | |||||
| ? attributes.getStringFromValueFunction() | |||||
| : [] (int v, int) { return String (v); }), | |||||
| intFromStringFunction (attributes.getValueFromStringFunction() != nullptr | |||||
| ? attributes.getValueFromStringFunction() | |||||
| : [] (const String& text) { return text.getIntValue(); }) | |||||
| { | { | ||||
| jassert (minValue < maxValue); // must have a non-zero range of values! | jassert (minValue < maxValue); // must have a non-zero range of values! | ||||
| if (stringFromIntFunction == nullptr) | |||||
| stringFromIntFunction = [] (int v, int) { return String (v); }; | |||||
| if (intFromStringFunction == nullptr) | |||||
| intFromStringFunction = [] (const String& text) { return text.getIntValue(); }; | |||||
| } | } | ||||
| AudioParameterInt::~AudioParameterInt() | AudioParameterInt::~AudioParameterInt() | ||||
| @@ -26,6 +26,13 @@ | |||||
| namespace juce | namespace juce | ||||
| { | { | ||||
| /** Properties of an AudioParameterInt. | |||||
| @see AudioParameterInt(), RangedAudioParameterAttributes() | |||||
| */ | |||||
| class AudioParameterIntAttributes : public RangedAudioParameterAttributes<AudioParameterIntAttributes, int> {}; | |||||
| //============================================================================== | |||||
| /** | /** | ||||
| Provides a class of AudioProcessorParameter that can be used as an | Provides a class of AudioProcessorParameter that can be used as an | ||||
| integer value with a given range. | integer value with a given range. | ||||
| @@ -39,11 +46,37 @@ class JUCE_API AudioParameterInt : public RangedAudioParameter | |||||
| public: | public: | ||||
| /** Creates a AudioParameterInt with the specified parameters. | /** Creates a AudioParameterInt with the specified parameters. | ||||
| Note that the attributes argument is optional and only needs to be | |||||
| supplied if you want to change options from their default values. | |||||
| Example usage: | |||||
| @code | |||||
| auto attributes = AudioParameterIntAttributes().withStringFromValueFunction ([] (auto x, auto) { return String (x); }) | |||||
| .withLabel ("things"); | |||||
| auto param = std::make_unique<AudioParameterInt> ("paramID", "Parameter Name", 0, 100, 50, attributes); | |||||
| @endcode | |||||
| @param parameterID The parameter ID to use | @param parameterID The parameter ID to use | ||||
| @param parameterName The parameter name to use | @param parameterName The parameter name to use | ||||
| @param minValue The minimum parameter value | @param minValue The minimum parameter value | ||||
| @param maxValue The maximum parameter value | @param maxValue The maximum parameter value | ||||
| @param defaultValue The default value | @param defaultValue The default value | ||||
| @param attributes Optional characteristics | |||||
| */ | |||||
| AudioParameterInt (const ParameterID& parameterID, | |||||
| const String& parameterName, | |||||
| int minValue, | |||||
| int maxValue, | |||||
| int defaultValue, | |||||
| const AudioParameterIntAttributes& attributes = {}); | |||||
| /** Creates a AudioParameterInt with the specified parameters. | |||||
| @param parameterID The parameter ID to use | |||||
| @param parameterName The parameter name to use | |||||
| @param minValue The minimum parameter value | |||||
| @param maxValue The maximum parameter value | |||||
| @param defaultValueIn The default value | |||||
| @param parameterLabel An optional label for the parameter's value | @param parameterLabel An optional label for the parameter's value | ||||
| @param stringFromInt An optional lambda function that converts a int | @param stringFromInt An optional lambda function that converts a int | ||||
| value to a string with a maximum length. This may | value to a string with a maximum length. This may | ||||
| @@ -51,15 +84,26 @@ public: | |||||
| @param intFromString An optional lambda function that parses a string | @param intFromString An optional lambda function that parses a string | ||||
| and converts it into an int. Some hosts use this | and converts it into an int. Some hosts use this | ||||
| to allow users to type in parameter values. | to allow users to type in parameter values. | ||||
| @param versionHint See AudioProcessorParameter::getVersionHint() | |||||
| */ | */ | ||||
| AudioParameterInt (const String& parameterID, const String& parameterName, | |||||
| int minValue, int maxValue, | |||||
| int defaultValue, | |||||
| const String& parameterLabel = String(), | |||||
| [[deprecated ("Prefer the signature taking an Attributes argument")]] | |||||
| AudioParameterInt (const ParameterID& parameterID, | |||||
| const String& parameterName, | |||||
| int minValue, | |||||
| int maxValue, | |||||
| int defaultValueIn, | |||||
| const String& parameterLabel, | |||||
| std::function<String (int value, int maximumStringLength)> stringFromInt = nullptr, | std::function<String (int value, int maximumStringLength)> stringFromInt = nullptr, | ||||
| std::function<int (const String& text)> intFromString = nullptr, | |||||
| int versionHint = 0); | |||||
| std::function<int (const String& text)> intFromString = nullptr) | |||||
| : AudioParameterInt (parameterID, | |||||
| parameterName, | |||||
| minValue, | |||||
| maxValue, | |||||
| defaultValueIn, | |||||
| AudioParameterIntAttributes().withLabel (parameterLabel) | |||||
| .withStringFromValueFunction (std::move (stringFromInt)) | |||||
| .withValueFromStringFunction (std::move (intFromString))) | |||||
| { | |||||
| } | |||||
| /** Destructor. */ | /** Destructor. */ | ||||
| ~AudioParameterInt() override; | ~AudioParameterInt() override; | ||||
| @@ -26,16 +26,17 @@ | |||||
| namespace juce | namespace juce | ||||
| { | { | ||||
| AudioProcessorParameterWithID::AudioProcessorParameterWithID (const String& idToUse, | |||||
| AudioProcessorParameterWithID::AudioProcessorParameterWithID (const ParameterID& idToUse, | |||||
| const String& nameToUse, | const String& nameToUse, | ||||
| const String& labelToUse, | |||||
| AudioProcessorParameter::Category categoryToUse, | |||||
| int versionHintToUse) | |||||
| : HostedAudioProcessorParameter (versionHintToUse), | |||||
| paramID (idToUse), | |||||
| const AudioProcessorParameterWithIDAttributes& attributes) | |||||
| : HostedAudioProcessorParameter (idToUse.getVersionHint()), | |||||
| paramID (idToUse.getParamID()), | |||||
| name (nameToUse), | name (nameToUse), | ||||
| label (labelToUse), | |||||
| category (categoryToUse) | |||||
| label (attributes.getLabel()), | |||||
| category (attributes.getCategory()), | |||||
| meta (attributes.getMeta()), | |||||
| automatable (attributes.getAutomatable()), | |||||
| inverted (attributes.getInverted()) | |||||
| { | { | ||||
| } | } | ||||
| @@ -26,6 +26,87 @@ | |||||
| namespace juce | namespace juce | ||||
| { | { | ||||
| /** | |||||
| Combines a parameter ID and a version hint. | |||||
| */ | |||||
| class ParameterID | |||||
| { | |||||
| public: | |||||
| ParameterID() = default; | |||||
| /** Constructs an instance. | |||||
| Note that this constructor implicitly converts from Strings and string-like types. | |||||
| @param identifier A string that uniquely identifies a single parameter | |||||
| @param versionHint Influences parameter ordering in Audio Unit plugins. | |||||
| Used to provide backwards compatibility of Audio Unit plugins in | |||||
| Logic and GarageBand. | |||||
| @see AudioProcessorParameter(int) | |||||
| */ | |||||
| template <typename StringLike, typename = DisableIfSameOrDerived<ParameterID, StringLike>> | |||||
| ParameterID (StringLike&& identifier, int versionHint = 0) | |||||
| : paramID (std::forward<StringLike> (identifier)), version (versionHint) {} | |||||
| /** @see AudioProcessorParameterWithID::paramID */ | |||||
| auto getParamID() const { return paramID; } | |||||
| /** @see AudioProcessorParameter(int) */ | |||||
| auto getVersionHint() const { return version; } | |||||
| private: | |||||
| String paramID; | |||||
| int version = 0; | |||||
| }; | |||||
| /** | |||||
| An instance of this class may be passed to the constructor of an AudioProcessorParameterWithID | |||||
| to set optional characteristics of that parameter. | |||||
| */ | |||||
| class AudioProcessorParameterWithIDAttributes | |||||
| { | |||||
| using This = AudioProcessorParameterWithIDAttributes; | |||||
| public: | |||||
| using Category = AudioProcessorParameter::Category; | |||||
| /** An optional label for the parameter's value */ | |||||
| JUCE_NODISCARD auto withLabel (String x) const { return withMember (*this, &This::label, std::move (x)); } | |||||
| /** The semantics of this parameter */ | |||||
| JUCE_NODISCARD auto withCategory (Category x) const { return withMember (*this, &This::category, std::move (x)); } | |||||
| /** @see AudioProcessorParameter::isMetaParameter() */ | |||||
| JUCE_NODISCARD auto withMeta (bool x) const { return withMember (*this, &This::meta, std::move (x)); } | |||||
| /** @see AudioProcessorParameter::isAutomatable() */ | |||||
| JUCE_NODISCARD auto withAutomatable (bool x) const { return withMember (*this, &This::automatable, std::move (x)); } | |||||
| /** @see AudioProcessorParameter::isOrientationInverted() */ | |||||
| JUCE_NODISCARD auto withInverted (bool x) const { return withMember (*this, &This::inverted, std::move (x)); } | |||||
| /** An optional label for the parameter's value */ | |||||
| JUCE_NODISCARD auto getLabel() const { return label; } | |||||
| /** The semantics of this parameter */ | |||||
| JUCE_NODISCARD auto getCategory() const { return category; } | |||||
| /** @see AudioProcessorParameter::isMetaParameter() */ | |||||
| JUCE_NODISCARD auto getMeta() const { return meta; } | |||||
| /** @see AudioProcessorParameter::isAutomatable() */ | |||||
| JUCE_NODISCARD auto getAutomatable() const { return automatable; } | |||||
| /** @see AudioProcessorParameter::isOrientationInverted() */ | |||||
| JUCE_NODISCARD auto getInverted() const { return inverted; } | |||||
| private: | |||||
| String label; | |||||
| Category category = AudioProcessorParameter::genericParameter; | |||||
| bool meta = false, automatable = true, inverted = false; | |||||
| }; | |||||
| //============================================================================== | |||||
| /** | /** | ||||
| This abstract base class is used by some AudioProcessorParameter helper classes. | This abstract base class is used by some AudioProcessorParameter helper classes. | ||||
| @@ -36,6 +117,26 @@ namespace juce | |||||
| class JUCE_API AudioProcessorParameterWithID : public HostedAudioProcessorParameter | class JUCE_API AudioProcessorParameterWithID : public HostedAudioProcessorParameter | ||||
| { | { | ||||
| public: | public: | ||||
| /** The creation of this object requires providing a name and ID which will be constant for its lifetime. | |||||
| Given that AudioProcessorParameterWithID is abstract, you'll probably call this constructor | |||||
| from a derived class constructor, e.g. | |||||
| @code | |||||
| MyParameterType (String paramID, String name, String label, bool automatable) | |||||
| : AudioProcessorParameterWithID (paramID, name, AudioProcessorParameterWithIDAttributes().withLabel (label) | |||||
| .withAutomatable (automatable)) | |||||
| { | |||||
| } | |||||
| @endcode | |||||
| @param parameterID Specifies the identifier, and optionally the parameter's version hint. | |||||
| @param parameterName The user-facing parameter name. | |||||
| @param attributes Other parameter properties. | |||||
| */ | |||||
| AudioProcessorParameterWithID (const ParameterID& parameterID, | |||||
| const String& parameterName, | |||||
| const AudioProcessorParameterWithIDAttributes& attributes = {}); | |||||
| /** The creation of this object requires providing a name and ID which will be | /** The creation of this object requires providing a name and ID which will be | ||||
| constant for its lifetime. | constant for its lifetime. | ||||
| @@ -43,13 +144,18 @@ public: | |||||
| @param parameterName The user-facing name of the parameter | @param parameterName The user-facing name of the parameter | ||||
| @param parameterLabel An optional label for the parameter's value | @param parameterLabel An optional label for the parameter's value | ||||
| @param parameterCategory The semantics of this parameter | @param parameterCategory The semantics of this parameter | ||||
| @param versionHint See AudioProcessorParameter::getVersionHint() | |||||
| */ | */ | ||||
| AudioProcessorParameterWithID (const String& parameterID, | |||||
| [[deprecated ("Prefer the signature taking an Attributes argument")]] | |||||
| AudioProcessorParameterWithID (const ParameterID& parameterID, | |||||
| const String& parameterName, | const String& parameterName, | ||||
| const String& parameterLabel = {}, | |||||
| Category parameterCategory = AudioProcessorParameter::genericParameter, | |||||
| int versionHint = 0); | |||||
| const String& parameterLabel, | |||||
| Category parameterCategory = AudioProcessorParameter::genericParameter) | |||||
| : AudioProcessorParameterWithID (parameterID, | |||||
| parameterName, | |||||
| AudioProcessorParameterWithIDAttributes().withLabel (parameterLabel) | |||||
| .withCategory (parameterCategory)) | |||||
| { | |||||
| } | |||||
| /** Provides access to the parameter's ID string. */ | /** Provides access to the parameter's ID string. */ | ||||
| const String paramID; | const String paramID; | ||||
| @@ -67,9 +173,14 @@ public: | |||||
| String getLabel() const override; | String getLabel() const override; | ||||
| Category getCategory() const override; | Category getCategory() const override; | ||||
| String getParameterID() const override { return paramID; } | |||||
| String getParameterID() const override { return paramID; } | |||||
| bool isMetaParameter() const override { return meta; } | |||||
| bool isAutomatable() const override { return automatable; } | |||||
| bool isOrientationInverted() const override { return inverted; } | |||||
| private: | private: | ||||
| bool meta = false, automatable = true, inverted = false; | |||||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioProcessorParameterWithID) | JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioProcessorParameterWithID) | ||||
| }; | }; | ||||
| @@ -27,42 +27,26 @@ namespace juce | |||||
| { | { | ||||
| //============================================================================== | //============================================================================== | ||||
| AudioProcessorValueTreeState::Parameter::Parameter (const String& parameterID, | |||||
| AudioProcessorValueTreeState::Parameter::Parameter (const ParameterID& parameterID, | |||||
| const String& parameterName, | const String& parameterName, | ||||
| const String& labelText, | |||||
| NormalisableRange<float> valueRange, | NormalisableRange<float> valueRange, | ||||
| float defaultParameterValue, | float defaultParameterValue, | ||||
| std::function<String (float)> valueToTextFunction, | |||||
| std::function<float (const String&)> textToValueFunction, | |||||
| bool isMetaParameter, | |||||
| bool isAutomatableParameter, | |||||
| bool isDiscrete, | |||||
| AudioProcessorParameter::Category parameterCategory, | |||||
| bool isBoolean, | |||||
| int versionHintToUse) | |||||
| const AudioProcessorValueTreeStateParameterAttributes& attributes) | |||||
| : AudioParameterFloat (parameterID, | : AudioParameterFloat (parameterID, | ||||
| parameterName, | parameterName, | ||||
| valueRange, | valueRange, | ||||
| defaultParameterValue, | defaultParameterValue, | ||||
| labelText, | |||||
| parameterCategory, | |||||
| valueToTextFunction == nullptr ? std::function<String (float v, int)>() | |||||
| : [valueToTextFunction] (float v, int) { return valueToTextFunction (v); }, | |||||
| std::move (textToValueFunction), | |||||
| versionHintToUse), | |||||
| attributes.getAudioParameterFloatAttributes()), | |||||
| unsnappedDefault (valueRange.convertTo0to1 (defaultParameterValue)), | unsnappedDefault (valueRange.convertTo0to1 (defaultParameterValue)), | ||||
| metaParameter (isMetaParameter), | |||||
| automatable (isAutomatableParameter), | |||||
| discrete (isDiscrete), | |||||
| boolean (isBoolean) | |||||
| discrete (attributes.getDiscrete()), | |||||
| boolean (attributes.getBoolean()) | |||||
| { | { | ||||
| } | } | ||||
| float AudioProcessorValueTreeState::Parameter::getDefaultValue() const { return unsnappedDefault; } | float AudioProcessorValueTreeState::Parameter::getDefaultValue() const { return unsnappedDefault; } | ||||
| int AudioProcessorValueTreeState::Parameter::getNumSteps() const { return RangedAudioParameter::getNumSteps(); } | int AudioProcessorValueTreeState::Parameter::getNumSteps() const { return RangedAudioParameter::getNumSteps(); } | ||||
| bool AudioProcessorValueTreeState::Parameter::isMetaParameter() const { return metaParameter; } | |||||
| bool AudioProcessorValueTreeState::Parameter::isAutomatable() const { return automatable; } | |||||
| bool AudioProcessorValueTreeState::Parameter::isDiscrete() const { return discrete; } | bool AudioProcessorValueTreeState::Parameter::isDiscrete() const { return discrete; } | ||||
| bool AudioProcessorValueTreeState::Parameter::isBoolean() const { return boolean; } | bool AudioProcessorValueTreeState::Parameter::isBoolean() const { return boolean; } | ||||
| @@ -305,18 +289,21 @@ RangedAudioParameter* AudioProcessorValueTreeState::createAndAddParameter (const | |||||
| AudioProcessorParameter::Category category, | AudioProcessorParameter::Category category, | ||||
| bool isBooleanParameter) | bool isBooleanParameter) | ||||
| { | { | ||||
| auto attributes = AudioProcessorValueTreeStateParameterAttributes() | |||||
| .withLabel (labelText) | |||||
| .withStringFromValueFunction ([fn = std::move (valueToTextFunction)] (float v, int) { return fn (v); }) | |||||
| .withValueFromStringFunction (std::move (textToValueFunction)) | |||||
| .withMeta (isMetaParameter) | |||||
| .withAutomatable (isAutomatableParameter) | |||||
| .withDiscrete (isDiscreteParameter) | |||||
| .withCategory (category) | |||||
| .withBoolean (isBooleanParameter); | |||||
| return createAndAddParameter (std::make_unique<Parameter> (paramID, | return createAndAddParameter (std::make_unique<Parameter> (paramID, | ||||
| paramName, | paramName, | ||||
| labelText, | |||||
| range, | range, | ||||
| defaultVal, | defaultVal, | ||||
| std::move (valueToTextFunction), | |||||
| std::move (textToValueFunction), | |||||
| isMetaParameter, | |||||
| isAutomatableParameter, | |||||
| isDiscreteParameter, | |||||
| category, | |||||
| isBooleanParameter)); | |||||
| std::move (attributes))); | |||||
| } | } | ||||
| RangedAudioParameter* AudioProcessorValueTreeState::createAndAddParameter (std::unique_ptr<RangedAudioParameter> param) | RangedAudioParameter* AudioProcessorValueTreeState::createAndAddParameter (std::unique_ptr<RangedAudioParameter> param) | ||||
| @@ -535,7 +522,7 @@ struct ParameterAdapterTests : public UnitTest | |||||
| { | { | ||||
| const auto test = [&] (NormalisableRange<float> range, float value) | const auto test = [&] (NormalisableRange<float> range, float value) | ||||
| { | { | ||||
| AudioParameterFloat param ({}, {}, range, value, {}); | |||||
| AudioParameterFloat param ({}, {}, range, value); | |||||
| AudioProcessorValueTreeState::ParameterAdapter adapter (param); | AudioProcessorValueTreeState::ParameterAdapter adapter (param); | ||||
| @@ -550,7 +537,7 @@ struct ParameterAdapterTests : public UnitTest | |||||
| { | { | ||||
| const auto test = [&] (NormalisableRange<float> range, float value) | const auto test = [&] (NormalisableRange<float> range, float value) | ||||
| { | { | ||||
| AudioParameterFloat param ({}, {}, range, {}, {}); | |||||
| AudioParameterFloat param ({}, {}, range, {}); | |||||
| AudioProcessorValueTreeState::ParameterAdapter adapter (param); | AudioProcessorValueTreeState::ParameterAdapter adapter (param); | ||||
| adapter.setDenormalisedValue (value); | adapter.setDenormalisedValue (value); | ||||
| @@ -567,7 +554,7 @@ struct ParameterAdapterTests : public UnitTest | |||||
| { | { | ||||
| const auto test = [&] (NormalisableRange<float> range, float value, String expected) | const auto test = [&] (NormalisableRange<float> range, float value, String expected) | ||||
| { | { | ||||
| AudioParameterFloat param ({}, {}, range, {}, {}); | |||||
| AudioParameterFloat param ({}, {}, range, {}); | |||||
| AudioProcessorValueTreeState::ParameterAdapter adapter (param); | AudioProcessorValueTreeState::ParameterAdapter adapter (param); | ||||
| expectEquals (adapter.getTextForDenormalisedValue (value), expected); | expectEquals (adapter.getTextForDenormalisedValue (value), expected); | ||||
| @@ -583,7 +570,7 @@ struct ParameterAdapterTests : public UnitTest | |||||
| { | { | ||||
| const auto test = [&] (NormalisableRange<float> range, String text, float expected) | const auto test = [&] (NormalisableRange<float> range, String text, float expected) | ||||
| { | { | ||||
| AudioParameterFloat param ({}, {}, range, {}, {}); | |||||
| AudioParameterFloat param ({}, {}, range, {}); | |||||
| AudioProcessorValueTreeState::ParameterAdapter adapter (param); | AudioProcessorValueTreeState::ParameterAdapter adapter (param); | ||||
| expectEquals (adapter.getDenormalisedValueForText (text), expected); | expectEquals (adapter.getDenormalisedValueForText (text), expected); | ||||
| @@ -623,6 +610,7 @@ private: | |||||
| using Parameter = AudioProcessorValueTreeState::Parameter; | using Parameter = AudioProcessorValueTreeState::Parameter; | ||||
| using ParameterGroup = AudioProcessorParameterGroup; | using ParameterGroup = AudioProcessorParameterGroup; | ||||
| using ParameterLayout = AudioProcessorValueTreeState::ParameterLayout; | using ParameterLayout = AudioProcessorValueTreeState::ParameterLayout; | ||||
| using Attributes = AudioProcessorValueTreeStateParameterAttributes; | |||||
| class TestAudioProcessor : public AudioProcessor | class TestAudioProcessor : public AudioProcessor | ||||
| { | { | ||||
| @@ -679,8 +667,11 @@ public: | |||||
| { | { | ||||
| TestAudioProcessor proc; | TestAudioProcessor proc; | ||||
| proc.state.createAndAddParameter (std::make_unique<Parameter> (String(), String(), String(), NormalisableRange<float>(), | |||||
| 0.0f, nullptr, nullptr)); | |||||
| proc.state.createAndAddParameter (std::make_unique<Parameter> ( | |||||
| String(), | |||||
| String(), | |||||
| NormalisableRange<float>(), | |||||
| 0.0f)); | |||||
| expectEquals (proc.getParameters().size(), 1); | expectEquals (proc.getParameters().size(), 1); | ||||
| } | } | ||||
| @@ -690,8 +681,11 @@ public: | |||||
| TestAudioProcessor proc; | TestAudioProcessor proc; | ||||
| const auto key = "id"; | const auto key = "id"; | ||||
| const auto param = proc.state.createAndAddParameter (std::make_unique<Parameter> (key, String(), String(), NormalisableRange<float>(), | |||||
| 0.0f, nullptr, nullptr)); | |||||
| const auto param = proc.state.createAndAddParameter (std::make_unique<Parameter> ( | |||||
| key, | |||||
| String(), | |||||
| NormalisableRange<float>(), | |||||
| 0.0f)); | |||||
| expect (proc.state.getParameter (key) == param); | expect (proc.state.getParameter (key) == param); | ||||
| } | } | ||||
| @@ -723,8 +717,12 @@ public: | |||||
| TestAudioProcessor proc; | TestAudioProcessor proc; | ||||
| const auto key = "id"; | const auto key = "id"; | ||||
| const auto param = proc.state.createAndAddParameter (std::make_unique<Parameter> (key, String(), String(), NormalisableRange<float>(), | |||||
| 0.0f, nullptr, nullptr, true)); | |||||
| const auto param = proc.state.createAndAddParameter (std::make_unique<Parameter> ( | |||||
| key, | |||||
| String(), | |||||
| NormalisableRange<float>(), | |||||
| 0.0f, | |||||
| Attributes().withMeta (true))); | |||||
| expect (param->isMetaParameter()); | expect (param->isMetaParameter()); | ||||
| } | } | ||||
| @@ -734,8 +732,12 @@ public: | |||||
| TestAudioProcessor proc; | TestAudioProcessor proc; | ||||
| const auto key = "id"; | const auto key = "id"; | ||||
| const auto param = proc.state.createAndAddParameter (std::make_unique<Parameter> (key, String(), String(), NormalisableRange<float>(), | |||||
| 0.0f, nullptr, nullptr, false, true)); | |||||
| const auto param = proc.state.createAndAddParameter (std::make_unique<Parameter> ( | |||||
| key, | |||||
| String(), | |||||
| NormalisableRange<float>(), | |||||
| 0.0f, | |||||
| Attributes().withAutomatable (true))); | |||||
| expect (param->isAutomatable()); | expect (param->isAutomatable()); | ||||
| } | } | ||||
| @@ -745,8 +747,12 @@ public: | |||||
| TestAudioProcessor proc; | TestAudioProcessor proc; | ||||
| const auto key = "id"; | const auto key = "id"; | ||||
| const auto param = proc.state.createAndAddParameter (std::make_unique<Parameter> (key, String(), String(), NormalisableRange<float>(), | |||||
| 0.0f, nullptr, nullptr, false, false, true)); | |||||
| const auto param = proc.state.createAndAddParameter (std::make_unique<Parameter> ( | |||||
| key, | |||||
| String(), | |||||
| NormalisableRange<float>(), | |||||
| 0.0f, | |||||
| Attributes().withDiscrete (true))); | |||||
| expect (param->isDiscrete()); | expect (param->isDiscrete()); | ||||
| } | } | ||||
| @@ -756,9 +762,12 @@ public: | |||||
| TestAudioProcessor proc; | TestAudioProcessor proc; | ||||
| const auto key = "id"; | const auto key = "id"; | ||||
| const auto param = proc.state.createAndAddParameter (std::make_unique<Parameter> (key, String(), String(), NormalisableRange<float>(), | |||||
| 0.0f, nullptr, nullptr, false, false, false, | |||||
| AudioProcessorParameter::Category::inputMeter)); | |||||
| const auto param = proc.state.createAndAddParameter (std::make_unique<Parameter> ( | |||||
| key, | |||||
| String(), | |||||
| NormalisableRange<float>(), | |||||
| 0.0f, | |||||
| Attributes().withCategory (AudioProcessorParameter::Category::inputMeter))); | |||||
| expect (param->category == AudioProcessorParameter::Category::inputMeter); | expect (param->category == AudioProcessorParameter::Category::inputMeter); | ||||
| } | } | ||||
| @@ -768,9 +777,12 @@ public: | |||||
| TestAudioProcessor proc; | TestAudioProcessor proc; | ||||
| const auto key = "id"; | const auto key = "id"; | ||||
| const auto param = proc.state.createAndAddParameter (std::make_unique<Parameter> (key, String(), String(), NormalisableRange<float>(), | |||||
| 0.0f, nullptr, nullptr, false, false, false, | |||||
| AudioProcessorParameter::Category::genericParameter, true)); | |||||
| const auto param = proc.state.createAndAddParameter (std::make_unique<Parameter> ( | |||||
| key, | |||||
| String(), | |||||
| NormalisableRange<float>(), | |||||
| 0.0f, | |||||
| Attributes().withBoolean (true))); | |||||
| expect (param->isBoolean()); | expect (param->isBoolean()); | ||||
| } | } | ||||
| @@ -790,11 +802,17 @@ public: | |||||
| { | { | ||||
| TestAudioProcessor proc; | TestAudioProcessor proc; | ||||
| const auto key = "id"; | const auto key = "id"; | ||||
| const auto param = proc.state.createAndAddParameter (std::make_unique<Parameter> (key, String(), String(), NormalisableRange<float>(), | |||||
| 0.0f, nullptr, nullptr)); | |||||
| const auto param = proc.state.createAndAddParameter (std::make_unique<Parameter> ( | |||||
| key, | |||||
| String(), | |||||
| NormalisableRange<float>(), | |||||
| 0.0f)); | |||||
| proc.state.createAndAddParameter (std::make_unique<Parameter> (key, String(), String(), NormalisableRange<float>(), | |||||
| 0.0f, nullptr, nullptr)); | |||||
| proc.state.createAndAddParameter (std::make_unique<Parameter> ( | |||||
| key, | |||||
| String(), | |||||
| NormalisableRange<float>(), | |||||
| 0.0f)); | |||||
| expectEquals (proc.getParameters().size(), 1); | expectEquals (proc.getParameters().size(), 1); | ||||
| expect (proc.getParameters().getFirst() == param); | expect (proc.getParameters().getFirst() == param); | ||||
| @@ -804,8 +822,11 @@ public: | |||||
| { | { | ||||
| TestAudioProcessor proc; | TestAudioProcessor proc; | ||||
| const auto key = "id"; | const auto key = "id"; | ||||
| const auto param = proc.state.createAndAddParameter (std::make_unique<Parameter> (key, String(), String(), NormalisableRange<float>(), | |||||
| 0.0f, nullptr, nullptr)); | |||||
| const auto param = proc.state.createAndAddParameter (std::make_unique<Parameter> ( | |||||
| key, | |||||
| String(), | |||||
| NormalisableRange<float>(), | |||||
| 0.0f)); | |||||
| const auto value = 0.5f; | const auto value = 0.5f; | ||||
| param->setValueNotifyingHost (value); | param->setValueNotifyingHost (value); | ||||
| @@ -822,11 +843,8 @@ public: | |||||
| proc.state.createAndAddParameter (std::make_unique<Parameter> ( | proc.state.createAndAddParameter (std::make_unique<Parameter> ( | ||||
| key, | key, | ||||
| String(), | String(), | ||||
| String(), | |||||
| NormalisableRange<float> (0.0f, 100.0f, 10.0f), | NormalisableRange<float> (0.0f, 100.0f, 10.0f), | ||||
| value, | |||||
| nullptr, | |||||
| nullptr)); | |||||
| value)); | |||||
| expectEquals (proc.state.getRawParameterValue (key)->load(), value); | expectEquals (proc.state.getRawParameterValue (key)->load(), value); | ||||
| } | } | ||||
| @@ -836,8 +854,11 @@ public: | |||||
| Listener listener; | Listener listener; | ||||
| TestAudioProcessor proc; | TestAudioProcessor proc; | ||||
| const auto key = "id"; | const auto key = "id"; | ||||
| const auto param = proc.state.createAndAddParameter (std::make_unique<Parameter> (key, String(), String(), NormalisableRange<float>(), | |||||
| 0.0f, nullptr, nullptr)); | |||||
| const auto param = proc.state.createAndAddParameter (std::make_unique<Parameter> ( | |||||
| key, | |||||
| String(), | |||||
| NormalisableRange<float>(), | |||||
| 0.0f)); | |||||
| proc.state.addParameterListener (key, &listener); | proc.state.addParameterListener (key, &listener); | ||||
| const auto value = 0.5f; | const auto value = 0.5f; | ||||
| @@ -893,8 +914,11 @@ public: | |||||
| TestAudioProcessor proc; | TestAudioProcessor proc; | ||||
| const auto key = "id"; | const auto key = "id"; | ||||
| const auto initialValue = 0.2f; | const auto initialValue = 0.2f; | ||||
| auto param = proc.state.createAndAddParameter (std::make_unique<Parameter> (key, String(), String(), NormalisableRange<float>(), | |||||
| initialValue, nullptr, nullptr)); | |||||
| auto param = proc.state.createAndAddParameter (std::make_unique<Parameter> ( | |||||
| key, | |||||
| String(), | |||||
| NormalisableRange<float>(), | |||||
| initialValue)); | |||||
| proc.state.state = ValueTree { "state" }; | proc.state.state = ValueTree { "state" }; | ||||
| auto value = proc.state.getParameterAsValue (key); | auto value = proc.state.getParameterAsValue (key); | ||||
| @@ -928,8 +952,11 @@ public: | |||||
| Listener listener; | Listener listener; | ||||
| TestAudioProcessor proc; | TestAudioProcessor proc; | ||||
| const auto key = "id"; | const auto key = "id"; | ||||
| proc.state.createAndAddParameter (std::make_unique<Parameter> (key, String(), String(), NormalisableRange<float>(), | |||||
| 0.0f, nullptr, nullptr)); | |||||
| proc.state.createAndAddParameter (std::make_unique<Parameter> ( | |||||
| key, | |||||
| String(), | |||||
| NormalisableRange<float>(), | |||||
| 0.0f)); | |||||
| proc.state.addParameterListener (key, &listener); | proc.state.addParameterListener (key, &listener); | ||||
| proc.state.state = ValueTree { "state" }; | proc.state.state = ValueTree { "state" }; | ||||
| @@ -26,6 +26,60 @@ | |||||
| namespace juce | namespace juce | ||||
| { | { | ||||
| /** Advanced properties of an AudioProcessorValueTreeState::Parameter. | |||||
| The members here have the same meaning as the similarly-named member functions of | |||||
| AudioParameterFloatAttributes. | |||||
| @see AudioParameterFloatAttributes, RangedAudioParameterAttributes | |||||
| */ | |||||
| class AudioProcessorValueTreeStateParameterAttributes | |||||
| { | |||||
| using This = AudioProcessorValueTreeStateParameterAttributes; | |||||
| using StringFromValue = AudioParameterFloatAttributes::StringFromValue; | |||||
| using ValueFromString = AudioParameterFloatAttributes::ValueFromString; | |||||
| using Category = AudioParameterFloatAttributes::Category; | |||||
| public: | |||||
| /** @see RangedAudioParameterAttributes::withStringFromValueFunction() */ | |||||
| JUCE_NODISCARD auto withStringFromValueFunction (StringFromValue x) const { return withMember (*this, &This::attributes, attributes.withStringFromValueFunction (std::move (x))); } | |||||
| /** @see RangedAudioParameterAttributes::withValueFromStringFunction() */ | |||||
| JUCE_NODISCARD auto withValueFromStringFunction (ValueFromString x) const { return withMember (*this, &This::attributes, attributes.withValueFromStringFunction (std::move (x))); } | |||||
| /** @see RangedAudioParameterAttributes::withLabel() */ | |||||
| JUCE_NODISCARD auto withLabel (String x) const { return withMember (*this, &This::attributes, attributes.withLabel (std::move (x))); } | |||||
| /** @see RangedAudioParameterAttributes::withCategory() */ | |||||
| JUCE_NODISCARD auto withCategory (Category x) const { return withMember (*this, &This::attributes, attributes.withCategory (std::move (x))); } | |||||
| /** @see RangedAudioParameterAttributes::withMeta() */ | |||||
| JUCE_NODISCARD auto withMeta (bool x) const { return withMember (*this, &This::attributes, attributes.withMeta (std::move (x))); } | |||||
| /** @see RangedAudioParameterAttributes::withAutomatable() */ | |||||
| JUCE_NODISCARD auto withAutomatable (bool x) const { return withMember (*this, &This::attributes, attributes.withAutomatable (std::move (x))); } | |||||
| /** @see RangedAudioParameterAttributes::withInverted() */ | |||||
| JUCE_NODISCARD auto withInverted (bool x) const { return withMember (*this, &This::attributes, attributes.withInverted (std::move (x))); } | |||||
| /** Pass 'true' if this parameter has discrete steps, or 'false' if the parameter is continuous. | |||||
| Using an AudioParameterChoice or AudioParameterInt might be a better choice than setting this flag. | |||||
| */ | |||||
| JUCE_NODISCARD auto withDiscrete (bool x) const { return withMember (*this, &This::discrete, std::move (x)); } | |||||
| /** Pass 'true' if this parameter only has two valid states. | |||||
| Using an AudioParameterBool might be a better choice than setting this flag. | |||||
| */ | |||||
| JUCE_NODISCARD auto withBoolean (bool x) const { return withMember (*this, &This::boolean, std::move (x)); } | |||||
| /** @returns all attributes that might also apply to an AudioParameterFloat */ | |||||
| JUCE_NODISCARD const auto& getAudioParameterFloatAttributes() const { return attributes; } | |||||
| /** @returns 'true' if this parameter has discrete steps, or 'false' if the parameter is continuous. */ | |||||
| JUCE_NODISCARD const auto& getDiscrete() const { return discrete; } | |||||
| /** @returns 'true' if this parameter only has two valid states. */ | |||||
| JUCE_NODISCARD const auto& getBoolean() const { return boolean; } | |||||
| private: | |||||
| AudioParameterFloatAttributes attributes; | |||||
| bool discrete = false, boolean = false; | |||||
| }; | |||||
| /** | /** | ||||
| This class contains a ValueTree that is used to manage an AudioProcessor's entire state. | This class contains a ValueTree that is used to manage an AudioProcessor's entire state. | ||||
| @@ -398,25 +452,65 @@ public: | |||||
| class Parameter final : public AudioParameterFloat | class Parameter final : public AudioParameterFloat | ||||
| { | { | ||||
| public: | public: | ||||
| Parameter (const String& parameterID, | |||||
| /** Constructs a parameter instance. | |||||
| Example usage: | |||||
| @code | |||||
| using Parameter = AudioProcessorValueTreeState::Parameter; | |||||
| using Attributes = AudioProcessorValueTreeStateParameterAttributes; | |||||
| auto parameter = std::make_unique<Parameter> (ParameterID { "uniqueID", 1 }, | |||||
| "Name", | |||||
| NormalisableRange<float> { 0.0f, 100.0f }, | |||||
| 50.0f, | |||||
| Attributes().withStringFromValueFunction (myStringFromValueFunction) | |||||
| .withValueFromStringFunction (myValueFromStringFunction) | |||||
| .withLabel ("%")); | |||||
| @endcode | |||||
| @param parameterID The globally-unique identifier of this parameter | |||||
| @param parameterName The user-facing name of this parameter | |||||
| @param valueRange The valid range of values for this parameter | |||||
| @param defaultValue The initial parameter value | |||||
| @param attributes Further advanced settings to customise the behaviour of this parameter | |||||
| */ | |||||
| Parameter (const ParameterID& parameterID, | |||||
| const String& parameterName, | const String& parameterName, | ||||
| const String& labelText, | |||||
| NormalisableRange<float> valueRange, | NormalisableRange<float> valueRange, | ||||
| float defaultValue, | float defaultValue, | ||||
| const AudioProcessorValueTreeStateParameterAttributes& attributes = {}); | |||||
| [[deprecated ("Prefer the signature taking an Attributes argument")]] | |||||
| Parameter (const ParameterID& parameterID, | |||||
| const String& parameterName, | |||||
| const String& labelText, | |||||
| NormalisableRange<float> valueRange, | |||||
| float defaultParameterValue, | |||||
| std::function<String (float)> valueToTextFunction, | std::function<String (float)> valueToTextFunction, | ||||
| std::function<float (const String&)> textToValueFunction, | std::function<float (const String&)> textToValueFunction, | ||||
| bool isMetaParameter = false, | |||||
| bool isAutomatableParameter = true, | |||||
| bool isDiscrete = false, | |||||
| AudioProcessorParameter::Category parameterCategory = AudioProcessorParameter::genericParameter, | |||||
| bool isBoolean = false, | |||||
| int versionHint = 0); | |||||
| bool isMetaParameter, | |||||
| bool isAutomatableParameter, | |||||
| bool isDiscrete, | |||||
| AudioProcessorParameter::Category parameterCategory, | |||||
| bool isBoolean) | |||||
| : Parameter (parameterID, | |||||
| parameterName, | |||||
| valueRange, | |||||
| defaultParameterValue, | |||||
| AudioProcessorValueTreeStateParameterAttributes().withLabel (labelText) | |||||
| .withStringFromValueFunction ([valueToTextFunction] (float v, int) { return valueToTextFunction (v); }) | |||||
| .withValueFromStringFunction (std::move (textToValueFunction)) | |||||
| .withMeta (isMetaParameter) | |||||
| .withAutomatable (isAutomatableParameter) | |||||
| .withDiscrete (isDiscrete) | |||||
| .withCategory (parameterCategory) | |||||
| .withBoolean (isBoolean)) | |||||
| { | |||||
| } | |||||
| float getDefaultValue() const override; | float getDefaultValue() const override; | ||||
| int getNumSteps() const override; | int getNumSteps() const override; | ||||
| bool isMetaParameter() const override; | |||||
| bool isAutomatable() const override; | |||||
| bool isDiscrete() const override; | bool isDiscrete() const override; | ||||
| bool isBoolean() const override; | bool isBoolean() const override; | ||||
| @@ -426,7 +520,7 @@ public: | |||||
| std::function<void()> onValueChanged; | std::function<void()> onValueChanged; | ||||
| const float unsnappedDefault; | const float unsnappedDefault; | ||||
| const bool metaParameter, automatable, discrete, boolean; | |||||
| const bool discrete, boolean; | |||||
| std::atomic<float> lastValue { -1.0f }; | std::atomic<float> lastValue { -1.0f }; | ||||
| friend class AudioProcessorValueTreeState::ParameterAdapter; | friend class AudioProcessorValueTreeState::ParameterAdapter; | ||||
| @@ -26,6 +26,67 @@ | |||||
| namespace juce | namespace juce | ||||
| { | { | ||||
| /** | |||||
| @internal | |||||
| Holds common attributes of audio parameters. | |||||
| CRTP is used here because we want the Attributes types for each parameter | |||||
| (Float, Bool, Choice, Int) to be distinct and extensible in the future. | |||||
| i.e. the identifiers AudioParameterFloatAttributes and RangedAudioParameterAttributes<float> | |||||
| should not be interchangable because we might need to add float-specific attributes in | |||||
| the future. Users should not refer directly to RangedAudioParameterAttributes. | |||||
| */ | |||||
| template <typename Derived, typename Value> | |||||
| class RangedAudioParameterAttributes | |||||
| { | |||||
| using This = RangedAudioParameterAttributes; | |||||
| public: | |||||
| using Category = AudioProcessorParameter::Category; | |||||
| using StringFromValue = std::function<String (Value, int)>; | |||||
| using ValueFromString = std::function<Value (const String&)>; | |||||
| /** An optional lambda function that converts a non-normalised value to a string with a maximum length. This may be used by hosts to display the parameter's value. */ | |||||
| JUCE_NODISCARD auto withStringFromValueFunction (StringFromValue x) const { return withMember (asDerived(), &Derived::stringFromValue, std::move (x)); } | |||||
| /** An optional lambda function that parses a string and converts it into a non-normalised value. Some hosts use this to allow users to type in parameter values. */ | |||||
| JUCE_NODISCARD auto withValueFromStringFunction (ValueFromString x) const { return withMember (asDerived(), &Derived::valueFromString, std::move (x)); } | |||||
| /** See AudioProcessorParameterWithIDAttributes::withLabel() */ | |||||
| JUCE_NODISCARD auto withLabel (String x) const { return withMember (asDerived(), &Derived::attributes, attributes.withLabel (std::move (x))); } | |||||
| /** See AudioProcessorParameterWithIDAttributes::withCategory() */ | |||||
| JUCE_NODISCARD auto withCategory (Category x) const { return withMember (asDerived(), &Derived::attributes, attributes.withCategory (std::move (x))); } | |||||
| /** See AudioProcessorParameter::isMetaParameter() */ | |||||
| JUCE_NODISCARD auto withMeta (bool x) const { return withMember (asDerived(), &Derived::attributes, attributes.withMeta (std::move (x))); } | |||||
| /** See AudioProcessorParameter::isAutomatable() */ | |||||
| JUCE_NODISCARD auto withAutomatable (bool x) const { return withMember (asDerived(), &Derived::attributes, attributes.withAutomatable (std::move (x))); } | |||||
| /** See AudioProcessorParameter::isOrientationInverted() */ | |||||
| JUCE_NODISCARD auto withInverted (bool x) const { return withMember (asDerived(), &Derived::attributes, attributes.withInverted (std::move (x))); } | |||||
| /** An optional lambda function that converts a non-normalised value to a string with a maximum length. This may be used by hosts to display the parameter's value. */ | |||||
| JUCE_NODISCARD const auto& getStringFromValueFunction() const { return stringFromValue; } | |||||
| /** An optional lambda function that parses a string and converts it into a non-normalised value. Some hosts use this to allow users to type in parameter values. */ | |||||
| JUCE_NODISCARD const auto& getValueFromStringFunction() const { return valueFromString; } | |||||
| /** Gets attributes that would also apply to an AudioProcessorParameterWithID */ | |||||
| JUCE_NODISCARD const auto& getAudioProcessorParameterWithIDAttributes() const { return attributes; } | |||||
| private: | |||||
| auto& asDerived() const { return *static_cast<const Derived*> (this); } | |||||
| AudioProcessorParameterWithIDAttributes attributes; | |||||
| StringFromValue stringFromValue; | |||||
| ValueFromString valueFromString; | |||||
| }; | |||||
| //============================================================================== | |||||
| /** | /** | ||||
| This abstract base class is used by some AudioProcessorParameter helper classes. | This abstract base class is used by some AudioProcessorParameter helper classes. | ||||
| @@ -36,15 +97,6 @@ namespace juce | |||||
| class JUCE_API RangedAudioParameter : public AudioProcessorParameterWithID | class JUCE_API RangedAudioParameter : public AudioProcessorParameterWithID | ||||
| { | { | ||||
| public: | public: | ||||
| /** The creation of this object requires providing a name and ID which will be | |||||
| constant for its lifetime. | |||||
| @param parameterID Used to uniquely identify the parameter | |||||
| @param parameterName The user-facing name of the parameter | |||||
| @param parameterLabel An optional label for the parameter's value | |||||
| @param parameterCategory The semantics of this parameter | |||||
| @param versionHint See AudioProcessorParameter::getVersionHint() | |||||
| */ | |||||
| using AudioProcessorParameterWithID::AudioProcessorParameterWithID; | using AudioProcessorParameterWithID::AudioProcessorParameterWithID; | ||||
| /** Returns the range of values that the parameter can take. */ | /** Returns the range of values that the parameter can take. */ | ||||
| @@ -69,4 +69,20 @@ struct NullCheckedInvocation | |||||
| static void invoke (std::nullptr_t, Args&&...) {} | static void invoke (std::nullptr_t, Args&&...) {} | ||||
| }; | }; | ||||
| /** Can be used to disable template constructors that would otherwise cause ambiguity with | |||||
| compiler-generated copy and move constructors. | |||||
| Adapted from https://ericniebler.com/2013/08/07/universal-references-and-the-copy-constructo/ | |||||
| */ | |||||
| template <typename A, typename B> | |||||
| using DisableIfSameOrDerived = typename std::enable_if_t<! std::is_base_of<A, std::remove_reference_t<B>>::value>; | |||||
| /** Copies an object, sets one of the copy's members to the specified value, and then returns the copy. */ | |||||
| template <typename Object, typename OtherObject, typename Member> | |||||
| Object withMember (Object copy, Member OtherObject::* member, Member&& value) | |||||
| { | |||||
| copy.*member = std::forward<Member> (value); | |||||
| return copy; | |||||
| } | |||||
| } // namespace juce | } // namespace juce | ||||