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.

520 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 handleAsyncUpdate() override
  299. {
  300. setValue (lastValue);
  301. }
  302. virtual void setValue (float) = 0;
  303. AudioProcessorValueTreeState& state;
  304. String paramID;
  305. float lastValue;
  306. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AttachedControlBase)
  307. };
  308. //==============================================================================
  309. struct AudioProcessorValueTreeState::SliderAttachment::Pimpl : private AttachedControlBase,
  310. private Slider::Listener
  311. {
  312. Pimpl (AudioProcessorValueTreeState& s, const String& p, Slider& sl)
  313. : AttachedControlBase (s, p), slider (sl)
  314. {
  315. NormalisableRange<float> range (s.getParameterRange (paramID));
  316. slider.setRange (range.start, range.end, range.interval);
  317. if (AudioProcessorParameter* param = state.getParameter (paramID))
  318. slider.setDoubleClickReturnValue (true, range.convertFrom0to1 (param->getDefaultValue()));
  319. sendInitialUpdate();
  320. slider.addListener (this);
  321. }
  322. ~Pimpl()
  323. {
  324. slider.removeListener (this);
  325. removeListener();
  326. }
  327. void setValue (float newValue) override
  328. {
  329. slider.setValue (newValue, sendNotificationSync);
  330. }
  331. void sliderValueChanged (Slider* s) override
  332. {
  333. if (! ModifierKeys::getCurrentModifiers().isRightButtonDown())
  334. setNewUnnormalisedValue ((float) s->getValue());
  335. }
  336. void sliderDragStarted (Slider*) override
  337. {
  338. if (AudioProcessorParameter* p = state.getParameter (paramID))
  339. p->beginChangeGesture();
  340. }
  341. void sliderDragEnded (Slider*) override
  342. {
  343. if (AudioProcessorParameter* p = state.getParameter (paramID))
  344. p->endChangeGesture();
  345. }
  346. Slider& slider;
  347. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Pimpl)
  348. };
  349. AudioProcessorValueTreeState::SliderAttachment::SliderAttachment (AudioProcessorValueTreeState& s, const String& p, Slider& sl)
  350. : pimpl (new Pimpl (s, p, sl))
  351. {
  352. }
  353. AudioProcessorValueTreeState::SliderAttachment::~SliderAttachment() {}
  354. //==============================================================================
  355. struct AudioProcessorValueTreeState::ComboBoxAttachment::Pimpl : private AttachedControlBase,
  356. private ComboBox::Listener
  357. {
  358. Pimpl (AudioProcessorValueTreeState& s, const String& p, ComboBox& c)
  359. : AttachedControlBase (s, p), combo (c)
  360. {
  361. sendInitialUpdate();
  362. combo.addListener (this);
  363. }
  364. ~Pimpl()
  365. {
  366. combo.removeListener (this);
  367. removeListener();
  368. }
  369. void setValue (float newValue) override
  370. {
  371. combo.setSelectedItemIndex (roundToInt (newValue), sendNotificationSync);
  372. }
  373. void comboBoxChanged (ComboBox* comboBox) override
  374. {
  375. setNewUnnormalisedValue ((float) comboBox->getSelectedId() - 1.0f);
  376. }
  377. ComboBox& combo;
  378. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Pimpl)
  379. };
  380. AudioProcessorValueTreeState::ComboBoxAttachment::ComboBoxAttachment (AudioProcessorValueTreeState& s, const String& p, ComboBox& c)
  381. : pimpl (new Pimpl (s, p, c))
  382. {
  383. }
  384. AudioProcessorValueTreeState::ComboBoxAttachment::~ComboBoxAttachment() {}
  385. //==============================================================================
  386. struct AudioProcessorValueTreeState::ButtonAttachment::Pimpl : private AttachedControlBase,
  387. private Button::Listener
  388. {
  389. Pimpl (AudioProcessorValueTreeState& s, const String& p, Button& b)
  390. : AttachedControlBase (s, p), button (b)
  391. {
  392. sendInitialUpdate();
  393. button.addListener (this);
  394. }
  395. ~Pimpl()
  396. {
  397. button.removeListener (this);
  398. removeListener();
  399. }
  400. void setValue (float newValue) override
  401. {
  402. button.setToggleState (newValue >= 0.5f, sendNotificationSync);
  403. }
  404. void buttonClicked (Button* b) override
  405. {
  406. setNewUnnormalisedValue (b->getToggleState() ? 1.0f : 0.0f);
  407. }
  408. Button& button;
  409. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Pimpl)
  410. };
  411. AudioProcessorValueTreeState::ButtonAttachment::ButtonAttachment (AudioProcessorValueTreeState& s, const String& p, Button& b)
  412. : pimpl (new Pimpl (s, p, b))
  413. {
  414. }
  415. AudioProcessorValueTreeState::ButtonAttachment::~ButtonAttachment() {}
  416. #endif