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.

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