| @@ -151,6 +151,11 @@ struct AutoResizingNSViewComponentWithParent : public AutoResizingNSViewCompone | |||
| #include "scanning/juce_KnownPluginList.cpp" | |||
| #include "scanning/juce_PluginDirectoryScanner.cpp" | |||
| #include "scanning/juce_PluginListComponent.cpp" | |||
| #include "utilities/juce_AudioProcessorParameters.cpp" | |||
| #include "processors/juce_AudioProcessorParameterGroup.cpp" | |||
| #include "utilities/juce_AudioProcessorParameterWithID.cpp" | |||
| #include "utilities/juce_RangedAudioParameter.cpp" | |||
| #include "utilities/juce_AudioParameterFloat.cpp" | |||
| #include "utilities/juce_AudioParameterInt.cpp" | |||
| #include "utilities/juce_AudioParameterBool.cpp" | |||
| #include "utilities/juce_AudioParameterChoice.cpp" | |||
| #include "utilities/juce_AudioProcessorValueTreeState.cpp" | |||
| @@ -0,0 +1,100 @@ | |||
| /* | |||
| ============================================================================== | |||
| This file is part of the JUCE library. | |||
| Copyright (c) 2017 - ROLI Ltd. | |||
| JUCE is an open source library subject to commercial or open-source | |||
| licensing. | |||
| By using JUCE, you agree to the terms of both the JUCE 5 End-User License | |||
| Agreement and JUCE 5 Privacy Policy (both updated and effective as of the | |||
| 27th April 2017). | |||
| End User License Agreement: www.juce.com/juce-5-licence | |||
| Privacy Policy: www.juce.com/juce-5-privacy-policy | |||
| Or: You may also use this code under the terms of the GPL v3 (see | |||
| www.gnu.org/licenses). | |||
| JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||
| EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||
| DISCLAIMED. | |||
| ============================================================================== | |||
| */ | |||
| namespace juce | |||
| { | |||
| AudioParameterBool::AudioParameterBool (const String& idToUse, const String& nameToUse, | |||
| bool def, const String& labelToUse, | |||
| std::function<String (bool, int)> stringFromBool, | |||
| std::function<bool (const String&)> boolFromString) | |||
| : RangedAudioParameter (idToUse, nameToUse, labelToUse), | |||
| value (def ? 1.0f : 0.0f), | |||
| defaultValue (value), | |||
| stringFromBoolFunction (stringFromBool), | |||
| boolFromStringFunction (boolFromString) | |||
| { | |||
| 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() {} | |||
| float AudioParameterBool::getValue() const { return value; } | |||
| void AudioParameterBool::setValue (float newValue) { value = newValue; valueChanged (get()); } | |||
| float AudioParameterBool::getDefaultValue() const { return defaultValue; } | |||
| int AudioParameterBool::getNumSteps() const { return 2; } | |||
| bool AudioParameterBool::isDiscrete() const { return true; } | |||
| bool AudioParameterBool::isBoolean() const { return true; } | |||
| void AudioParameterBool::valueChanged (bool) {} | |||
| float AudioParameterBool::getValueForText (const String& text) const | |||
| { | |||
| return boolFromStringFunction (text) ? 1.0f : 0.0f; | |||
| } | |||
| String AudioParameterBool::getText (float v, int maximumLength) const | |||
| { | |||
| return stringFromBoolFunction (v >= 0.5f, maximumLength); | |||
| } | |||
| AudioParameterBool& AudioParameterBool::operator= (bool newValue) | |||
| { | |||
| if (get() != newValue) | |||
| setValueNotifyingHost (newValue ? 1.0f : 0.0f); | |||
| return *this; | |||
| } | |||
| } // namespace juce | |||
| @@ -0,0 +1,119 @@ | |||
| /* | |||
| ============================================================================== | |||
| This file is part of the JUCE library. | |||
| Copyright (c) 2017 - ROLI Ltd. | |||
| JUCE is an open source library subject to commercial or open-source | |||
| licensing. | |||
| By using JUCE, you agree to the terms of both the JUCE 5 End-User License | |||
| Agreement and JUCE 5 Privacy Policy (both updated and effective as of the | |||
| 27th April 2017). | |||
| End User License Agreement: www.juce.com/juce-5-licence | |||
| Privacy Policy: www.juce.com/juce-5-privacy-policy | |||
| Or: You may also use this code under the terms of the GPL v3 (see | |||
| www.gnu.org/licenses). | |||
| JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||
| EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||
| DISCLAIMED. | |||
| ============================================================================== | |||
| */ | |||
| 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) | |||
| : RangedAudioParameter (idToUse, nameToUse, labelToUse), choices (c), | |||
| range (0.0f, choices.size() - 1.0f, | |||
| [](float, float end, float v) { return jlimit (0.0f, end, v * end); }, | |||
| [](float, float end, float v) { return jlimit (0.0f, 1.0f, v / end); }, | |||
| [](float start, float end, float v) { return (float) roundToInt (juce::jlimit (start, end, v)); }), | |||
| value ((float) def), | |||
| defaultValue (convertTo0to1 ((float) def)), | |||
| stringFromIndexFunction (stringFromIndex), | |||
| indexFromStringFunction (indexFromString) | |||
| { | |||
| jassert (choices.size() > 0); // 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() {} | |||
| float AudioParameterChoice::getValue() const { return convertTo0to1 (value); } | |||
| void AudioParameterChoice::setValue (float newValue) { value = convertFrom0to1 (newValue); valueChanged (getIndex()); } | |||
| float AudioParameterChoice::getDefaultValue() const { return defaultValue; } | |||
| int AudioParameterChoice::getNumSteps() const { return choices.size(); } | |||
| bool AudioParameterChoice::isDiscrete() const { return true; } | |||
| float AudioParameterChoice::getValueForText (const String& text) const { return convertTo0to1 ((float) indexFromStringFunction (text)); } | |||
| String AudioParameterChoice::getText (float v, int length) const { return stringFromIndexFunction ((int) convertFrom0to1 (v), length); } | |||
| void AudioParameterChoice::valueChanged (int) {} | |||
| AudioParameterChoice& AudioParameterChoice::operator= (int newValue) | |||
| { | |||
| if (getIndex() != newValue) | |||
| setValueNotifyingHost (convertTo0to1 ((float) newValue)); | |||
| return *this; | |||
| } | |||
| #if JUCE_UNIT_TESTS | |||
| static struct AudioParameterChoiceTests final : public UnitTest | |||
| { | |||
| AudioParameterChoiceTests() : UnitTest ("AudioParameterChoice", "AudioProcessor parameters") {} | |||
| void runTest() override | |||
| { | |||
| beginTest ("Three options switches at the correct points"); | |||
| { | |||
| AudioParameterChoice choice ({}, {}, { "a", "b", "c" }, {}); | |||
| choice.setValueNotifyingHost (0.0f); | |||
| expectEquals (choice.getIndex(), 0); | |||
| choice.setValueNotifyingHost (0.2f); | |||
| expectEquals (choice.getIndex(), 0); | |||
| choice.setValueNotifyingHost (0.3f); | |||
| expectEquals (choice.getIndex(), 1); | |||
| choice.setValueNotifyingHost (0.7f); | |||
| expectEquals (choice.getIndex(), 1); | |||
| choice.setValueNotifyingHost (0.8f); | |||
| expectEquals (choice.getIndex(), 2); | |||
| choice.setValueNotifyingHost (1.0f); | |||
| expectEquals (choice.getIndex(), 2); | |||
| } | |||
| beginTest ("Out-of-bounds input"); | |||
| { | |||
| AudioParameterChoice choiceParam ({}, {}, { "a", "b", "c" }, {}); | |||
| choiceParam.setValueNotifyingHost (-0.5f); | |||
| expectEquals (choiceParam.getIndex(), 0); | |||
| choiceParam.setValueNotifyingHost (1.5f); | |||
| expectEquals (choiceParam.getIndex(), 2); | |||
| } | |||
| } | |||
| } audioParameterChoiceTests; | |||
| #endif | |||
| } // namespace juce | |||
| @@ -0,0 +1,97 @@ | |||
| /* | |||
| ============================================================================== | |||
| This file is part of the JUCE library. | |||
| Copyright (c) 2017 - ROLI Ltd. | |||
| JUCE is an open source library subject to commercial or open-source | |||
| licensing. | |||
| By using JUCE, you agree to the terms of both the JUCE 5 End-User License | |||
| Agreement and JUCE 5 Privacy Policy (both updated and effective as of the | |||
| 27th April 2017). | |||
| End User License Agreement: www.juce.com/juce-5-licence | |||
| Privacy Policy: www.juce.com/juce-5-privacy-policy | |||
| Or: You may also use this code under the terms of the GPL v3 (see | |||
| www.gnu.org/licenses). | |||
| JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||
| EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||
| DISCLAIMED. | |||
| ============================================================================== | |||
| */ | |||
| 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) | |||
| : RangedAudioParameter (idToUse, nameToUse, labelToUse, categoryToUse), | |||
| range (r), value (def), defaultValue (def), | |||
| stringFromValueFunction (stringFromValue), | |||
| valueFromStringFunction (valueFromString) | |||
| { | |||
| if (stringFromValueFunction == nullptr) | |||
| { | |||
| auto numDecimalPlacesToDisplay = [this] | |||
| { | |||
| int numDecimalPlaces = 7; | |||
| if (range.interval != 0.0f) | |||
| { | |||
| if (approximatelyEqual (std::abs (range.interval - (int) range.interval), 0.0f)) | |||
| return 0; | |||
| auto v = std::abs (roundToInt (range.interval * pow (10, numDecimalPlaces))); | |||
| while ((v % 10) == 0 && numDecimalPlaces > 0) | |||
| { | |||
| --numDecimalPlaces; | |||
| v /= 10; | |||
| } | |||
| } | |||
| return numDecimalPlaces; | |||
| }(); | |||
| stringFromValueFunction = [numDecimalPlacesToDisplay] (float v, int length) | |||
| { | |||
| String asText (v, numDecimalPlacesToDisplay); | |||
| return length > 0 ? asText.substring (0, length) : asText; | |||
| }; | |||
| } | |||
| if (valueFromStringFunction == nullptr) | |||
| valueFromStringFunction = [] (const String& text) { return text.getFloatValue(); }; | |||
| } | |||
| AudioParameterFloat::AudioParameterFloat (String pid, String nm, float minValue, float maxValue, float def) | |||
| : AudioParameterFloat (pid, nm, { minValue, maxValue, 0.01f }, def) | |||
| { | |||
| } | |||
| 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); } | |||
| 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)); } | |||
| void AudioParameterFloat::valueChanged (float) {} | |||
| AudioParameterFloat& AudioParameterFloat::operator= (float newValue) | |||
| { | |||
| if (value != newValue) | |||
| setValueNotifyingHost (convertTo0to1 (newValue)); | |||
| return *this; | |||
| } | |||
| } // namespace juce | |||
| @@ -0,0 +1,124 @@ | |||
| /* | |||
| ============================================================================== | |||
| This file is part of the JUCE library. | |||
| Copyright (c) 2017 - ROLI Ltd. | |||
| JUCE is an open source library subject to commercial or open-source | |||
| licensing. | |||
| By using JUCE, you agree to the terms of both the JUCE 5 End-User License | |||
| Agreement and JUCE 5 Privacy Policy (both updated and effective as of the | |||
| 27th April 2017). | |||
| End User License Agreement: www.juce.com/juce-5-licence | |||
| Privacy Policy: www.juce.com/juce-5-privacy-policy | |||
| Or: You may also use this code under the terms of the GPL v3 (see | |||
| www.gnu.org/licenses). | |||
| JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||
| EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||
| DISCLAIMED. | |||
| ============================================================================== | |||
| */ | |||
| namespace juce | |||
| { | |||
| AudioParameterInt::AudioParameterInt (const String& 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) | |||
| : RangedAudioParameter (idToUse, nameToUse, labelToUse), | |||
| range ((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)); }), | |||
| value ((float) def), | |||
| defaultValue (convertTo0to1 ((float) def)), | |||
| stringFromIntFunction (stringFromInt), | |||
| intFromStringFunction (intFromString) | |||
| { | |||
| 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() {} | |||
| float AudioParameterInt::getValue() const { return convertTo0to1 (value); } | |||
| void AudioParameterInt::setValue (float newValue) { value = convertFrom0to1 (newValue); valueChanged (get()); } | |||
| float AudioParameterInt::getDefaultValue() const { return defaultValue; } | |||
| int AudioParameterInt::getNumSteps() const { return ((int) getNormalisableRange().getRange().getLength()) + 1; } | |||
| float AudioParameterInt::getValueForText (const String& text) const { return convertTo0to1 ((float) intFromStringFunction (text)); } | |||
| String AudioParameterInt::getText (float v, int length) const { return stringFromIntFunction ((int) convertFrom0to1 (v), length); } | |||
| void AudioParameterInt::valueChanged (int) {} | |||
| AudioParameterInt& AudioParameterInt::operator= (int newValue) | |||
| { | |||
| if (get() != newValue) | |||
| setValueNotifyingHost (convertTo0to1 ((float) newValue)); | |||
| return *this; | |||
| } | |||
| #if JUCE_UNIT_TESTS | |||
| static struct AudioParameterIntTests final : public UnitTest | |||
| { | |||
| AudioParameterIntTests() : UnitTest ("AudioParameterInt", "AudioProcessor parameters") {} | |||
| void runTest() override | |||
| { | |||
| beginTest ("Three options switches at the correct points"); | |||
| { | |||
| AudioParameterInt intParam ({}, {}, 1, 3, 1); | |||
| intParam.setValueNotifyingHost (0.0f); | |||
| expectEquals (intParam.get(), 1); | |||
| intParam.setValueNotifyingHost (0.2f); | |||
| expectEquals (intParam.get(), 1); | |||
| intParam.setValueNotifyingHost (0.3f); | |||
| expectEquals (intParam.get(), 2); | |||
| intParam.setValueNotifyingHost (0.7f); | |||
| expectEquals (intParam.get(), 2); | |||
| intParam.setValueNotifyingHost (0.8f); | |||
| expectEquals (intParam.get(), 3); | |||
| intParam.setValueNotifyingHost (1.0f); | |||
| expectEquals (intParam.get(), 3); | |||
| } | |||
| beginTest ("Out-of-bounds input"); | |||
| { | |||
| AudioParameterInt intParam ({}, {}, -1, 2, 0); | |||
| intParam.setValueNotifyingHost (-0.5f); | |||
| expectEquals (intParam.get(), -1); | |||
| intParam.setValueNotifyingHost (1.5f); | |||
| expectEquals (intParam.get(), 2); | |||
| intParam = -5; | |||
| expectEquals (intParam.get(), -1); | |||
| intParam = 5; | |||
| expectEquals (intParam.get(), 2); | |||
| } | |||
| } | |||
| } audioParameterIntTests; | |||
| #endif | |||
| } // namespace juce | |||
| @@ -0,0 +1,41 @@ | |||
| /* | |||
| ============================================================================== | |||
| This file is part of the JUCE library. | |||
| Copyright (c) 2017 - ROLI Ltd. | |||
| JUCE is an open source library subject to commercial or open-source | |||
| licensing. | |||
| By using JUCE, you agree to the terms of both the JUCE 5 End-User License | |||
| Agreement and JUCE 5 Privacy Policy (both updated and effective as of the | |||
| 27th April 2017). | |||
| End User License Agreement: www.juce.com/juce-5-licence | |||
| Privacy Policy: www.juce.com/juce-5-privacy-policy | |||
| Or: You may also use this code under the terms of the GPL v3 (see | |||
| www.gnu.org/licenses). | |||
| JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||
| EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||
| DISCLAIMED. | |||
| ============================================================================== | |||
| */ | |||
| namespace juce | |||
| { | |||
| AudioProcessorParameterWithID::AudioProcessorParameterWithID (const String& idToUse, | |||
| const String& nameToUse, | |||
| const String& labelToUse, | |||
| AudioProcessorParameter::Category categoryToUse) | |||
| : paramID (idToUse), name (nameToUse), label (labelToUse), category (categoryToUse) {} | |||
| AudioProcessorParameterWithID::~AudioProcessorParameterWithID() {} | |||
| String AudioProcessorParameterWithID::getName (int maximumStringLength) const { return name.substring (0, maximumStringLength); } | |||
| String AudioProcessorParameterWithID::getLabel() const { return label; } | |||
| AudioProcessorParameter::Category AudioProcessorParameterWithID::getCategory() const { return category; } | |||
| } // namespace juce | |||
| @@ -1,360 +0,0 @@ | |||
| /* | |||
| ============================================================================== | |||
| This file is part of the JUCE library. | |||
| Copyright (c) 2017 - ROLI Ltd. | |||
| JUCE is an open source library subject to commercial or open-source | |||
| licensing. | |||
| By using JUCE, you agree to the terms of both the JUCE 5 End-User License | |||
| Agreement and JUCE 5 Privacy Policy (both updated and effective as of the | |||
| 27th April 2017). | |||
| End User License Agreement: www.juce.com/juce-5-licence | |||
| Privacy Policy: www.juce.com/juce-5-privacy-policy | |||
| Or: You may also use this code under the terms of the GPL v3 (see | |||
| www.gnu.org/licenses). | |||
| JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||
| EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||
| DISCLAIMED. | |||
| ============================================================================== | |||
| */ | |||
| namespace juce | |||
| { | |||
| // This file contains the implementations of the various AudioParameter[XYZ] classes.. | |||
| AudioProcessorParameterWithID::AudioProcessorParameterWithID (const String& idToUse, | |||
| const String& nameToUse, | |||
| const String& labelToUse, | |||
| AudioProcessorParameter::Category categoryToUse) | |||
| : paramID (idToUse), name (nameToUse), label (labelToUse), category (categoryToUse) {} | |||
| AudioProcessorParameterWithID::~AudioProcessorParameterWithID() {} | |||
| String AudioProcessorParameterWithID::getName (int maximumStringLength) const { return name.substring (0, maximumStringLength); } | |||
| String AudioProcessorParameterWithID::getLabel() const { return label; } | |||
| AudioProcessorParameter::Category AudioProcessorParameterWithID::getCategory() const { return category; } | |||
| //============================================================================== | |||
| 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) | |||
| : RangedAudioParameter (idToUse, nameToUse, labelToUse, categoryToUse), | |||
| range (r), value (def), defaultValue (def), | |||
| stringFromValueFunction (stringFromValue), | |||
| valueFromStringFunction (valueFromString) | |||
| { | |||
| if (stringFromValueFunction == nullptr) | |||
| { | |||
| auto numDecimalPlacesToDisplay = [this] | |||
| { | |||
| int numDecimalPlaces = 7; | |||
| if (range.interval != 0.0f) | |||
| { | |||
| if (approximatelyEqual (std::abs (range.interval - (int) range.interval), 0.0f)) | |||
| return 0; | |||
| auto v = std::abs (roundToInt (range.interval * pow (10, numDecimalPlaces))); | |||
| while ((v % 10) == 0 && numDecimalPlaces > 0) | |||
| { | |||
| --numDecimalPlaces; | |||
| v /= 10; | |||
| } | |||
| } | |||
| return numDecimalPlaces; | |||
| }(); | |||
| stringFromValueFunction = [numDecimalPlacesToDisplay] (float v, int length) | |||
| { | |||
| String asText (v, numDecimalPlacesToDisplay); | |||
| return length > 0 ? asText.substring (0, length) : asText; | |||
| }; | |||
| } | |||
| if (valueFromStringFunction == nullptr) | |||
| valueFromStringFunction = [] (const String& text) { return text.getFloatValue(); }; | |||
| } | |||
| AudioParameterFloat::AudioParameterFloat (String pid, String nm, float minValue, float maxValue, float def) | |||
| : AudioParameterFloat (pid, nm, { minValue, maxValue, 0.01f }, def) | |||
| { | |||
| } | |||
| 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); } | |||
| 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)); } | |||
| void AudioParameterFloat::valueChanged (float) {} | |||
| AudioParameterFloat& AudioParameterFloat::operator= (float newValue) | |||
| { | |||
| if (value != newValue) | |||
| setValueNotifyingHost (convertTo0to1 (newValue)); | |||
| return *this; | |||
| } | |||
| //============================================================================== | |||
| AudioParameterInt::AudioParameterInt (const String& 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) | |||
| : RangedAudioParameter (idToUse, nameToUse, labelToUse), | |||
| range ((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)); }), | |||
| value ((float) def), | |||
| defaultValue (convertTo0to1 ((float) def)), | |||
| stringFromIntFunction (stringFromInt), | |||
| intFromStringFunction (intFromString) | |||
| { | |||
| 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() {} | |||
| float AudioParameterInt::getValue() const { return convertTo0to1 (value); } | |||
| void AudioParameterInt::setValue (float newValue) { value = convertFrom0to1 (newValue); valueChanged (get()); } | |||
| float AudioParameterInt::getDefaultValue() const { return defaultValue; } | |||
| int AudioParameterInt::getNumSteps() const { return ((int) getNormalisableRange().getRange().getLength()) + 1; } | |||
| float AudioParameterInt::getValueForText (const String& text) const { return convertTo0to1 ((float) intFromStringFunction (text)); } | |||
| String AudioParameterInt::getText (float v, int length) const { return stringFromIntFunction ((int) convertFrom0to1 (v), length); } | |||
| void AudioParameterInt::valueChanged (int) {} | |||
| AudioParameterInt& AudioParameterInt::operator= (int newValue) | |||
| { | |||
| if (get() != newValue) | |||
| setValueNotifyingHost (convertTo0to1 ((float) newValue)); | |||
| return *this; | |||
| } | |||
| //============================================================================== | |||
| AudioParameterBool::AudioParameterBool (const String& idToUse, const String& nameToUse, | |||
| bool def, const String& labelToUse, | |||
| std::function<String (bool, int)> stringFromBool, | |||
| std::function<bool (const String&)> boolFromString) | |||
| : RangedAudioParameter (idToUse, nameToUse, labelToUse), | |||
| value (def ? 1.0f : 0.0f), | |||
| defaultValue (value), | |||
| stringFromBoolFunction (stringFromBool), | |||
| boolFromStringFunction (boolFromString) | |||
| { | |||
| 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() {} | |||
| float AudioParameterBool::getValue() const { return value; } | |||
| void AudioParameterBool::setValue (float newValue) { value = newValue; valueChanged (get()); } | |||
| float AudioParameterBool::getDefaultValue() const { return defaultValue; } | |||
| int AudioParameterBool::getNumSteps() const { return 2; } | |||
| bool AudioParameterBool::isDiscrete() const { return true; } | |||
| bool AudioParameterBool::isBoolean() const { return true; } | |||
| void AudioParameterBool::valueChanged (bool) {} | |||
| float AudioParameterBool::getValueForText (const String& text) const | |||
| { | |||
| return boolFromStringFunction (text) ? 1.0f : 0.0f; | |||
| } | |||
| String AudioParameterBool::getText (float v, int maximumLength) const | |||
| { | |||
| return stringFromBoolFunction (v >= 0.5f, maximumLength); | |||
| } | |||
| AudioParameterBool& AudioParameterBool::operator= (bool newValue) | |||
| { | |||
| if (get() != newValue) | |||
| setValueNotifyingHost (newValue ? 1.0f : 0.0f); | |||
| return *this; | |||
| } | |||
| //============================================================================== | |||
| 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) | |||
| : RangedAudioParameter (idToUse, nameToUse, labelToUse), choices (c), | |||
| range (0.0f, choices.size() - 1.0f, | |||
| [](float, float end, float v) { return jlimit (0.0f, end, v * end); }, | |||
| [](float, float end, float v) { return jlimit (0.0f, 1.0f, v / end); }, | |||
| [](float start, float end, float v) { return (float) roundToInt (juce::jlimit (start, end, v)); }), | |||
| value ((float) def), | |||
| defaultValue (convertTo0to1 ((float) def)), | |||
| stringFromIndexFunction (stringFromIndex), | |||
| indexFromStringFunction (indexFromString) | |||
| { | |||
| jassert (choices.size() > 0); // 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() {} | |||
| float AudioParameterChoice::getValue() const { return convertTo0to1 (value); } | |||
| void AudioParameterChoice::setValue (float newValue) { value = convertFrom0to1 (newValue); valueChanged (getIndex()); } | |||
| float AudioParameterChoice::getDefaultValue() const { return defaultValue; } | |||
| int AudioParameterChoice::getNumSteps() const { return choices.size(); } | |||
| bool AudioParameterChoice::isDiscrete() const { return true; } | |||
| float AudioParameterChoice::getValueForText (const String& text) const { return convertTo0to1 ((float) indexFromStringFunction (text)); } | |||
| String AudioParameterChoice::getText (float v, int length) const { return stringFromIndexFunction ((int) convertFrom0to1 (v), length); } | |||
| void AudioParameterChoice::valueChanged (int) {} | |||
| AudioParameterChoice& AudioParameterChoice::operator= (int newValue) | |||
| { | |||
| if (getIndex() != newValue) | |||
| setValueNotifyingHost (convertTo0to1 ((float) newValue)); | |||
| return *this; | |||
| } | |||
| #if JUCE_UNIT_TESTS | |||
| static struct SpecialisedAudioParameterTests final : public UnitTest | |||
| { | |||
| SpecialisedAudioParameterTests() : UnitTest ("Specialised Audio Parameters", "AudioProcessor parameters") {} | |||
| void runTest() override | |||
| { | |||
| beginTest ("A choice parameter with three options switches at the correct points"); | |||
| { | |||
| AudioParameterChoice choice ({}, {}, { "a", "b", "c" }, {}); | |||
| choice.setValueNotifyingHost (0.0f); | |||
| expectEquals (choice.getIndex(), 0); | |||
| choice.setValueNotifyingHost (0.2f); | |||
| expectEquals (choice.getIndex(), 0); | |||
| choice.setValueNotifyingHost (0.3f); | |||
| expectEquals (choice.getIndex(), 1); | |||
| choice.setValueNotifyingHost (0.7f); | |||
| expectEquals (choice.getIndex(), 1); | |||
| choice.setValueNotifyingHost (0.8f); | |||
| expectEquals (choice.getIndex(), 2); | |||
| choice.setValueNotifyingHost (1.0f); | |||
| expectEquals (choice.getIndex(), 2); | |||
| } | |||
| beginTest ("An int parameter with three options switches at the correct points"); | |||
| { | |||
| AudioParameterInt intParam ({}, {}, 1, 3, 1); | |||
| intParam.setValueNotifyingHost (0.0f); | |||
| expectEquals (intParam.get(), 1); | |||
| intParam.setValueNotifyingHost (0.2f); | |||
| expectEquals (intParam.get(), 1); | |||
| intParam.setValueNotifyingHost (0.3f); | |||
| expectEquals (intParam.get(), 2); | |||
| intParam.setValueNotifyingHost (0.7f); | |||
| expectEquals (intParam.get(), 2); | |||
| intParam.setValueNotifyingHost (0.8f); | |||
| expectEquals (intParam.get(), 3); | |||
| intParam.setValueNotifyingHost (1.0f); | |||
| expectEquals (intParam.get(), 3); | |||
| } | |||
| beginTest ("Choice parameters handle out-of-bounds input"); | |||
| { | |||
| AudioParameterChoice choiceParam ({}, {}, { "a", "b", "c" }, {}); | |||
| choiceParam.setValueNotifyingHost (-0.5f); | |||
| expectEquals (choiceParam.getIndex(), 0); | |||
| choiceParam.setValueNotifyingHost (1.5f); | |||
| expectEquals (choiceParam.getIndex(), 2); | |||
| } | |||
| beginTest ("Int parameters handle out-of-bounds input"); | |||
| { | |||
| AudioParameterInt intParam ({}, {}, -1, 2, 0); | |||
| intParam.setValueNotifyingHost (-0.5f); | |||
| expectEquals (intParam.get(), -1); | |||
| intParam.setValueNotifyingHost (1.5f); | |||
| expectEquals (intParam.get(), 2); | |||
| intParam = -5; | |||
| expectEquals (intParam.get(), -1); | |||
| intParam = 5; | |||
| expectEquals (intParam.get(), 2); | |||
| } | |||
| } | |||
| } specialisedAudioParameterTests; | |||
| #endif | |||
| } // namespace juce | |||
| @@ -0,0 +1,60 @@ | |||
| /* | |||
| ============================================================================== | |||
| This file is part of the JUCE library. | |||
| Copyright (c) 2017 - ROLI Ltd. | |||
| JUCE is an open source library subject to commercial or open-source | |||
| licensing. | |||
| By using JUCE, you agree to the terms of both the JUCE 5 End-User License | |||
| Agreement and JUCE 5 Privacy Policy (both updated and effective as of the | |||
| 27th April 2017). | |||
| End User License Agreement: www.juce.com/juce-5-licence | |||
| Privacy Policy: www.juce.com/juce-5-privacy-policy | |||
| Or: You may also use this code under the terms of the GPL v3 (see | |||
| www.gnu.org/licenses). | |||
| JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||
| EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||
| DISCLAIMED. | |||
| ============================================================================== | |||
| */ | |||
| namespace juce | |||
| { | |||
| RangedAudioParameter::RangedAudioParameter (const String& parameterID, | |||
| const String& name, | |||
| const String& label, | |||
| Category category) | |||
| : AudioProcessorParameterWithID (parameterID, name, label, category) | |||
| { | |||
| } | |||
| int RangedAudioParameter::getNumSteps() const | |||
| { | |||
| const auto& range = getNormalisableRange(); | |||
| if (range.interval > 0) | |||
| return (static_cast<int> ((range.end - range.start) / range.interval) + 1); | |||
| return AudioProcessor::getDefaultNumParameterSteps(); | |||
| } | |||
| float RangedAudioParameter::convertTo0to1 (float v) const noexcept | |||
| { | |||
| const auto& range = getNormalisableRange(); | |||
| return range.convertTo0to1 (range.snapToLegalValue (v)); | |||
| } | |||
| float RangedAudioParameter::convertFrom0to1 (float v) const noexcept | |||
| { | |||
| const auto& range = getNormalisableRange(); | |||
| return range.snapToLegalValue (range.convertFrom0to1 (jlimit (0.0f, 1.0f, v))); | |||
| } | |||
| } // namespace juce | |||
| @@ -43,8 +43,7 @@ public: | |||
| RangedAudioParameter (const String& parameterID, | |||
| const String& name, | |||
| const String& label = {}, | |||
| Category category = AudioProcessorParameter::genericParameter) | |||
| : AudioProcessorParameterWithID (parameterID, name, label, category) {} | |||
| Category category = AudioProcessorParameter::genericParameter); | |||
| /** Returns the range of values that the parameter can take. */ | |||
| virtual const NormalisableRange<float>& getNormalisableRange() const = 0; | |||
| @@ -53,29 +52,13 @@ public: | |||
| If you are using lambda functions to define the normalisable range's snapping behaviour | |||
| then you should override this function so that it returns the number of snapping points. | |||
| */ | |||
| int getNumSteps() const override | |||
| { | |||
| const auto& range = getNormalisableRange(); | |||
| if (range.interval > 0) | |||
| return (static_cast<int> ((range.end - range.start) / range.interval) + 1); | |||
| return AudioProcessor::getDefaultNumParameterSteps(); | |||
| } | |||
| int getNumSteps() const override; | |||
| /** Normalises and snaps a value based on the normalisable range. */ | |||
| float convertTo0to1 (float v) const noexcept | |||
| { | |||
| const auto& range = getNormalisableRange(); | |||
| return range.convertTo0to1 (range.snapToLegalValue (v)); | |||
| } | |||
| float convertTo0to1 (float v) const noexcept; | |||
| /** Denormalises and snaps a value based on the normalisable range. */ | |||
| float convertFrom0to1 (float v) const noexcept | |||
| { | |||
| const auto& range = getNormalisableRange(); | |||
| return range.snapToLegalValue (range.convertFrom0to1 (jlimit (0.0f, 1.0f, v))); | |||
| } | |||
| float convertFrom0to1 (float v) const noexcept; | |||
| }; | |||
| } // namespace juce | |||
| @@ -551,23 +551,10 @@ public: | |||
| CFRelease (numberRef); | |||
| } | |||
| ~OSXTypeface() override | |||
| { | |||
| if (attributedStringAtts != nullptr) | |||
| CFRelease (attributedStringAtts); | |||
| if (fontRef != nullptr) | |||
| { | |||
| #if JUCE_MAC && defined (MAC_OS_X_VERSION_10_8) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_8 | |||
| CTFontManagerUnregisterGraphicsFont (fontRef, nullptr); | |||
| #endif | |||
| CGFontRelease (fontRef); | |||
| } | |||
| if (ctFontRef != nullptr) | |||
| CFRelease (ctFontRef); | |||
| } | |||
| // The implementation of at least one overridden function needs to be outside | |||
| // of the class definition to avoid spurious warning messages when dynamically | |||
| // loading libraries at runtime on macOS... | |||
| ~OSXTypeface() override; | |||
| float getAscent() const override { return ascent; } | |||
| float getDescent() const override { return 1.0f - ascent; } | |||
| @@ -697,6 +684,24 @@ private: | |||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OSXTypeface) | |||
| }; | |||
| OSXTypeface::~OSXTypeface() | |||
| { | |||
| if (attributedStringAtts != nullptr) | |||
| CFRelease (attributedStringAtts); | |||
| if (fontRef != nullptr) | |||
| { | |||
| #if JUCE_MAC && defined (MAC_OS_X_VERSION_10_8) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_8 | |||
| CTFontManagerUnregisterGraphicsFont (fontRef, nullptr); | |||
| #endif | |||
| CGFontRelease (fontRef); | |||
| } | |||
| if (ctFontRef != nullptr) | |||
| CFRelease (ctFontRef); | |||
| } | |||
| CTFontRef getCTFontFromTypeface (const Font& f) | |||
| { | |||
| if (auto* tf = dynamic_cast<OSXTypeface*> (f.getTypeface())) | |||