| @@ -878,7 +878,15 @@ public: | |||||
| { | { | ||||
| #if ! JUCE_FORCE_LEGACY_PARAMETER_AUTOMATION_TYPE | #if ! JUCE_FORCE_LEGACY_PARAMETER_AUTOMATION_TYPE | ||||
| if (isParameterDiscrete) | if (isParameterDiscrete) | ||||
| { | |||||
| outParameterInfo.unit = kAudioUnitParameterUnit_Indexed; | outParameterInfo.unit = kAudioUnitParameterUnit_Indexed; | ||||
| if (auto* param = juceFilter->getParameters()[index]) | |||||
| { | |||||
| if (param->isBoolean()) | |||||
| outParameterInfo.unit = kAudioUnitParameterUnit_Boolean; | |||||
| } | |||||
| } | |||||
| #endif | #endif | ||||
| } | } | ||||
| @@ -1826,18 +1834,18 @@ private: | |||||
| OwnedArray<const __CFString>* stringValues = nullptr; | OwnedArray<const __CFString>* stringValues = nullptr; | ||||
| #if ! JUCE_FORCE_LEGACY_PARAMETER_AUTOMATION_TYPE | #if ! JUCE_FORCE_LEGACY_PARAMETER_AUTOMATION_TYPE | ||||
| if (juceFilter->isParameterDiscrete (index)) | |||||
| if (auto* param = juceFilter->getParameters()[index]) | |||||
| { | { | ||||
| if (auto* param = juceFilter->getParameters()[index]) | |||||
| if (param->isDiscrete()) | |||||
| { | { | ||||
| const auto numSteps = juceFilter->getParameterNumSteps (index); | |||||
| const auto numSteps = param->getNumSteps(); | |||||
| stringValues = new OwnedArray<const __CFString>(); | stringValues = new OwnedArray<const __CFString>(); | ||||
| stringValues->ensureStorageAllocated (numSteps); | stringValues->ensureStorageAllocated (numSteps); | ||||
| const auto maxValue = getMaximumParameterValue (index); | const auto maxValue = getMaximumParameterValue (index); | ||||
| for (int i = 0; i < numSteps; ++i) | for (int i = 0; i < numSteps; ++i) | ||||
| stringValues->add (CFStringCreateCopy (nullptr, (param->getText ((float) i / maxValue, 0)).toCFString())); ; | |||||
| stringValues->add (CFStringCreateCopy (nullptr, (param->getText ((float) i / maxValue, 0)).toCFString())); | |||||
| } | } | ||||
| } | } | ||||
| #endif | #endif | ||||
| @@ -1182,7 +1182,7 @@ private: | |||||
| { | { | ||||
| if (param->isDiscrete()) | if (param->isDiscrete()) | ||||
| { | { | ||||
| unit = kAudioUnitParameterUnit_Indexed; | |||||
| unit = param->isBoolean() ? kAudioUnitParameterUnit_Boolean : kAudioUnitParameterUnit_Indexed; | |||||
| auto maxValue = getMaximumParameterValue (idx); | auto maxValue = getMaximumParameterValue (idx); | ||||
| auto numSteps = param->getNumSteps(); | auto numSteps = param->getNumSteps(); | ||||
| @@ -1365,6 +1365,7 @@ bool AudioProcessorParameter::isMetaParameter() const | |||||
| AudioProcessorParameter::Category AudioProcessorParameter::getCategory() const { return genericParameter; } | AudioProcessorParameter::Category AudioProcessorParameter::getCategory() const { return genericParameter; } | ||||
| int AudioProcessorParameter::getNumSteps() const { return AudioProcessor::getDefaultNumParameterSteps(); } | int AudioProcessorParameter::getNumSteps() const { return AudioProcessor::getDefaultNumParameterSteps(); } | ||||
| bool AudioProcessorParameter::isDiscrete() const { return false; } | bool AudioProcessorParameter::isDiscrete() const { return false; } | ||||
| bool AudioProcessorParameter::isBoolean() const { return false; } | |||||
| String AudioProcessorParameter::getText (float value, int /*maximumStringLength*/) const | String AudioProcessorParameter::getText (float value, int /*maximumStringLength*/) const | ||||
| { | { | ||||
| @@ -133,6 +133,18 @@ public: | |||||
| */ | */ | ||||
| virtual bool isDiscrete() const; | virtual bool isDiscrete() const; | ||||
| /** Returns whether the parameter represents a boolean switch, typically with | |||||
| "On" and "Off" states. | |||||
| This information may or may not be used, depending on the host. If you | |||||
| want the host to display a switch, rather than a two item dropdown menu, | |||||
| override this method to return true. You also need to override | |||||
| isDiscrete() to return `true` and getNumSteps() to return `2`. | |||||
| @see isDiscrete getNumSteps | |||||
| */ | |||||
| virtual bool isBoolean() const; | |||||
| /** Returns a textual version of the supplied parameter value. | /** Returns a textual version of the supplied parameter value. | ||||
| The default implementation just returns the floating point value | The default implementation just returns the floating point value | ||||
| as a string, but this could do anything you need for a custom type | as a string, but this could do anything you need for a custom type | ||||
| @@ -60,17 +60,19 @@ protected: | |||||
| private: | private: | ||||
| //============================================================================== | //============================================================================== | ||||
| float value; | |||||
| const float defaultValue; | |||||
| float getValue() const override; | float getValue() const override; | ||||
| void setValue (float newValue) override; | void setValue (float newValue) override; | ||||
| float getDefaultValue() const override; | float getDefaultValue() const override; | ||||
| int getNumSteps() const override; | int getNumSteps() const override; | ||||
| bool isDiscrete() const override; | bool isDiscrete() const override; | ||||
| bool isBoolean() const override; | |||||
| String getText (float, int) const override; | String getText (float, int) const override; | ||||
| float getValueForText (const String&) const override; | float getValueForText (const String&) const override; | ||||
| float value; | |||||
| const float defaultValue; | |||||
| StringArray onStrings, offStrings; | |||||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioParameterBool) | JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioParameterBool) | ||||
| }; | }; | ||||
| @@ -121,6 +121,13 @@ AudioParameterBool::AudioParameterBool (const String& idToUse, const String& nam | |||||
| value (def ? 1.0f : 0.0f), | value (def ? 1.0f : 0.0f), | ||||
| defaultValue (value) | defaultValue (value) | ||||
| { | { | ||||
| onStrings.add (TRANS("on")); | |||||
| onStrings.add (TRANS("yes")); | |||||
| onStrings.add (TRANS("true")); | |||||
| offStrings.add (TRANS("off")); | |||||
| offStrings.add (TRANS("no")); | |||||
| offStrings.add (TRANS("false")); | |||||
| } | } | ||||
| AudioParameterBool::~AudioParameterBool() {} | AudioParameterBool::~AudioParameterBool() {} | ||||
| @@ -130,10 +137,29 @@ void AudioParameterBool::setValue (float newValue) { value | |||||
| float AudioParameterBool::getDefaultValue() const { return defaultValue; } | float AudioParameterBool::getDefaultValue() const { return defaultValue; } | ||||
| int AudioParameterBool::getNumSteps() const { return 2; } | int AudioParameterBool::getNumSteps() const { return 2; } | ||||
| bool AudioParameterBool::isDiscrete() const { return true; } | bool AudioParameterBool::isDiscrete() const { return true; } | ||||
| float AudioParameterBool::getValueForText (const String& text) const { return text.getIntValue() != 0 ? 1.0f : 0.0f; } | |||||
| String AudioParameterBool::getText (float v, int /*length*/) const { return String ((int) (v > 0.5f ? 1 : 0)); } | |||||
| bool AudioParameterBool::isBoolean() const { return true; } | |||||
| void AudioParameterBool::valueChanged (bool) {} | void AudioParameterBool::valueChanged (bool) {} | ||||
| float AudioParameterBool::getValueForText (const String& text) const | |||||
| { | |||||
| String lowercaseText (text.toLowerCase()); | |||||
| for (auto& testText : onStrings) | |||||
| if (lowercaseText == testText) | |||||
| return 1.0f; | |||||
| for (auto& testText : offStrings) | |||||
| if (lowercaseText == testText) | |||||
| return 0.0f; | |||||
| return text.getIntValue() != 0 ? 1.0f : 0.0f; | |||||
| } | |||||
| String AudioParameterBool::getText (float v, int /*length*/) const | |||||
| { | |||||
| return v < 0.5f ? TRANS("Off") : TRANS("On"); | |||||
| } | |||||
| AudioParameterBool& AudioParameterBool::operator= (bool newValue) | AudioParameterBool& AudioParameterBool::operator= (bool newValue) | ||||
| { | { | ||||
| if (get() != newValue) | if (get() != newValue) | ||||