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