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.

659 lines
32KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2022 - Raw Material Software Limited
  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 7 End-User License
  8. Agreement and JUCE Privacy Policy.
  9. End User License Agreement: www.juce.com/juce-7-licence
  10. Privacy Policy: www.juce.com/juce-privacy-policy
  11. Or: You may also use this code under the terms of the GPL v3 (see
  12. www.gnu.org/licenses).
  13. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  14. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  15. DISCLAIMED.
  16. ==============================================================================
  17. */
  18. namespace juce
  19. {
  20. /** Advanced properties of an AudioProcessorValueTreeState::Parameter.
  21. The members here have the same meaning as the similarly-named member functions of
  22. AudioParameterFloatAttributes.
  23. @see AudioParameterFloatAttributes, RangedAudioParameterAttributes
  24. */
  25. class AudioProcessorValueTreeStateParameterAttributes
  26. {
  27. using This = AudioProcessorValueTreeStateParameterAttributes;
  28. using StringFromValue = AudioParameterFloatAttributes::StringFromValue;
  29. using ValueFromString = AudioParameterFloatAttributes::ValueFromString;
  30. using Category = AudioParameterFloatAttributes::Category;
  31. public:
  32. /** @see RangedAudioParameterAttributes::withStringFromValueFunction() */
  33. JUCE_NODISCARD auto withStringFromValueFunction (StringFromValue x) const { return withMember (*this, &This::attributes, attributes.withStringFromValueFunction (std::move (x))); }
  34. /** @see RangedAudioParameterAttributes::withValueFromStringFunction() */
  35. JUCE_NODISCARD auto withValueFromStringFunction (ValueFromString x) const { return withMember (*this, &This::attributes, attributes.withValueFromStringFunction (std::move (x))); }
  36. /** @see RangedAudioParameterAttributes::withLabel() */
  37. JUCE_NODISCARD auto withLabel (String x) const { return withMember (*this, &This::attributes, attributes.withLabel (std::move (x))); }
  38. /** @see RangedAudioParameterAttributes::withCategory() */
  39. JUCE_NODISCARD auto withCategory (Category x) const { return withMember (*this, &This::attributes, attributes.withCategory (std::move (x))); }
  40. /** @see RangedAudioParameterAttributes::withMeta() */
  41. JUCE_NODISCARD auto withMeta (bool x) const { return withMember (*this, &This::attributes, attributes.withMeta (std::move (x))); }
  42. /** @see RangedAudioParameterAttributes::withAutomatable() */
  43. JUCE_NODISCARD auto withAutomatable (bool x) const { return withMember (*this, &This::attributes, attributes.withAutomatable (std::move (x))); }
  44. /** @see RangedAudioParameterAttributes::withInverted() */
  45. JUCE_NODISCARD auto withInverted (bool x) const { return withMember (*this, &This::attributes, attributes.withInverted (std::move (x))); }
  46. /** Pass 'true' if this parameter has discrete steps, or 'false' if the parameter is continuous.
  47. Using an AudioParameterChoice or AudioParameterInt might be a better choice than setting this flag.
  48. */
  49. JUCE_NODISCARD auto withDiscrete (bool x) const { return withMember (*this, &This::discrete, std::move (x)); }
  50. /** Pass 'true' if this parameter only has two valid states.
  51. Using an AudioParameterBool might be a better choice than setting this flag.
  52. */
  53. JUCE_NODISCARD auto withBoolean (bool x) const { return withMember (*this, &This::boolean, std::move (x)); }
  54. /** @returns all attributes that might also apply to an AudioParameterFloat */
  55. JUCE_NODISCARD const auto& getAudioParameterFloatAttributes() const { return attributes; }
  56. /** @returns 'true' if this parameter has discrete steps, or 'false' if the parameter is continuous. */
  57. JUCE_NODISCARD const auto& getDiscrete() const { return discrete; }
  58. /** @returns 'true' if this parameter only has two valid states. */
  59. JUCE_NODISCARD const auto& getBoolean() const { return boolean; }
  60. private:
  61. AudioParameterFloatAttributes attributes;
  62. bool discrete = false, boolean = false;
  63. };
  64. /**
  65. This class contains a ValueTree that is used to manage an AudioProcessor's entire state.
  66. It has its own internal class of parameter object that is linked to values
  67. within its ValueTree, and which are each identified by a string ID.
  68. You can get access to the underlying ValueTree object via the state member variable,
  69. so you can add extra properties to it as necessary.
  70. It also provides some utility child classes for connecting parameters directly to
  71. GUI controls like sliders.
  72. The favoured constructor of this class takes a collection of RangedAudioParameters or
  73. AudioProcessorParameterGroups of RangedAudioParameters and adds them to the attached
  74. AudioProcessor directly.
  75. The deprecated way of using this class is as follows:
  76. 1) Create an AudioProcessorValueTreeState, and give it some parameters using createAndAddParameter().
  77. 2) Initialise the state member variable with a type name.
  78. The deprecated constructor will be removed from the API in a future version of JUCE!
  79. @tags{Audio}
  80. */
  81. class JUCE_API AudioProcessorValueTreeState : private Timer,
  82. private ValueTree::Listener
  83. {
  84. public:
  85. //==============================================================================
  86. /** A class to contain a set of RangedAudioParameters and AudioProcessorParameterGroups
  87. containing RangedAudioParameters.
  88. This class is used in the AudioProcessorValueTreeState constructor to allow
  89. arbitrarily grouped RangedAudioParameters to be passed to an AudioProcessor.
  90. */
  91. class JUCE_API ParameterLayout final
  92. {
  93. private:
  94. //==============================================================================
  95. template <typename It>
  96. using ValidIfIterator = decltype (std::next (std::declval<It>()));
  97. public:
  98. //==============================================================================
  99. template <typename... Items>
  100. ParameterLayout (std::unique_ptr<Items>... items) { add (std::move (items)...); }
  101. template <typename It, typename = ValidIfIterator<It>>
  102. ParameterLayout (It begin, It end) { add (begin, end); }
  103. template <typename... Items>
  104. void add (std::unique_ptr<Items>... items)
  105. {
  106. parameters.reserve (parameters.size() + sizeof... (items));
  107. // We can replace this with some nicer code once generic lambdas become available. A
  108. // sequential context like an array initialiser is required to ensure we get the correct
  109. // order from the parameter pack.
  110. int unused[] { (parameters.emplace_back (MakeContents() (std::move (items))), 0)... };
  111. ignoreUnused (unused);
  112. }
  113. template <typename It, typename = ValidIfIterator<It>>
  114. void add (It begin, It end)
  115. {
  116. parameters.reserve (parameters.size() + std::size_t (std::distance (begin, end)));
  117. std::transform (std::make_move_iterator (begin),
  118. std::make_move_iterator (end),
  119. std::back_inserter (parameters),
  120. MakeContents());
  121. }
  122. ParameterLayout (const ParameterLayout& other) = delete;
  123. ParameterLayout (ParameterLayout&& other) noexcept { swap (other); }
  124. ParameterLayout& operator= (const ParameterLayout& other) = delete;
  125. ParameterLayout& operator= (ParameterLayout&& other) noexcept { swap (other); return *this; }
  126. void swap (ParameterLayout& other) noexcept { std::swap (other.parameters, parameters); }
  127. private:
  128. //==============================================================================
  129. struct Visitor
  130. {
  131. virtual ~Visitor() = default;
  132. // If you have a compiler error telling you that there is no matching
  133. // member function to call for 'visit', then you are probably attempting
  134. // to add a parameter that is not derived from RangedAudioParameter to
  135. // the AudioProcessorValueTreeState.
  136. virtual void visit (std::unique_ptr<RangedAudioParameter>) const = 0;
  137. virtual void visit (std::unique_ptr<AudioProcessorParameterGroup>) const = 0;
  138. };
  139. struct ParameterStorageBase
  140. {
  141. virtual ~ParameterStorageBase() = default;
  142. virtual void accept (const Visitor& visitor) = 0;
  143. };
  144. template <typename Contents>
  145. struct ParameterStorage : ParameterStorageBase
  146. {
  147. explicit ParameterStorage (std::unique_ptr<Contents> input) : contents (std::move (input)) {}
  148. void accept (const Visitor& visitor) override { visitor.visit (std::move (contents)); }
  149. std::unique_ptr<Contents> contents;
  150. };
  151. struct MakeContents final
  152. {
  153. template <typename Item>
  154. std::unique_ptr<ParameterStorageBase> operator() (std::unique_ptr<Item> item) const
  155. {
  156. return std::unique_ptr<ParameterStorageBase> (new ParameterStorage<Item> (std::move (item)));
  157. }
  158. };
  159. void add() {}
  160. friend class AudioProcessorValueTreeState;
  161. std::vector<std::unique_ptr<ParameterStorageBase>> parameters;
  162. };
  163. //==============================================================================
  164. /** Creates a state object for a given processor, and sets up all the parameters
  165. that will control that processor.
  166. You should *not* assign a new ValueTree to the state, or call
  167. createAndAddParameter, after using this constructor.
  168. Note that each AudioProcessorValueTreeState should be attached to only one
  169. processor, and must have the same lifetime as the processor, as they will
  170. have dependencies on each other.
  171. The ParameterLayout parameter has a set of constructors that allow you to
  172. add multiple RangedAudioParameters and AudioProcessorParameterGroups containing
  173. RangedAudioParameters to the AudioProcessorValueTreeState inside this constructor.
  174. @code
  175. YourAudioProcessor()
  176. : apvts (*this, &undoManager, "PARAMETERS",
  177. { std::make_unique<AudioParameterFloat> ("a", "Parameter A", NormalisableRange<float> (-100.0f, 100.0f), 0),
  178. std::make_unique<AudioParameterInt> ("b", "Parameter B", 0, 5, 2) })
  179. @endcode
  180. To add parameters programmatically you can call `add` repeatedly on a
  181. ParameterLayout instance:
  182. @code
  183. AudioProcessorValueTreeState::ParameterLayout createParameterLayout()
  184. {
  185. AudioProcessorValueTreeState::ParameterLayout layout;
  186. for (int i = 1; i < 9; ++i)
  187. layout.add (std::make_unique<AudioParameterInt> (String (i), String (i), 0, i, 0));
  188. return layout;
  189. }
  190. YourAudioProcessor()
  191. : apvts (*this, &undoManager, "PARAMETERS", createParameterLayout())
  192. {
  193. }
  194. @endcode
  195. @param processorToConnectTo The Processor that will be managed by this object
  196. @param undoManagerToUse An optional UndoManager to use; pass nullptr if no UndoManager is required
  197. @param valueTreeType The identifier used to initialise the internal ValueTree
  198. @param parameterLayout An object that holds all parameters and parameter groups that the
  199. AudioProcessor should use.
  200. */
  201. AudioProcessorValueTreeState (AudioProcessor& processorToConnectTo,
  202. UndoManager* undoManagerToUse,
  203. const Identifier& valueTreeType,
  204. ParameterLayout parameterLayout);
  205. /** This constructor is discouraged and will be deprecated in a future version of JUCE!
  206. Use the other constructor instead.
  207. Creates a state object for a given processor.
  208. The UndoManager is optional and can be a nullptr. After creating your state object,
  209. you should add parameters with the createAndAddParameter() method. Note that each
  210. AudioProcessorValueTreeState should be attached to only one processor, and must have
  211. the same lifetime as the processor, as they will have dependencies on each other.
  212. */
  213. AudioProcessorValueTreeState (AudioProcessor& processorToConnectTo, UndoManager* undoManagerToUse);
  214. /** Destructor. */
  215. ~AudioProcessorValueTreeState() override;
  216. //==============================================================================
  217. #ifndef DOXYGEN
  218. /** Previous calls to
  219. @code
  220. createAndAddParameter (paramID1, paramName1, ...);
  221. @endcode
  222. can be replaced with
  223. @code
  224. using Parameter = AudioProcessorValueTreeState::Parameter;
  225. createAndAddParameter (std::make_unique<Parameter> (paramID1, paramName1, ...));
  226. @endcode
  227. However, a much better approach is to use the AudioProcessorValueTreeState
  228. constructor directly
  229. @code
  230. using Parameter = AudioProcessorValueTreeState::Parameter;
  231. YourAudioProcessor()
  232. : apvts (*this, &undoManager, "PARAMETERS", { std::make_unique<Parameter> (paramID1, paramName1, ...),
  233. std::make_unique<Parameter> (paramID2, paramName2, ...),
  234. ... })
  235. @endcode
  236. @see AudioProcessorValueTreeState::AudioProcessorValueTreeState
  237. This function creates and returns a new parameter object for controlling a
  238. parameter with the given ID.
  239. Calling this will create and add a special type of AudioProcessorParameter to the
  240. AudioProcessor to which this state is attached.
  241. */
  242. [[deprecated ("This function is deprecated and will be removed in a future version of JUCE! "
  243. "See the method docs for a code example of the replacement methods.")]]
  244. RangedAudioParameter* createAndAddParameter (const String& parameterID,
  245. const String& parameterName,
  246. const String& labelText,
  247. NormalisableRange<float> valueRange,
  248. float defaultValue,
  249. std::function<String (float)> valueToTextFunction,
  250. std::function<float (const String&)> textToValueFunction,
  251. bool isMetaParameter = false,
  252. bool isAutomatableParameter = true,
  253. bool isDiscrete = false,
  254. AudioProcessorParameter::Category parameterCategory = AudioProcessorParameter::genericParameter,
  255. bool isBoolean = false);
  256. #endif
  257. /** This function adds a parameter to the attached AudioProcessor and that parameter will
  258. be managed by this AudioProcessorValueTreeState object.
  259. */
  260. RangedAudioParameter* createAndAddParameter (std::unique_ptr<RangedAudioParameter> parameter);
  261. //==============================================================================
  262. /** Returns a parameter by its ID string. */
  263. RangedAudioParameter* getParameter (StringRef parameterID) const noexcept;
  264. /** Returns a pointer to a floating point representation of a particular parameter which a realtime
  265. process can read to find out its current value.
  266. Note that calling this method from within AudioProcessorValueTreeState::Listener::parameterChanged()
  267. is not guaranteed to return an up-to-date value for the parameter.
  268. */
  269. std::atomic<float>* getRawParameterValue (StringRef parameterID) const noexcept;
  270. //==============================================================================
  271. /** A listener class that can be attached to an AudioProcessorValueTreeState.
  272. Use AudioProcessorValueTreeState::addParameterListener() to register a callback.
  273. */
  274. struct JUCE_API Listener
  275. {
  276. virtual ~Listener() = default;
  277. /** This callback method is called by the AudioProcessorValueTreeState when a parameter changes.
  278. Within this call, retrieving the value of the parameter that has changed via the getRawParameterValue()
  279. or getParameter() methods is not guaranteed to return the up-to-date value. If you need this you should
  280. instead use the newValue parameter.
  281. */
  282. virtual void parameterChanged (const String& parameterID, float newValue) = 0;
  283. };
  284. /** Attaches a callback to one of the parameters, which will be called when the parameter changes. */
  285. void addParameterListener (StringRef parameterID, Listener* listener);
  286. /** Removes a callback that was previously added with addParameterCallback(). */
  287. void removeParameterListener (StringRef parameterID, Listener* listener);
  288. //==============================================================================
  289. /** Returns a Value object that can be used to control a particular parameter. */
  290. Value getParameterAsValue (StringRef parameterID) const;
  291. /** Returns the range that was set when the given parameter was created. */
  292. NormalisableRange<float> getParameterRange (StringRef parameterID) const noexcept;
  293. //==============================================================================
  294. /** Returns a copy of the state value tree.
  295. The AudioProcessorValueTreeState's ValueTree is updated internally on the
  296. message thread, but there may be cases when you may want to access the state
  297. from a different thread (getStateInformation is a good example). This method
  298. flushes all pending audio parameter value updates and returns a copy of the
  299. state in a thread safe way.
  300. Note: This method uses locks to synchronise thread access, so whilst it is
  301. thread-safe, it is not realtime-safe. Do not call this method from within
  302. your audio processing code!
  303. */
  304. ValueTree copyState();
  305. /** Replaces the state value tree.
  306. The AudioProcessorValueTreeState's ValueTree is updated internally on the
  307. message thread, but there may be cases when you may want to modify the state
  308. from a different thread (setStateInformation is a good example). This method
  309. allows you to replace the state in a thread safe way.
  310. Note: This method uses locks to synchronise thread access, so whilst it is
  311. thread-safe, it is not realtime-safe. Do not call this method from within
  312. your audio processing code!
  313. */
  314. void replaceState (const ValueTree& newState);
  315. //==============================================================================
  316. /** A reference to the processor with which this state is associated. */
  317. AudioProcessor& processor;
  318. /** The state of the whole processor.
  319. This must be initialised after all calls to createAndAddParameter().
  320. You can replace this with your own ValueTree object, and can add properties and
  321. children to the tree. This class will automatically add children for each of the
  322. parameter objects that are created by createAndAddParameter().
  323. */
  324. ValueTree state;
  325. /** Provides access to the undo manager that this object is using. */
  326. UndoManager* const undoManager;
  327. private:
  328. //==============================================================================
  329. class ParameterAdapter;
  330. public:
  331. //==============================================================================
  332. /** A parameter class that maintains backwards compatibility with deprecated
  333. AudioProcessorValueTreeState functionality.
  334. Previous calls to
  335. @code
  336. createAndAddParameter (paramID1, paramName1, ...);
  337. @endcode
  338. can be replaced with
  339. @code
  340. using Parameter = AudioProcessorValueTreeState::Parameter;
  341. createAndAddParameter (std::make_unique<Parameter> (paramID1, paramName1, ...));
  342. @endcode
  343. However, a much better approach is to use the AudioProcessorValueTreeState
  344. constructor directly
  345. @code
  346. using Parameter = AudioProcessorValueTreeState::Parameter;
  347. YourAudioProcessor()
  348. : apvts (*this, &undoManager, "PARAMETERS", { std::make_unique<Parameter> (paramID1, paramName1, ...),
  349. std::make_unique<Parameter> (paramID2, paramName2, ...),
  350. ... })
  351. @endcode
  352. */
  353. class Parameter final : public AudioParameterFloat
  354. {
  355. public:
  356. /** Constructs a parameter instance.
  357. Example usage:
  358. @code
  359. using Parameter = AudioProcessorValueTreeState::Parameter;
  360. using Attributes = AudioProcessorValueTreeStateParameterAttributes;
  361. auto parameter = std::make_unique<Parameter> (ParameterID { "uniqueID", 1 },
  362. "Name",
  363. NormalisableRange<float> { 0.0f, 100.0f },
  364. 50.0f,
  365. Attributes().withStringFromValueFunction (myStringFromValueFunction)
  366. .withValueFromStringFunction (myValueFromStringFunction)
  367. .withLabel ("%"));
  368. @endcode
  369. @param parameterID The globally-unique identifier of this parameter
  370. @param parameterName The user-facing name of this parameter
  371. @param valueRange The valid range of values for this parameter
  372. @param defaultValue The initial parameter value
  373. @param attributes Further advanced settings to customise the behaviour of this parameter
  374. */
  375. Parameter (const ParameterID& parameterID,
  376. const String& parameterName,
  377. NormalisableRange<float> valueRange,
  378. float defaultValue,
  379. const AudioProcessorValueTreeStateParameterAttributes& attributes = {});
  380. [[deprecated ("Prefer the signature taking an Attributes argument")]]
  381. Parameter (const ParameterID& parameterID,
  382. const String& parameterName,
  383. const String& labelText,
  384. NormalisableRange<float> valueRange,
  385. float defaultParameterValue,
  386. std::function<String (float)> valueToTextFunction,
  387. std::function<float (const String&)> textToValueFunction,
  388. bool isMetaParameter = false,
  389. bool isAutomatableParameter = true,
  390. bool isDiscrete = false,
  391. AudioProcessorParameter::Category parameterCategory = AudioProcessorParameter::genericParameter,
  392. bool isBoolean = false)
  393. : Parameter (parameterID,
  394. parameterName,
  395. valueRange,
  396. defaultParameterValue,
  397. AudioProcessorValueTreeStateParameterAttributes().withLabel (labelText)
  398. .withStringFromValueFunction ([valueToTextFunction] (float v, int) { return valueToTextFunction (v); })
  399. .withValueFromStringFunction (std::move (textToValueFunction))
  400. .withMeta (isMetaParameter)
  401. .withAutomatable (isAutomatableParameter)
  402. .withDiscrete (isDiscrete)
  403. .withCategory (parameterCategory)
  404. .withBoolean (isBoolean))
  405. {
  406. }
  407. float getDefaultValue() const override;
  408. int getNumSteps() const override;
  409. bool isDiscrete() const override;
  410. bool isBoolean() const override;
  411. private:
  412. void valueChanged (float) override;
  413. std::function<void()> onValueChanged;
  414. const float unsnappedDefault;
  415. const bool discrete, boolean;
  416. std::atomic<float> lastValue { -1.0f };
  417. friend class AudioProcessorValueTreeState::ParameterAdapter;
  418. };
  419. //==============================================================================
  420. /** An object of this class maintains a connection between a Slider and a parameter
  421. in an AudioProcessorValueTreeState.
  422. During the lifetime of this SliderAttachment object, it keeps the two things in
  423. sync, making it easy to connect a slider to a parameter. When this object is
  424. deleted, the connection is broken. Make sure that your AudioProcessorValueTreeState
  425. and Slider aren't deleted before this object!
  426. */
  427. class JUCE_API SliderAttachment
  428. {
  429. public:
  430. SliderAttachment (AudioProcessorValueTreeState& stateToUse,
  431. const String& parameterID,
  432. Slider& slider);
  433. private:
  434. std::unique_ptr<SliderParameterAttachment> attachment;
  435. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (SliderAttachment)
  436. };
  437. //==============================================================================
  438. /** An object of this class maintains a connection between a ComboBox and a parameter
  439. in an AudioProcessorValueTreeState.
  440. Combobox items will be spaced linearly across the range of the parameter. For
  441. example if the range is specified by NormalisableRange<float> (-0.5f, 0.5f, 0.5f)
  442. and you add three items then the first will be mapped to a value of -0.5, the
  443. second to 0, and the third to 0.5.
  444. During the lifetime of this ComboBoxAttachment object, it keeps the two things in
  445. sync, making it easy to connect a combo box to a parameter. When this object is
  446. deleted, the connection is broken. Make sure that your AudioProcessorValueTreeState
  447. and ComboBox aren't deleted before this object!
  448. */
  449. class JUCE_API ComboBoxAttachment
  450. {
  451. public:
  452. ComboBoxAttachment (AudioProcessorValueTreeState& stateToUse,
  453. const String& parameterID,
  454. ComboBox& combo);
  455. private:
  456. std::unique_ptr<ComboBoxParameterAttachment> attachment;
  457. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ComboBoxAttachment)
  458. };
  459. //==============================================================================
  460. /** An object of this class maintains a connection between a Button and a parameter
  461. in an AudioProcessorValueTreeState.
  462. During the lifetime of this ButtonAttachment object, it keeps the two things in
  463. sync, making it easy to connect a button to a parameter. When this object is
  464. deleted, the connection is broken. Make sure that your AudioProcessorValueTreeState
  465. and Button aren't deleted before this object!
  466. */
  467. class JUCE_API ButtonAttachment
  468. {
  469. public:
  470. ButtonAttachment (AudioProcessorValueTreeState& stateToUse,
  471. const String& parameterID,
  472. Button& button);
  473. private:
  474. std::unique_ptr<ButtonParameterAttachment> attachment;
  475. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ButtonAttachment)
  476. };
  477. private:
  478. //==============================================================================
  479. /** Code that looks like this:
  480. @code
  481. auto paramA = apvts.createParameter ("a", "Parameter A", {}, { -100, 100 }, ...);
  482. auto paramB = apvts.createParameter ("b", "Parameter B", {}, { 0, 5 }, ...);
  483. addParameterGroup (std::make_unique<AudioProcessorParameterGroup> ("g1", "Group 1", " | ", std::move (paramA), std::move (paramB)));
  484. apvts.state = ValueTree (Identifier ("PARAMETERS"));
  485. @endcode
  486. can instead create the APVTS like this, avoiding the two-step initialization process and leveraging one of JUCE's
  487. pre-built parameter types (or your own custom type derived from RangedAudioParameter):
  488. @code
  489. using Parameter = AudioProcessorValueTreeState::Parameter;
  490. YourAudioProcessor()
  491. : apvts (*this, &undoManager, "PARAMETERS",
  492. { std::make_unique<AudioProcessorParameterGroup> ("g1", "Group 1", " | ",
  493. std::make_unique<Parameter> ("a", "Parameter A", "", NormalisableRange<float> (-100, 100), ...),
  494. std::make_unique<Parameter> ("b", "Parameter B", "", NormalisableRange<float> (0, 5), ...)) })
  495. @endcode
  496. */
  497. [[deprecated ("This method was introduced to allow you to use AudioProcessorValueTreeState parameters in "
  498. "an AudioProcessorParameterGroup, but there is now a much nicer way to achieve this. See the "
  499. "method docs for a code example.")]]
  500. std::unique_ptr<RangedAudioParameter> createParameter (const String&, const String&, const String&, NormalisableRange<float>,
  501. float, std::function<String (float)>, std::function<float (const String&)>,
  502. bool, bool, bool, AudioProcessorParameter::Category, bool);
  503. //==============================================================================
  504. #if JUCE_UNIT_TESTS
  505. friend struct ParameterAdapterTests;
  506. #endif
  507. void addParameterAdapter (RangedAudioParameter&);
  508. ParameterAdapter* getParameterAdapter (StringRef) const;
  509. bool flushParameterValuesToValueTree();
  510. void setNewState (ValueTree);
  511. void timerCallback() override;
  512. void valueTreePropertyChanged (ValueTree&, const Identifier&) override;
  513. void valueTreeChildAdded (ValueTree&, ValueTree&) override;
  514. void valueTreeRedirected (ValueTree&) override;
  515. void updateParameterConnectionsToChildTrees();
  516. const Identifier valueType { "PARAM" }, valuePropertyID { "value" }, idPropertyID { "id" };
  517. struct StringRefLessThan final
  518. {
  519. bool operator() (StringRef a, StringRef b) const noexcept { return a.text.compare (b.text) < 0; }
  520. };
  521. std::map<StringRef, std::unique_ptr<ParameterAdapter>, StringRefLessThan> adapterTable;
  522. CriticalSection valueTreeChanging;
  523. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioProcessorValueTreeState)
  524. };
  525. } // namespace juce