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.

361 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. {
  44. auto numDecimalPlacesToDisplay = [this]
  45. {
  46. int numDecimalPlaces = 7;
  47. if (range.interval != 0.0f)
  48. {
  49. if (approximatelyEqual (std::abs (range.interval - (int) range.interval), 0.0f))
  50. return 0;
  51. auto v = std::abs (roundToInt (range.interval * pow (10, numDecimalPlaces)));
  52. while ((v % 10) == 0 && numDecimalPlaces > 0)
  53. {
  54. --numDecimalPlaces;
  55. v /= 10;
  56. }
  57. }
  58. return numDecimalPlaces;
  59. }();
  60. stringFromValueFunction = [numDecimalPlacesToDisplay] (float v, int length)
  61. {
  62. String asText (v, numDecimalPlacesToDisplay);
  63. return length > 0 ? asText.substring (0, length) : asText;
  64. };
  65. }
  66. if (valueFromStringFunction == nullptr)
  67. valueFromStringFunction = [] (const String& text) { return text.getFloatValue(); };
  68. }
  69. AudioParameterFloat::AudioParameterFloat (String pid, String nm, float minValue, float maxValue, float def)
  70. : AudioParameterFloat (pid, nm, { minValue, maxValue }, def)
  71. {
  72. }
  73. AudioParameterFloat::~AudioParameterFloat() {}
  74. float AudioParameterFloat::getValue() const { return convertTo0to1 (value); }
  75. void AudioParameterFloat::setValue (float newValue) { value = convertFrom0to1 (newValue); valueChanged (get()); }
  76. float AudioParameterFloat::getDefaultValue() const { return convertTo0to1 (defaultValue); }
  77. int AudioParameterFloat::getNumSteps() const { return AudioProcessorParameterWithID::getNumSteps(); }
  78. String AudioParameterFloat::getText (float v, int length) const { return stringFromValueFunction (convertFrom0to1 (v), length); }
  79. float AudioParameterFloat::getValueForText (const String& text) const { return convertTo0to1 (valueFromStringFunction (text)); }
  80. void AudioParameterFloat::valueChanged (float) {}
  81. AudioParameterFloat& AudioParameterFloat::operator= (float newValue)
  82. {
  83. if (value != newValue)
  84. setValueNotifyingHost (convertTo0to1 (newValue));
  85. return *this;
  86. }
  87. //==============================================================================
  88. AudioParameterInt::AudioParameterInt (const String& idToUse, const String& nameToUse,
  89. int minValue, int maxValue, int def,
  90. const String& labelToUse,
  91. std::function<String (int, int)> stringFromInt,
  92. std::function<int (const String&)> intFromString)
  93. : RangedAudioParameter (idToUse, nameToUse, labelToUse),
  94. range ((float) minValue, (float) maxValue,
  95. [](float start, float end, float v) { return jlimit (start, end, v * (end - start) + start); },
  96. [](float start, float end, float v) { return jlimit (0.0f, 1.0f, (v - start) / (end - start)); },
  97. [](float start, float end, float v) { return (float) roundToInt (juce::jlimit (start, end, v)); }),
  98. value ((float) def),
  99. defaultValue (convertTo0to1 ((float) def)),
  100. stringFromIntFunction (stringFromInt),
  101. intFromStringFunction (intFromString)
  102. {
  103. jassert (minValue < maxValue); // must have a non-zero range of values!
  104. if (stringFromIntFunction == nullptr)
  105. stringFromIntFunction = [] (int v, int) { return String (v); };
  106. if (intFromStringFunction == nullptr)
  107. intFromStringFunction = [] (const String& text) { return text.getIntValue(); };
  108. }
  109. AudioParameterInt::~AudioParameterInt() {}
  110. float AudioParameterInt::getValue() const { return convertTo0to1 (value); }
  111. void AudioParameterInt::setValue (float newValue) { value = convertFrom0to1 (newValue); valueChanged (get()); }
  112. float AudioParameterInt::getDefaultValue() const { return defaultValue; }
  113. int AudioParameterInt::getNumSteps() const { return ((int) getNormalisableRange().getRange().getLength()) + 1; }
  114. float AudioParameterInt::getValueForText (const String& text) const { return convertTo0to1 ((float) intFromStringFunction (text)); }
  115. String AudioParameterInt::getText (float v, int length) const { return stringFromIntFunction ((int) convertFrom0to1 (v), length); }
  116. void AudioParameterInt::valueChanged (int) {}
  117. AudioParameterInt& AudioParameterInt::operator= (int newValue)
  118. {
  119. if (get() != newValue)
  120. setValueNotifyingHost (convertTo0to1 ((float) newValue));
  121. return *this;
  122. }
  123. //==============================================================================
  124. AudioParameterBool::AudioParameterBool (const String& idToUse, const String& nameToUse,
  125. bool def, const String& labelToUse,
  126. std::function<String (bool, int)> stringFromBool,
  127. std::function<bool (const String&)> boolFromString)
  128. : RangedAudioParameter (idToUse, nameToUse, labelToUse),
  129. value (def ? 1.0f : 0.0f),
  130. defaultValue (value),
  131. stringFromBoolFunction (stringFromBool),
  132. boolFromStringFunction (boolFromString)
  133. {
  134. if (stringFromBoolFunction == nullptr)
  135. stringFromBoolFunction = [] (bool v, int) { return v ? TRANS("On") : TRANS("Off"); };
  136. if (boolFromStringFunction == nullptr)
  137. {
  138. StringArray onStrings;
  139. onStrings.add (TRANS("on"));
  140. onStrings.add (TRANS("yes"));
  141. onStrings.add (TRANS("true"));
  142. StringArray offStrings;
  143. offStrings.add (TRANS("off"));
  144. offStrings.add (TRANS("no"));
  145. offStrings.add (TRANS("false"));
  146. boolFromStringFunction = [onStrings, offStrings] (const String& text)
  147. {
  148. String lowercaseText (text.toLowerCase());
  149. for (auto& testText : onStrings)
  150. if (lowercaseText == testText)
  151. return true;
  152. for (auto& testText : offStrings)
  153. if (lowercaseText == testText)
  154. return false;
  155. return text.getIntValue() != 0;
  156. };
  157. }
  158. }
  159. AudioParameterBool::~AudioParameterBool() {}
  160. float AudioParameterBool::getValue() const { return value; }
  161. void AudioParameterBool::setValue (float newValue) { value = newValue; valueChanged (get()); }
  162. float AudioParameterBool::getDefaultValue() const { return defaultValue; }
  163. int AudioParameterBool::getNumSteps() const { return 2; }
  164. bool AudioParameterBool::isDiscrete() const { return true; }
  165. bool AudioParameterBool::isBoolean() const { return true; }
  166. void AudioParameterBool::valueChanged (bool) {}
  167. float AudioParameterBool::getValueForText (const String& text) const
  168. {
  169. return boolFromStringFunction (text) ? 1.0f : 0.0f;
  170. }
  171. String AudioParameterBool::getText (float v, int maximumLength) const
  172. {
  173. return stringFromBoolFunction (v >= 0.5f, maximumLength);
  174. }
  175. AudioParameterBool& AudioParameterBool::operator= (bool newValue)
  176. {
  177. if (get() != newValue)
  178. setValueNotifyingHost (newValue ? 1.0f : 0.0f);
  179. return *this;
  180. }
  181. //==============================================================================
  182. AudioParameterChoice::AudioParameterChoice (const String& idToUse, const String& nameToUse,
  183. const StringArray& c, int def, const String& labelToUse,
  184. std::function<String (int, int)> stringFromIndex,
  185. std::function<int (const String&)> indexFromString)
  186. : RangedAudioParameter (idToUse, nameToUse, labelToUse), choices (c),
  187. range (0.0f, choices.size() - 1.0f,
  188. [](float, float end, float v) { return jlimit (0.0f, end, v * end); },
  189. [](float, float end, float v) { return jlimit (0.0f, 1.0f, v / end); },
  190. [](float start, float end, float v) { return (float) roundToInt (juce::jlimit (start, end, v)); }),
  191. value ((float) def),
  192. defaultValue (convertTo0to1 ((float) def)),
  193. stringFromIndexFunction (stringFromIndex),
  194. indexFromStringFunction (indexFromString)
  195. {
  196. jassert (choices.size() > 0); // you must supply an actual set of items to choose from!
  197. if (stringFromIndexFunction == nullptr)
  198. stringFromIndexFunction = [this] (int index, int) { return choices [index]; };
  199. if (indexFromStringFunction == nullptr)
  200. indexFromStringFunction = [this] (const String& text) { return choices.indexOf (text); };
  201. }
  202. AudioParameterChoice::~AudioParameterChoice() {}
  203. float AudioParameterChoice::getValue() const { return convertTo0to1 (value); }
  204. void AudioParameterChoice::setValue (float newValue) { value = convertFrom0to1 (newValue); valueChanged (getIndex()); }
  205. float AudioParameterChoice::getDefaultValue() const { return defaultValue; }
  206. int AudioParameterChoice::getNumSteps() const { return choices.size(); }
  207. bool AudioParameterChoice::isDiscrete() const { return true; }
  208. float AudioParameterChoice::getValueForText (const String& text) const { return convertTo0to1 ((float) indexFromStringFunction (text)); }
  209. String AudioParameterChoice::getText (float v, int length) const { return stringFromIndexFunction ((int) convertFrom0to1 (v), length); }
  210. void AudioParameterChoice::valueChanged (int) {}
  211. AudioParameterChoice& AudioParameterChoice::operator= (int newValue)
  212. {
  213. if (getIndex() != newValue)
  214. setValueNotifyingHost (convertTo0to1 ((float) newValue));
  215. return *this;
  216. }
  217. #if JUCE_UNIT_TESTS
  218. static struct SpecialisedAudioParameterTests final : public UnitTest
  219. {
  220. SpecialisedAudioParameterTests() : UnitTest ("Specialised Audio Parameters", "AudioProcessor parameters") {}
  221. void runTest() override
  222. {
  223. beginTest ("A choice parameter with three options switches at the correct points");
  224. {
  225. AudioParameterChoice choice ({}, {}, { "a", "b", "c" }, {});
  226. choice.setValueNotifyingHost (0.0f);
  227. expectEquals (choice.getIndex(), 0);
  228. choice.setValueNotifyingHost (0.2f);
  229. expectEquals (choice.getIndex(), 0);
  230. choice.setValueNotifyingHost (0.3f);
  231. expectEquals (choice.getIndex(), 1);
  232. choice.setValueNotifyingHost (0.7f);
  233. expectEquals (choice.getIndex(), 1);
  234. choice.setValueNotifyingHost (0.8f);
  235. expectEquals (choice.getIndex(), 2);
  236. choice.setValueNotifyingHost (1.0f);
  237. expectEquals (choice.getIndex(), 2);
  238. }
  239. beginTest ("An int parameter with three options switches at the correct points");
  240. {
  241. AudioParameterInt intParam ({}, {}, 1, 3, 1);
  242. intParam.setValueNotifyingHost (0.0f);
  243. expectEquals (intParam.get(), 1);
  244. intParam.setValueNotifyingHost (0.2f);
  245. expectEquals (intParam.get(), 1);
  246. intParam.setValueNotifyingHost (0.3f);
  247. expectEquals (intParam.get(), 2);
  248. intParam.setValueNotifyingHost (0.7f);
  249. expectEquals (intParam.get(), 2);
  250. intParam.setValueNotifyingHost (0.8f);
  251. expectEquals (intParam.get(), 3);
  252. intParam.setValueNotifyingHost (1.0f);
  253. expectEquals (intParam.get(), 3);
  254. }
  255. beginTest ("Choice parameters handle out-of-bounds input");
  256. {
  257. AudioParameterChoice choiceParam ({}, {}, { "a", "b", "c" }, {});
  258. choiceParam.setValueNotifyingHost (-0.5f);
  259. expectEquals (choiceParam.getIndex(), 0);
  260. choiceParam.setValueNotifyingHost (1.5f);
  261. expectEquals (choiceParam.getIndex(), 2);
  262. }
  263. beginTest ("Int parameters handle out-of-bounds input");
  264. {
  265. AudioParameterInt intParam ({}, {}, -1, 2, 0);
  266. intParam.setValueNotifyingHost (-0.5f);
  267. expectEquals (intParam.get(), -1);
  268. intParam.setValueNotifyingHost (1.5f);
  269. expectEquals (intParam.get(), 2);
  270. intParam = -5;
  271. expectEquals (intParam.get(), -1);
  272. intParam = 5;
  273. expectEquals (intParam.get(), 2);
  274. }
  275. }
  276. } specialisedAudioParameterTests;
  277. #endif
  278. } // namespace juce