Dual mode slider (frequency OR note value), elegant options?


#1

Hi there,
I am actually trying to solve a standard problem in plugin development: having a slider than can display alternatively two different types of values.
My slider should be able to switch between frequency display or note value display (1/8, 1/16 …).
Actually I have a custom slider “DualSlider” that inherits from Slider class and overrides getTextFromValue() / getValueFromText() , these methods implement a test that uses the value of a ToggleButton to switch the display mode. It works but in the current version my class DualSlider includes a pointer to my processor to test the ToggleButton, it’s not very generic … I will have to adapt that code if I want to use it in other projects.

Therefore, I think it would be better to implement a new class that have both properties from Slider and ToggleButton but I am not very confortable with this kind of topic… Does someone can advise me a good direction to start? Should I make a composition of Slider and ToggleButton or multiple inheritance from these classes? I guess I will have to manage many ambiguities because Slider and TB have a lot of methods in common…


#2

here is some code exemple of my actual class to have an idea:

class DualSlider: public Slider
{
public:
DualSlider();
DualSlider(MyAudioProcessor* processor);
~DualSlider();

void switchToMode1();
void switchToMode2();

bool isInMode1();
bool isInMode2();

private:
bool mode = 0; // two alternative modes of display
MyAudioProcessor* processor = nullptr;
String getTextFromValue (double value) override;
double getValueFromText (const String& ext) override;
};

String DualSlider::getTextFromValue (double value)
{
auto toggleValue = processor->getVTSparam(“lfo_host_sync”);
if(!toggleValue) {return mode1TextFromValue();} // mode 1
else {return mode2TextFromValue();} // mode 2

}


#3

I would approach it differently : you can have 2 different sliders, one for each display mode, and call setVisible() on them according to the mode you want.


#4

Thank you. This is really simpler to do this way :slight_smile: I guess this is a really common and basic problem ! I just tried to call the setVisible(toggleValue) in the paint() method of my GUI and it works well without surprise :wink: It is also easier to keep track of everything in the ValueTreeState parameters … Thanks again, I keep your approach!


#5

This is a really dangerous approach, since setVisible() triggers a paint(), so you are just lucky not to get unwanted effects.


#6

Thank you, I changed my code to not call setVisible() in the paint() method: I assigned a function to the button via onClick that calls the setVisible method. My button is already attached to an AudioProcessorValueTreeState so a click to this button calls onClick and also my parameterChanged() method in my processor. I hope it’s a reasonable option … it seems to work.


#7

We’ve used the 2 sliders approach:

Before going that way we’ve looked on other implementations (here is an example):

The model is the critical part I think and each has advantages and disadvantages.
In our case we wanted to be able to follow BPM changes and seamlessly switch back and forth between the two.

Our model: 3 parameters (switch, bpm, ms)
H-Delay: 2 parameters (handling re-calculation based on switching)
Logic Delay: splitting parameter into 2 ranges for BPM and absolute time values.

For the 2 others (with less than 3 parameters) you can simply make one variable for state and make your lambdas (for APVTS) convert the correct value based on the current state or area within the range.


#8

You are right, it really depends of the behaviour you want from your plugin and your model depends from this behaviour… In my case I wanted a simple switch from a BPM mode to an absolute time mode. You have the same behaviour in Ableton delays:

absoluteTime hostSync

Here, when I switch from time to sync mode, the delay value goes from 110ms to a BPM synced value which is far superior to the previous one.
About the lambdas in your createAndAddParameter() method, I may have missed something but they can only take one input parameter so how do you test your state variable? Also if you assign functions instead of lambdas they have to be defined static and you don’t have access to your class variables inside.


#9

Lambdas are very powerful and tricky.
Just remember in terms of performance that we use them for non real-time so some performance penalty favor simplicity is ok (IMHO).

Check this out, you can tell the lambda function which additional context will be provided - http://en.cppreference.com/w/cpp/language/lambda


#10

Thank you, I will have a look to this !