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.

513 lines
17KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2013 - Raw Material Software Ltd.
  5. Permission is granted to use this software under the terms of either:
  6. a) the GPL v2 (or any later version)
  7. b) the Affero GPL v3
  8. Details of these licenses can be found at: www.gnu.org/licenses
  9. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  10. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  11. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  12. ------------------------------------------------------------------------------
  13. To release a closed-source product which uses JUCE, commercial licenses are
  14. available: visit www.juce.com for more information.
  15. ==============================================================================
  16. */
  17. #if JUCE_COMPILER_SUPPORTS_LAMBDAS
  18. //==============================================================================
  19. struct AudioProcessorValueTreeState::Parameter : public AudioProcessorParameter,
  20. private ValueTree::Listener
  21. {
  22. Parameter (AudioProcessorValueTreeState& s,
  23. String parameterID, String paramName, String labelText,
  24. NormalisableRange<float> r, float defaultVal,
  25. std::function<String (float)> valueToText,
  26. std::function<float (const String&)> textToValue)
  27. : owner (s), paramID (parameterID), name (paramName), label (labelText),
  28. valueToTextFunction (valueToText),
  29. textToValueFunction (textToValue),
  30. range (r), value (defaultVal), defaultValue (defaultVal),
  31. listenersNeedCalling (true)
  32. {
  33. state.addListener (this);
  34. needsUpdate.set (1);
  35. }
  36. ~Parameter()
  37. {
  38. // should have detached all callbacks before destroying the parameters!
  39. jassert (listeners.size() <= 1);
  40. }
  41. float getValue() const override { return range.convertTo0to1 (value); }
  42. float getDefaultValue() const override { return range.convertTo0to1 (defaultValue); }
  43. String getName (int maximumStringLength) const override { return name.substring (0, maximumStringLength); }
  44. String getLabel() const override { return label; }
  45. float getValueForText (const String& text) const override
  46. {
  47. return range.convertTo0to1 (textToValueFunction != nullptr ? textToValueFunction (text)
  48. : text.getFloatValue());
  49. }
  50. String getText (float v, int length) const override
  51. {
  52. return valueToTextFunction != nullptr ? valueToTextFunction (range.convertFrom0to1 (v))
  53. : AudioProcessorParameter::getText (v, length);
  54. }
  55. void setValue (float newValue) override
  56. {
  57. newValue = range.snapToLegalValue (range.convertFrom0to1 (newValue));
  58. if (value != newValue || listenersNeedCalling)
  59. {
  60. value = newValue;
  61. listeners.call (&AudioProcessorValueTreeState::Listener::parameterChanged, paramID, value);
  62. listenersNeedCalling = false;
  63. needsUpdate.set (1);
  64. }
  65. }
  66. void setNewState (const ValueTree& v)
  67. {
  68. state = v;
  69. updateFromValueTree();
  70. }
  71. void setUnnormalisedValue (float newUnnormalisedValue)
  72. {
  73. if (value != newUnnormalisedValue)
  74. {
  75. const float newValue = range.convertTo0to1 (newUnnormalisedValue);
  76. setValueNotifyingHost (newValue);
  77. }
  78. }
  79. void updateFromValueTree()
  80. {
  81. setUnnormalisedValue (state.getProperty (owner.valuePropertyID, defaultValue));
  82. }
  83. void copyValueToValueTree()
  84. {
  85. if (state.isValid())
  86. state.setProperty (owner.valuePropertyID, value, owner.undoManager);
  87. }
  88. void valueTreePropertyChanged (ValueTree&, const Identifier& property) override
  89. {
  90. if (property == owner.valuePropertyID)
  91. updateFromValueTree();
  92. }
  93. void valueTreeChildAdded (ValueTree&, ValueTree&) override {}
  94. void valueTreeChildRemoved (ValueTree&, ValueTree&, int) override {}
  95. void valueTreeChildOrderChanged (ValueTree&, int, int) override {}
  96. void valueTreeParentChanged (ValueTree&) override {}
  97. static Parameter* getParameterForID (AudioProcessor& processor, StringRef paramID) noexcept
  98. {
  99. const int numParams = processor.getParameters().size();
  100. for (int i = 0; i < numParams; ++i)
  101. {
  102. AudioProcessorParameter* const ap = processor.getParameters().getUnchecked(i);
  103. // When using this class, you must allow it to manage all the parameters in your AudioProcessor, and
  104. // not add any parameter objects of other types!
  105. jassert (dynamic_cast<Parameter*> (ap) != nullptr);
  106. Parameter* const p = static_cast<Parameter*> (ap);
  107. if (paramID == p->paramID)
  108. return p;
  109. }
  110. return nullptr;
  111. }
  112. AudioProcessorValueTreeState& owner;
  113. ValueTree state;
  114. String paramID, name, label;
  115. ListenerList<AudioProcessorValueTreeState::Listener> listeners;
  116. std::function<String (float)> valueToTextFunction;
  117. std::function<float (const String&)> textToValueFunction;
  118. NormalisableRange<float> range;
  119. float value, defaultValue;
  120. Atomic<int> needsUpdate;
  121. bool listenersNeedCalling;
  122. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Parameter)
  123. };
  124. //==============================================================================
  125. AudioProcessorValueTreeState::AudioProcessorValueTreeState (AudioProcessor& p, UndoManager* um)
  126. : processor (p),
  127. undoManager (um),
  128. valueType ("PARAM"),
  129. valuePropertyID ("value"),
  130. idPropertyID ("id"),
  131. updatingConnections (false)
  132. {
  133. startTimerHz (10);
  134. state.addListener (this);
  135. }
  136. AudioProcessorValueTreeState::~AudioProcessorValueTreeState() {}
  137. AudioProcessorParameter* AudioProcessorValueTreeState::createAndAddParameter (String paramID, String paramName, String labelText,
  138. NormalisableRange<float> r, float defaultVal,
  139. std::function<String (float)> valueToTextFunction,
  140. std::function<float (const String&)> textToValueFunction)
  141. {
  142. // All parameters must be created before giving this manager a ValueTree state!
  143. jassert (! state.isValid());
  144. jassert (MessageManager::getInstance()->isThisTheMessageThread());
  145. Parameter* p = new Parameter (*this, paramID, paramName, labelText, r,
  146. defaultVal, valueToTextFunction, textToValueFunction);
  147. processor.addParameter (p);
  148. return p;
  149. }
  150. void AudioProcessorValueTreeState::addParameterListener (StringRef paramID, Listener* listener)
  151. {
  152. if (Parameter* p = Parameter::getParameterForID (processor, paramID))
  153. p->listeners.add (listener);
  154. }
  155. void AudioProcessorValueTreeState::removeParameterListener (StringRef paramID, Listener* listener)
  156. {
  157. if (Parameter* p = Parameter::getParameterForID (processor, paramID))
  158. p->listeners.remove (listener);
  159. }
  160. Value AudioProcessorValueTreeState::getParameterAsValue (StringRef paramID) const
  161. {
  162. if (Parameter* p = Parameter::getParameterForID (processor, paramID))
  163. return p->state.getPropertyAsValue (valuePropertyID, undoManager);
  164. return Value();
  165. }
  166. NormalisableRange<float> AudioProcessorValueTreeState::getParameterRange (StringRef paramID) const noexcept
  167. {
  168. if (Parameter* p = Parameter::getParameterForID (processor, paramID))
  169. return p->range;
  170. return NormalisableRange<float>();
  171. }
  172. AudioProcessorParameter* AudioProcessorValueTreeState::getParameter (StringRef paramID) const noexcept
  173. {
  174. return Parameter::getParameterForID (processor, paramID);
  175. }
  176. float* AudioProcessorValueTreeState::getRawParameterValue (StringRef paramID) const noexcept
  177. {
  178. if (Parameter* p = Parameter::getParameterForID (processor, paramID))
  179. return &(p->value);
  180. return nullptr;
  181. }
  182. ValueTree AudioProcessorValueTreeState::getOrCreateChildValueTree (const String& paramID)
  183. {
  184. ValueTree v (state.getChildWithProperty (idPropertyID, paramID));
  185. if (! v.isValid())
  186. {
  187. v = ValueTree (valueType);
  188. v.setProperty (idPropertyID, paramID, undoManager);
  189. state.addChild (v, -1, undoManager);
  190. }
  191. return v;
  192. }
  193. void AudioProcessorValueTreeState::updateParameterConnectionsToChildTrees()
  194. {
  195. if (! updatingConnections)
  196. {
  197. ScopedValueSetter<bool> svs (updatingConnections, true, false);
  198. const int numParams = processor.getParameters().size();
  199. for (int i = 0; i < numParams; ++i)
  200. {
  201. AudioProcessorParameter* const ap = processor.getParameters().getUnchecked(i);
  202. jassert (dynamic_cast<Parameter*> (ap) != nullptr);
  203. Parameter* p = static_cast<Parameter*> (ap);
  204. p->setNewState (getOrCreateChildValueTree (p->paramID));
  205. }
  206. }
  207. }
  208. void AudioProcessorValueTreeState::valueTreePropertyChanged (ValueTree&, const Identifier& property)
  209. {
  210. if (property == idPropertyID)
  211. updateParameterConnectionsToChildTrees();
  212. }
  213. void AudioProcessorValueTreeState::valueTreeChildAdded (ValueTree& parent, ValueTree&)
  214. {
  215. if (parent == state)
  216. updateParameterConnectionsToChildTrees();
  217. }
  218. void AudioProcessorValueTreeState::valueTreeChildRemoved (ValueTree& parent, ValueTree&, int)
  219. {
  220. if (parent == state)
  221. updateParameterConnectionsToChildTrees();
  222. }
  223. void AudioProcessorValueTreeState::valueTreeRedirected (ValueTree& v)
  224. {
  225. if (v == state)
  226. updateParameterConnectionsToChildTrees();
  227. }
  228. void AudioProcessorValueTreeState::valueTreeChildOrderChanged (ValueTree&, int, int) {}
  229. void AudioProcessorValueTreeState::valueTreeParentChanged (ValueTree&) {}
  230. void AudioProcessorValueTreeState::timerCallback()
  231. {
  232. const int numParams = processor.getParameters().size();
  233. bool anythingUpdated = false;
  234. for (int i = 0; i < numParams; ++i)
  235. {
  236. AudioProcessorParameter* const ap = processor.getParameters().getUnchecked(i);
  237. jassert (dynamic_cast<Parameter*> (ap) != nullptr);
  238. Parameter* p = static_cast<Parameter*> (ap);
  239. if (p->needsUpdate.compareAndSetBool (0, 1))
  240. {
  241. p->copyValueToValueTree();
  242. anythingUpdated = true;
  243. }
  244. }
  245. startTimer (anythingUpdated ? 1000 / 50
  246. : jlimit (50, 500, getTimerInterval() + 20));
  247. }
  248. AudioProcessorValueTreeState::Listener::Listener() {}
  249. AudioProcessorValueTreeState::Listener::~Listener() {}
  250. //==============================================================================
  251. struct AttachedControlBase : public AudioProcessorValueTreeState::Listener,
  252. public AsyncUpdater
  253. {
  254. AttachedControlBase (AudioProcessorValueTreeState& s, const String& p)
  255. : state (s), paramID (p), lastValue (0)
  256. {
  257. state.addParameterListener (paramID, this);
  258. }
  259. void removeListener()
  260. {
  261. state.removeParameterListener (paramID, this);
  262. }
  263. void setNewUnnormalisedValue (float newUnnormalisedValue)
  264. {
  265. if (AudioProcessorParameter* p = state.getParameter (paramID))
  266. {
  267. const float newValue = state.getParameterRange (paramID)
  268. .convertTo0to1 (newUnnormalisedValue);
  269. if (p->getValue() != newValue)
  270. p->setValueNotifyingHost (newValue);
  271. }
  272. }
  273. void sendInitialUpdate()
  274. {
  275. if (float* v = state.getRawParameterValue (paramID))
  276. parameterChanged (paramID, *v);
  277. }
  278. void parameterChanged (const String&, float newValue) override
  279. {
  280. lastValue = newValue;
  281. if (MessageManager::getInstance()->isThisTheMessageThread())
  282. {
  283. cancelPendingUpdate();
  284. setValue (newValue);
  285. }
  286. else
  287. {
  288. triggerAsyncUpdate();
  289. }
  290. }
  291. void handleAsyncUpdate() override
  292. {
  293. setValue (lastValue);
  294. }
  295. virtual void setValue (float) = 0;
  296. AudioProcessorValueTreeState& state;
  297. String paramID;
  298. float lastValue;
  299. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AttachedControlBase)
  300. };
  301. //==============================================================================
  302. struct AudioProcessorValueTreeState::SliderAttachment::Pimpl : private AttachedControlBase,
  303. private Slider::Listener
  304. {
  305. Pimpl (AudioProcessorValueTreeState& s, const String& p, Slider& sl)
  306. : AttachedControlBase (s, p), slider (sl)
  307. {
  308. NormalisableRange<float> range (s.getParameterRange (paramID));
  309. slider.setRange (range.start, range.end, range.interval);
  310. if (AudioProcessorParameter* param = state.getParameter (paramID))
  311. slider.setDoubleClickReturnValue (true, range.convertFrom0to1 (param->getDefaultValue()));
  312. sendInitialUpdate();
  313. slider.addListener (this);
  314. }
  315. ~Pimpl()
  316. {
  317. slider.removeListener (this);
  318. removeListener();
  319. }
  320. void setValue (float newValue) override
  321. {
  322. slider.setValue (newValue, sendNotificationSync);
  323. }
  324. void sliderValueChanged (Slider* s) override
  325. {
  326. if (! ModifierKeys::getCurrentModifiers().isRightButtonDown())
  327. setNewUnnormalisedValue ((float) s->getValue());
  328. }
  329. void sliderDragStarted (Slider*) override
  330. {
  331. if (AudioProcessorParameter* p = state.getParameter (paramID))
  332. p->beginChangeGesture();
  333. }
  334. void sliderDragEnded (Slider*) override
  335. {
  336. if (AudioProcessorParameter* p = state.getParameter (paramID))
  337. p->endChangeGesture();
  338. }
  339. Slider& slider;
  340. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Pimpl)
  341. };
  342. AudioProcessorValueTreeState::SliderAttachment::SliderAttachment (AudioProcessorValueTreeState& s, const String& p, Slider& sl)
  343. : pimpl (new Pimpl (s, p, sl))
  344. {
  345. }
  346. AudioProcessorValueTreeState::SliderAttachment::~SliderAttachment() {}
  347. //==============================================================================
  348. struct AudioProcessorValueTreeState::ComboBoxAttachment::Pimpl : private AttachedControlBase,
  349. private ComboBox::Listener
  350. {
  351. Pimpl (AudioProcessorValueTreeState& s, const String& p, ComboBox& c)
  352. : AttachedControlBase (s, p), combo (c)
  353. {
  354. sendInitialUpdate();
  355. combo.addListener (this);
  356. }
  357. ~Pimpl()
  358. {
  359. combo.removeListener (this);
  360. removeListener();
  361. }
  362. void setValue (float newValue) override
  363. {
  364. combo.setSelectedItemIndex (roundToInt (newValue), sendNotificationSync);
  365. }
  366. void comboBoxChanged (ComboBox* comboBox) override
  367. {
  368. setNewUnnormalisedValue ((float) comboBox->getSelectedId() - 1.0f);
  369. }
  370. ComboBox& combo;
  371. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Pimpl)
  372. };
  373. AudioProcessorValueTreeState::ComboBoxAttachment::ComboBoxAttachment (AudioProcessorValueTreeState& s, const String& p, ComboBox& c)
  374. : pimpl (new Pimpl (s, p, c))
  375. {
  376. }
  377. AudioProcessorValueTreeState::ComboBoxAttachment::~ComboBoxAttachment() {}
  378. //==============================================================================
  379. struct AudioProcessorValueTreeState::ButtonAttachment::Pimpl : private AttachedControlBase,
  380. private Button::Listener
  381. {
  382. Pimpl (AudioProcessorValueTreeState& s, const String& p, Button& b)
  383. : AttachedControlBase (s, p), button (b)
  384. {
  385. sendInitialUpdate();
  386. button.addListener (this);
  387. }
  388. ~Pimpl()
  389. {
  390. button.removeListener (this);
  391. removeListener();
  392. }
  393. void setValue (float newValue) override
  394. {
  395. button.setToggleState (newValue >= 0.5f, sendNotificationSync);
  396. }
  397. void buttonClicked (Button* b) override
  398. {
  399. setNewUnnormalisedValue (b->getToggleState() ? 1.0f : 0.0f);
  400. }
  401. Button& button;
  402. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Pimpl)
  403. };
  404. AudioProcessorValueTreeState::ButtonAttachment::ButtonAttachment (AudioProcessorValueTreeState& s, const String& p, Button& b)
  405. : pimpl (new Pimpl (s, p, b))
  406. {
  407. }
  408. AudioProcessorValueTreeState::ButtonAttachment::~ButtonAttachment() {}
  409. #endif