How to sync two sliders in Audio Plugin?

Hello All,

I am working on an Audio plugin, all the parameters are added using AudioProcessorValueTreeState --createParameterLayout() procedure.

on GUI, there are two sliders, which are needed to be in sync, if any of it moves, other should move on UI in real time,
how to achieve this?

(I had implemented ValueTree & setProperty() once in GUI app, but not sure how to do that in Audio Plugin with AudioProcessorValueTreeState)

Any help/suggestion is appreciated, TIA!

Thanks

Are both Sliders altering the same AudioParameter? If so, you can add a SliderAttachment from the APVTS to both Sliders with the same AudioParameter.

If not, you could attach a SliderListener to both sliders and every time the vale change event occurs, call the other sliders setValue function. But be careful not to run in any callback loops.

Thanks @Rincewind , adding slider attachment solved the issue.
But I need slider 2 disabled in One working mode, (Where Slider 1 is not present on the UI)
That fails due to same Audio Parameter used in APVTS

By “disabled”, do you mean you are calling Component::setEnabled (false) on slider 2?

What is it that “fails” about that?

@refusesoftware Something similar to it, I don’t want Slider 2 working in Mode A(say).
Mode A has Slider 2 on UI, and slider 1 in setVisible(false),
But, since Slider1 and Slider2 have same Audio Parameter altering, slider2 moves too (slider1 is working backend, even though setVisible(false))

OK, I think I understand better. So you want to add or remove the SliderAttachment dynamically, depending on the mode?

I haven’t tried it, but I’d guess that if the Editor had a std::unique_ptr<AttachmentClass> member, you could set that to nullptr to remove the attachment, and call std::make_unique to add the attachment, when switching modes?

@refusesoftware That’s correct, SliderAttachment use depends on the mode.
Can you explain more about

?

@PP02 Sorry if that was a little vague. I can try to fill in the blanks a bit. Before getting more specific, it would help to know that I understand how your plugin’s Editor class is currently set up, so here’s a couple questions:

Does your Editor currently have a pair of SliderAttachment class members, one for each of the Sliders?

And, do you have a change listener of some kind where you are detecting changing from Mode A to Mode B?

@refusesoftware Apologies for delayed response, I was distracted due to some other issues and had to pause this one.
getting back to it, SliderAttachment class members for 2 sliders – one is in Editor and other one is different Component (which is included in Editor)

And for changing from Mode A to B the button is used. (onClick)

Since, the attachments are passed in Editor constructor, it doesn’t allow anything to change when button is operated for mode change

OK I think I understand your setup, and you’re right that a SliderAttachment can only be initialized once.

So my thought is that, instead of having the SliderAttachment be a class member, you instead have the class member be a smart pointer to a SliderAttachment, and then you can create and destroy it when you switch between modes.

So the class member would be declared as:

std::unique_ptr<SliderAttachment> sliderTwoAttachment;

And then in your onClick lambda for the mode button (with some pseudocode obviously, since I don’t know your other variable names):

if (mode == A) 
  sliderTwoAttachment = nullptr;
else
  sliderTwoAttachment = std::make_unique<SliderAttachment> (apvtsReference, "parameterFoo", sliderTwoReference);

I haven’t tried that myself but I think that would work.

@PP02 I don’t know if that applies to you, but in case that is happening to you or anyone else:
Reusing the same std::unique_ptr to switch the same component to different parameters imposes a hard to catch bug. As a practical example: I’m dealing with a preset editor for an ADSR envelope. Four sliders altering a certain preset (1 of 16 selected by a combo box). So every time the user changes the preset he wants to edit, this method is called to reattach the four sliders:

void ADSRPresetEditor::attachPresetParameters(AdsrParameterSet parameters)
{
  attackAttachment      = nullptr;
  attackCurvAttachment  = nullptr;
  releaseAttachment     = nullptr;
  releaseCurvAttachment = nullptr;
  
  attackAttachment      = std::make_unique<juce::SliderParameterAttachment>(*parameters.attack,        sliderBar.sliderAttack.slider,  undo);
  attackCurvAttachment  = std::make_unique<juce::SliderParameterAttachment>(*parameters.attackCurve,   sliderBar.sliderDecay.slider,   undo);
  releaseAttachment     = std::make_unique<juce::SliderParameterAttachment>(*parameters.release,       sliderBar.sliderRelease.slider, undo);
  releaseCurvAttachment = std::make_unique<juce::SliderParameterAttachment>(*parameters.releaseCurve,  sliderBar.sliderSustain.slider, undo);
}

You need to zero out the current attachments first. Otherwise the new attachment for the new parameter will be created (and by that setting the current parameter value to the slider) while the old attachment is still active - picking up on the slider value change and altering the previous parameter to the current value of the new parameter.

1 Like

That’s a great point, and I can see how that would be a tricky bug to catch. I haven’t tried this myself, but it looks like if you didn’t zero out the old attachments first, then you would momentarily have two attachments in existence, between the time std::make_unique constructed a new SliderParameterAttachment, and assigning that to the std::unique_ptr member.

In @PP02 's case, I was suggesting switching the same std::unique_ptr between nullptr and a new attachment object, so they wouldn’t have to worry about that particular bug. But thank you for that caveat.