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.

564 lines
19KB

  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. //==============================================================================
  20. struct AudioProcessorValueTreeState::Parameter : public AudioProcessorParameterWithID,
  21. private ValueTree::Listener
  22. {
  23. Parameter (AudioProcessorValueTreeState& s,
  24. const String& parameterID, const String& paramName, const String& labelText,
  25. NormalisableRange<float> r, float defaultVal,
  26. std::function<String (float)> valueToText,
  27. std::function<float (const String&)> textToValue,
  28. bool meta)
  29. : AudioProcessorParameterWithID (parameterID, paramName, labelText),
  30. owner (s), valueToTextFunction (valueToText), textToValueFunction (textToValue),
  31. range (r), value (defaultVal), defaultValue (defaultVal),
  32. listenersNeedCalling (true),
  33. isMeta (meta)
  34. {
  35. state.addListener (this);
  36. needsUpdate.set (1);
  37. }
  38. ~Parameter()
  39. {
  40. // should have detached all callbacks before destroying the parameters!
  41. jassert (listeners.size() <= 1);
  42. }
  43. float getValue() const override { return range.convertTo0to1 (value); }
  44. float getDefaultValue() const override { return range.convertTo0to1 (defaultValue); }
  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. int getNumSteps() const override
  56. {
  57. if (range.interval > 0)
  58. return (static_cast<int> ((range.end - range.start) / range.interval) + 1);
  59. return AudioProcessor::getDefaultNumParameterSteps();
  60. }
  61. void setValue (float newValue) override
  62. {
  63. newValue = range.snapToLegalValue (range.convertFrom0to1 (newValue));
  64. if (value != newValue || listenersNeedCalling)
  65. {
  66. value = newValue;
  67. listeners.call (&AudioProcessorValueTreeState::Listener::parameterChanged, paramID, value);
  68. listenersNeedCalling = false;
  69. needsUpdate.set (1);
  70. }
  71. }
  72. void setNewState (const ValueTree& v)
  73. {
  74. state = v;
  75. updateFromValueTree();
  76. }
  77. void setUnnormalisedValue (float newUnnormalisedValue)
  78. {
  79. if (value != newUnnormalisedValue)
  80. {
  81. const float newValue = range.convertTo0to1 (newUnnormalisedValue);
  82. setValueNotifyingHost (newValue);
  83. }
  84. }
  85. void updateFromValueTree()
  86. {
  87. setUnnormalisedValue (state.getProperty (owner.valuePropertyID, defaultValue));
  88. }
  89. void copyValueToValueTree()
  90. {
  91. if (state.isValid())
  92. state.setPropertyExcludingListener (this, owner.valuePropertyID, value, owner.undoManager);
  93. }
  94. void valueTreePropertyChanged (ValueTree&, const Identifier& property) override
  95. {
  96. if (property == owner.valuePropertyID)
  97. updateFromValueTree();
  98. }
  99. void valueTreeChildAdded (ValueTree&, ValueTree&) override {}
  100. void valueTreeChildRemoved (ValueTree&, ValueTree&, int) override {}
  101. void valueTreeChildOrderChanged (ValueTree&, int, int) override {}
  102. void valueTreeParentChanged (ValueTree&) override {}
  103. static Parameter* getParameterForID (AudioProcessor& processor, StringRef paramID) noexcept
  104. {
  105. const int numParams = processor.getParameters().size();
  106. for (int i = 0; i < numParams; ++i)
  107. {
  108. AudioProcessorParameter* const ap = processor.getParameters().getUnchecked(i);
  109. // When using this class, you must allow it to manage all the parameters in your AudioProcessor, and
  110. // not add any parameter objects of other types!
  111. jassert (dynamic_cast<Parameter*> (ap) != nullptr);
  112. Parameter* const p = static_cast<Parameter*> (ap);
  113. if (paramID == p->paramID)
  114. return p;
  115. }
  116. return nullptr;
  117. }
  118. bool isMetaParameter() const override { return isMeta; }
  119. AudioProcessorValueTreeState& owner;
  120. ValueTree state;
  121. ListenerList<AudioProcessorValueTreeState::Listener> listeners;
  122. std::function<String (float)> valueToTextFunction;
  123. std::function<float (const String&)> textToValueFunction;
  124. NormalisableRange<float> range;
  125. float value, defaultValue;
  126. Atomic<int> needsUpdate;
  127. bool listenersNeedCalling;
  128. bool isMeta;
  129. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Parameter)
  130. };
  131. //==============================================================================
  132. AudioProcessorValueTreeState::AudioProcessorValueTreeState (AudioProcessor& p, UndoManager* um)
  133. : processor (p),
  134. undoManager (um),
  135. valueType ("PARAM"),
  136. valuePropertyID ("value"),
  137. idPropertyID ("id"),
  138. updatingConnections (false)
  139. {
  140. startTimerHz (10);
  141. state.addListener (this);
  142. }
  143. AudioProcessorValueTreeState::~AudioProcessorValueTreeState() {}
  144. AudioProcessorParameterWithID* AudioProcessorValueTreeState::createAndAddParameter (const String& paramID, const String& paramName,
  145. const String& labelText, NormalisableRange<float> r,
  146. float defaultVal, std::function<String (float)> valueToTextFunction,
  147. std::function<float (const String&)> textToValueFunction,
  148. bool isMetaParameter)
  149. {
  150. // All parameters must be created before giving this manager a ValueTree state!
  151. jassert (! state.isValid());
  152. #if ! JUCE_LINUX
  153. jassert (MessageManager::getInstance()->isThisTheMessageThread());
  154. #endif
  155. Parameter* p = new Parameter (*this, paramID, paramName, labelText, r,
  156. defaultVal, valueToTextFunction, textToValueFunction,
  157. isMetaParameter);
  158. processor.addParameter (p);
  159. return p;
  160. }
  161. void AudioProcessorValueTreeState::addParameterListener (StringRef paramID, Listener* listener)
  162. {
  163. if (Parameter* p = Parameter::getParameterForID (processor, paramID))
  164. p->listeners.add (listener);
  165. }
  166. void AudioProcessorValueTreeState::removeParameterListener (StringRef paramID, Listener* listener)
  167. {
  168. if (Parameter* p = Parameter::getParameterForID (processor, paramID))
  169. p->listeners.remove (listener);
  170. }
  171. Value AudioProcessorValueTreeState::getParameterAsValue (StringRef paramID) const
  172. {
  173. if (Parameter* p = Parameter::getParameterForID (processor, paramID))
  174. return p->state.getPropertyAsValue (valuePropertyID, undoManager);
  175. return Value();
  176. }
  177. NormalisableRange<float> AudioProcessorValueTreeState::getParameterRange (StringRef paramID) const noexcept
  178. {
  179. if (Parameter* p = Parameter::getParameterForID (processor, paramID))
  180. return p->range;
  181. return NormalisableRange<float>();
  182. }
  183. AudioProcessorParameterWithID* AudioProcessorValueTreeState::getParameter (StringRef paramID) const noexcept
  184. {
  185. return Parameter::getParameterForID (processor, paramID);
  186. }
  187. float* AudioProcessorValueTreeState::getRawParameterValue (StringRef paramID) const noexcept
  188. {
  189. if (Parameter* p = Parameter::getParameterForID (processor, paramID))
  190. return &(p->value);
  191. return nullptr;
  192. }
  193. ValueTree AudioProcessorValueTreeState::getOrCreateChildValueTree (const String& paramID)
  194. {
  195. ValueTree v (state.getChildWithProperty (idPropertyID, paramID));
  196. if (! v.isValid())
  197. {
  198. v = ValueTree (valueType);
  199. v.setProperty (idPropertyID, paramID, undoManager);
  200. state.addChild (v, -1, undoManager);
  201. }
  202. return v;
  203. }
  204. void AudioProcessorValueTreeState::updateParameterConnectionsToChildTrees()
  205. {
  206. if (! updatingConnections)
  207. {
  208. ScopedValueSetter<bool> svs (updatingConnections, true, false);
  209. const int numParams = processor.getParameters().size();
  210. for (int i = 0; i < numParams; ++i)
  211. {
  212. AudioProcessorParameter* const ap = processor.getParameters().getUnchecked(i);
  213. jassert (dynamic_cast<Parameter*> (ap) != nullptr);
  214. Parameter* p = static_cast<Parameter*> (ap);
  215. p->setNewState (getOrCreateChildValueTree (p->paramID));
  216. }
  217. }
  218. }
  219. void AudioProcessorValueTreeState::valueTreePropertyChanged (ValueTree& tree, const Identifier& property)
  220. {
  221. if (property == idPropertyID && tree.hasType (valueType) && tree.getParent() == state)
  222. updateParameterConnectionsToChildTrees();
  223. }
  224. void AudioProcessorValueTreeState::valueTreeChildAdded (ValueTree& parent, ValueTree& tree)
  225. {
  226. if (parent == state && tree.hasType (valueType))
  227. updateParameterConnectionsToChildTrees();
  228. }
  229. void AudioProcessorValueTreeState::valueTreeChildRemoved (ValueTree& parent, ValueTree& tree, int)
  230. {
  231. if (parent == state && tree.hasType (valueType))
  232. updateParameterConnectionsToChildTrees();
  233. }
  234. void AudioProcessorValueTreeState::valueTreeRedirected (ValueTree& v)
  235. {
  236. if (v == state)
  237. updateParameterConnectionsToChildTrees();
  238. }
  239. void AudioProcessorValueTreeState::valueTreeChildOrderChanged (ValueTree&, int, int) {}
  240. void AudioProcessorValueTreeState::valueTreeParentChanged (ValueTree&) {}
  241. void AudioProcessorValueTreeState::timerCallback()
  242. {
  243. const int numParams = processor.getParameters().size();
  244. bool anythingUpdated = false;
  245. for (int i = 0; i < numParams; ++i)
  246. {
  247. AudioProcessorParameter* const ap = processor.getParameters().getUnchecked(i);
  248. jassert (dynamic_cast<Parameter*> (ap) != nullptr);
  249. Parameter* p = static_cast<Parameter*> (ap);
  250. if (p->needsUpdate.compareAndSetBool (0, 1))
  251. {
  252. p->copyValueToValueTree();
  253. anythingUpdated = true;
  254. }
  255. }
  256. startTimer (anythingUpdated ? 1000 / 50
  257. : jlimit (50, 500, getTimerInterval() + 20));
  258. }
  259. AudioProcessorValueTreeState::Listener::Listener() {}
  260. AudioProcessorValueTreeState::Listener::~Listener() {}
  261. //==============================================================================
  262. struct AttachedControlBase : public AudioProcessorValueTreeState::Listener,
  263. public AsyncUpdater
  264. {
  265. AttachedControlBase (AudioProcessorValueTreeState& s, const String& p)
  266. : state (s), paramID (p), lastValue (0)
  267. {
  268. state.addParameterListener (paramID, this);
  269. }
  270. void removeListener()
  271. {
  272. state.removeParameterListener (paramID, this);
  273. }
  274. void setNewUnnormalisedValue (float newUnnormalisedValue)
  275. {
  276. if (AudioProcessorParameter* p = state.getParameter (paramID))
  277. {
  278. const float newValue = state.getParameterRange (paramID)
  279. .convertTo0to1 (newUnnormalisedValue);
  280. if (p->getValue() != newValue)
  281. p->setValueNotifyingHost (newValue);
  282. }
  283. }
  284. void sendInitialUpdate()
  285. {
  286. if (float* v = state.getRawParameterValue (paramID))
  287. parameterChanged (paramID, *v);
  288. }
  289. void parameterChanged (const String&, float newValue) override
  290. {
  291. lastValue = newValue;
  292. if (MessageManager::getInstance()->isThisTheMessageThread())
  293. {
  294. cancelPendingUpdate();
  295. setValue (newValue);
  296. }
  297. else
  298. {
  299. triggerAsyncUpdate();
  300. }
  301. }
  302. void beginParameterChange()
  303. {
  304. if (AudioProcessorParameter* p = state.getParameter (paramID))
  305. p->beginChangeGesture();
  306. }
  307. void endParameterChange()
  308. {
  309. if (AudioProcessorParameter* p = state.getParameter (paramID))
  310. p->endChangeGesture();
  311. }
  312. void handleAsyncUpdate() override
  313. {
  314. setValue (lastValue);
  315. }
  316. virtual void setValue (float) = 0;
  317. AudioProcessorValueTreeState& state;
  318. String paramID;
  319. float lastValue;
  320. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AttachedControlBase)
  321. };
  322. //==============================================================================
  323. struct AudioProcessorValueTreeState::SliderAttachment::Pimpl : private AttachedControlBase,
  324. private Slider::Listener
  325. {
  326. Pimpl (AudioProcessorValueTreeState& s, const String& p, Slider& sl)
  327. : AttachedControlBase (s, p), slider (sl), ignoreCallbacks (false)
  328. {
  329. NormalisableRange<float> range (s.getParameterRange (paramID));
  330. slider.setRange (range.start, range.end, range.interval);
  331. slider.setSkewFactor (range.skew, range.symmetricSkew);
  332. if (AudioProcessorParameter* param = state.getParameter (paramID))
  333. slider.setDoubleClickReturnValue (true, range.convertFrom0to1 (param->getDefaultValue()));
  334. sendInitialUpdate();
  335. slider.addListener (this);
  336. }
  337. ~Pimpl()
  338. {
  339. slider.removeListener (this);
  340. removeListener();
  341. }
  342. void setValue (float newValue) override
  343. {
  344. const ScopedLock selfCallbackLock (selfCallbackMutex);
  345. {
  346. ScopedValueSetter<bool> svs (ignoreCallbacks, true);
  347. slider.setValue (newValue, sendNotificationSync);
  348. }
  349. }
  350. void sliderValueChanged (Slider* s) override
  351. {
  352. const ScopedLock selfCallbackLock (selfCallbackMutex);
  353. if ((! ignoreCallbacks) && (! ModifierKeys::getCurrentModifiers().isRightButtonDown()))
  354. setNewUnnormalisedValue ((float) s->getValue());
  355. }
  356. void sliderDragStarted (Slider*) override { beginParameterChange(); }
  357. void sliderDragEnded (Slider*) override { endParameterChange(); }
  358. Slider& slider;
  359. bool ignoreCallbacks;
  360. CriticalSection selfCallbackMutex;
  361. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Pimpl)
  362. };
  363. AudioProcessorValueTreeState::SliderAttachment::SliderAttachment (AudioProcessorValueTreeState& s, const String& p, Slider& sl)
  364. : pimpl (new Pimpl (s, p, sl))
  365. {
  366. }
  367. AudioProcessorValueTreeState::SliderAttachment::~SliderAttachment() {}
  368. //==============================================================================
  369. struct AudioProcessorValueTreeState::ComboBoxAttachment::Pimpl : private AttachedControlBase,
  370. private ComboBox::Listener
  371. {
  372. Pimpl (AudioProcessorValueTreeState& s, const String& p, ComboBox& c)
  373. : AttachedControlBase (s, p), combo (c), ignoreCallbacks (false)
  374. {
  375. sendInitialUpdate();
  376. combo.addListener (this);
  377. }
  378. ~Pimpl()
  379. {
  380. combo.removeListener (this);
  381. removeListener();
  382. }
  383. void setValue (float newValue) override
  384. {
  385. const ScopedLock selfCallbackLock (selfCallbackMutex);
  386. {
  387. ScopedValueSetter<bool> svs (ignoreCallbacks, true);
  388. combo.setSelectedItemIndex (roundToInt (newValue), sendNotificationSync);
  389. }
  390. }
  391. void comboBoxChanged (ComboBox* comboBox) override
  392. {
  393. const ScopedLock selfCallbackLock (selfCallbackMutex);
  394. if (! ignoreCallbacks)
  395. {
  396. beginParameterChange();
  397. setNewUnnormalisedValue ((float) comboBox->getSelectedId() - 1.0f);
  398. endParameterChange();
  399. }
  400. }
  401. ComboBox& combo;
  402. bool ignoreCallbacks;
  403. CriticalSection selfCallbackMutex;
  404. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Pimpl)
  405. };
  406. AudioProcessorValueTreeState::ComboBoxAttachment::ComboBoxAttachment (AudioProcessorValueTreeState& s, const String& p, ComboBox& c)
  407. : pimpl (new Pimpl (s, p, c))
  408. {
  409. }
  410. AudioProcessorValueTreeState::ComboBoxAttachment::~ComboBoxAttachment() {}
  411. //==============================================================================
  412. struct AudioProcessorValueTreeState::ButtonAttachment::Pimpl : private AttachedControlBase,
  413. private Button::Listener
  414. {
  415. Pimpl (AudioProcessorValueTreeState& s, const String& p, Button& b)
  416. : AttachedControlBase (s, p), button (b), ignoreCallbacks (false)
  417. {
  418. sendInitialUpdate();
  419. button.addListener (this);
  420. }
  421. ~Pimpl()
  422. {
  423. button.removeListener (this);
  424. removeListener();
  425. }
  426. void setValue (float newValue) override
  427. {
  428. const ScopedLock selfCallbackLock (selfCallbackMutex);
  429. {
  430. ScopedValueSetter<bool> svs (ignoreCallbacks, true);
  431. button.setToggleState (newValue >= 0.5f, sendNotificationSync);
  432. }
  433. }
  434. void buttonClicked (Button* b) override
  435. {
  436. const ScopedLock selfCallbackLock (selfCallbackMutex);
  437. if (! ignoreCallbacks)
  438. {
  439. beginParameterChange();
  440. setNewUnnormalisedValue (b->getToggleState() ? 1.0f : 0.0f);
  441. endParameterChange();
  442. }
  443. }
  444. Button& button;
  445. bool ignoreCallbacks;
  446. CriticalSection selfCallbackMutex;
  447. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Pimpl)
  448. };
  449. AudioProcessorValueTreeState::ButtonAttachment::ButtonAttachment (AudioProcessorValueTreeState& s, const String& p, Button& b)
  450. : pimpl (new Pimpl (s, p, b))
  451. {
  452. }
  453. AudioProcessorValueTreeState::ButtonAttachment::~ButtonAttachment() {}