AudioProcessorParameter and their indices

I've developed a bunch of plug-ins over the past years using the "indexed" methods in AudioProcessor to let the host access the automated parameters.

The mapping "host index"->"internal parameter" was explicit in each of those methods (be it an array index, a big switch/case, whatever).

Now, with AudioProcessorParameter (which I like for the most part), I get that each parameter is assigned its automation index incrementally, depending on the order of the AudioProcessor::addParameter() calls.

So let's say I start with my plug-in having two parameters for "low" and "high" eq, for example:

processor->addParameter (lowGain);    // index: 0
processor->addParameter (highGain);   // index: 1

After a first release, I decide to add a "mid" eq. The natural place where I will feel it is appropriate to add it is between those two, so

processor->addParameter (lowGain);    // index: 0
processor->addParameter (midGain);    // index: 1
processor->addParameter (highGain);   // index: 2

Now, all sessions where the "high" of my plug-in was automated (with index 1) will automate the "mid" parameter after the update.

Now I wonder, wouldn't it be appropriate to leave a chance to developers to explictly state which index they want to use, in order to cope with similar scenarios?

Perhaps something along the lines of:

processor->insertParameter (lowGain, 0);
processor->insertParameter (midGain, 2);
processor->insertParameter (highGain, 1);

So that one can add the parameters in their most natural order, and still have the existing parameter indices unchanged throughout the lifetime of the plug-in.

(in my case, I totally would add an enum that lists the parameters in the order they have been added to the project, and then use those as automation indices: ).

enum AutomationIndex { indexLow = 0, indexHigh = 1, indexMid = 2 };

processor->insertParameter (lowGain,  indexLow);
processor->insertParameter (midGain,  indexMid);
processor->insertParameter (highGain, indexHigh);

That seems like it'd be a bit convoluted and confusing.. Maybe you could do it by using your own class that knows its intended index, then add all your parameters to a temporary array, sort the array by their index, then add them in that order to the AudioProcessor?

The solution that you suggest is the convoluted one, in my opinion:

It is made more so by one aspect I left out of my example, but applied to my real use case:

The "guts" of my AudioProcessor is a chain of simpler effects (Volume, Eq, etc), each of which has its automated parameters.

The most straightforward implementation of that is to have the automated parameters added in each effect constructor.

If I change the creation order of the effects, I end having a different order for the parameters of the AudioProcessor, while if I were allowed to specify the index at which I want each parameter, the order of parameters will be guaranteed no matter what order I follow for instantiating my effects.

Also, if I had to add all those parameters to a "temporary" array, to be sorted later on for the sole purpose of adding the parameters in the right order, this means that I should expose this temporary array to the single effects, while in the current implementation it would be enough to pass them a reference to the AudioProcessor in which they will operate, that they should get anyway.

 

Final note, upon re-reading my post I realize that insertParameter() is not what I meant actually, in the sense of the insert() method in arrays.

The behavior I actually described is the one of a

setParameter (parameterInstance, index)

which sets the given parameter instance at the given postion in the array of AudioProcessorParameters, enlarging it to a size of index + 1 if it is not big enough.

This would also add back one side feature that was present with the indexed parameters of AudioProcessor but that is now missing when adding AudioProcessorParameters:  the possibility to leave some indices unused/spare/reserved for future usage. With the current implementation, all indices are assigned by addParameter() without the possibility to leave gaps, meaning that if additional parameters are to be added in later versions of the plug-in, they will have to forcibly be appended at the end of the array. Or am I missing something?

Personally, if I was writing that, I'd give these smaller effects a virtual method that returns an array of their parameters, and then assemble them in the correct order.

The main reason I avoided a set/insert method is because I deliberately don't want to have gaps in the list! That would cause problems for the many, many places in the codebase where it expects a plugin to have a list of parameters, and which absolutely do not expect them to be null. The ripple effects of making a change like that could cause horrible edge-case errors in lots of code!

Sigh.. let the proliferation of DummyReservedParameter instances begin, then :(