Keeping listeners when using getStateInformation/setStateInformation

Hi all,
I’m using an AudioProcessorValueTreeState to store parameters and a couple of properties.
I want to hide the information stored in the properties from the user, but I have some listeners to respond to changes of some properties.

To save and load the state, I do this.

void PluginProcessor::getStateInformation (MemoryBlock& destData)
{
    auto state = parameters.copyState();
    std::unique_ptr<XmlElement> xml (state.createXml());
    copyXmlToBinary (*xml, destData);
}

copyState() doesn’t copy the listeners, which I understand to some extend.
Is there a way to store and recall the state without losing the listeners?

Thanks

you should add your listeners when you create your components…

I want to hide the information stored in the properties from the user

Who is the user here?

Hey, thanks for your reply!

I am of course adding listeners in my components. However copying the state doesn’t copy the listeners that where added (Value and Listeners)

The user is the person using the plugin :smiley: Sorry for being unclear here… I guess what I wanted to say was, that I’m not using regular parameters because then the values I’m storing will show up in the automation dialog in the DAW, which doesn’t make sense in this case.

That’s unfortunate… I just started writing some code that was about to go this same route :sweat_smile:

You may be able to do your listener setup in a function so that you can call it from multiple places.
This way you could call it once in the GUI constructor, and then whenever setStateInformation() is called you could trigger the function (I guess via async update, can’t remember what thread these state methods happen on…) again if the editor is open

Are you attaching listeners to the tree itself or are you using something like juce::ValueTree::getPropertyAsValue()? I’m using the later in my new code but haven’t gotten to state/saving loading myself

Maybe there is some kind of structure you can do that you can pull from the existing state before you replace it with the new state.

struct ListenerValuePair
{
    Value::Listener* listener;
    juce::Value* property;
};

iterate your old tree, grab all of the properties that have listeners,
then iterate the new state, go through the properties that match, and re-add listeners?

I don’t know, maybe that’s garbage. sounds like you might need to rethink your model to get around this…

Hey Tony,
what a coincidence :sweat_smile:

I’m setting a listener on the ValueTree of the AudioProcessorValueTreeState

class MainWindow    : public Component,
                                ValueTree::Listener
{
public:
    MainWindow(PluginProcessor& p) : p (p)
    {
        parameters = p.getParameterTree()->state;
        parameters.addListener(this);
    ...
    ...

I think using async update or the ChangeBroadcaster might be the easiest solution.
I’ll let you know what I come up with :wink:

1 Like

for the standalone plugin, getStateInformation is called from the GUI thread.
not sure about the rest of 'em though…

1 Like

So would you have some kind of SafePointer<AudioProcessorEditor> owned by the processor that gets set in

AudioProcessorEditor* TestAudioProcessor::createEditor()
{
    return new TestAudioProcessorEditor (*this);
}

which checks to see if the editor is alive before calling ‘editor->attachListeners()’ or something?

juce::AudioProcessor::getActiveEditor() :slight_smile:

Of course the documentation says this may return nullptr even with an editor open, but I’ve had luck with it on every host we’ve been testing with

1 Like

ah, and it is implemented using:

    Component::SafePointer<AudioProcessorEditor> activeEditor;

so i feel kinda smart suggesting something they’re already using! er, at least thinking the way the juce team thinks!

1 Like