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.

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