TwoValueHorizontal Slider SliderAttachment

Hi!

I used the following code to attach the roomsize parameter to a rotary slider and it works well.
roomsizeAttach = std::make_uniquejuce::AudioProcessorValueTreeState::SliderAttachment(audioProcessor.treeState , roomsizeID, reverbDial1);

However, how can I do that for a TwoValueHorizontal slider, as there is only one slider but two values?
SliderAttachment (AudioProcessorValueTreeState& stateToUse, const String& parameterID, Slider& slider);

I tried this but it didn’t work (obviously):
lowcutAttach = std::make_uniquejuce::AudioProcessorValueTreeState::SliderAttachment(audioProcessor.treeState, lowcutID, doubleSlider);
highcutAttach = std::make_uniquejuce::AudioProcessorValueTreeState::SliderAttachment(audioProcessor.treeState, highcutID, doubleSlider);

Any ideas? I couldn’t find any examples online :confused:

Thankss!

That’s a classic, and it is now much easier using the juce::ParameterAttachment:

lowCutAttach = std::make_unique_ptr<juce::ParameterAttachment>(
    *audioProcessor.treeState.getParameter(lowCutID), [doubleSlider](float value)
    {
        doubleSlider.setMinValue(value);
    }, nullptr);
);
highCutAttach = std::make_unique_ptr<juce::ParameterAttachment>(
    *audioProcessor.treeState.getParameter(highCutID), [doubleSlider](float value)
    {
        doubleSlider.setMaxValue(value);
    }, nullptr);
);

Adding checks/jassert for the getParameter call is left as an exercise

EDIT: I forgot the other way round, you need to listen to the slider and call the appropriate functions on the attachments. Maybe better to wrap it all in a struct.

struct TwoValueAttachment
{
    juce::Slider& slider;
    juce::RangedAudioParameter& minParameter;
    juce::RangedAudioParameter& maxParameter;
    std::unique_ptr<juce::ParameterAttachment> minAttach;
    std::unique_ptr<juce::ParameterAttachment> maxAttach;

    TwoValueAttachment(juce::Slider& s, 
                       juce::RangedAudioParameter& min, 
                       juce::RangedAudioParameter& max)
     : slider (s), minParameter (min), maxParameter (max)
    {
        auto& s (slider); // cannot capture members
        minAttachment = std::make_unique_ptr<juce::ParameterAttachment>(minParameter, [s](float value)
        {
            s.setMinValue(value);
        }, nullptr);

        maxAttachment = std::make_unique_ptr<juce::ParameterAttachment>(maxParameter, [s](float value)
        {
            s.setMaxValue(value);
        }, nullptr);

        slider.onDragStart = [s]
        {
            if (s.getThumbBeingDragged() == 1)
                minAttachment->beginChangeGesture();
            else if (s.getThumbBeingDragged() == 2)
                maxAttachment->beginChangeGesture();
        }

        slider.onDragEnd = [s]
        {
            if (s.getThumbBeingDragged() == 1)
                minAttachment->endChangeGesture();
            else if (s.getThumbBeingDragged() == 2)
                maxAttachment->endChangeGesture();
        }

        slider.onValueChange = [s]
        {
            if (s.getThumbBeingDragged() == 1)
                minAttachment.setValueAsPartOfGesture (slider.getMinValue());
            else if (s.getThumbBeingDragged() == 2)
                maxAttachment.setValueAsPartOfGesture (slider.getMaxValue());
        }
    }
};

That was longer than I expected, but should do the trick… untested…