New way of adding parameters to AudioProcessorValueTreeState not sufficient for many, identical parameters

The latest tip of the develop branch has deprecated the AudioProcessorValueTreeState::createParameter method in favour of creating parameters in the APVTS constructor:


However, this isn’t at all sufficient for plug-ins with many, duplicated parameters.

In my case, I have a plug-in with N filters (where N is a constant defined in a header file) and each filter has parameters for corner, gain, q, etc. and so I use a simple for loop to create the parameters using APVTS::createParameter.
What would be the recommended way of doing this now, I don’t fancy having a mess of copy-pasted code to setup all my parameters!

1 Like

There’s a version of the function that takes a unique ptr:

I had considered using createAndAddParameter but from what I understand I can’t then add that parameter to a group since it’s added directly to the processor?

Maybe you can achieve it in the way it’s doing it internally:

I’m not super familiar with these new changes but it looks like you may be able to create your parameters and group(s) and still pass the parameters to the createAndAddParameter() function

Here’s one way of doing it:

AudioProcessorValueTreeState::ParameterLayout createParameterLayout()
{
    std::vector<std::unique_ptr<AudioParameterInt>> params;

    for (int i = 1; i < 9; ++i)
        params.push_back (std::make_unique<AudioParameterInt> (String (i), String (i), 0, i, 0));

    return { params.begin(), params.end() };
}

YourAudioProcessor()
    : parameters (*this, &undoManager, "PARAMS", createParameterLayout())
5 Likes

You can also iterate over AudioProcessorParameterGroups in the same manner.

1 Like

This works great, thanks Tom!

Also means I can use AudioParameterInt/Float/Bool again which is nice! :slight_smile:

Hi,
I am writing a dynamic plugin that loads from an XML document. The different process blocks are connected using AudioProcessorGraph. Each process block requires different parameters depending on what it is. It will be fully user editable. I have to load a couple of hundred unnamed parameters and add/remove names to show/hide. It appears as though a number of other JUCE users are doing similar projects, especially synths. Over the years of threads, there was always a hint of JUCE supporting dynamic parameters. Being able to load parameters based on an initial presets would have been great. This latest change appears to be a definitive move away creating parameters from a preset.
Thank you

How so? I can’t see how this change has changed anything too drastically in that regard.

1 Like

I am not the best programmer, but I am learning.
It appears that some limited parameter creation can still happen in setStateInformation. I am still looking through the JUCE code to see when setStateInformation occurs, but I assume the DAW gets the initial preset before setting up final DAW automation, etc. APVTS and the new groups are limited to initialisation, before loading this initial preset.
I love what JUCE are doing, but I am wondering if they are painting the code into an unnecessary corner.
Thank you

They were previously limited to the constructor, so almost nothing has changed there. Whilst these APVTS improvements are related to parameter management, supporting a dynamic number of parameters is a separate issue.

Hi Tom,
Thank you so much for your time. You are very talented and I mean no disrespect.

I am aware of this. I have added groups. They are fantastic. I love the idea fo specialisation of parameter types, this will replace a lot of my coding.
Does the consolidation of the methods, to a single initialisation, indicate that they will not ever be able to be used in setStateInformation, though the plugin architecture may have technically allowed some form of APVTS to be used in setStateInformation. I still have to look further into the order of method calls for parameter creation and setStateInformation.
Thanks

No disrespect taken at all!

Previously you still needed to fix the number of APVTS parameters in the constructor, before any call to setStateInformation. What sort of limited parameter creation are you thinking of?

I currently show or hide parameters based on extra information stored in my preset XML file. I would love to eventually be able to create the APVTS based on this saved information.
Thanks

Hi Tom,
Can any of my large number of the parameters be edited in the initial setStateInformation? For example can the parameter Lamdas be added on a per needs basis in the initial setStateInformation?
Thank you

Not the answer for what you asked, but kind of:
You can’t rely on that there is a setStateInformation at all. A host does not know anything about your plugin’s save format at all. There has to be at least one getStateInformation call before (could have happened in a previous session, that is now being restored).
Many hosts send only one time a setStateInformation, when a session is restored, but not at all for a new session.

If you use your own RangedAudioParameter subclass then you can do whatever modifications you wish. The difficulty is propagating this information via the plug-in SDKs to the host. For example, parameter name changes have only just become possible via the VST3 SDK (and are not yet supported by JUCE):

With dynamic parameter ranges you may have differing levels of success in different hosts and formats.

Thank you both for that info.

The issue:
I used Projucer 5.4.1 to create new Audio Plug-In project for VS2017 platform on Windows 7.

I am getting the follwing error when trying to build on MSVC2017.

1>…\testplugin\source\pluginprocessor.cpp(41): error C2440: ‘=’: cannot convert from ‘float *’ to ‘int *’
1>…\testplugin\source\pluginprocessor.cpp(41): note: Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast

…pointing at line:

test_int_Parameter = parameters.getRawParameterValue(“test_int”);

I made following changes in Projucer settings:
ticked: Plugin MIDI Input, Plugin MIDI output, MIDI Effect Plugin.

…and following are the only changes I made to code generated by Projucer:

in “PluginProcessor.h

class TestPluginAudioProcessor  : public AudioProcessor
{
public:
  /* ... */

private:
	AudioProcessorValueTreeState parameters;  // ja:testbug
	float* test_float_Parameter;
	int*   test_int_Parameter  ;
    //==============================================================================
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TestPluginAudioProcessor)
};

in “PluginProcessor.cpp” :

TestPluginAudioProcessor::TestPluginAudioProcessor()
#ifndef JucePlugin_PreferredChannelConfigurations
     : AudioProcessor (BusesProperties()
                     #if ! JucePlugin_IsMidiEffect
                      #if ! JucePlugin_IsSynth
                       .withInput  ("Input",  AudioChannelSet::stereo(), true)
                      #endif
                       .withOutput ("Output", AudioChannelSet::stereo(), true)
                     #endif
                       )
#endif
	, parameters(*this, nullptr, Identifier("APVTSTutorial"),
		{
			std::make_unique<AudioParameterFloat>("test_float",       // parameter ID
												  "test float",       // parameter name
												   0.0f,              // minimum value
												   1.0f,              // maximum value
												   0.5f),             // default value
			std::make_unique<AudioParameterInt>  ("test_int",         // parameter ID
												   "test int",        // parameter name
												   0.0f,              // minimum value
												   1.0f,              // maximum value
												   0.5f)              // default value
		})
{
	test_float_Parameter = parameters.getRawParameterValue("test_float");
	test_int_Parameter   = parameters.getRawParameterValue("test_int");   // error C2440: '=': cannot convert from 'float *' to 'int *'

}

Please advise.

Just a guess. Should they be ints?

AudioParameterInt::AudioParameterInt (const String& idToUse, const String& nameToUse,
                                  int minValue, int maxValue, int def