| @@ -1,6 +1,34 @@ | |||
| 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 | |||
| ============= | |||
| @@ -1601,7 +1601,7 @@ namespace AAXClasses | |||
| if (bypassParameter == nullptr) | |||
| { | |||
| ownedBypassParameter.reset (new AudioParameterBool (cDefaultMasterBypassID, "Master Bypass", false, {}, {}, {})); | |||
| ownedBypassParameter.reset (new AudioParameterBool (cDefaultMasterBypassID, "Master Bypass", false)); | |||
| bypassParameter = ownedBypassParameter.get(); | |||
| } | |||
| @@ -526,7 +526,7 @@ private: | |||
| if (bypassParameter == nullptr) | |||
| { | |||
| vst3WrapperProvidedBypassParam = true; | |||
| ownedBypassParameter.reset (new AudioParameterBool ("byps", "Bypass", false, {}, {}, {})); | |||
| ownedBypassParameter.reset (new AudioParameterBool ("byps", "Bypass", false)); | |||
| bypassParameter = ownedBypassParameter.get(); | |||
| } | |||
| @@ -26,49 +26,36 @@ | |||
| namespace juce | |||
| { | |||
| AudioParameterBool::AudioParameterBool (const String& idToUse, | |||
| AudioParameterBool::AudioParameterBool (const ParameterID& idToUse, | |||
| const String& nameToUse, | |||
| 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() | |||
| @@ -81,7 +68,7 @@ AudioParameterBool::~AudioParameterBool() | |||
| float AudioParameterBool::getValue() const { return value; } | |||
| 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; } | |||
| bool AudioParameterBool::isDiscrete() const { return true; } | |||
| bool AudioParameterBool::isBoolean() const { return true; } | |||
| @@ -26,6 +26,13 @@ | |||
| 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. | |||
| @@ -36,6 +43,28 @@ namespace juce | |||
| class JUCE_API AudioParameterBool : public RangedAudioParameter | |||
| { | |||
| 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. | |||
| @param parameterID The parameter ID to use | |||
| @@ -48,13 +77,22 @@ public: | |||
| @param boolFromString An optional lambda function that parses a string and | |||
| converts it into a bool value. Some hosts use this | |||
| 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<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. */ | |||
| ~AudioParameterBool() override; | |||
| @@ -90,7 +128,7 @@ private: | |||
| const NormalisableRange<float> range { 0.0f, 1.0f, 1.0f }; | |||
| std::atomic<float> value; | |||
| const float defaultValue; | |||
| const float valueDefault; | |||
| std::function<String (bool, int)> stringFromBoolFunction; | |||
| std::function<bool (const String&)> boolFromStringFunction; | |||
| @@ -26,12 +26,12 @@ | |||
| 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), | |||
| range ([this] | |||
| { | |||
| @@ -44,16 +44,14 @@ AudioParameterChoice::AudioParameterChoice (const String& idToUse, const String& | |||
| }()), | |||
| value ((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! | |||
| 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() | |||
| @@ -26,6 +26,13 @@ | |||
| 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 | |||
| an indexed, named choice from a list. | |||
| @@ -39,10 +46,33 @@ class JUCE_API AudioParameterChoice : public RangedAudioParameter | |||
| public: | |||
| /** 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 parameterName The parameter name to use | |||
| @param choices The set of choices to use | |||
| @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 stringFromIndex An optional lambda function that converts a choice | |||
| 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 | |||
| converts it into a choice index. Some hosts use this | |||
| 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, | |||
| const String& parameterLabel = String(), | |||
| const String& parameterLabel, | |||
| 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. */ | |||
| ~AudioParameterChoice() override; | |||
| @@ -26,16 +26,17 @@ | |||
| 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) | |||
| { | |||
| @@ -71,7 +72,7 @@ AudioParameterFloat::AudioParameterFloat (const String& idToUse, const String& n | |||
| 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) | |||
| { | |||
| } | |||
| @@ -86,7 +87,7 @@ AudioParameterFloat::~AudioParameterFloat() | |||
| float AudioParameterFloat::getValue() const { return convertTo0to1 (value); } | |||
| 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(); } | |||
| String AudioParameterFloat::getText (float v, int length) const { return stringFromValueFunction (convertFrom0to1 (v), length); } | |||
| float AudioParameterFloat::getValueForText (const String& text) const { return convertTo0to1 (valueFromStringFunction (text)); } | |||
| @@ -26,6 +26,13 @@ | |||
| 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 | |||
| parameter which maps onto a given NormalisableRange. | |||
| @@ -37,6 +44,30 @@ namespace juce | |||
| class JUCE_API AudioParameterFloat : public RangedAudioParameter | |||
| { | |||
| 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. | |||
| @param parameterID The parameter ID to use | |||
| @@ -51,25 +82,34 @@ public: | |||
| @param valueFromString 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. | |||
| @param versionHint See AudioProcessorParameter::getVersionHint() | |||
| */ | |||
| AudioParameterFloat (const String& parameterID, | |||
| [[deprecated ("Prefer the signature taking an Attributes argument")]] | |||
| AudioParameterFloat (const ParameterID& parameterID, | |||
| const String& parameterName, | |||
| NormalisableRange<float> normalisableRange, | |||
| float defaultValue, | |||
| const String& parameterLabel = String(), | |||
| const String& parameterLabel, | |||
| Category parameterCategory = AudioProcessorParameter::genericParameter, | |||
| 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. | |||
| On creation, its value is set to the default value. | |||
| For control over skew factors, you can use the other | |||
| constructor and provide a NormalisableRange. | |||
| */ | |||
| AudioParameterFloat (String parameterID, | |||
| String parameterName, | |||
| AudioParameterFloat (const ParameterID& parameterID, | |||
| const String& parameterName, | |||
| float minValue, | |||
| float maxValue, | |||
| float defaultValue); | |||
| @@ -108,7 +148,7 @@ private: | |||
| float getValueForText (const String&) const override; | |||
| std::atomic<float> value; | |||
| const float defaultValue; | |||
| const float valueDefault; | |||
| std::function<String (float, int)> stringFromValueFunction; | |||
| std::function<float (const String&)> valueFromStringFunction; | |||
| @@ -26,34 +26,29 @@ | |||
| namespace juce | |||
| { | |||
| AudioParameterInt::AudioParameterInt (const String& idToUse, const String& nameToUse, | |||
| AudioParameterInt::AudioParameterInt (const ParameterID& idToUse, const String& nameToUse, | |||
| 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! | |||
| if (stringFromIntFunction == nullptr) | |||
| stringFromIntFunction = [] (int v, int) { return String (v); }; | |||
| if (intFromStringFunction == nullptr) | |||
| intFromStringFunction = [] (const String& text) { return text.getIntValue(); }; | |||
| } | |||
| AudioParameterInt::~AudioParameterInt() | |||
| @@ -26,6 +26,13 @@ | |||
| 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 | |||
| integer value with a given range. | |||
| @@ -39,11 +46,37 @@ class JUCE_API AudioParameterInt : public RangedAudioParameter | |||
| public: | |||
| /** 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 parameterName The parameter name to use | |||
| @param minValue The minimum parameter value | |||
| @param maxValue The maximum parameter 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 stringFromInt An optional lambda function that converts a int | |||
| 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 | |||
| and converts it into an int. Some hosts use this | |||
| 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<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. */ | |||
| ~AudioParameterInt() override; | |||
| @@ -26,16 +26,17 @@ | |||
| namespace juce | |||
| { | |||
| AudioProcessorParameterWithID::AudioProcessorParameterWithID (const String& idToUse, | |||
| AudioProcessorParameterWithID::AudioProcessorParameterWithID (const ParameterID& idToUse, | |||
| 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), | |||
| 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 | |||
| { | |||
| /** | |||
| 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. | |||
| @@ -36,6 +117,26 @@ namespace juce | |||
| class JUCE_API AudioProcessorParameterWithID : public HostedAudioProcessorParameter | |||
| { | |||
| 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 | |||
| constant for its lifetime. | |||
| @@ -43,13 +144,18 @@ public: | |||
| @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() | |||
| */ | |||
| AudioProcessorParameterWithID (const String& parameterID, | |||
| [[deprecated ("Prefer the signature taking an Attributes argument")]] | |||
| AudioProcessorParameterWithID (const ParameterID& parameterID, | |||
| 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. */ | |||
| const String paramID; | |||
| @@ -67,9 +173,14 @@ public: | |||
| String getLabel() 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: | |||
| bool meta = false, automatable = true, inverted = false; | |||
| 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& labelText, | |||
| NormalisableRange<float> valueRange, | |||
| 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, | |||
| parameterName, | |||
| valueRange, | |||
| 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)), | |||
| metaParameter (isMetaParameter), | |||
| automatable (isAutomatableParameter), | |||
| discrete (isDiscrete), | |||
| boolean (isBoolean) | |||
| discrete (attributes.getDiscrete()), | |||
| boolean (attributes.getBoolean()) | |||
| { | |||
| } | |||
| float AudioProcessorValueTreeState::Parameter::getDefaultValue() const { return unsnappedDefault; } | |||
| 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::isBoolean() const { return boolean; } | |||
| @@ -305,18 +289,21 @@ RangedAudioParameter* AudioProcessorValueTreeState::createAndAddParameter (const | |||
| AudioProcessorParameter::Category category, | |||
| 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, | |||
| paramName, | |||
| labelText, | |||
| range, | |||
| defaultVal, | |||
| std::move (valueToTextFunction), | |||
| std::move (textToValueFunction), | |||
| isMetaParameter, | |||
| isAutomatableParameter, | |||
| isDiscreteParameter, | |||
| category, | |||
| isBooleanParameter)); | |||
| std::move (attributes))); | |||
| } | |||
| RangedAudioParameter* AudioProcessorValueTreeState::createAndAddParameter (std::unique_ptr<RangedAudioParameter> param) | |||
| @@ -535,7 +522,7 @@ struct ParameterAdapterTests : public UnitTest | |||
| { | |||
| const auto test = [&] (NormalisableRange<float> range, float value) | |||
| { | |||
| AudioParameterFloat param ({}, {}, range, value, {}); | |||
| AudioParameterFloat param ({}, {}, range, value); | |||
| AudioProcessorValueTreeState::ParameterAdapter adapter (param); | |||
| @@ -550,7 +537,7 @@ struct ParameterAdapterTests : public UnitTest | |||
| { | |||
| const auto test = [&] (NormalisableRange<float> range, float value) | |||
| { | |||
| AudioParameterFloat param ({}, {}, range, {}, {}); | |||
| AudioParameterFloat param ({}, {}, range, {}); | |||
| AudioProcessorValueTreeState::ParameterAdapter adapter (param); | |||
| adapter.setDenormalisedValue (value); | |||
| @@ -567,7 +554,7 @@ struct ParameterAdapterTests : public UnitTest | |||
| { | |||
| const auto test = [&] (NormalisableRange<float> range, float value, String expected) | |||
| { | |||
| AudioParameterFloat param ({}, {}, range, {}, {}); | |||
| AudioParameterFloat param ({}, {}, range, {}); | |||
| AudioProcessorValueTreeState::ParameterAdapter adapter (param); | |||
| expectEquals (adapter.getTextForDenormalisedValue (value), expected); | |||
| @@ -583,7 +570,7 @@ struct ParameterAdapterTests : public UnitTest | |||
| { | |||
| const auto test = [&] (NormalisableRange<float> range, String text, float expected) | |||
| { | |||
| AudioParameterFloat param ({}, {}, range, {}, {}); | |||
| AudioParameterFloat param ({}, {}, range, {}); | |||
| AudioProcessorValueTreeState::ParameterAdapter adapter (param); | |||
| expectEquals (adapter.getDenormalisedValueForText (text), expected); | |||
| @@ -623,6 +610,7 @@ private: | |||
| using Parameter = AudioProcessorValueTreeState::Parameter; | |||
| using ParameterGroup = AudioProcessorParameterGroup; | |||
| using ParameterLayout = AudioProcessorValueTreeState::ParameterLayout; | |||
| using Attributes = AudioProcessorValueTreeStateParameterAttributes; | |||
| class TestAudioProcessor : public AudioProcessor | |||
| { | |||
| @@ -679,8 +667,11 @@ public: | |||
| { | |||
| 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); | |||
| } | |||
| @@ -690,8 +681,11 @@ public: | |||
| TestAudioProcessor proc; | |||
| 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); | |||
| } | |||
| @@ -723,8 +717,12 @@ public: | |||
| TestAudioProcessor proc; | |||
| 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()); | |||
| } | |||
| @@ -734,8 +732,12 @@ public: | |||
| TestAudioProcessor proc; | |||
| 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()); | |||
| } | |||
| @@ -745,8 +747,12 @@ public: | |||
| TestAudioProcessor proc; | |||
| 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()); | |||
| } | |||
| @@ -756,9 +762,12 @@ public: | |||
| TestAudioProcessor proc; | |||
| 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); | |||
| } | |||
| @@ -768,9 +777,12 @@ public: | |||
| TestAudioProcessor proc; | |||
| 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()); | |||
| } | |||
| @@ -790,11 +802,17 @@ public: | |||
| { | |||
| TestAudioProcessor proc; | |||
| 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); | |||
| expect (proc.getParameters().getFirst() == param); | |||
| @@ -804,8 +822,11 @@ public: | |||
| { | |||
| TestAudioProcessor proc; | |||
| 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; | |||
| param->setValueNotifyingHost (value); | |||
| @@ -822,11 +843,8 @@ public: | |||
| proc.state.createAndAddParameter (std::make_unique<Parameter> ( | |||
| key, | |||
| String(), | |||
| String(), | |||
| NormalisableRange<float> (0.0f, 100.0f, 10.0f), | |||
| value, | |||
| nullptr, | |||
| nullptr)); | |||
| value)); | |||
| expectEquals (proc.state.getRawParameterValue (key)->load(), value); | |||
| } | |||
| @@ -836,8 +854,11 @@ public: | |||
| Listener listener; | |||
| TestAudioProcessor proc; | |||
| 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); | |||
| const auto value = 0.5f; | |||
| @@ -893,8 +914,11 @@ public: | |||
| TestAudioProcessor proc; | |||
| const auto key = "id"; | |||
| 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" }; | |||
| auto value = proc.state.getParameterAsValue (key); | |||
| @@ -928,8 +952,11 @@ public: | |||
| Listener listener; | |||
| TestAudioProcessor proc; | |||
| 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.state = ValueTree { "state" }; | |||
| @@ -26,6 +26,60 @@ | |||
| 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. | |||
| @@ -398,25 +452,65 @@ public: | |||
| class Parameter final : public AudioParameterFloat | |||
| { | |||
| 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& labelText, | |||
| NormalisableRange<float> valueRange, | |||
| 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<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; | |||
| int getNumSteps() const override; | |||
| bool isMetaParameter() const override; | |||
| bool isAutomatable() const override; | |||
| bool isDiscrete() const override; | |||
| bool isBoolean() const override; | |||
| @@ -426,7 +520,7 @@ public: | |||
| std::function<void()> onValueChanged; | |||
| const float unsnappedDefault; | |||
| const bool metaParameter, automatable, discrete, boolean; | |||
| const bool discrete, boolean; | |||
| std::atomic<float> lastValue { -1.0f }; | |||
| friend class AudioProcessorValueTreeState::ParameterAdapter; | |||
| @@ -26,6 +26,67 @@ | |||
| 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. | |||
| @@ -36,15 +97,6 @@ namespace juce | |||
| class JUCE_API RangedAudioParameter : public AudioProcessorParameterWithID | |||
| { | |||
| 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; | |||
| /** Returns the range of values that the parameter can take. */ | |||
| @@ -69,4 +69,20 @@ struct NullCheckedInvocation | |||
| 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 | |||