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.

557 lines
18KB

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