AudioParameterFloat taking abstract NormalisableRange parent class ptr instead of a NormalisableRange object

Right now you are stuck with the ValueRemapFunctions, which are really annoying whenever your additional Range behaviour needs additional member variables or subclassing for some other reason.

Instead of subclassing the (right now not existing) abstract normalisableRange parent class, I need to generate a normalisableRange from my other range implementation:

//in my norm range class

juce::NormalisableRange<FloatType> getNormRange(float start, float end, float interval)
        auto fromNorm = [this] (float start, float end, float value) {
            return this->xToY (value);
        auto toNorm = [this] (float start, float end, float value) {
            return this->yToX (value);

        juce::NormalisableRange<float> range (start, end,{ fromNorm }, { toNorm });
        range.interval = interval;
        return range;

The problem is, that now my other object must be alive during the life time of the normalisableRange object.
Creating a new object of my range class in every ValueRemapFunction would be way too expensive for per-sample host automation.
Using static would maybe work, but then I have to instantiate my class three times instead of one time + I want to avoid static as much as possible when dealing with audio plugins.

Any thoughts on this? Am I missing something?

You don’t need statics or additional members for your mapping functions.
Since they are std::functions you can capture a member of your processor by reference. If this leads to a great UX is a different question, but it should solve your use case.

Neglecting that JUCE doesn’t implement per-sample automation anyway, by making it abstract you are adding the overhead of a virtual call. However I don’t know what is worse: a virtual call or calling a std::function…


I feel like these are workarounds and the abstract class would be the OO way of doing it

I learned OO with Smalltalk ST-80. so I feel like you. However, in performance critical places it is better to minimise the use of OO.
But like I mentioned above, std::function might be worse.

I have no conclusive opinion if an abstract NormalisableRange is a good idea or not.

i think there are some pretty good examples of parameter types where these functions depend on other parameter states and stuff. for example:

  1. a delay’s or lfo’s rate parameter that depends on the state of the temposync switch to define if it paints its values in hz or beats.

  2. a panning parameter that paints L and R at -1 and 1, but only if the plugin is not in mid/side mode rn, in which case it’s M and S ofc.

  3. a pitch parameter where inputting a frequency value (400hz) evaluates to different pitches according to the state of the tuning parameters (master tune, base pitch, xen scale etc)

so what i usually do in these cases:

either i discard the idea entirely because it turns out not being useful anyway (like with the rate parameters that could also just be 2 individual rate parameters where only one is visible in the gui),
or i put state into the processor as a member or reference other parameters in those functions (like the panning one).