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.

561 lines
19KB

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