A question on syncing Sliders with AudioProcessorParameters

Hi,

I am writing a small clipper plugin with just two parameters. When these parameters are modified it calculates and updates a lookup table for a waveshaper that the clipper uses in its calculations.

This means I don’t directly pass the clipper’s parameters into its process function:

in PluginProcessor.cpp processBlock:

...
clipper.process(buffer);
...

Instead, I have it setup so when the Slider in the ui changes value, it tells the audio processor.

In PluginEditor.cpp constructor:

threshold_slider.onValueChange = [this] {t = threshold_slider.getValue(); audioProcessor.thresholdChanged(t); shaperView.updateGraph(k, t);};

shaperView is a UI component that displays the current state of the waveshaper, like other clipping plugins such as V-clip.

My question then becomes: is there a way to have a callback such as Slider.onValueChanged but for AudioParameters? I want to only calculate this wavetable when the values actually change.

Cheers

If you want to pipe it through an AudioParameter, you’ll want to do the following:

  • Move the setup of the slider into the audio parameter (min/max value, skewing, text to value, value to text, etc.)
  • Use a SliderParameterAttachment to make the slider control the audio parameter and vice versa
  • Add a listener to the AudioParameter (could also be your processor) and call thresholdChanged.
  • Add a listener to the AudioParameter in side your shaperView so it may update itself. Pass the two AudioParameters via the constructor.

I see, I was thinking about simply making the audio processor a APVTS::Listener. However this would mean I would have a function that looks like this

void parameterChanged (const juce::String &id, float newValue)
{
    if (id == "param1")
        ...
    else if (id == "param2")
        ..
}

which seems like not a good paradigm for something that could be called many times a second. Should I worry about the overhead of doing all these String comparison operations? I wonder how other people handle logic inside this funciton. I also wonder if it would be worth creating a Hash Table that converts strings to actual parameter id numbers that I have in an enum class.
Does anyone know why parameter integer ID’s aren’t supported in the framework? seems strange for it to be a stringly typed system.

First of all, don’t optimise anything that you don’t know will cause an issue. In this case: won’t be an issue!

Second: I (and I know I’m not alone with this) steer clear from the APVTS. It has a few multi threading downsides and “undocumented” side affects that cause a lot of headache when you don’t watch out, so I always avoid it entirely. And it is for sure not necessary for your small two parameter plugin.
The main thing I’d be missing without APVTS is the load and save state functions. But with just two parameters, you can implement that yourself relatively easy!

  • parameterChanged() will get called only when the parameters (attached by the listener) changes. Usually it will not called many times a second. However,
    • if you do worry about the calculation of the wavetable, you may suspend the audio processing during calculation
    • and be aware of the thread safety issue (since you may modify the clipper in a listener thread while it processing audio)
  • For Sliders, juce::AudioProcessorValueTreeState::SliderAttachment is able to ’ maintains a connection between a Slider and a parameter in an APVTS’, which may save you lots of time.