How do I handle a parameter change in a "non-GUI" scenario, in this example here?

My plugin works fine in GUI mode, but for non-GUI situations in my test DAWs Reaper and Ableton, its not behaving how I want it to, despite giving the toggle buttons a RadioGroupID.

In Ableton, when I single-click the ToggleButton it seems to work but it does not visually turn off the previous ToggleButton. But it does when I double-click it.
In Reaper when I click the ToggleButton it does not turn off the previous one, in fact I can turn on all my Radio ToggleButtons, and they don’t act like they are mutually exclusive.

I’m struggling to find a way to listen to the changes that happen in the Processor non-GUI mode and pick them up in the Editor, despite having seemingly the appropriate attachments (below).

Any ideas on how I can approach this in a threadsafe way?

Button definitions:

    mBlueToggleButton.addListener(this);                                   
    mBlueToggleButton.setToggleable(true);
    mBlueToggleButton.setClickingTogglesState(true);
    mBlueToggleButton.setToggleState(true, juce::NotificationType::dontSendNotification);
    mBlueToggleButton.setRadioGroupId(radioGroupId, juce::NotificationType::dontSendNotification);
    addAndMakeVisible(mBlueToggleButton);

    mGreenToggleButton.addListener(this);                              
    mGreenToggleButton.setToggleable(true);
    mGreenToggleButton.setClickingTogglesState(true);
    mGreenToggleButton.setToggleState(false, juce::NotificationType::dontSendNotification);
    mGreenToggleButton.setRadioGroupId(radioGroupId, juce::NotificationType::dontSendNotification);
    addAndMakeVisible(mGreenToggleButton);
//-------------------------------------------
    juce::TextButton mBlueToggleButton;
    juce::TextButton mGreenToggleButton;
    juce::AudioProcessorValueTreeState::ButtonAttachment mBlueToggleButton_buttonAttachment;
    juce::AudioProcessorValueTreeState::ButtonAttachment mGreenToggleButton_buttonAttachment;
//--------------------------------------------
//Constructor
    mGreenToggleButton("Green Toggle Button"),   
    mGreenToggleButton_buttonAttachment(audioProcessor.apvts, "greenToggleButtonParameterID", mGreenToggleButton),  
//Blue the same

In non-GUI situations, buttonClicked() in the Editor is not called seemingly. Is anything triggered in the Editor in the non-GUI scenario that I can pick up on?

image
image

It sounds like this would be better modelled as a single “choice” parameter with two states (blue/green) or maybe three (off/blue/green). Then, you can use a custom ParameterAttachment in each button to listen to the state of the parameter, and illuminate the “blue” button if and only if the parameter is in the “blue” state etc. Similarly, pressing the “blue” button can set the parameter value to “blue”.

So check for changes in this AudioParameterChoice with some code in the Editor in timercallback() - is that the only way the Editor can find out what happened in the audioProcessor to this parameterChoice? Or is the Editor notified another way?

When you construct an instance of the ParameterAttachment class, you provide it with a std::function that will be called each time the parameter changes. You can update the state of a button (for example) inside this callback. When the button is clicked, you can call setValueAsCompleteGesture on the same ParameterAttachment to update the parameter.

I used:

       auto* myColorParam = dynamic_cast<juce::AudioParameterChoice*>(audioProcessor.apvts.getParameter("myColorChoiceID"));
       if (myColorParam) {
           myColorParam->beginChangeGesture();
           myColorParam->setValueNotifyingHost(2.0f);   
           myColorParam->endChangeGesture();
       }

this wasn’t a member setValueAsCompleteGesture

Any problems you see with this ?

That’s a member of the ParameterAttachment class:

https://docs.juce.com/master/classParameterAttachment.html