# Resources on SliderAttachment and ParameterAttachment

**URL:** https://forum.juce.com/t/resources-on-sliderattachment-and-parameterattachment/58426
**Category:** General JUCE discussion
**Created:** [October 21, 2023, 1:20am UTC](https://forum.juce.com/t/resources-on-sliderattachment-and-parameterattachment/58426 "2023-10-21T01:20:32Z")
**Posts on this page:** 10
**Page:** 1

<div class="post-metadata">

### Author: ![kriskeillor](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.juce.com/kriskeillor/32/20074_2.png) [@kriskeillor](https://forum.juce.com/u/kriskeillor)
#### Post date: [October 21, 2023, 1:20am UTC](https://forum.juce.com/t/resources-on-sliderattachment-and-parameterattachment/58426/1 "2023-10-21T01:20:33Z")

</div>

Hello,

I am trying to have a slider which clicks between 0 and 7 make visible one of eight groups of six sliders. These sliders will all control parameters for the comb filters in the built-in reverb module. 0 selects group 0, 1 selects 1, and so on… these sliders are all added to a flexbox (two actually). At the moment it seems the flexbox will properly display the banks just by toggling their visibility, but I haven’t fully tested that.

My main problem right now is understanding how to attach a GUI listener to the parameter changing. I created a SliderAttachment like so:

```auto
    AudioProcessorValueTreeState::SliderAttachment combIDAttachment;
    // And these are my other variables...
    AudioProcessorValueTreeState& valueTreeState;
    LabeledSlider combID;

```

I called it in my editor’s initialization list like so:

```auto
      combIDAttachment(valueTreeState, "combID", combID.getModSlider()),

```

All well and good. However I then go to create the callback:

```auto
    combIDAttachment.onParameterChanged = [this]() {
        for (int i = Constants::Parameter::combIDStart;
            i <= Constants::Parameter::combIDEnd;
            i += Constants::Parameter::combIDInterval)
        {
            DBG("combID parameter changed callback");
            // I need the new value of combID, but I don't know how it's passed in
            // Call it "newValue"
            float newValue = 0;
            bool visible = (i == static_cast<int>(newValue) ? true : false);
            combTap[i].setVisible(visible);;
            combDampingL[i].setVisible(visible);;
            combDampingR[i].setVisible(visible);;
            combFeedbackL[i].setVisible(visible);;
            combFeedbackR[i].setVisible(visible);;
        }
    }

```

And I’m warned that `onParameterChanged` does not exist; of course looking at the [SliderAttachment documentation](https://docs.juce.com/master/classAudioProcessorValueTreeState_1_1SliderAttachment.html), it’s true.

This leads me to the [ParameterAttachment class reference](https://docs.juce.com/master/classParameterAttachment.html) which leads me to think I may be totally on the wrong path.

The [AVPTS tutorial](https://docs.juce.com/master/tutorial_audio_processor_value_tree_state.html) shows you how to add attachments - of the Slider and Button type, not Parameter - but it doesn’t show you how to add a callback.

I see of course the function callback is simply a parameter in the ParameterAttachment constructor, but is that the right attachment to use? I have read a few forum threads on issues with both types, but frequently people don’t even include the callback code snippets…! Is there something obvious I’m missing?

Thank you 🙂

---

<div class="post-metadata">

### Author: ![zsliu98](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.juce.com/zsliu98/32/22502_2.png) [@zsliu98](https://forum.juce.com/u/zsliu98)
#### Post date: [October 21, 2023, 3:03am UTC](https://forum.juce.com/t/resources-on-sliderattachment-and-parameterattachment/58426/2 "2023-10-21T03:03:30Z")

</div>

I would suggest inheriting from `juce::AudioProcessorValueTreeState::Listener` instead of modifying the attachment. After that, you can put the same callback code into `parameterChanged()`.

---

<div class="post-metadata">

### Author: ![Mrugalla](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.juce.com/mrugalla/32/13092_2.png) [@Mrugalla](https://forum.juce.com/u/Mrugalla)
#### Post date: [October 21, 2023, 9:46am UTC](https://forum.juce.com/t/resources-on-sliderattachment-and-parameterattachment/58426/3 "2023-10-21T09:46:14Z")

</div>

> [@kriskeillor](#):
>
> My main problem right now is understanding how to attach a GUI listener to the parameter changing. I created a SliderAttachment like so:
> 
> ```auto
> AudioProcessorValueTreeState::SliderAttachment combIDAttachment;
> // And these are my other variables...
> AudioProcessorValueTreeState& valueTreeState;
> LabeledSlider combID;
> 
> ```

replace slider and attachment with each other. the slider must exist before the attachment because the attachment’s constructor wants a reference to the slider.

> [@kriskeillor](#):
>
> Is there something obvious I’m missing?

idk if it can work the way you approach it with the callback of the attachment. it would make sense to me. but you could also just use a timerCallback to update your components’ visibility

---

<div class="post-metadata">

### Author: ![kriskeillor](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.juce.com/kriskeillor/32/20074_2.png) [@kriskeillor](https://forum.juce.com/u/kriskeillor)
#### Post date: [October 23, 2023, 7:51pm UTC](https://forum.juce.com/t/resources-on-sliderattachment-and-parameterattachment/58426/4 "2023-10-23T19:51:24Z")

</div>

> [@zsliu98](#):
>
> I would suggest inheriting from `juce::AudioProcessorValueTreeState::Listener` instead of modifying the attachment. After that, you can put the same callback code into `parameterChanged()`.

Thanks for the suggestion! It’s not ideal in my case because I have lots of LabeledSliders but only one that requires a callback. Of course, I could create a LabeledSliderWithCallback class - but that gets harder to maintain.

> [@Mrugalla](#):
>
> the slider must exist before the attachment because the attachment’s constructor wants a reference to the slider.

The slider’s constructor is called before the attachment’s constructor. Here’s both in the order they appear:

```auto
      combID(this),
      combIDAttachment(valueTreeState, "combID", combID.getModSlider()),

```

comID is the slider, and combIDAttachment is the attachment.

> [@Mrugalla](#):
>
> idk if it can work the way you approach it with the callback of the attachment. it would make sense to me. but you could also just use a timerCallback to update your components’ visibility

I see how a regularly polling timer function could handle updating the GUI visibility with no impact on the user experience. This is another good option if nothing else pans out.

* * *

I am going to look further into the [ParameterAttachment class](https://docs.juce.com/master/classParameterAttachment.html) because I really think I just started down the wrong path. I would like an elegant solution that is easy to maintain, including in my mental map of the code, and doesn’t impact performance.

---

<div class="post-metadata">

### Author: ![kriskeillor](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.juce.com/kriskeillor/32/20074_2.png) [@kriskeillor](https://forum.juce.com/u/kriskeillor)
#### Post date: [October 23, 2023, 9:38pm UTC](https://forum.juce.com/t/resources-on-sliderattachment-and-parameterattachment/58426/5 "2023-10-23T21:38:18Z")

</div>

So it turned out to be pretty easy using ParameterAttachment. I struggled just a little with declaring and referencing the lambda function, so I’ll share how I did that for anyone else. But first, the result:

![2023_10_23-comb_selector](https://us1.discourse-cdn.com/flex026/uploads/juce/original/3X/6/7/672dabf5d90d9873fce5193cc60ec5b5a5f5cccc.gif)

Both in the header and source, the callback is written like any other function:

```auto
// Header
    void onCombIDChanged(float newValue);

```

The sliders are just stored as an array and the callback function sets the visibility of all sliders in each array with a ternary bool:

```auto
// Source
void GlobeLovelerEditor::onCombIDChanged(float newValue) {
    //DBG("onCombIDChanged callback, new value " + std::to_string(newValue));
    for (int i = Constants::Parameter::combIDStart;
        i <= Constants::Parameter::combIDEnd;
        i += Constants::Parameter::combIDInterval)
    {
        bool visible = (i == static_cast<int>(newValue) ? true : false);
        //DBG("visibility of " + std::to_string(i) + ": " + std::to_string(visible));
        combTap[i].setVisible(visible);;
        combDampingL[i].setVisible(visible);;
        combDampingR[i].setVisible(visible);;
        combFeedbackL[i].setVisible(visible);;
        combFeedbackR[i].setVisible(visible);;
    }
}

```

The initializer for the ParameterAttachment is where the lambda syntax comes into play:

```auto
    combIDAttachment(*vts.getParameter("combID"), 
        [this](float newValue) { onCombIDChanged(newValue); }),

```

There is still much work to be done to connect the comb filter internals to these sliders, but I’m on the way! Thank you again for the suggestions @zsliu98 and @Mrugalla.

edit: One thing I thought strange was that none of the parameters updated their values in the saved xml parameter file until I had jiggled them. Any insight as to why that is, or if I’m missing a step in initializing new parameters? Their default values are set during initialization, so why wouldn’t they be saved until I had touched them?

---

<div class="post-metadata">

### Author: ![zsliu98](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.juce.com/zsliu98/32/22502_2.png) [@zsliu98](https://forum.juce.com/u/zsliu98)
#### Post date: [October 24, 2023, 12:44am UTC](https://forum.juce.com/t/resources-on-sliderattachment-and-parameterattachment/58426/6 "2023-10-24T00:44:48Z")

</div>

Your methods looks wonderful. I will definitely try ParameterAttachment next time to save myself from adding/removing listeners.

> One thing I thought strange was that none of the parameters updated their values in the saved xml parameter file until I had jiggled them.

Which XML do you refer to? The one saved by `getStateInformation`? Why would a slider updates APVTS before you touch it? If you are using APVTS, the example in tutorial would work in most cases.

---

<div class="post-metadata">

### Author: ![kriskeillor](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.juce.com/kriskeillor/32/20074_2.png) [@kriskeillor](https://forum.juce.com/u/kriskeillor)
#### Post date: [October 24, 2023, 1:32am UTC](https://forum.juce.com/t/resources-on-sliderattachment-and-parameterattachment/58426/7 "2023-10-24T01:32:56Z")

</div>

Thanks and I’m glad it could help you!!

Yes, the `getStateInformation` XML. As for why a slider would update it: Sorry for my poor phrasing. It’s the AudioParameterFloats I’m adding, with default values, that I expected to fill out the APVTS.

I’m not able to replicate the issue now despite deleting the AppData/app.settings file and saving the default AVPTS, so perhaps I was ahead of myself with testing. It seems to work as expected now.

---

<div class="post-metadata">

### Author: ![kriskeillor](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.juce.com/kriskeillor/32/20074_2.png) [@kriskeillor](https://forum.juce.com/u/kriskeillor)
#### Post date: [October 26, 2023, 7:11pm UTC](https://forum.juce.com/t/resources-on-sliderattachment-and-parameterattachment/58426/8 "2023-10-26T19:11:54Z")

</div>

Hey all I’m running into some weird behavior while accessing VTS parameter values from the editor during initialization.

I want to run my show/hide method on startup so that the correct bank of sliders displays, according to whatever combID is in the saved state.

This is the range and interval of my combID slider:

```auto
        constexpr int combIDStart = 0;
        constexpr int combIDEnd = 7;
        constexpr int combIDInterval = 1;

```

This is the initialization of visibility:

```auto
    float combID = valueTreeState.getParameter("combID")->getValue();
    onCombIDChanged(combID);

```

But combID-\>getValue is evaluating as:  
`{0, 0.142857, 0.285714, 0.428571, 0.571429, 0.714286, 0.857143, 1}`  
when the program exits with the combID {0, 1, … 7}.

Why is the value normalized to its range when it’s saved, and loaded on startup?

It’s an easy enough fix, just have to multiply by seven, but it’s certainly confusing to me.

---

<div class="post-metadata">

### Author: ![Mrugalla](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.juce.com/mrugalla/32/13092_2.png) [@Mrugalla](https://forum.juce.com/u/Mrugalla)
#### Post date: [October 26, 2023, 9:11pm UTC](https://forum.juce.com/t/resources-on-sliderattachment-and-parameterattachment/58426/9 "2023-10-26T21:11:56Z")

</div>

getValue() returns the normalized value of a parameter. that’s why every RangedAudioParameter has a NormalisableRange object for denormalizing the value as well as checking if the denormalized value is legal. Not sure if you can access the range object from all the different parameter subclasses, but they surely always offer some method for convertingFrom0to1() or so

---

<div class="post-metadata">

### Author: ![kriskeillor](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.juce.com/kriskeillor/32/20074_2.png) [@kriskeillor](https://forum.juce.com/u/kriskeillor)
#### Post date: [October 26, 2023, 9:35pm UTC](https://forum.juce.com/t/resources-on-sliderattachment-and-parameterattachment/58426/10 "2023-10-26T21:35:10Z")

</div>

Jeez… thank you! I’ve seen many discussions about that but this is my first time encountering it. Much appreciate the info even if it was a silly ask!
