Make logarithmic slider attached to an AudioParameterFloat

On my plugin I create a simple slider for volume.
I created on PluginProcessor.h an AudioProcessorValueTreeState instance,
on PluginProcessor.cpp on constructor added this code:
processorValueTreeState(* this , nullptr , Identifier(“processorValueTree”),
{
std::make_unique(“volume”, “Volume”, -120.0f, 6.0f , 0.0f)
}
and finally on my PluginEditor I created a SliderAttachment to attach that AudioParameterFloat to a slider created on editor.
All works, but I’d like that the behave of my slider should be as, for example , the behave of a cubase volume slider. Actually it works in linear way and also if I open the automation lane of plugin on Cubase this works in linear way. How can I do?

Really thank you in advice!

Slider::setSkewFactor

1 Like

Thank you for answer!
I try to use it, but it seems that nothing happens…

post your code. place three tick marks ``` around it to format it.

Edit: to set the skew factor of your parameter so it shows up properly in automation, you may want to be using the skewFactor field in the constructor of NormalisableRange when you create the parameter itself.

1 Like

On my PluginProcessor.h:

AudioProcessorValueTreeState processorValueTreeState;

On my PluginProcessor.cpp:

#ifndef JucePlugin_PreferredChannelConfigurations
     : AudioProcessor (BusesProperties()
                     #if ! JucePlugin_IsMidiEffect
                      #if ! JucePlugin_IsSynth
                       .withInput  ("Input",  AudioChannelSet::stereo(), true)
                      #endif
                       .withOutput ("Output", AudioChannelSet::stereo(), true)
                     #endif
                       ),
#endif
processorValueTreeState(*this, nullptr, Identifier("processorValueTree"),
{
    std::make_unique<AudioParameterFloat>("volume", "Volume", -120.0f, 6.0f , 0.0f),
    std::make_unique<AudioParameterInt>("panpot", "Panpot", -100, 100 , 0),
    std::make_unique<AudioParameterBool>("mute", "Mute", false)
}) {}

On My PluginEditor.h:

{
public:
    MyProcessorEditor (MyProcessorEditor&, AudioProcessorValueTreeState&);
    ~MyProcessorEditor();

    //==============================================================================
    void paint (Graphics&) override;
    void resized() override;

private:
    
    typedef AudioProcessorValueTreeState::SliderAttachment SliderAttachment;
    typedef AudioProcessorValueTreeState::ButtonAttachment ButtonAttachment;
    
    MyProcessor& processor;
    
    Slider volume{"volume"}, panpot{"panpot"};
    
    Rectangle<float> panpotRect;
    Rectangle<float> volumeRect;
    Rectangle<float> otherRect;
    
    std::unique_ptr<SliderAttachment> volumeAttachment;
    std::unique_ptr<SliderAttachment> panpotAttachment;
    std::unique_ptr<ButtonAttachment> muteAttachment;
    
    AudioProcessorValueTreeState& valueTreeState;
};

On my ProcessorEditor.cpp:

MyProcessorEditor::MyProcessorEditor (MyProcessor& p, AudioProcessorValueTreeState& vts)
    : AudioProcessorEditor (&p), processor (p), valueTreeState (vts)
{
    setSize (250, 580);
    
    addAndMakeVisible(volume);
    addAndMakeVisible(panpot);
    addAndMakeVisible(mute);
    
    volume.setSliderStyle(Slider::LinearVertical);
    volume.setTextBoxStyle(Slider::TextBoxBelow, false, 100, 20);
    volume.setColour(Slider::textBoxOutlineColourId, Colour());
    volume.setColour(Slider::trackColourId, getLookAndFeel().findColour(Slider::backgroundColourId));
    volume.setRange(-120, 6.0);
    volume.setSkewFactor('xyz?');
    
    panpot.setSliderStyle(Slider::LinearHorizontal);
    panpot.setTextBoxStyle(Slider::TextBoxBelow, false, 100, 20);
    panpot.setColour(Slider::textBoxOutlineColourId, Colour());
    panpot.setColour(Slider::trackColourId, getLookAndFeel().findColour(Slider::backgroundColourId));
    panpot.setRange(-100, 100);
    
    mute.setClickingTogglesState(true);
    mute.setColour(TextButton::buttonOnColourId, Colour::fromRGB(15, 18, 20));
    mute.setWantsKeyboardFocus(false);
    
    volumeAttachment.reset (new SliderAttachment (valueTreeState, "volume", volume));
    panpotAttachment.reset (new SliderAttachment (valueTreeState, "panpot", panpot));
    muteAttachment.reset (new ButtonAttachment (valueTreeState, "mute", mute));

Really ThankYou Again!! :slight_smile:

First note: using a SliderAttachment will undo all settings you did before on your slider.

Then: for consistency it is advisable to set the range, step and skew in the constructor of AudioParameterFloat, namely the NormalisableRange.

Third: if you wanted to use the setSkewFromMidPoint, that is not available in the constructor, but you can nick the formula of the NormalisableRange:

(partly repeating Holy_City :slight_smile: )

1 Like

Thank you guys! Now it’s so much better! But other 2 questions, I don’t find any skew factor that make my fader perfectly as cubase fader (this sounds like my whim, but I really need it for my pupose), I try also to use volumeRange.setSkewForCentre(-8.31) where -8.31 is the value of cubase’s fader centre, but is not really the same. Moreover using skew factor it doesn’t reaches the max value of 6.02 but a maximum of 6.0199966, there’s a way to fix it? And there’s a way to round up the value to forget the numbers after hundredths?

Really thank you again!

Technically, a floating-point value cannot represent 6.02 exactly. However, you are free to display floating points as if they were rounded to a specific decimal point.

Using a NormalisableRange when creating your parameter, in addition to the skewFactor, you can specify the intervalValue, which describes the “step size” that numbers will “snap” to. (Or, you can specify a snapToLegalValue function to do that conversion yourself.)

So you could specify 0.01 as an intervalValue, and your displayed results would snap to 6.02 automatically.

Or, you could address the difference yourself in whatever you use to display the value, such as by multiplying the parameter value by 100, rounding to the nearest integer, then converting that to a string and inserting a decimal point in the desired position.

There are probably other way to handle that as well.

@HowardAntares really thank you! Now this thing works! But what could be the best way to use a custom scale for the slider? Let say I find my function how can I Apply to my NormalisableRange? When I set a skew it apply always the same formula changing only that skew parameter.

Sorry for trouble and thank you again!

I would think about my data model. The stored number, that the host sees is a number between 0 and 1. And if you program a ramp in the automation, it will be a straight line. None of the settings about skew etc. matters to the host.

For instance a level slider, you could define the float number as factor (gain) or as dB value (level).
In the first case, the DSP can simply multiply, but the display will probably convert from gain to level using Decibels::gainToDecibels().
The other case will display the accurate dB value in the slider, but the DSP has to convert it each time to a factor it can apply.

BTW. if you have it as level, it is no problem to convert decibelsToGain once a processBlock. But I would try to avoid it for each sample.

1 Like

Thank you, but in this way I would only change the graphic of the slider, wouldn’t it?

No, it actually changes the behaviour.

Imagine you program a linear ramp in the automation: if the slider value is defined as gain, after 50% it reaches the factor 0.5 = -6 dB. But if it is defined as level from -100 dB to 0 dB, it reaches after 50 % a value of -50 dB = 0.003 factor.