How to save non-parameter values in a plugin as presets etc

Hi All,

Is anyone able to give me a rough idea of the best approach for saving state in an AudioProcessor for non-parameter values. Basically for members of the AudioProcessor which I do not wish to be automatable ?

I’m guessing the best way is somehow through a value tree.

I’d like to know how to do this and also save these values as a plugin preset of some description.

Any help greatly appreciated.

Cheers

Would something like this work for you:

class JuceDemoPluginAudioProcessor  : public AudioProcessor
{
public:
    //==============================================================================
    JuceDemoPluginAudioProcessor()
    {
        pluginState.state.setProperty (myCoolParameterID, var(5), nullptr);
        myCoolParameter.referTo (pluginState.state.getPropertyAsValue (myCoolParameterID, nullptr));
    }
    .
    .
    .
    
    void someFunction()
    {
        myCoolParameter.setValue (7);
    }
    
    // this is a parameter which should not be visible in the DAW
    Value myCoolParameter;
    
    // Our public & hidden parameters: includes cool parameter above
    AudioProcessorValueTreeState pluginState;
    
    void getStateInformation (MemoryBlock& destData)
    {
        MemoryOutputStream stream (destData, true);
        pluginState.state.writeToStream (stream);
    }
    
    void setStateInformation (const void* data, int sizeInBytes)
    {
        MemoryInputStream stream (data, sizeInBytes, false);
        pluginState.state.readFromStream (stream);
    }
    
    //
    static Identifier myCoolParameterID;
    .
    .
    .

    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (JuceDemoPluginAudioProcessor)
};
        
Identifier JuceDemoPluginAudioProcessor::myCoolParameter ("myCoolParameter");
1 Like

Awesome. Thanks a bunch @fabian

Does this approach mean the host/DAW will save the state information in whatever project file it uses ? So if I shut down the host and load up the project file again the state will be remembered ?

I’m just a little unsure as to how this behaviour works.

I’m hoping i can also write the state to some file location to handle recalling presets etc ? (Showing my general ignorance here I expect!)

(Sorry I’m currently at work in .Net land so cannot test this out till later).

Thanks for the help

Yup exactly!

You should be reporting your presets via the falling callbacks:

 int getNumPrograms() override                                               { return 0; }
 int getCurrentProgram() override                                            { return 0; }
 void setCurrentProgram (int /*index*/) override                             {}
 const String getProgramName (int /*index*/) override                        { return String(); }
 void changeProgramName (int /*index*/, const String& /*name*/) override     {}

With these, the DAW should manage saving the state to various presets for you.

1 Like

Brilliant. :+1:

@fabian

Just out of interest what would be the best way to update GUI components related to these non-parameter values in the call to setStateInformation() when a preset is loaded ?

Is it safe to send some sort of change message or broadcast and event from the setStateInformation() call ?

I realise I cannot refer to the GUI components in this method as they may not yet exist. On the GUI/Editor load I can check these values by reading the AudioProcessorValueTreeState::state but need to be able to update the controls on a preset/program load etc.

I’d prefer to do this without a timer polling the non-parameter values as they will only ever be updated by the GUI components or the setStateInformation() call (obviously no automation or anything like that going on)

EDIT: Apologies the forum is full of me mulling over parameter stuff today :confused:

You can just attach a listener to the Values. See Value::Listener.

Is it possible to then set a Value object without notifying its listeners ?

Say if the component attached to the non-parameter value is a Slider.

Seems like I’d then be calling the Slider’s Value::Listener callback every time the slider is moved and updates the Value (The value would be a non-parameter float) ? Is this a normal approach ?

Fabian - was your example thread-safe? i.e. that value object can be accessed from the audio thread?

Also will it still be connected after pluginState.state.readFromStream() completes?? Surely that replaces the valuetree and loses the connection?

1 Like

Yeah that example is very old is not quite right anymore. The correct approach is to use the AudioProcessorValueTreeState::SliderAttachment or similar classes when connecting your parameters to the GUI. To load/save the state, I think this code is better:

void getStateInformation (juce::MemoryBlock& destData) override
{
    ScopedPointer<XmlElement> xml (processorState.state.createXml());

    if (xml != nullptr)
        copyXmlToBinary (*xml, destData);
}

void setStateInformation (const void* data, int sizeInBytes) override
{
    ScopedPointer<XmlElement> xml (getXmlFromBinary (data, sizeInBytes));

    if (xml != nullptr)
        processorState.state = ValueTree::fromXml (*xml);
}

Removed usage of ScopedPointer in favour of unique_ptr

void getStateInformation(MemoryBlock &destData) {
    if (auto xml = stateTree.state.createXml())
        copyXmlToBinary(*xml, destData);
}

void setStateInformation(const void *data, int sizeInBytes) {
    if (auto xml = getXmlFromBinary (data, sizeInBytes))
        stateTree.state = ValueTree::fromXml(*xml);
}
3 Likes

Hello,

I have some settings in my plug-in which should be saved and loaded, but those settings should not appear as parameters in the DAW, since I don’t want to provide automation for this settings.

The save and load works just fine - no problem, I’m doing it this way:

void PluginProcessor::setStateInformation (const void* data, int sizeInBytes)
{ 
    std::unique_ptr<juce::XmlElement> xmlState(getXmlFromBinary(data, sizeInBytes));
    if (xmlState.get() != nullptr)
    {
        if (xmlState->hasTagName("Example")) 
        {
            settingXY = (int)xmlState->getIntAttribute("settingXY", 0);
        }
    }
}

–> settingXY has the correct value!
I just don’t know how to get the information to the GUI.

In the processor the setStateInformation function triggers and loads the saved settings.
The editor holds a reference to the processor, so I can access the information. But how can I notify the editor that there’s an update?

I’m not sure how that should work with Value::Listener … I mean I’ve used the listener before in the context of a slider, so when the user changes the slider in the GUI I can react to it.

But what I want is the different direction now…

I’ve checked the tutorials https://docs.juce.com/master/tutorial_audio_parameter.html and https://docs.juce.com/master/tutorial_audio_processor_value_tree_state.html but that’s a different situation, because I don’t want the DAW to know this parameters. I think I really only need to find a way to notify the Editor that somehting has changed - then the Editor can call a get function of the processor who provides the information, and I can update the GUI.

Edit: So what I basically want is that the Editor listens to the processor for changes (“event”) and once this triggers, the editor can call the correct processor function to get the information - because I know the processor should be independet from 1-* editors, but the editor(s) have a reference to the processor. Ahm, but how do I implement a broadcast/listener system here?

Hints? :slight_smile: thanks in advance

Nevermind- I found a solution.

you want to share it?

We just poll the Processor from the Editor’s time callback to see if some particular item has changed or not. And in the XML we have other nodes besides the parameter data where we can store things that are not parameters (or that act like parameters but don’t want the host to see).

1 Like

alright thanks