How do I get this SliderAttachment set up properly... I'm halfway there...?

I had been using the sliderValueChanged() method to update my parameters, but apparently its better to use ParameterAttachement() or SliderAttachment() so the PluginProcessor can update the parameters, and pick up, for example, any automation of that parameter in track envelopes etc.

I’m fairly new to JUCE, I’ve been looking for example code etc., there’s very little out there on ParameterAttachement especially.

Anyway, here’s what I’ve got so far. How can I implement this properly in PluginProcessor?

In PluginEditor.h

juce::Slider myGain_slider;
juce::AudioProcessorValueTreeState::SliderAttachment myGain_sliderAttachment;

In PluginEditor.cpp

myGain_slider.setTextBoxStyle(juce::Slider::TextBoxBelow, true, 40, 20);
myGain_slider.setRange(0.0f, 1.0f, 0.01f);
myGain_slider.setValue(0.0f);
addAndMakeVisible(myGain_slider);

(constructor):

mypluginnameEditor::mypluginnameEditor (mypluginnameProcessor& p)
    : AudioProcessorEditor (&p), audioProcessor (p),

myGain_sliderAttachment(audioProcessor.apvts, "Gain", myGain_slider)

In PluginProcessor.cpp and PluginProcessor.h
this is where things get cloudy for me. How do I implement a simple apvts ?
Or I’d be open to advice on how to use ParameterAttachment().

This tutorial covers a simple apvts.
https://docs.juce.com/master/tutorial_audio_processor_value_tree_state.html

If you scroll down to ‘Adding Parameters Programatically’ they outline a more convenient approach using the createParameterLayout() function.

1 Like

Got it working, thanks… I’m working now on how to change those default horizontal sliders to rotary ones and position them. :+1:

that tutorial is a nice starting point, but not well executed. first of all it doesn’t even show that one should use a method call to create the parameter layout, and 2ndly it uses unique_ptr for the attachments instead of just explaining what an initializer list is good for, even though one was used for apvts itself.

creating parameters with a free function is not required, but just best practice, so that the constructor of the processor doesn’t look so cluttered and in case some intermediate variables need to be constructed before being passed on at parameter creation. generally a much more pleasant experience.

and unique_ptr is just overkill for that situation. even considering that it automatically handles its scope it’s slightly more of a burdon than something that is just normally instantiated on the stack and has you use the → operator all the time.
watch this tut and you hopefully know what i mean. don’t worry. it’s easy peasy: Member Initializer Lists in C++ (Constructor Initializer List) - YouTube

1 Like

thanks :+1: I did look at the Juce tutorial, but found a video online which helped me through the process too.
Here’s what I went for
in PluginProcessor.h:

static juce::AudioProcessorValueTreeState::ParameterLayout createParameterLayout();
juce::AudioProcessorValueTreeState apvts{ *this, nullptr, "Parameters", createParameterLayout() };

In PluginProcessor.cpp:

juce::AudioProcessorEditor* mypluginname::createEditor()
{
    //return new mypluginnameAudioProcessorEditor (*this);
    return new juce::GenericAudioProcessorEditor(*this);
}
juce::AudioProcessorValueTreeState::ParameterLayout mypluginnameAudioProcessor::createParameterLayout()
{
    juce::AudioProcessorValueTreeState::ParameterLayout layout;
    layout.add(std::make_unique<juce::AudioParameterFloat>("mGain", "Gain",
        juce::NormalisableRange<float>(0.0, 1.0, 0.1, 1.f), 0.0));
... etc...
    return layout; }

and to access the values: gain_value = apvts.getRawParameterValue("mGain")->load();

nice. you probably want to find a better way to access the parameter though. a string compare is expensive. i personally like to make an enum with all the parameters so i can index them with their names, but without having to use a string. some people prefer to just give each parameter its own member variable in the processor. all has their pros and cons

1 Like

Hey, I found this interesting and looked under the hood. getRawParameterValue takes a StringRef and uses it to look up the pointer to the corresponding ParameterAdapter in a std::map (adapterTable). So it’s just performing a table look-up. Shouldn’t it be fast enough?

It’s still unnecessary overhead, you might not want to have if you have, say, hundreds of parameters in your plugin. I am currently working on a plugin with about 20 parameters and using getRawParameterValue, but I might look into changing that at some point. (The plugin seems to be one that is going to need a ton more parameters in the future…)

1 Like