How to update sliders in the GUI by using the parameterIDs

Hello,
I am trying to create a kind of preset mixer. I have two different xml files that i have my parameter id names in them. I am able to read these files and pull the parameter names and values from them. I have a lot of parameters. I am comparing the name of the parameters , once my mixer code finds the same ones, it changes the value of the slider from editor by calling the

     void PresetMixerPlugin::parameterChanged (const String& parameterID,
                                                  float newValue)

which is normally in the audio processor. Since i have the name of the parameters in an array, it is easy to change the values. It is working in the background. I can hear the difference in the sound. But my knobs and slider stay the same. They don’t move. I tried to refresh the GUI by repaint() and even by calling the resized().None of them worked. I feel like the mechanism works differently :smiley:

I can simply type the all name of the sliders and then change the slider values by calling sliderName.setValue(double newValue); in a switch case but this means that i have to do this for all parameters one by one.
Do you have any suggestions for me to use the paramter id names to do this properly? I also think that the calling parameterChanged (const String& parameterID, float newValue) from the GUI is not the correct way of doing this. What you think about this?

Thanks in advance :pray:

I also have this problem, since it is not possible to communicate anything to the editor directly, I set a flag in the processor that indicates that the parameters were updated. And the editor checks it in timer callback. The problem is that you have to check each controller manually.

There must be some better way. It’s insufferable

use juce::ParameterAttachment for every action in the gui that should be triggered by a parameter change. you only give it its rangedAudioParam on init so you won’t need any string compares after that

1 Like

I am migrating to that new method but I have run into a problem that I do not understand, the state is not restored correctly due to skew, if it is set to a value less than 1, I get smaller values every time.

previously it would update the value directly with getRawParameter value, and then in the editor the controls would be updated with setValue correctly. Now I use the sequence begin / setValueNotify / end and this problem happens.


Edit:

I think I have detected part of the problem, with getRawValue I save the real value, while getValue saves the position of the control. But I don’t want to save the position of the control, I want to save the real value after applying the skew.

But I can’t save the real value if by loading it later I can’t modify the raw value directly. Should I do it in the callback function manually? This is all a bit strange

The idea is not to use any of the getValue() or getRawParameterValue() functions.
You didn’t mention what kind of control you are using, may I assume it is a juce::Slider?
The rough approach is similar for all though:

When you create the SliderParameterAttachment, it will propagate the NormalisableRange from the parameter to the Slider which includes the skew or any mapping function the NormalisableRange may use. It will also do the initial update of the Slider to fit the parameter value.

If you write conversion functions for all the interaction steps it is much to easy to get stuff wrong.

Hope that helps a bit.

N.B.:

  • getValue() is called by the host therefore it’s normalised to 0…1.
  • getRawParameterValue() is an atomic in unnormalised values, that is it will have the values as they appear in your processing or displayed in the controls.
  • it’s best not work with setValue and setValueNotifyingHost directly. If you do keep in mind that to each value change there is a handshake API starting with beginChangeGesture and ends with endChangeGesture. That is needed for the host because depending on automation setting (read/write/latch) the host can ignore or override changes from the GUI. And the host needs to know what change to record and what to ignore.

Hope that helps a little bit

1 Like

Thanks for the help, I already understand.

I have finally solved it using the conversion functions, so I save the raw parameter as before, and normalize the value after loading it

     treeState.getParameter(strID)->beginChangeGesture();
     treeState.getParameter(strID)->setValueNotifyingHost(treeState.getParameter(strID)->convertTo0to1(rawValue));
     treeState.getParameter(strID)->endChangeGesture();

Where are you calling that OOI?

The whole idea of the attachment classes is that you don’t need to manually set the value yourself - and the widget you attach to will be set up to have the same range, skew, etc.

I don’t know what an OOI is. I am loading and saving the values directly from get and setStateInformation.

I understand that setValueNotifyingHost updates states of controls, but I do not want to update the control, at least for now, since at any time I could modify it, or even not use them. I want to save raw values, even if they don’t have a control attached.

So I simply update the control with its normalized value, it doesn’t seem like a fudge, I no longer have to worry about anything since any control with any configuration will always adapt to the raw value.

If you do this in getStateInformation and setStateInformation, the information is going round in circles.
This snippet is meant to be used when a user interaction on the control happens.

In setStateInformation the host sets your plugin to a known state (that was saved previously using getStateInformation). If you call setValueNotifyingHost that information is seen as a new user interaction. But in fact all you wanted to do is to update the control to reflect the stored value.

If you use the AudioProcessorValueTreeState all you have to do is to replace the public state of the treeState with the restored one. The ParameterAttachments are Listeners to the state and will update the controls accordingly (Model-Observer pattern).

auto tree = juce::ValueTree::readFromData (data, size_t (sizeInBytes));
if (tree.isValid())
    treeState.copyPropertiesAndChildrenFrom (tree, nullptr);
1 Like

this works fine, the parameter updates and listener calls of the attached controls are done correctly

I have only lost a little control when saving each parameter, but I prefer to get rid of this. I would just need to know if if there is any simple way that as I add new parameters to the valueTree, I can load old states from saved files