Best way to handle parameter units in an audio plugin?


(Edited to clarify my question a bit)

I’m using an AudioProcessorValueTreeState to handle the parameters in my audio plugin. I’m guessing this is still the recommended best practice for this sort of thing? If not, I’m open for suggestions!

What is considered best practice regarding ranges and units for parameters in audio plugins in JUCE?

What I’ve done so far is that I’ve given all unipolar parameters the range 0.0 - 1.0, all bipolar parameters -1.0 - 1.0, and stepped parameters are A…B with step 1 (i e NormalisableRange<float> (A, B, 1.0f)).

In my editor I create my Sliders and SliderAttachments, and I enable popup displays on my Sliders by calling Slider.setPopupDisplayEnabled(true, true, nullptr).

But the tooltip will of course only show the “normalized value” of each parameter. So it will say “0.244375”, although I’d prefer to have it say something like “Room Mix: 24%” instead.

I thought that implementing the valueToText and textToValue functions when adding the parameters to the value tree would have an effect on the tooltips, but they seem to stay the same?

What would be the recommended way to change the formatting of the tooltips? Maybe I have overlooked something obvious in the API, or maybe I am going the wrong way about this entirely?

I don’t mind completely redoing the way I handle parameters if there’s a better way to do it.


That’s strange, the attachment sets the slider’s textFromValueFunction based off of what the parameter’s text conversion function is… Obviously the SliderAttachment is there since the slider displays the parameter value, but are you sure the parameter has lambdas provided for text-to-value and value-to-text? Does your slider have a text box that also exhibits this issue?


I’m not using lambdas, but function pointers, i e:

parameters.createAndAddParameter("ambience_level", "Ambience Level", "Ambience", NormalisableRange<float>(0.0f, 1.0f), settings.getAmbienceLevel(), toPercent, fromPercent);


static String toPercent(float value) { return String(std::round(value * 100)) + "%"; }

The code compiles, it just doesn’t seem to make any difference… My sliders don’t have any text boxes, just tooltips.


Yes, the SliderAttachment only forwards the lambdas, not the function pointers, AFAIK.
You can inherit the Slider and use the same function there, but the more modern approach is to use the lambdas:

parameters.createAndAddParameter("ambience_level", "Ambience Level", "Ambience", 
        NormalisableRange<float>(0.0f, 1.0f), settings.getAmbienceLevel(), 
        [] (float value) { return String (std::round (value * 100.0f)) + "%"; }, 
        [] (String text) { return text.dropLastCharacters (1).getFloatValue() / 100.0f; } );


I tried using lambdas as you suggested, but I still see the internal parameter value in the tooltip instead of the text…

I’m using my own subclass of Slider, but I’m only overriding paint(), so I’m thinking that shouldn’t be a problem?

But if I use the following methods instead:

ambienceLevelSlider->setRange(0, 100, 1);

Then it will show the value as “55%” etc! But I can’t make it say something like “Room Mix: 55%”, unless I override Slider::getTextFromValue(), I guess?


The lambdas are copied in the moment you are creating the SliderAttachment. You can easily replace them in your GUI afterwards with a different lambda than used in the processor setting the public member Slider::textFromValueFunction.

In your case:

ambienceLevelSlider->textFromValueFunction = [](double value)
{ return "Room Mix: " + String (value) + "%"; } );
ambienceLevelSlider->valueFromTextFunction = [](String text)
{ return text.subString (10).dropLastCharacters (1).getDoubleValue() / 100.0; } );

Even nicer would be, to keep the name out, so you can re-use the lambdas:

ambienceLevelSlider->setName ("Room mix");

ambienceLevelSlider->textFromValueFunction = [slider = *ambienceLevelSlider](double value)
{ return slider.getName() + ": " + String (value) + "%"; } );
ambienceLevelSlider->valueFromTextFunction = [slider = *ambienceLevelSlider](String text)
{ return text.subString (slider.getName().length() + 2).dropLastCharacters (1).getDoubleValue() / 100.0; } );


I don’t have those fields in Slider, it seems they were added recently? I’m on JUCE 5.2.0 from October 2017. But they would certainly take care of my problem, so I guess it’s time to upgrade to the latest version of JUCE now. :smiley:

Thank you so much for your help, I really appreciate it!