Which parameter paradigm is recommended?

I’m a bit confused. There seems to be two completely different paradigms for parameters and their visualisation and the newer paradigm seems to break Juce own Coding Standard and is also hard to understand from a design perspective.

In the tutorial Control audio levels parameters and their gui-controller are added as actual members to some main class (in this case an inheritor of AudioAppComponent). It’s corresponding slider and the sliders size etc are set in the constructor and resized(). All fine I understand how this works.

But in the tutorial Adding plug-in parameters a completely different paradigm is used, where the parameter instead is a pointer and must(?) be initialized with a new. Since projects often have a lot of parameters there’s going to be a lot of new but the Coding Standard says:

“Do not use new unless there’s no alternative. Whenever you type new , always treat it as a failure to find a better solution.”

So this is a failure? I read in the tutorial explaining why it’s “safe” to use raw pointers in this case and I’m sure that’s correct but what is the actual benefit on making raw pointers in the first place when it’s not recommended and there was already a solution not using raw pointers?

Also this parameter is only a parameter with no obvious connection to the design of it’s control (a slider in this case) so I have no clue on where to go to alter the design , size e.t.c. of the slider.

To me the “old style” seems much more direct, useful and nice looking but of course if there’s a huge drawback I miss here I will use the new standard. What would that be? And anyone who can point me to the direction of understanding how to resize and design the corresponding gui-component to a AudioParameter-pointer?

It’s totally fine to use new if the lifetime of the object you’re creating is going to be handled by some RAII container, like a smart pointer.

For example
std::unique_ptr<Object> object = new Object{ someParameters };

Although a better alternative would be
auto object = std::make_unique<Object> (someParameters);

The “Adding plug-in parameters” tutorial uses a method of adding parameters that I wouldn’t recommend (adding them to the processor directly). Instead, I’d recommend following the way it’s doing in Saving and loading your plug-in state.

Great, thanks. Yes, having a quick look it seems it also covers the GUI aspect and saving the state is obviously also very important.

It’s a bit confusing with the tutorials that sometimes takes you in different directions.

I don’t think that would compile, but there is a constructor taking a raw pointer:

std::unique_ptr<Object> object (new Object (someParameters));

I followed the link though and couldn’t find new in any code example?

And another thing: The tutorials are partially standalone apps, where the AudioProcessorParameter classes are not usable. That might explain the differences, together with the passing time and changing best practices.

The link to the second example was wrong, now corrected. new is on line 58 in AudioParameterTutorial_01.h

Am I right to assume these two are completely equivalent?

I think so yes. There is a minor difference but I doubt in practice you could tell the difference:

  • the make_unique will create a unique_ptr and move it to the lValue
  • the constructor will create an empty unique_ptr (pointing to nullptr) and reset it to the pointee

So you might get a different byte code, but maybe not.

The corrected link can be explained: addParameter is a very old function that takes a raw pointer and will manage it, see the docs for addParameter (AudioProcessorParameter*):

Adds a parameter to the AudioProcessor.

The parameter object will be managed and deleted automatically by the AudioProcessor when no longer needed.

A modern version should probably look like:

void addParameter (std::unique_ptr<AudioProcessorParameter>&& newParameter);

Maybe we will see this in the future

OK thanks.

I’m not sure I understand the constructs with two ampersands and how you mean this would be used but I might save that for a rainy day. It’s perhaps a bit too advanced topics for me right now. :slightly_smiling_face:

The two && is the so called move operator. That means when calling that function, the argument will be moved into the function rather than copied or referenced. This is the only way to transfer ownership with a std::unique_ptr.
Please be aware that in the calling scope the unique_ptr will become invalidated and mustn’t be used afterwards. Otherwise the object would be owned in two places (which is the reason why unique_ptr is not copyable in the first place).

OK, thanks.