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.

528 lines
17KB

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