The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

338 lines
15KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2017 - ROLI Ltd.
  5. JUCE is an open source library subject to commercial or open-source
  6. licensing.
  7. By using JUCE, you agree to the terms of both the JUCE 5 End-User License
  8. Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
  9. 27th April 2017).
  10. End User License Agreement: www.juce.com/juce-5-licence
  11. Privacy Policy: www.juce.com/juce-5-privacy-policy
  12. Or: You may also use this code under the terms of the GPL v3 (see
  13. www.gnu.org/licenses).
  14. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  15. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  16. DISCLAIMED.
  17. ==============================================================================
  18. */
  19. namespace juce
  20. {
  21. // This file contains the implementations of the various AudioParameter[XYZ] classes..
  22. AudioProcessorParameterWithID::AudioProcessorParameterWithID (const String& idToUse,
  23. const String& nameToUse,
  24. const String& labelToUse,
  25. AudioProcessorParameter::Category categoryToUse)
  26. : paramID (idToUse), name (nameToUse), label (labelToUse), category (categoryToUse) {}
  27. AudioProcessorParameterWithID::~AudioProcessorParameterWithID() {}
  28. String AudioProcessorParameterWithID::getName (int maximumStringLength) const { return name.substring (0, maximumStringLength); }
  29. String AudioProcessorParameterWithID::getLabel() const { return label; }
  30. AudioProcessorParameter::Category AudioProcessorParameterWithID::getCategory() const { return category; }
  31. //==============================================================================
  32. AudioParameterFloat::AudioParameterFloat (const String& idToUse, const String& nameToUse,
  33. NormalisableRange<float> r, float def,
  34. const String& labelToUse, Category categoryToUse,
  35. std::function<String (float, int)> stringFromValue,
  36. std::function<float (const String&)> valueFromString)
  37. : RangedAudioParameter (idToUse, nameToUse, labelToUse, categoryToUse),
  38. range (r), value (def), defaultValue (def),
  39. stringFromValueFunction (stringFromValue),
  40. valueFromStringFunction (valueFromString)
  41. {
  42. if (stringFromValueFunction == nullptr)
  43. stringFromValueFunction = [] (float v, int length)
  44. {
  45. String asText (v, 2);
  46. return length > 0 ? asText.substring (0, length) : asText;
  47. };
  48. if (valueFromStringFunction == nullptr)
  49. valueFromStringFunction = [] (const String& text) { return text.getFloatValue(); };
  50. }
  51. AudioParameterFloat::AudioParameterFloat (String pid, String nm, float minValue, float maxValue, float def)
  52. : AudioParameterFloat (pid, nm, { minValue, maxValue }, def)
  53. {
  54. }
  55. AudioParameterFloat::~AudioParameterFloat() {}
  56. float AudioParameterFloat::getValue() const { return convertTo0to1 (value); }
  57. void AudioParameterFloat::setValue (float newValue) { value = convertFrom0to1 (newValue); valueChanged (get()); }
  58. float AudioParameterFloat::getDefaultValue() const { return convertTo0to1 (defaultValue); }
  59. int AudioParameterFloat::getNumSteps() const { return AudioProcessorParameterWithID::getNumSteps(); }
  60. String AudioParameterFloat::getText (float v, int length) const { return stringFromValueFunction (convertFrom0to1 (v), length); }
  61. float AudioParameterFloat::getValueForText (const String& text) const { return convertTo0to1 (valueFromStringFunction (text)); }
  62. void AudioParameterFloat::valueChanged (float) {}
  63. AudioParameterFloat& AudioParameterFloat::operator= (float newValue)
  64. {
  65. if (value != newValue)
  66. setValueNotifyingHost (convertTo0to1 (newValue));
  67. return *this;
  68. }
  69. //==============================================================================
  70. AudioParameterInt::AudioParameterInt (const String& idToUse, const String& nameToUse,
  71. int minValue, int maxValue, int def,
  72. const String& labelToUse,
  73. std::function<String (int, int)> stringFromInt,
  74. std::function<int (const String&)> intFromString)
  75. : RangedAudioParameter (idToUse, nameToUse, labelToUse),
  76. range ((float) minValue, (float) maxValue,
  77. [](float start, float end, float v) { return jlimit (start, end, v * (end - start) + start); },
  78. [](float start, float end, float v) { return jlimit (0.0f, 1.0f, (v - start) / (end - start)); },
  79. [](float start, float end, float v) { return (float) roundToInt (juce::jlimit (start, end, v)); }),
  80. value ((float) def),
  81. defaultValue (convertTo0to1 ((float) def)),
  82. stringFromIntFunction (stringFromInt),
  83. intFromStringFunction (intFromString)
  84. {
  85. jassert (minValue < maxValue); // must have a non-zero range of values!
  86. if (stringFromIntFunction == nullptr)
  87. stringFromIntFunction = [] (int v, int) { return String (v); };
  88. if (intFromStringFunction == nullptr)
  89. intFromStringFunction = [] (const String& text) { return text.getIntValue(); };
  90. }
  91. AudioParameterInt::~AudioParameterInt() {}
  92. float AudioParameterInt::getValue() const { return convertTo0to1 (value); }
  93. void AudioParameterInt::setValue (float newValue) { value = convertFrom0to1 (newValue); valueChanged (get()); }
  94. float AudioParameterInt::getDefaultValue() const { return defaultValue; }
  95. int AudioParameterInt::getNumSteps() const { return ((int) getNormalisableRange().getRange().getLength()) + 1; }
  96. float AudioParameterInt::getValueForText (const String& text) const { return convertTo0to1 ((float) intFromStringFunction (text)); }
  97. String AudioParameterInt::getText (float v, int length) const { return stringFromIntFunction ((int) convertFrom0to1 (v), length); }
  98. void AudioParameterInt::valueChanged (int) {}
  99. AudioParameterInt& AudioParameterInt::operator= (int newValue)
  100. {
  101. if (get() != newValue)
  102. setValueNotifyingHost (convertTo0to1 ((float) newValue));
  103. return *this;
  104. }
  105. //==============================================================================
  106. AudioParameterBool::AudioParameterBool (const String& idToUse, const String& nameToUse,
  107. bool def, const String& labelToUse,
  108. std::function<String (bool, int)> stringFromBool,
  109. std::function<bool (const String&)> boolFromString)
  110. : RangedAudioParameter (idToUse, nameToUse, labelToUse),
  111. value (def ? 1.0f : 0.0f),
  112. defaultValue (value),
  113. stringFromBoolFunction (stringFromBool),
  114. boolFromStringFunction (boolFromString)
  115. {
  116. if (stringFromBoolFunction == nullptr)
  117. stringFromBoolFunction = [] (bool v, int) { return v ? TRANS("On") : TRANS("Off"); };
  118. if (boolFromStringFunction == nullptr)
  119. {
  120. StringArray onStrings;
  121. onStrings.add (TRANS("on"));
  122. onStrings.add (TRANS("yes"));
  123. onStrings.add (TRANS("true"));
  124. StringArray offStrings;
  125. offStrings.add (TRANS("off"));
  126. offStrings.add (TRANS("no"));
  127. offStrings.add (TRANS("false"));
  128. boolFromStringFunction = [onStrings, offStrings] (const String& text)
  129. {
  130. String lowercaseText (text.toLowerCase());
  131. for (auto& testText : onStrings)
  132. if (lowercaseText == testText)
  133. return true;
  134. for (auto& testText : offStrings)
  135. if (lowercaseText == testText)
  136. return false;
  137. return text.getIntValue() != 0;
  138. };
  139. }
  140. }
  141. AudioParameterBool::~AudioParameterBool() {}
  142. float AudioParameterBool::getValue() const { return value; }
  143. void AudioParameterBool::setValue (float newValue) { value = newValue; valueChanged (get()); }
  144. float AudioParameterBool::getDefaultValue() const { return defaultValue; }
  145. int AudioParameterBool::getNumSteps() const { return 2; }
  146. bool AudioParameterBool::isDiscrete() const { return true; }
  147. bool AudioParameterBool::isBoolean() const { return true; }
  148. void AudioParameterBool::valueChanged (bool) {}
  149. float AudioParameterBool::getValueForText (const String& text) const
  150. {
  151. return boolFromStringFunction (text) ? 1.0f : 0.0f;
  152. }
  153. String AudioParameterBool::getText (float v, int maximumLength) const
  154. {
  155. return stringFromBoolFunction (v >= 0.5f, maximumLength);
  156. }
  157. AudioParameterBool& AudioParameterBool::operator= (bool newValue)
  158. {
  159. if (get() != newValue)
  160. setValueNotifyingHost (newValue ? 1.0f : 0.0f);
  161. return *this;
  162. }
  163. //==============================================================================
  164. AudioParameterChoice::AudioParameterChoice (const String& idToUse, const String& nameToUse,
  165. const StringArray& c, int def, const String& labelToUse,
  166. std::function<String (int, int)> stringFromIndex,
  167. std::function<int (const String&)> indexFromString)
  168. : RangedAudioParameter (idToUse, nameToUse, labelToUse), choices (c),
  169. range (0.0f, choices.size() - 1.0f,
  170. [](float, float end, float v) { return jlimit (0.0f, end, v * end); },
  171. [](float, float end, float v) { return jlimit (0.0f, 1.0f, v / end); },
  172. [](float start, float end, float v) { return (float) roundToInt (juce::jlimit (start, end, v)); }),
  173. value ((float) def),
  174. defaultValue (convertTo0to1 ((float) def)),
  175. stringFromIndexFunction (stringFromIndex),
  176. indexFromStringFunction (indexFromString)
  177. {
  178. jassert (choices.size() > 0); // you must supply an actual set of items to choose from!
  179. if (stringFromIndexFunction == nullptr)
  180. stringFromIndexFunction = [this] (int index, int) { return choices [index]; };
  181. if (indexFromStringFunction == nullptr)
  182. indexFromStringFunction = [this] (const String& text) { return choices.indexOf (text); };
  183. }
  184. AudioParameterChoice::~AudioParameterChoice() {}
  185. float AudioParameterChoice::getValue() const { return convertTo0to1 (value); }
  186. void AudioParameterChoice::setValue (float newValue) { value = convertFrom0to1 (newValue); valueChanged (getIndex()); }
  187. float AudioParameterChoice::getDefaultValue() const { return defaultValue; }
  188. int AudioParameterChoice::getNumSteps() const { return choices.size(); }
  189. bool AudioParameterChoice::isDiscrete() const { return true; }
  190. float AudioParameterChoice::getValueForText (const String& text) const { return convertTo0to1 ((float) indexFromStringFunction (text)); }
  191. String AudioParameterChoice::getText (float v, int length) const { return stringFromIndexFunction ((int) convertFrom0to1 (v), length); }
  192. void AudioParameterChoice::valueChanged (int) {}
  193. AudioParameterChoice& AudioParameterChoice::operator= (int newValue)
  194. {
  195. if (getIndex() != newValue)
  196. setValueNotifyingHost (convertTo0to1 ((float) newValue));
  197. return *this;
  198. }
  199. #if JUCE_UNIT_TESTS
  200. static struct SpecialisedAudioParameterTests final : public UnitTest
  201. {
  202. SpecialisedAudioParameterTests() : UnitTest ("Specialised Audio Parameters", "AudioProcessor parameters") {}
  203. void runTest() override
  204. {
  205. beginTest ("A choice parameter with three options switches at the correct points");
  206. {
  207. AudioParameterChoice choice ({}, {}, { "a", "b", "c" }, {});
  208. choice.setValueNotifyingHost (0.0f);
  209. expectEquals (choice.getIndex(), 0);
  210. choice.setValueNotifyingHost (0.2f);
  211. expectEquals (choice.getIndex(), 0);
  212. choice.setValueNotifyingHost (0.3f);
  213. expectEquals (choice.getIndex(), 1);
  214. choice.setValueNotifyingHost (0.7f);
  215. expectEquals (choice.getIndex(), 1);
  216. choice.setValueNotifyingHost (0.8f);
  217. expectEquals (choice.getIndex(), 2);
  218. choice.setValueNotifyingHost (1.0f);
  219. expectEquals (choice.getIndex(), 2);
  220. }
  221. beginTest ("An int parameter with three options switches at the correct points");
  222. {
  223. AudioParameterInt intParam ({}, {}, 1, 3, 1);
  224. intParam.setValueNotifyingHost (0.0f);
  225. expectEquals (intParam.get(), 1);
  226. intParam.setValueNotifyingHost (0.2f);
  227. expectEquals (intParam.get(), 1);
  228. intParam.setValueNotifyingHost (0.3f);
  229. expectEquals (intParam.get(), 2);
  230. intParam.setValueNotifyingHost (0.7f);
  231. expectEquals (intParam.get(), 2);
  232. intParam.setValueNotifyingHost (0.8f);
  233. expectEquals (intParam.get(), 3);
  234. intParam.setValueNotifyingHost (1.0f);
  235. expectEquals (intParam.get(), 3);
  236. }
  237. beginTest ("Choice parameters handle out-of-bounds input");
  238. {
  239. AudioParameterChoice choiceParam ({}, {}, { "a", "b", "c" }, {});
  240. choiceParam.setValueNotifyingHost (-0.5f);
  241. expectEquals (choiceParam.getIndex(), 0);
  242. choiceParam.setValueNotifyingHost (1.5f);
  243. expectEquals (choiceParam.getIndex(), 2);
  244. }
  245. beginTest ("Int parameters handle out-of-bounds input");
  246. {
  247. AudioParameterInt intParam ({}, {}, -1, 2, 0);
  248. intParam.setValueNotifyingHost (-0.5f);
  249. expectEquals (intParam.get(), -1);
  250. intParam.setValueNotifyingHost (1.5f);
  251. expectEquals (intParam.get(), 2);
  252. intParam = -5;
  253. expectEquals (intParam.get(), -1);
  254. intParam = 5;
  255. expectEquals (intParam.get(), 2);
  256. }
  257. }
  258. } specialisedAudioParameterTests;
  259. #endif
  260. } // namespace juce