@@ -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())) | |||