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.

1199 lines
45KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2017 - ROLI Ltd.
  5. JUCE is an open source library subject to commercial or open-source
  6. licensing.
  7. By using JUCE, you agree to the terms of both the JUCE 5 End-User License
  8. Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
  9. 27th April 2017).
  10. End User License Agreement: www.juce.com/juce-5-licence
  11. Privacy Policy: www.juce.com/juce-5-privacy-policy
  12. Or: You may also use this code under the terms of the GPL v3 (see
  13. www.gnu.org/licenses).
  14. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  15. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  16. DISCLAIMED.
  17. ==============================================================================
  18. */
  19. namespace juce
  20. {
  21. //==============================================================================
  22. AudioProcessorValueTreeState::Parameter::Parameter (const String& parameterID,
  23. const String& parameterName,
  24. const String& labelText,
  25. NormalisableRange<float> valueRange,
  26. float defaultParameterValue,
  27. std::function<String(float)> valueToTextFunction,
  28. std::function<float(const String&)> textToValueFunction,
  29. bool isMetaParameter,
  30. bool isAutomatableParameter,
  31. bool isDiscrete,
  32. AudioProcessorParameter::Category parameterCategory,
  33. bool isBoolean)
  34. : AudioParameterFloat (parameterID,
  35. parameterName,
  36. valueRange,
  37. defaultParameterValue,
  38. labelText,
  39. parameterCategory,
  40. valueToTextFunction == nullptr ? std::function<String(float v, int)>()
  41. : [valueToTextFunction](float v, int) { return valueToTextFunction (v); },
  42. std::move (textToValueFunction)),
  43. unsnappedDefault (valueRange.convertTo0to1 (defaultParameterValue)),
  44. metaParameter (isMetaParameter),
  45. automatable (isAutomatableParameter),
  46. discrete (isDiscrete),
  47. boolean (isBoolean)
  48. {
  49. }
  50. float AudioProcessorValueTreeState::Parameter::getDefaultValue() const { return unsnappedDefault; }
  51. int AudioProcessorValueTreeState::Parameter::getNumSteps() const { return RangedAudioParameter::getNumSteps(); }
  52. bool AudioProcessorValueTreeState::Parameter::isMetaParameter() const { return metaParameter; }
  53. bool AudioProcessorValueTreeState::Parameter::isAutomatable() const { return automatable; }
  54. bool AudioProcessorValueTreeState::Parameter::isDiscrete() const { return discrete; }
  55. bool AudioProcessorValueTreeState::Parameter::isBoolean() const { return boolean; }
  56. void AudioProcessorValueTreeState::Parameter::valueChanged (float newValue)
  57. {
  58. if (lastValue == newValue)
  59. return;
  60. lastValue = newValue;
  61. if (onValueChanged != nullptr)
  62. onValueChanged();
  63. }
  64. //==============================================================================
  65. class AudioProcessorValueTreeState::ParameterAdapter : private AudioProcessorParameter::Listener
  66. {
  67. private:
  68. using Listener = AudioProcessorValueTreeState::Listener;
  69. public:
  70. explicit ParameterAdapter (RangedAudioParameter& parameterIn)
  71. : parameter (parameterIn),
  72. // For legacy reasons, the unnormalised value should *not* be snapped on construction
  73. unnormalisedValue (getRange().convertFrom0to1 (parameter.getDefaultValue()))
  74. {
  75. parameter.addListener (this);
  76. if (auto* ptr = dynamic_cast<Parameter*> (&parameter))
  77. ptr->onValueChanged = [this] { parameterValueChanged ({}, {}); };
  78. }
  79. ~ParameterAdapter() override { parameter.removeListener (this); }
  80. void addListener (Listener* l) { listeners.add (l); }
  81. void removeListener (Listener* l) { listeners.remove (l); }
  82. RangedAudioParameter& getParameter() { return parameter; }
  83. const RangedAudioParameter& getParameter() const { return parameter; }
  84. const NormalisableRange<float>& getRange() const { return parameter.getNormalisableRange(); }
  85. float getDenormalisedDefaultValue() const { return denormalise (parameter.getDefaultValue()); }
  86. void setDenormalisedValue (float value)
  87. {
  88. if (value == unnormalisedValue)
  89. return;
  90. setNormalisedValue (normalise (value));
  91. }
  92. float getDenormalisedValueForText (const String& text) const
  93. {
  94. return denormalise (parameter.getValueForText (text));
  95. }
  96. String getTextForDenormalisedValue (float value) const
  97. {
  98. return parameter.getText (normalise (value), 0);
  99. }
  100. float getDenormalisedValue() const { return unnormalisedValue; }
  101. float& getRawDenormalisedValue() { return unnormalisedValue; }
  102. bool flushToTree (const Identifier& key, UndoManager* um)
  103. {
  104. auto needsUpdateTestValue = true;
  105. if (! needsUpdate.compare_exchange_strong (needsUpdateTestValue, false))
  106. return false;
  107. if (auto valueProperty = tree.getPropertyPointer (key))
  108. {
  109. if ((float) *valueProperty != unnormalisedValue)
  110. {
  111. ScopedValueSetter<bool> svs (ignoreParameterChangedCallbacks, true);
  112. tree.setProperty (key, unnormalisedValue, um);
  113. }
  114. }
  115. else
  116. {
  117. tree.setProperty (key, unnormalisedValue, nullptr);
  118. }
  119. return true;
  120. }
  121. ValueTree tree;
  122. private:
  123. void parameterGestureChanged (int, bool) override {}
  124. void parameterValueChanged (int, float) override
  125. {
  126. const auto newValue = denormalise (parameter.getValue());
  127. if (unnormalisedValue == newValue && ! listenersNeedCalling)
  128. return;
  129. unnormalisedValue = newValue;
  130. listeners.call ([=](Listener& l) { l.parameterChanged (parameter.paramID, unnormalisedValue); });
  131. listenersNeedCalling = false;
  132. needsUpdate = true;
  133. }
  134. float denormalise (float normalised) const
  135. {
  136. return getParameter().convertFrom0to1 (normalised);
  137. }
  138. float normalise (float denormalised) const
  139. {
  140. return getParameter().convertTo0to1 (denormalised);
  141. }
  142. void setNormalisedValue (float value)
  143. {
  144. if (ignoreParameterChangedCallbacks)
  145. return;
  146. parameter.setValueNotifyingHost (value);
  147. }
  148. RangedAudioParameter& parameter;
  149. ListenerList<Listener> listeners;
  150. float unnormalisedValue{};
  151. std::atomic<bool> needsUpdate { true };
  152. bool listenersNeedCalling { true }, ignoreParameterChangedCallbacks { false };
  153. };
  154. //==============================================================================
  155. AudioProcessorValueTreeState::AudioProcessorValueTreeState (AudioProcessor& processorToConnectTo,
  156. UndoManager* undoManagerToUse,
  157. const Identifier& valueTreeType,
  158. ParameterLayout parameterLayout)
  159. : AudioProcessorValueTreeState (processorToConnectTo, undoManagerToUse)
  160. {
  161. struct PushBackVisitor : ParameterLayout::Visitor
  162. {
  163. explicit PushBackVisitor (AudioProcessorValueTreeState& stateIn)
  164. : state (&stateIn) {}
  165. void visit (std::unique_ptr<RangedAudioParameter> param) const override
  166. {
  167. if (param == nullptr)
  168. {
  169. jassertfalse;
  170. return;
  171. }
  172. state->addParameterAdapter (*param);
  173. state->processor.addParameter (param.release());
  174. }
  175. void visit (std::unique_ptr<AudioProcessorParameterGroup> group) const override
  176. {
  177. if (group == nullptr)
  178. {
  179. jassertfalse;
  180. return;
  181. }
  182. for (const auto param : group->getParameters (true))
  183. {
  184. if (const auto rangedParam = dynamic_cast<RangedAudioParameter*> (param))
  185. {
  186. state->addParameterAdapter (*rangedParam);
  187. }
  188. else
  189. {
  190. // If you hit this assertion then you are attempting to add a parameter that is
  191. // not derived from RangedAudioParameter to the AudioProcessorValueTreeState.
  192. jassertfalse;
  193. }
  194. }
  195. state->processor.addParameterGroup (move (group));
  196. }
  197. AudioProcessorValueTreeState* state;
  198. };
  199. for (auto& item : parameterLayout.parameters)
  200. item->accept (PushBackVisitor (*this));
  201. state = ValueTree (valueTreeType);
  202. }
  203. AudioProcessorValueTreeState::AudioProcessorValueTreeState (AudioProcessor& p, UndoManager* um)
  204. : processor (p), undoManager (um)
  205. {
  206. startTimerHz (10);
  207. state.addListener (this);
  208. }
  209. AudioProcessorValueTreeState::~AudioProcessorValueTreeState() {}
  210. //==============================================================================
  211. RangedAudioParameter* AudioProcessorValueTreeState::createAndAddParameter (const String& paramID,
  212. const String& paramName,
  213. const String& labelText,
  214. NormalisableRange<float> range,
  215. float defaultVal,
  216. std::function<String(float)> valueToTextFunction,
  217. std::function<float(const String&)> textToValueFunction,
  218. bool isMetaParameter,
  219. bool isAutomatableParameter,
  220. bool isDiscreteParameter,
  221. AudioProcessorParameter::Category category,
  222. bool isBooleanParameter)
  223. {
  224. return createAndAddParameter (std::make_unique<Parameter> (paramID,
  225. paramName,
  226. labelText,
  227. range,
  228. defaultVal,
  229. std::move (valueToTextFunction),
  230. std::move (textToValueFunction),
  231. isMetaParameter,
  232. isAutomatableParameter,
  233. isDiscreteParameter,
  234. category,
  235. isBooleanParameter));
  236. }
  237. RangedAudioParameter* AudioProcessorValueTreeState::createAndAddParameter (std::unique_ptr<RangedAudioParameter> param)
  238. {
  239. if (param == nullptr)
  240. return nullptr;
  241. // All parameters must be created before giving this manager a ValueTree state!
  242. jassert (! state.isValid());
  243. if (getParameter (param->paramID) != nullptr)
  244. return nullptr;
  245. addParameterAdapter (*param);
  246. processor.addParameter (param.get());
  247. return param.release();
  248. }
  249. //==============================================================================
  250. void AudioProcessorValueTreeState::addParameterAdapter (RangedAudioParameter& param)
  251. {
  252. adapterTable.emplace (param.paramID, std::make_unique<ParameterAdapter> (param));
  253. }
  254. AudioProcessorValueTreeState::ParameterAdapter* AudioProcessorValueTreeState::getParameterAdapter (StringRef paramID) const
  255. {
  256. auto it = adapterTable.find (paramID);
  257. return it == adapterTable.end() ? nullptr : it->second.get();
  258. }
  259. void AudioProcessorValueTreeState::addParameterListener (StringRef paramID, Listener* listener)
  260. {
  261. if (auto* p = getParameterAdapter (paramID))
  262. p->addListener (listener);
  263. }
  264. void AudioProcessorValueTreeState::removeParameterListener (StringRef paramID, Listener* listener)
  265. {
  266. if (auto* p = getParameterAdapter (paramID))
  267. p->removeListener (listener);
  268. }
  269. Value AudioProcessorValueTreeState::getParameterAsValue (StringRef paramID) const
  270. {
  271. if (auto* adapter = getParameterAdapter (paramID))
  272. if (adapter->tree.isValid())
  273. return adapter->tree.getPropertyAsValue (valuePropertyID, undoManager);
  274. return {};
  275. }
  276. NormalisableRange<float> AudioProcessorValueTreeState::getParameterRange (StringRef paramID) const noexcept
  277. {
  278. if (auto* p = getParameterAdapter (paramID))
  279. return p->getRange();
  280. return {};
  281. }
  282. RangedAudioParameter* AudioProcessorValueTreeState::getParameter (StringRef paramID) const noexcept
  283. {
  284. if (auto adapter = getParameterAdapter (paramID))
  285. return &adapter->getParameter();
  286. return nullptr;
  287. }
  288. float* AudioProcessorValueTreeState::getRawParameterValue (StringRef paramID) const noexcept
  289. {
  290. if (auto* p = getParameterAdapter (paramID))
  291. return &p->getRawDenormalisedValue();
  292. return nullptr;
  293. }
  294. ValueTree AudioProcessorValueTreeState::copyState()
  295. {
  296. ScopedLock lock (valueTreeChanging);
  297. flushParameterValuesToValueTree();
  298. return state.createCopy();
  299. }
  300. void AudioProcessorValueTreeState::replaceState (const ValueTree& newState)
  301. {
  302. ScopedLock lock (valueTreeChanging);
  303. state = newState;
  304. if (undoManager != nullptr)
  305. undoManager->clearUndoHistory();
  306. }
  307. void AudioProcessorValueTreeState::setNewState (ValueTree vt)
  308. {
  309. jassert (vt.getParent() == state);
  310. if (auto* p = getParameterAdapter (vt.getProperty (idPropertyID).toString()))
  311. {
  312. p->tree = vt;
  313. p->setDenormalisedValue (p->tree.getProperty (valuePropertyID, p->getDenormalisedDefaultValue()));
  314. }
  315. }
  316. void AudioProcessorValueTreeState::updateParameterConnectionsToChildTrees()
  317. {
  318. ScopedLock lock (valueTreeChanging);
  319. for (auto& p : adapterTable)
  320. p.second->tree = ValueTree();
  321. for (const auto& child : state)
  322. setNewState (child);
  323. for (auto& p : adapterTable)
  324. {
  325. auto& adapter = *p.second;
  326. if (! adapter.tree.isValid())
  327. {
  328. adapter.tree = ValueTree (valueType);
  329. adapter.tree.setProperty (idPropertyID, adapter.getParameter().paramID, nullptr);
  330. state.appendChild (adapter.tree, nullptr);
  331. }
  332. }
  333. flushParameterValuesToValueTree();
  334. }
  335. void AudioProcessorValueTreeState::valueTreePropertyChanged (ValueTree& tree, const Identifier&)
  336. {
  337. if (tree.hasType (valueType) && tree.getParent() == state)
  338. setNewState (tree);
  339. }
  340. void AudioProcessorValueTreeState::valueTreeChildAdded (ValueTree& parent, ValueTree& tree)
  341. {
  342. if (parent == state && tree.hasType (valueType))
  343. setNewState (tree);
  344. }
  345. void AudioProcessorValueTreeState::valueTreeRedirected (ValueTree& v)
  346. {
  347. if (v == state)
  348. updateParameterConnectionsToChildTrees();
  349. }
  350. bool AudioProcessorValueTreeState::flushParameterValuesToValueTree()
  351. {
  352. ScopedLock lock (valueTreeChanging);
  353. bool anyUpdated = false;
  354. for (auto& p : adapterTable)
  355. anyUpdated |= p.second->flushToTree (valuePropertyID, undoManager);
  356. return anyUpdated;
  357. }
  358. void AudioProcessorValueTreeState::timerCallback()
  359. {
  360. auto anythingUpdated = flushParameterValuesToValueTree();
  361. startTimer (anythingUpdated ? 1000 / 50
  362. : jlimit (50, 500, getTimerInterval() + 20));
  363. }
  364. //==============================================================================
  365. struct AttachedControlBase : public AudioProcessorValueTreeState::Listener,
  366. public AsyncUpdater
  367. {
  368. AttachedControlBase (AudioProcessorValueTreeState& s, const String& p)
  369. : state (s), paramID (p), lastValue (0)
  370. {
  371. state.addParameterListener (paramID, this);
  372. }
  373. void removeListener()
  374. {
  375. state.removeParameterListener (paramID, this);
  376. }
  377. void setNewDenormalisedValue (float newDenormalisedValue)
  378. {
  379. if (auto* p = state.getParameter (paramID))
  380. {
  381. const float newValue = state.getParameterRange (paramID)
  382. .convertTo0to1 (newDenormalisedValue);
  383. if (p->getValue() != newValue)
  384. p->setValueNotifyingHost (newValue);
  385. }
  386. }
  387. void sendInitialUpdate()
  388. {
  389. if (auto* v = state.getRawParameterValue (paramID))
  390. parameterChanged (paramID, *v);
  391. }
  392. void parameterChanged (const String&, float newValue) override
  393. {
  394. lastValue = newValue;
  395. if (MessageManager::getInstance()->isThisTheMessageThread())
  396. {
  397. cancelPendingUpdate();
  398. setValue (newValue);
  399. }
  400. else
  401. {
  402. triggerAsyncUpdate();
  403. }
  404. }
  405. void beginParameterChange()
  406. {
  407. if (auto* p = state.getParameter (paramID))
  408. {
  409. if (state.undoManager != nullptr)
  410. state.undoManager->beginNewTransaction();
  411. p->beginChangeGesture();
  412. }
  413. }
  414. void endParameterChange()
  415. {
  416. if (AudioProcessorParameter* p = state.getParameter (paramID))
  417. p->endChangeGesture();
  418. }
  419. void handleAsyncUpdate() override
  420. {
  421. setValue (lastValue);
  422. }
  423. virtual void setValue (float) = 0;
  424. AudioProcessorValueTreeState& state;
  425. String paramID;
  426. float lastValue;
  427. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AttachedControlBase)
  428. };
  429. //==============================================================================
  430. struct AudioProcessorValueTreeState::SliderAttachment::Pimpl : private AttachedControlBase,
  431. private Slider::Listener
  432. {
  433. Pimpl (AudioProcessorValueTreeState& s, const String& p, Slider& sl)
  434. : AttachedControlBase (s, p), slider (sl), ignoreCallbacks (false)
  435. {
  436. NormalisableRange<float> range (state.getParameterRange (paramID));
  437. if (auto* param = state.getParameterAdapter (paramID))
  438. {
  439. slider.valueFromTextFunction = [param](const String& text) { return (double) param->getDenormalisedValueForText (text); };
  440. slider.textFromValueFunction = [param](double value) { return param->getTextForDenormalisedValue ((float) value); };
  441. slider.setDoubleClickReturnValue (true, range.convertFrom0to1 (param->getParameter().getDefaultValue()));
  442. }
  443. auto convertFrom0To1Function = [range](double currentRangeStart,
  444. double currentRangeEnd,
  445. double normalisedValue) mutable
  446. {
  447. range.start = (float) currentRangeStart;
  448. range.end = (float) currentRangeEnd;
  449. return (double) range.convertFrom0to1 ((float) normalisedValue);
  450. };
  451. auto convertTo0To1Function = [range](double currentRangeStart,
  452. double currentRangeEnd,
  453. double mappedValue) mutable
  454. {
  455. range.start = (float) currentRangeStart;
  456. range.end = (float) currentRangeEnd;
  457. return (double) range.convertTo0to1 ((float) mappedValue);
  458. };
  459. auto snapToLegalValueFunction = [range](double currentRangeStart,
  460. double currentRangeEnd,
  461. double valueToSnap) mutable
  462. {
  463. range.start = (float) currentRangeStart;
  464. range.end = (float) currentRangeEnd;
  465. return (double) range.snapToLegalValue ((float) valueToSnap);
  466. };
  467. NormalisableRange<double> newRange { (double) range.start,
  468. (double) range.end,
  469. convertFrom0To1Function,
  470. convertTo0To1Function,
  471. snapToLegalValueFunction };
  472. newRange.interval = (double) range.interval;
  473. newRange.skew = (double) range.skew;
  474. slider.setNormalisableRange (newRange);
  475. sendInitialUpdate();
  476. slider.addListener (this);
  477. }
  478. ~Pimpl() override
  479. {
  480. slider.removeListener (this);
  481. removeListener();
  482. }
  483. void setValue (float newValue) override
  484. {
  485. const ScopedLock selfCallbackLock (selfCallbackMutex);
  486. {
  487. ScopedValueSetter<bool> svs (ignoreCallbacks, true);
  488. slider.setValue (newValue, sendNotificationSync);
  489. }
  490. }
  491. void sliderValueChanged (Slider* s) override
  492. {
  493. const ScopedLock selfCallbackLock (selfCallbackMutex);
  494. if ((! ignoreCallbacks) && (! ModifierKeys::currentModifiers.isRightButtonDown()))
  495. setNewDenormalisedValue ((float) s->getValue());
  496. }
  497. void sliderDragStarted (Slider*) override { beginParameterChange(); }
  498. void sliderDragEnded (Slider*) override { endParameterChange(); }
  499. Slider& slider;
  500. bool ignoreCallbacks;
  501. CriticalSection selfCallbackMutex;
  502. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Pimpl)
  503. };
  504. AudioProcessorValueTreeState::SliderAttachment::SliderAttachment (AudioProcessorValueTreeState& s, const String& p, Slider& sl)
  505. : pimpl (new Pimpl (s, p, sl))
  506. {
  507. }
  508. AudioProcessorValueTreeState::SliderAttachment::~SliderAttachment() {}
  509. //==============================================================================
  510. struct AudioProcessorValueTreeState::ComboBoxAttachment::Pimpl : private AttachedControlBase,
  511. private ComboBox::Listener
  512. {
  513. Pimpl (AudioProcessorValueTreeState& s, const String& p, ComboBox& c)
  514. : AttachedControlBase (s, p), combo (c), ignoreCallbacks (false)
  515. {
  516. sendInitialUpdate();
  517. combo.addListener (this);
  518. }
  519. ~Pimpl() override
  520. {
  521. combo.removeListener (this);
  522. removeListener();
  523. }
  524. void setValue (float newValue) override
  525. {
  526. const ScopedLock selfCallbackLock (selfCallbackMutex);
  527. if (state.getParameter (paramID) != nullptr)
  528. {
  529. auto normValue = state.getParameterRange (paramID)
  530. .convertTo0to1 (newValue);
  531. auto index = roundToInt (normValue * (combo.getNumItems() - 1));
  532. if (index != combo.getSelectedItemIndex())
  533. {
  534. ScopedValueSetter<bool> svs (ignoreCallbacks, true);
  535. combo.setSelectedItemIndex (index, sendNotificationSync);
  536. }
  537. }
  538. }
  539. void comboBoxChanged (ComboBox*) override
  540. {
  541. const ScopedLock selfCallbackLock (selfCallbackMutex);
  542. if (! ignoreCallbacks)
  543. {
  544. if (auto* p = state.getParameter (paramID))
  545. {
  546. auto newValue = (float) combo.getSelectedItemIndex() / (combo.getNumItems() - 1);
  547. if (p->getValue() != newValue)
  548. {
  549. beginParameterChange();
  550. p->setValueNotifyingHost (newValue);
  551. endParameterChange();
  552. }
  553. }
  554. }
  555. }
  556. ComboBox& combo;
  557. bool ignoreCallbacks;
  558. CriticalSection selfCallbackMutex;
  559. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Pimpl)
  560. };
  561. AudioProcessorValueTreeState::ComboBoxAttachment::ComboBoxAttachment (AudioProcessorValueTreeState& s, const String& p, ComboBox& c)
  562. : pimpl (new Pimpl (s, p, c))
  563. {
  564. }
  565. AudioProcessorValueTreeState::ComboBoxAttachment::~ComboBoxAttachment() {}
  566. //==============================================================================
  567. struct AudioProcessorValueTreeState::ButtonAttachment::Pimpl : private AttachedControlBase,
  568. private Button::Listener
  569. {
  570. Pimpl (AudioProcessorValueTreeState& s, const String& p, Button& b)
  571. : AttachedControlBase (s, p), button (b), ignoreCallbacks (false)
  572. {
  573. sendInitialUpdate();
  574. button.addListener (this);
  575. }
  576. ~Pimpl() override
  577. {
  578. button.removeListener (this);
  579. removeListener();
  580. }
  581. void setValue (float newValue) override
  582. {
  583. const ScopedLock selfCallbackLock (selfCallbackMutex);
  584. {
  585. ScopedValueSetter<bool> svs (ignoreCallbacks, true);
  586. button.setToggleState (newValue >= 0.5f, sendNotificationSync);
  587. }
  588. }
  589. void buttonClicked (Button* b) override
  590. {
  591. const ScopedLock selfCallbackLock (selfCallbackMutex);
  592. if (! ignoreCallbacks)
  593. {
  594. beginParameterChange();
  595. setNewDenormalisedValue (b->getToggleState() ? 1.0f : 0.0f);
  596. endParameterChange();
  597. }
  598. }
  599. Button& button;
  600. bool ignoreCallbacks;
  601. CriticalSection selfCallbackMutex;
  602. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Pimpl)
  603. };
  604. AudioProcessorValueTreeState::ButtonAttachment::ButtonAttachment (AudioProcessorValueTreeState& s, const String& p, Button& b)
  605. : pimpl (new Pimpl (s, p, b))
  606. {
  607. }
  608. AudioProcessorValueTreeState::ButtonAttachment::~ButtonAttachment() {}
  609. //==============================================================================
  610. //==============================================================================
  611. #if JUCE_UNIT_TESTS
  612. struct ParameterAdapterTests : public UnitTest
  613. {
  614. ParameterAdapterTests()
  615. : UnitTest ("Parameter Adapter", UnitTestCategories::audioProcessorParameters)
  616. {}
  617. void runTest() override
  618. {
  619. beginTest ("The default value is returned correctly");
  620. {
  621. const auto test = [&] (NormalisableRange<float> range, float value)
  622. {
  623. AudioParameterFloat param ({}, {}, range, value, {});
  624. AudioProcessorValueTreeState::ParameterAdapter adapter (param);
  625. expectEquals (adapter.getDenormalisedDefaultValue(), value);
  626. };
  627. test ({ -100, 100 }, 0);
  628. test ({ -2.5, 12.5 }, 10);
  629. }
  630. beginTest ("Denormalised parameter values can be retrieved");
  631. {
  632. const auto test = [&](NormalisableRange<float> range, float value)
  633. {
  634. AudioParameterFloat param ({}, {}, range, {}, {});
  635. AudioProcessorValueTreeState::ParameterAdapter adapter (param);
  636. adapter.setDenormalisedValue (value);
  637. expectEquals (adapter.getDenormalisedValue(), value);
  638. expectEquals (adapter.getRawDenormalisedValue(), value);
  639. };
  640. test ({ -20, -10 }, -15);
  641. test ({ 0, 7.5 }, 2.5);
  642. }
  643. beginTest ("Floats can be converted to text");
  644. {
  645. const auto test = [&](NormalisableRange<float> range, float value, String expected)
  646. {
  647. AudioParameterFloat param ({}, {}, range, {}, {});
  648. AudioProcessorValueTreeState::ParameterAdapter adapter (param);
  649. expectEquals (adapter.getTextForDenormalisedValue (value), expected);
  650. };
  651. test ({ -100, 100 }, 0, "0.0000000");
  652. test ({ -2.5, 12.5 }, 10, "10.0000000");
  653. test ({ -20, -10 }, -15, "-15.0000000");
  654. test ({ 0, 7.5 }, 2.5, "2.5000000");
  655. }
  656. beginTest ("Text can be converted to floats");
  657. {
  658. const auto test = [&](NormalisableRange<float> range, String text, float expected)
  659. {
  660. AudioParameterFloat param ({}, {}, range, {}, {});
  661. AudioProcessorValueTreeState::ParameterAdapter adapter (param);
  662. expectEquals (adapter.getDenormalisedValueForText (text), expected);
  663. };
  664. test ({ -100, 100 }, "0.0", 0);
  665. test ({ -2.5, 12.5 }, "10.0", 10);
  666. test ({ -20, -10 }, "-15.0", -15);
  667. test ({ 0, 7.5 }, "2.5", 2.5);
  668. }
  669. }
  670. };
  671. static ParameterAdapterTests parameterAdapterTests;
  672. namespace
  673. {
  674. template <typename ValueType>
  675. inline bool operator== (const NormalisableRange<ValueType>& a,
  676. const NormalisableRange<ValueType>& b)
  677. {
  678. return std::tie (a.start, a.end, a.interval, a.skew, a.symmetricSkew)
  679. == std::tie (b.start, b.end, b.interval, b.skew, b.symmetricSkew);
  680. }
  681. template <typename ValueType>
  682. inline bool operator!= (const NormalisableRange<ValueType>& a,
  683. const NormalisableRange<ValueType>& b)
  684. {
  685. return ! (a == b);
  686. }
  687. } // namespace
  688. class AudioProcessorValueTreeStateTests : public UnitTest
  689. {
  690. private:
  691. using Parameter = AudioProcessorValueTreeState::Parameter;
  692. using ParameterGroup = AudioProcessorParameterGroup;
  693. using ParameterLayout = AudioProcessorValueTreeState::ParameterLayout;
  694. class TestAudioProcessor : public AudioProcessor
  695. {
  696. public:
  697. TestAudioProcessor() = default;
  698. explicit TestAudioProcessor (ParameterLayout layout)
  699. : state (*this, nullptr, "state", std::move (layout)) {}
  700. const String getName() const override { return {}; }
  701. void prepareToPlay (double, int) override {}
  702. void releaseResources() override {}
  703. void processBlock (AudioBuffer<float>&, MidiBuffer&) override {}
  704. using AudioProcessor::processBlock;
  705. double getTailLengthSeconds() const override { return {}; }
  706. bool acceptsMidi() const override { return {}; }
  707. bool producesMidi() const override { return {}; }
  708. AudioProcessorEditor* createEditor() override { return {}; }
  709. bool hasEditor() const override { return {}; }
  710. int getNumPrograms() override { return 1; }
  711. int getCurrentProgram() override { return {}; }
  712. void setCurrentProgram (int) override {}
  713. const String getProgramName (int) override { return {}; }
  714. void changeProgramName (int, const String&) override {}
  715. void getStateInformation (MemoryBlock&) override {}
  716. void setStateInformation (const void*, int) override {}
  717. AudioProcessorValueTreeState state { *this, nullptr };
  718. };
  719. struct Listener final : public AudioProcessorValueTreeState::Listener
  720. {
  721. void parameterChanged (const String& idIn, float valueIn) override
  722. {
  723. id = idIn;
  724. value = valueIn;
  725. }
  726. String id;
  727. float value{};
  728. };
  729. public:
  730. AudioProcessorValueTreeStateTests()
  731. : UnitTest ("Audio Processor Value Tree State", UnitTestCategories::audioProcessorParameters)
  732. {}
  733. void runTest() override
  734. {
  735. ScopedJuceInitialiser_GUI scopedJuceInitialiser_gui;
  736. beginTest ("After calling createAndAddParameter, the number of parameters increases by one");
  737. {
  738. TestAudioProcessor proc;
  739. proc.state.createAndAddParameter (std::make_unique<Parameter> (String(), String(), String(), NormalisableRange<float>(),
  740. 0.0f, nullptr, nullptr));
  741. expectEquals (proc.getParameters().size(), 1);
  742. }
  743. beginTest ("After creating a normal named parameter, we can later retrieve that parameter");
  744. {
  745. TestAudioProcessor proc;
  746. const auto key = "id";
  747. const auto param = proc.state.createAndAddParameter (std::make_unique<Parameter> (key, String(), String(), NormalisableRange<float>(),
  748. 0.0f, nullptr, nullptr));
  749. expect (proc.state.getParameter (key) == param);
  750. }
  751. beginTest ("After construction, the value tree has the expected format");
  752. {
  753. TestAudioProcessor proc ({
  754. std::make_unique<AudioProcessorParameterGroup> ("", "", "",
  755. std::make_unique<AudioParameterBool> ("a", "", false),
  756. std::make_unique<AudioParameterFloat> ("b", "", NormalisableRange<float>{}, 0.0f)),
  757. std::make_unique<AudioProcessorParameterGroup> ("", "", "",
  758. std::make_unique<AudioParameterInt> ("c", "", 0, 1, 0),
  759. std::make_unique<AudioParameterChoice> ("d", "", StringArray { "foo", "bar" }, 0)) });
  760. const auto valueTree = proc.state.copyState();
  761. expectEquals (valueTree.getNumChildren(), 4);
  762. for (auto child : valueTree)
  763. {
  764. expect (child.hasType ("PARAM"));
  765. expect (child.hasProperty ("id"));
  766. expect (child.hasProperty ("value"));
  767. }
  768. }
  769. beginTest ("Meta parameters can be created");
  770. {
  771. TestAudioProcessor proc;
  772. const auto key = "id";
  773. const auto param = proc.state.createAndAddParameter (std::make_unique<Parameter> (key, String(), String(), NormalisableRange<float>(),
  774. 0.0f, nullptr, nullptr, true));
  775. expect (param->isMetaParameter());
  776. }
  777. beginTest ("Automatable parameters can be created");
  778. {
  779. TestAudioProcessor proc;
  780. const auto key = "id";
  781. const auto param = proc.state.createAndAddParameter (std::make_unique<Parameter> (key, String(), String(), NormalisableRange<float>(),
  782. 0.0f, nullptr, nullptr, false, true));
  783. expect (param->isAutomatable());
  784. }
  785. beginTest ("Discrete parameters can be created");
  786. {
  787. TestAudioProcessor proc;
  788. const auto key = "id";
  789. const auto param = proc.state.createAndAddParameter (std::make_unique<Parameter> (key, String(), String(), NormalisableRange<float>(),
  790. 0.0f, nullptr, nullptr, false, false, true));
  791. expect (param->isDiscrete());
  792. }
  793. beginTest ("Custom category parameters can be created");
  794. {
  795. TestAudioProcessor proc;
  796. const auto key = "id";
  797. const auto param = proc.state.createAndAddParameter (std::make_unique<Parameter> (key, String(), String(), NormalisableRange<float>(),
  798. 0.0f, nullptr, nullptr, false, false, false,
  799. AudioProcessorParameter::Category::inputMeter));
  800. expect (param->category == AudioProcessorParameter::Category::inputMeter);
  801. }
  802. beginTest ("Boolean parameters can be created");
  803. {
  804. TestAudioProcessor proc;
  805. const auto key = "id";
  806. const auto param = proc.state.createAndAddParameter (std::make_unique<Parameter> (key, String(), String(), NormalisableRange<float>(),
  807. 0.0f, nullptr, nullptr, false, false, false,
  808. AudioProcessorParameter::Category::genericParameter, true));
  809. expect (param->isBoolean());
  810. }
  811. beginTest ("After creating a custom named parameter, we can later retrieve that parameter");
  812. {
  813. const auto key = "id";
  814. auto param = std::make_unique<AudioParameterBool> (key, "", false);
  815. const auto paramPtr = param.get();
  816. TestAudioProcessor proc (std::move (param));
  817. expect (proc.state.getParameter (key) == paramPtr);
  818. }
  819. beginTest ("After adding a normal parameter that already exists, the AudioProcessor parameters are unchanged");
  820. {
  821. TestAudioProcessor proc;
  822. const auto key = "id";
  823. const auto param = proc.state.createAndAddParameter (std::make_unique<Parameter> (key, String(), String(), NormalisableRange<float>(),
  824. 0.0f, nullptr, nullptr));
  825. proc.state.createAndAddParameter (std::make_unique<Parameter> (key, String(), String(), NormalisableRange<float>(),
  826. 0.0f, nullptr, nullptr));
  827. expectEquals (proc.getParameters().size(), 1);
  828. expect (proc.getParameters().getFirst() == param);
  829. }
  830. beginTest ("After setting a parameter value, that value is reflected in the state");
  831. {
  832. TestAudioProcessor proc;
  833. const auto key = "id";
  834. const auto param = proc.state.createAndAddParameter (std::make_unique<Parameter> (key, String(), String(), NormalisableRange<float>(),
  835. 0.0f, nullptr, nullptr));
  836. const auto value = 0.5f;
  837. param->setValueNotifyingHost (value);
  838. expectEquals (*proc.state.getRawParameterValue (key), value);
  839. }
  840. beginTest ("After adding an APVTS::Parameter, its value is the default value");
  841. {
  842. TestAudioProcessor proc;
  843. const auto key = "id";
  844. const auto value = 5.0f;
  845. proc.state.createAndAddParameter (std::make_unique<Parameter> (
  846. key,
  847. String(),
  848. String(),
  849. NormalisableRange<float> (0.0f, 100.0f, 10.0f),
  850. value,
  851. nullptr,
  852. nullptr));
  853. expectEquals (*proc.state.getRawParameterValue (key), value);
  854. }
  855. beginTest ("Listeners receive notifications when parameters change");
  856. {
  857. Listener listener;
  858. TestAudioProcessor proc;
  859. const auto key = "id";
  860. const auto param = proc.state.createAndAddParameter (std::make_unique<Parameter> (key, String(), String(), NormalisableRange<float>(),
  861. 0.0f, nullptr, nullptr));
  862. proc.state.addParameterListener (key, &listener);
  863. const auto value = 0.5f;
  864. param->setValueNotifyingHost (value);
  865. expectEquals (listener.id, String { key });
  866. expectEquals (listener.value, value);
  867. }
  868. beginTest ("Bool parameters have a range of 0-1");
  869. {
  870. const auto key = "id";
  871. TestAudioProcessor proc (std::make_unique<AudioParameterBool> (key, "", false));
  872. expect (proc.state.getParameterRange (key) == NormalisableRange<float> (0.0f, 1.0f, 1.0f));
  873. }
  874. beginTest ("Float parameters retain their specified range");
  875. {
  876. const auto key = "id";
  877. const auto range = NormalisableRange<float> { -100, 100, 0.7f, 0.2f, true };
  878. TestAudioProcessor proc (std::make_unique<AudioParameterFloat> (key, "", range, 0.0f));
  879. expect (proc.state.getParameterRange (key) == range);
  880. }
  881. beginTest ("Int parameters retain their specified range");
  882. {
  883. const auto key = "id";
  884. const auto min = -27;
  885. const auto max = 53;
  886. TestAudioProcessor proc (std::make_unique<AudioParameterInt> (key, "", min, max, 0));
  887. expect (proc.state.getParameterRange (key) == NormalisableRange<float> (float (min), float (max), 1.0f));
  888. }
  889. beginTest ("Choice parameters retain their specified range");
  890. {
  891. const auto key = "id";
  892. const auto choices = StringArray { "", "", "" };
  893. TestAudioProcessor proc (std::make_unique<AudioParameterChoice> (key, "", choices, 0));
  894. expect (proc.state.getParameterRange (key) == NormalisableRange<float> (0.0f, (float) (choices.size() - 1), 1.0f));
  895. expect (proc.state.getParameter (key)->getNumSteps() == choices.size());
  896. }
  897. beginTest ("When the parameter value is changed, normal parameter values are updated");
  898. {
  899. TestAudioProcessor proc;
  900. const auto key = "id";
  901. const auto initialValue = 0.2f;
  902. auto param = proc.state.createAndAddParameter (std::make_unique<Parameter> (key, String(), String(), NormalisableRange<float>(),
  903. initialValue, nullptr, nullptr));
  904. proc.state.state = ValueTree { "state" };
  905. auto value = proc.state.getParameterAsValue (key);
  906. expectEquals (float (value.getValue()), initialValue);
  907. const auto newValue = 0.75f;
  908. value = newValue;
  909. expectEquals (param->getValue(), newValue);
  910. expectEquals (*proc.state.getRawParameterValue (key), newValue);
  911. }
  912. beginTest ("When the parameter value is changed, custom parameter values are updated");
  913. {
  914. const auto key = "id";
  915. const auto choices = StringArray ("foo", "bar", "baz");
  916. auto param = std::make_unique<AudioParameterChoice> (key, "", choices, 0);
  917. const auto paramPtr = param.get();
  918. TestAudioProcessor proc (std::move (param));
  919. const auto newValue = 2.0f;
  920. auto value = proc.state.getParameterAsValue (key);
  921. value = newValue;
  922. expectEquals (paramPtr->getCurrentChoiceName(), choices[int (newValue)]);
  923. expectEquals (*proc.state.getRawParameterValue (key), newValue);
  924. }
  925. beginTest ("When the parameter value is changed, listeners are notified");
  926. {
  927. Listener listener;
  928. TestAudioProcessor proc;
  929. const auto key = "id";
  930. proc.state.createAndAddParameter (std::make_unique<Parameter> (key, String(), String(), NormalisableRange<float>(),
  931. 0.0f, nullptr, nullptr));
  932. proc.state.addParameterListener (key, &listener);
  933. proc.state.state = ValueTree { "state" };
  934. const auto newValue = 0.75f;
  935. proc.state.getParameterAsValue (key) = newValue;
  936. expectEquals (listener.value, newValue);
  937. expectEquals (listener.id, String { key });
  938. }
  939. beginTest ("When the parameter value is changed, listeners are notified");
  940. {
  941. const auto key = "id";
  942. const auto choices = StringArray { "foo", "bar", "baz" };
  943. Listener listener;
  944. TestAudioProcessor proc (std::make_unique<AudioParameterChoice> (key, "", choices, 0));
  945. proc.state.addParameterListener (key, &listener);
  946. const auto newValue = 2.0f;
  947. proc.state.getParameterAsValue (key) = newValue;
  948. expectEquals (listener.value, newValue);
  949. expectEquals (listener.id, String (key));
  950. }
  951. }
  952. };
  953. static AudioProcessorValueTreeStateTests audioProcessorValueTreeStateTests;
  954. #endif
  955. } // namespace juce