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.

692 lines
25KB

  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. struct AudioProcessorValueTreeState::Parameter : public AudioProcessorParameterWithID,
  22. private ValueTree::Listener
  23. {
  24. Parameter (AudioProcessorValueTreeState& s,
  25. const String& parameterID, const String& paramName, const String& labelText,
  26. NormalisableRange<float> r, float defaultVal,
  27. std::function<String (float)> valueToText,
  28. std::function<float (const String&)> textToValue,
  29. bool meta,
  30. bool automatable,
  31. bool discrete,
  32. AudioProcessorParameter::Category paramCategory,
  33. bool boolean)
  34. : AudioProcessorParameterWithID (parameterID, paramName, labelText, paramCategory),
  35. owner (s), valueToTextFunction (valueToText), textToValueFunction (textToValue),
  36. range (r), value (defaultVal), defaultValue (defaultVal),
  37. listenersNeedCalling (true),
  38. isMetaParam (meta),
  39. isAutomatableParam (automatable),
  40. isDiscreteParam (discrete),
  41. isBooleanParam (boolean)
  42. {
  43. value = defaultValue;
  44. state.addListener (this);
  45. }
  46. ~Parameter()
  47. {
  48. // should have detached all callbacks before destroying the parameters!
  49. jassert (listeners.size() <= 1);
  50. }
  51. float getValue() const override { return range.convertTo0to1 (value); }
  52. float getDefaultValue() const override { return range.convertTo0to1 (defaultValue); }
  53. float getValueForText (const String& text) const override
  54. {
  55. return range.convertTo0to1 (textToValueFunction != nullptr ? textToValueFunction (text)
  56. : text.getFloatValue());
  57. }
  58. String getText (float normalisedValue, int /*length*/) const override
  59. {
  60. auto v = range.convertFrom0to1 (normalisedValue);
  61. return valueToTextFunction != nullptr ? valueToTextFunction (v)
  62. : String (v, 2);
  63. }
  64. int getNumSteps() const override
  65. {
  66. if (range.interval > 0)
  67. return (static_cast<int> ((range.end - range.start) / range.interval) + 1);
  68. return AudioProcessor::getDefaultNumParameterSteps();
  69. }
  70. void setValue (float newValue) override
  71. {
  72. newValue = range.snapToLegalValue (range.convertFrom0to1 (newValue));
  73. if (value != newValue || listenersNeedCalling)
  74. {
  75. value = newValue;
  76. listeners.call ([=] (AudioProcessorValueTreeState::Listener& l) { l.parameterChanged (paramID, value); });
  77. listenersNeedCalling = false;
  78. needsUpdate = true;
  79. }
  80. }
  81. void setNewState (const ValueTree& v)
  82. {
  83. state = v;
  84. updateFromValueTree();
  85. }
  86. void setUnnormalisedValue (float newUnnormalisedValue)
  87. {
  88. if (value != newUnnormalisedValue)
  89. {
  90. const float newValue = range.convertTo0to1 (newUnnormalisedValue);
  91. setValueNotifyingHost (newValue);
  92. }
  93. }
  94. void updateFromValueTree()
  95. {
  96. setUnnormalisedValue (state.getProperty (owner.valuePropertyID, defaultValue));
  97. }
  98. void copyValueToValueTree()
  99. {
  100. if (auto* valueProperty = state.getPropertyPointer (owner.valuePropertyID))
  101. {
  102. if ((float) *valueProperty != value)
  103. {
  104. ScopedValueSetter<bool> svs (ignoreParameterChangedCallbacks, true);
  105. state.setProperty (owner.valuePropertyID, value, owner.undoManager);
  106. }
  107. }
  108. else
  109. {
  110. state.setProperty (owner.valuePropertyID, value, nullptr);
  111. }
  112. }
  113. void valueTreePropertyChanged (ValueTree&, const Identifier& property) override
  114. {
  115. if (ignoreParameterChangedCallbacks)
  116. return;
  117. if (property == owner.valuePropertyID)
  118. updateFromValueTree();
  119. }
  120. void valueTreeChildAdded (ValueTree&, ValueTree&) override {}
  121. void valueTreeChildRemoved (ValueTree&, ValueTree&, int) override {}
  122. void valueTreeChildOrderChanged (ValueTree&, int, int) override {}
  123. void valueTreeParentChanged (ValueTree&) override {}
  124. static Parameter* getParameterForID (AudioProcessor& processor, StringRef paramID) noexcept
  125. {
  126. for (auto* ap : processor.getParameters())
  127. {
  128. // When using this class, you must allow it to manage all the parameters in your AudioProcessor, and
  129. // not add any parameter objects of other types!
  130. jassert (dynamic_cast<Parameter*> (ap) != nullptr);
  131. auto* p = static_cast<Parameter*> (ap);
  132. if (paramID == p->paramID)
  133. return p;
  134. }
  135. return nullptr;
  136. }
  137. bool isMetaParameter() const override { return isMetaParam; }
  138. bool isAutomatable() const override { return isAutomatableParam; }
  139. bool isDiscrete() const override { return isDiscreteParam; }
  140. bool isBoolean() const override { return isBooleanParam; }
  141. AudioProcessorValueTreeState& owner;
  142. ValueTree state;
  143. ListenerList<AudioProcessorValueTreeState::Listener> listeners;
  144. std::function<String (float)> valueToTextFunction;
  145. std::function<float (const String&)> textToValueFunction;
  146. NormalisableRange<float> range;
  147. float value, defaultValue;
  148. std::atomic<bool> needsUpdate { true };
  149. bool listenersNeedCalling;
  150. const bool isMetaParam, isAutomatableParam, isDiscreteParam, isBooleanParam;
  151. bool ignoreParameterChangedCallbacks = false;
  152. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Parameter)
  153. };
  154. //==============================================================================
  155. AudioProcessorValueTreeState::AudioProcessorValueTreeState (AudioProcessor& p, UndoManager* um)
  156. : processor (p), undoManager (um)
  157. {
  158. startTimerHz (10);
  159. state.addListener (this);
  160. }
  161. AudioProcessorValueTreeState::~AudioProcessorValueTreeState() {}
  162. std::unique_ptr<AudioProcessorParameterWithID> AudioProcessorValueTreeState::createParameter (const String& paramID, const String& paramName,
  163. const String& labelText, NormalisableRange<float> r,
  164. float defaultVal, std::function<String (float)> valueToTextFunction,
  165. std::function<float (const String&)> textToValueFunction,
  166. bool isMetaParameter,
  167. bool isAutomatableParameter,
  168. bool isDiscreteParameter,
  169. AudioProcessorParameter::Category category,
  170. bool isBooleanParameter)
  171. {
  172. // All parameters must be created before giving this manager a ValueTree state!
  173. jassert (! state.isValid());
  174. return std::unique_ptr<AudioProcessorParameterWithID> (new Parameter (*this, paramID, paramName, labelText, r,
  175. defaultVal, valueToTextFunction, textToValueFunction,
  176. isMetaParameter, isAutomatableParameter,
  177. isDiscreteParameter, category, isBooleanParameter));
  178. }
  179. AudioProcessorParameterWithID* AudioProcessorValueTreeState::createAndAddParameter (const String& paramID, const String& paramName,
  180. const String& labelText, NormalisableRange<float> r,
  181. float defaultVal, std::function<String (float)> valueToTextFunction,
  182. std::function<float (const String&)> textToValueFunction,
  183. bool isMetaParameter,
  184. bool isAutomatableParameter,
  185. bool isDiscreteParameter,
  186. AudioProcessorParameter::Category category,
  187. bool isBooleanParameter)
  188. {
  189. auto* p = createParameter (paramID, paramName, labelText, r, defaultVal,
  190. valueToTextFunction, textToValueFunction,
  191. isMetaParameter, isAutomatableParameter, isDiscreteParameter,
  192. category, isBooleanParameter).release();
  193. processor.addParameter (p);
  194. return p;
  195. }
  196. void AudioProcessorValueTreeState::addParameterListener (StringRef paramID, Listener* listener)
  197. {
  198. if (auto* p = Parameter::getParameterForID (processor, paramID))
  199. p->listeners.add (listener);
  200. }
  201. void AudioProcessorValueTreeState::removeParameterListener (StringRef paramID, Listener* listener)
  202. {
  203. if (auto* p = Parameter::getParameterForID (processor, paramID))
  204. p->listeners.remove (listener);
  205. }
  206. Value AudioProcessorValueTreeState::getParameterAsValue (StringRef paramID) const
  207. {
  208. if (auto* p = Parameter::getParameterForID (processor, paramID))
  209. return p->state.getPropertyAsValue (valuePropertyID, undoManager);
  210. return {};
  211. }
  212. NormalisableRange<float> AudioProcessorValueTreeState::getParameterRange (StringRef paramID) const noexcept
  213. {
  214. if (auto* p = Parameter::getParameterForID (processor, paramID))
  215. return p->range;
  216. return NormalisableRange<float>();
  217. }
  218. AudioProcessorParameterWithID* AudioProcessorValueTreeState::getParameter (StringRef paramID) const noexcept
  219. {
  220. return Parameter::getParameterForID (processor, paramID);
  221. }
  222. float* AudioProcessorValueTreeState::getRawParameterValue (StringRef paramID) const noexcept
  223. {
  224. if (auto* p = Parameter::getParameterForID (processor, paramID))
  225. return &(p->value);
  226. return nullptr;
  227. }
  228. ValueTree AudioProcessorValueTreeState::copyState()
  229. {
  230. ScopedLock lock (valueTreeChanging);
  231. flushParameterValuesToValueTree();
  232. return state.createCopy();
  233. }
  234. void AudioProcessorValueTreeState::replaceState (const ValueTree& newState)
  235. {
  236. ScopedLock lock (valueTreeChanging);
  237. state = newState;
  238. if (undoManager != nullptr)
  239. undoManager->clearUndoHistory();
  240. }
  241. ValueTree AudioProcessorValueTreeState::getOrCreateChildValueTree (const String& paramID)
  242. {
  243. ValueTree v (state.getChildWithProperty (idPropertyID, paramID));
  244. if (! v.isValid())
  245. {
  246. v = ValueTree (valueType);
  247. v.setProperty (idPropertyID, paramID, nullptr);
  248. state.appendChild (v, nullptr);
  249. }
  250. return v;
  251. }
  252. void AudioProcessorValueTreeState::updateParameterConnectionsToChildTrees()
  253. {
  254. ScopedLock lock (valueTreeChanging);
  255. for (auto* param : processor.getParameters())
  256. {
  257. jassert (dynamic_cast<Parameter*> (param) != nullptr);
  258. auto* p = static_cast<Parameter*> (param);
  259. p->setNewState (getOrCreateChildValueTree (p->paramID));
  260. }
  261. }
  262. void AudioProcessorValueTreeState::valueTreePropertyChanged (ValueTree& tree, const Identifier& property)
  263. {
  264. if (property == idPropertyID && tree.hasType (valueType) && tree.getParent() == state)
  265. updateParameterConnectionsToChildTrees();
  266. }
  267. void AudioProcessorValueTreeState::valueTreeChildAdded (ValueTree& parent, ValueTree& tree)
  268. {
  269. if (parent == state && tree.hasType (valueType))
  270. if (auto* param = Parameter::getParameterForID (processor, tree.getProperty (idPropertyID).toString()))
  271. param->setNewState (getOrCreateChildValueTree (param->paramID));
  272. }
  273. void AudioProcessorValueTreeState::valueTreeChildRemoved (ValueTree& parent, ValueTree& tree, int)
  274. {
  275. if (parent == state && tree.hasType (valueType))
  276. if (auto* param = Parameter::getParameterForID (processor, tree.getProperty (idPropertyID).toString()))
  277. param->setNewState (getOrCreateChildValueTree (param->paramID));
  278. }
  279. void AudioProcessorValueTreeState::valueTreeRedirected (ValueTree& v)
  280. {
  281. if (v == state)
  282. updateParameterConnectionsToChildTrees();
  283. }
  284. void AudioProcessorValueTreeState::valueTreeChildOrderChanged (ValueTree&, int, int) {}
  285. void AudioProcessorValueTreeState::valueTreeParentChanged (ValueTree&) {}
  286. bool AudioProcessorValueTreeState::flushParameterValuesToValueTree()
  287. {
  288. ScopedLock lock (valueTreeChanging);
  289. bool anythingUpdated = false;
  290. for (auto* ap : processor.getParameters())
  291. {
  292. jassert (dynamic_cast<Parameter*> (ap) != nullptr);
  293. auto* p = static_cast<Parameter*> (ap);
  294. bool needsUpdateTestValue = true;
  295. if (p->needsUpdate.compare_exchange_strong (needsUpdateTestValue, false))
  296. {
  297. p->copyValueToValueTree();
  298. anythingUpdated = true;
  299. }
  300. }
  301. return anythingUpdated;
  302. }
  303. void AudioProcessorValueTreeState::timerCallback()
  304. {
  305. auto anythingUpdated = flushParameterValuesToValueTree();
  306. startTimer (anythingUpdated ? 1000 / 50
  307. : jlimit (50, 500, getTimerInterval() + 20));
  308. }
  309. AudioProcessorValueTreeState::Listener::Listener() {}
  310. AudioProcessorValueTreeState::Listener::~Listener() {}
  311. //==============================================================================
  312. struct AttachedControlBase : public AudioProcessorValueTreeState::Listener,
  313. public AsyncUpdater
  314. {
  315. AttachedControlBase (AudioProcessorValueTreeState& s, const String& p)
  316. : state (s), paramID (p), lastValue (0)
  317. {
  318. state.addParameterListener (paramID, this);
  319. }
  320. void removeListener()
  321. {
  322. state.removeParameterListener (paramID, this);
  323. }
  324. void setNewUnnormalisedValue (float newUnnormalisedValue)
  325. {
  326. if (auto* p = state.getParameter (paramID))
  327. {
  328. const float newValue = state.getParameterRange (paramID)
  329. .convertTo0to1 (newUnnormalisedValue);
  330. if (p->getValue() != newValue)
  331. p->setValueNotifyingHost (newValue);
  332. }
  333. }
  334. void sendInitialUpdate()
  335. {
  336. if (auto* v = state.getRawParameterValue (paramID))
  337. parameterChanged (paramID, *v);
  338. }
  339. void parameterChanged (const String&, float newValue) override
  340. {
  341. lastValue = newValue;
  342. if (MessageManager::getInstance()->isThisTheMessageThread())
  343. {
  344. cancelPendingUpdate();
  345. setValue (newValue);
  346. }
  347. else
  348. {
  349. triggerAsyncUpdate();
  350. }
  351. }
  352. void beginParameterChange()
  353. {
  354. if (auto* p = state.getParameter (paramID))
  355. {
  356. if (state.undoManager != nullptr)
  357. state.undoManager->beginNewTransaction();
  358. p->beginChangeGesture();
  359. }
  360. }
  361. void endParameterChange()
  362. {
  363. if (AudioProcessorParameter* p = state.getParameter (paramID))
  364. p->endChangeGesture();
  365. }
  366. void handleAsyncUpdate() override
  367. {
  368. setValue (lastValue);
  369. }
  370. virtual void setValue (float) = 0;
  371. AudioProcessorValueTreeState& state;
  372. String paramID;
  373. float lastValue;
  374. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AttachedControlBase)
  375. };
  376. //==============================================================================
  377. struct AudioProcessorValueTreeState::SliderAttachment::Pimpl : private AttachedControlBase,
  378. private Slider::Listener
  379. {
  380. Pimpl (AudioProcessorValueTreeState& s, const String& p, Slider& sl)
  381. : AttachedControlBase (s, p), slider (sl), ignoreCallbacks (false)
  382. {
  383. NormalisableRange<float> range (state.getParameterRange (paramID));
  384. if (range.interval != 0.0f || range.skew != 1.0f)
  385. {
  386. slider.setRange (range.start, range.end, range.interval);
  387. slider.setSkewFactor (range.skew, range.symmetricSkew);
  388. }
  389. else
  390. {
  391. auto convertFrom0To1Function = [range] (double currentRangeStart,
  392. double currentRangeEnd,
  393. double normalisedValue) mutable
  394. {
  395. range.start = (float) currentRangeStart;
  396. range.end = (float) currentRangeEnd;
  397. return (double) range.convertFrom0to1 ((float) normalisedValue);
  398. };
  399. auto convertTo0To1Function = [range] (double currentRangeStart,
  400. double currentRangeEnd,
  401. double mappedValue) mutable
  402. {
  403. range.start = (float) currentRangeStart;
  404. range.end = (float) currentRangeEnd;
  405. return (double) range.convertTo0to1 ((float) mappedValue);
  406. };
  407. auto snapToLegalValueFunction = [range] (double currentRangeStart,
  408. double currentRangeEnd,
  409. double valueToSnap) mutable
  410. {
  411. range.start = (float) currentRangeStart;
  412. range.end = (float) currentRangeEnd;
  413. return (double) range.snapToLegalValue ((float) valueToSnap);
  414. };
  415. slider.setNormalisableRange ({ (double) range.start, (double) range.end,
  416. convertFrom0To1Function,
  417. convertTo0To1Function,
  418. snapToLegalValueFunction });
  419. }
  420. if (auto* param = dynamic_cast<AudioProcessorValueTreeState::Parameter*> (state.getParameter (paramID)))
  421. {
  422. if (param->textToValueFunction != nullptr)
  423. slider.valueFromTextFunction = [param] (const String& text) { return (double) param->textToValueFunction (text); };
  424. if (param->valueToTextFunction != nullptr)
  425. slider.textFromValueFunction = [param] (double value) { return param->valueToTextFunction ((float) value); };
  426. slider.setDoubleClickReturnValue (true, range.convertFrom0to1 (param->getDefaultValue()));
  427. }
  428. sendInitialUpdate();
  429. slider.addListener (this);
  430. }
  431. ~Pimpl()
  432. {
  433. slider.removeListener (this);
  434. removeListener();
  435. }
  436. void setValue (float newValue) override
  437. {
  438. const ScopedLock selfCallbackLock (selfCallbackMutex);
  439. {
  440. ScopedValueSetter<bool> svs (ignoreCallbacks, true);
  441. slider.setValue (newValue, sendNotificationSync);
  442. }
  443. }
  444. void sliderValueChanged (Slider* s) override
  445. {
  446. const ScopedLock selfCallbackLock (selfCallbackMutex);
  447. if ((! ignoreCallbacks) && (! ModifierKeys::currentModifiers.isRightButtonDown()))
  448. setNewUnnormalisedValue ((float) s->getValue());
  449. }
  450. void sliderDragStarted (Slider*) override { beginParameterChange(); }
  451. void sliderDragEnded (Slider*) override { endParameterChange(); }
  452. Slider& slider;
  453. bool ignoreCallbacks;
  454. CriticalSection selfCallbackMutex;
  455. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Pimpl)
  456. };
  457. AudioProcessorValueTreeState::SliderAttachment::SliderAttachment (AudioProcessorValueTreeState& s, const String& p, Slider& sl)
  458. : pimpl (new Pimpl (s, p, sl))
  459. {
  460. }
  461. AudioProcessorValueTreeState::SliderAttachment::~SliderAttachment() {}
  462. //==============================================================================
  463. struct AudioProcessorValueTreeState::ComboBoxAttachment::Pimpl : private AttachedControlBase,
  464. private ComboBox::Listener
  465. {
  466. Pimpl (AudioProcessorValueTreeState& s, const String& p, ComboBox& c)
  467. : AttachedControlBase (s, p), combo (c), ignoreCallbacks (false)
  468. {
  469. sendInitialUpdate();
  470. combo.addListener (this);
  471. }
  472. ~Pimpl()
  473. {
  474. combo.removeListener (this);
  475. removeListener();
  476. }
  477. void setValue (float newValue) override
  478. {
  479. const ScopedLock selfCallbackLock (selfCallbackMutex);
  480. if (state.getParameter (paramID) != nullptr)
  481. {
  482. auto normValue = state.getParameterRange (paramID)
  483. .convertTo0to1 (newValue);
  484. auto index = roundToInt (normValue * (combo.getNumItems() - 1));
  485. if (index != combo.getSelectedItemIndex())
  486. {
  487. ScopedValueSetter<bool> svs (ignoreCallbacks, true);
  488. combo.setSelectedItemIndex (index, sendNotificationSync);
  489. }
  490. }
  491. }
  492. void comboBoxChanged (ComboBox*) override
  493. {
  494. const ScopedLock selfCallbackLock (selfCallbackMutex);
  495. if (! ignoreCallbacks)
  496. {
  497. if (auto* p = state.getParameter (paramID))
  498. {
  499. auto newValue = (float) combo.getSelectedItemIndex() / (combo.getNumItems() - 1);
  500. if (p->getValue() != newValue)
  501. {
  502. beginParameterChange();
  503. p->setValueNotifyingHost (newValue);
  504. endParameterChange();
  505. }
  506. }
  507. }
  508. }
  509. ComboBox& combo;
  510. bool ignoreCallbacks;
  511. CriticalSection selfCallbackMutex;
  512. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Pimpl)
  513. };
  514. AudioProcessorValueTreeState::ComboBoxAttachment::ComboBoxAttachment (AudioProcessorValueTreeState& s, const String& p, ComboBox& c)
  515. : pimpl (new Pimpl (s, p, c))
  516. {
  517. }
  518. AudioProcessorValueTreeState::ComboBoxAttachment::~ComboBoxAttachment() {}
  519. //==============================================================================
  520. struct AudioProcessorValueTreeState::ButtonAttachment::Pimpl : private AttachedControlBase,
  521. private Button::Listener
  522. {
  523. Pimpl (AudioProcessorValueTreeState& s, const String& p, Button& b)
  524. : AttachedControlBase (s, p), button (b), ignoreCallbacks (false)
  525. {
  526. sendInitialUpdate();
  527. button.addListener (this);
  528. }
  529. ~Pimpl()
  530. {
  531. button.removeListener (this);
  532. removeListener();
  533. }
  534. void setValue (float newValue) override
  535. {
  536. const ScopedLock selfCallbackLock (selfCallbackMutex);
  537. {
  538. ScopedValueSetter<bool> svs (ignoreCallbacks, true);
  539. button.setToggleState (newValue >= 0.5f, sendNotificationSync);
  540. }
  541. }
  542. void buttonClicked (Button* b) override
  543. {
  544. const ScopedLock selfCallbackLock (selfCallbackMutex);
  545. if (! ignoreCallbacks)
  546. {
  547. beginParameterChange();
  548. setNewUnnormalisedValue (b->getToggleState() ? 1.0f : 0.0f);
  549. endParameterChange();
  550. }
  551. }
  552. Button& button;
  553. bool ignoreCallbacks;
  554. CriticalSection selfCallbackMutex;
  555. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Pimpl)
  556. };
  557. AudioProcessorValueTreeState::ButtonAttachment::ButtonAttachment (AudioProcessorValueTreeState& s, const String& p, Button& b)
  558. : pimpl (new Pimpl (s, p, b))
  559. {
  560. }
  561. AudioProcessorValueTreeState::ButtonAttachment::~ButtonAttachment() {}
  562. } // namespace juce