NormalisableRange skew factor in custom Sliders doesn't work?

I’m using an AudioParameterValueTreeState and SliderAttachments with my custom Sliders, I have some AudioParameterFloats set up with NormalisableRanges, here’s an example:

layout.add(std::make_unique<juce::AudioParameterFloat>(
        "HpfFreq", 
        "HPF Freq", 
        juce::NormalisableRange<float>(20.f, 20000.f, 1.f, 0.30f), // min, max, step, skew
        20.f
    ));

The min, max, and steps work perfectly, but the skew factor seems to be ignored.

My custom Slider keeps a pointer to the parameter, so I’ve tried to get around this by going setSkewFactor((double) m_param->getNormalisableRange().skew) in the constructor, but that didn’t help. I’ve searched for help in the forum in similar topics, but those didn’t seem to help either, any advice would be appreciated!

The parameter creation looks good.

The SliderAttachment should take care of applying the skew to the Slider, so calling the setSkewFactor should not be required.

Random things to check that I can think of

  • Making sure that you add the parameter to the layout before creating the APVTS from that layout
  • Checking that just creating a SliderAttachment with a non-custom Slider and the same apvts instance and the HpfFreq id works correctly. It should.

Then if your custom slider inherits from juce::Slider it should keep working as you keep adding extra behaviour.

Also I’ve found, that you can achieve a lot just by changing the LookAndFeel for the Slider, thus I’ve never been compelled to inherit from Slider.

Thanks for the reply! I know for sure that the parameter is getting added, as not only does everything else work, I can print the skew factor with DBG from the custom Slider class. I’ll try changing one of the sliders to a normal one and see if that works. :slight_smile:

UPDATE: I’ve tried switching out a custom Slider for a normal one, and the skew factor does work as intended. My custom class inherits from Slider, but for some reason, this doesn’t seem to carry over.

Otherwise, I guess the reason why I created a custom class was to be able to reuse all its configurations, plus print labels not only for the current value, but also for also the min and max values of the full range. Ideally, if I can the skew right, then also for intermediate values as well, like a frequency knob in an SSL EQ for instance. I guess this may not be the best practice?

It’s possible that inheriting from Slider is the cleanest option in your case, I can’t tell.

I just mentioned that one can also create a custom control class not by inheriting from Slider but just having one as a member, and supplying a custom LookAndFeel class to it to change its appearance. Going this way gives a greater confidence that the core functionality of the Slider will work correctly.

Now that you have a working Slider, you can keep adding back the extra features one by one and seeing which one breaks the skew.

SUCCESS! I fixed it.

In case it may help someone else:
In the custom Slider’s paint function, I was calling drawRotarySlider(juce::Graphics &g, int x, int y, int width, int height, float sliderPosProportional, float rotaryStartAngle, float rotaryEndAngle, juce::Slider &slider) with a normalizing jmap at the float sliderPosProportional argument like so:

auto range = getRange();
// ...
getLookAndFeel().drawRotarySlider(g,
                                  sliderBounds.getX(),
                                  sliderBounds.getY(),
                                  sliderBounds.getWidth(),
                                  sliderBounds.getHeight(),
                                  jmap(getValue(), range.getStart(), range.getEnd(), 0.0, 1.0),
                                  startAngle,
                                  endAngle,
                                  *this);
// ...

Turns out, instead of the jmap, I should’ve been doing simply:

m_param->convertTo0to1(getValue())