How to use the ValueTree to restore an application state?

I’m building my first mid-scale standalone application that should manage the application state through a ValueTree.

My approach currently looks like this (a bit simplified): I have some GUI Components that reflect the state of the underlying dsp processing chain and which can be used to control the processing. Each dsp processing block has a ValueTree that contains all its parameters as properties. The dsp processing blocks as well as the GUI are listeners to those trees, so modifying properties from any side of the tree leads to a perfect synchronization of the listeners.

Now my application base class owns a root value tree object. All processing block value trees are children of this root tree. Storing this root tree to xml works great, the xml generated perfectly reflects the hierarchical structure of the design and contains all current values. However I’m struggling on how to restore an application state at runtime.

I can load the stored xml and create a ValueTree from it through ValueTree::fromXml, however I can’t see how to simply apply those loaded settings to the current root tree and notify all listeners listening to the child trees that the whole application state gets updated at all ends. Simply assigning the loaded tree to the current root tree obviously doesn’t do the trick.

So what’s the usual way to achieve this?

I got it working with this function, that simply iterates over all properties and children in the tree loaded from xml and sets the properties if they exist in the destination tree. Besides from possibly blocking the message thread a bit long in case of a complex data structure is there any downside of this approach (or is there anything similar I have not found so far?)

void syncValueTreeNotifyListeners (const juce::ValueTree& source, juce::ValueTree& destination)
    const int numProperties = source.getNumProperties();
    for (int i = 0; i < numProperties; ++i)
        auto propertyName = source.getPropertyName (i);

        if (destination.hasProperty (propertyName))
            destination.setProperty (propertyName, source.getProperty (propertyName), nullptr);

    for (const auto& child : source)
        auto childType = child.getType();
        auto childInDestination = destination.getChildWithName (childType);

        if (childInDestination.isValid())
            syncValueTreeNotifyListeners (child, childInDestination);

not sure if this is the usual way, but I used that recently:
destinationValueTree.copyPropertiesAndChildrenFrom (ValueTree::fromXml (xmlElementToLoad), nullptr);

I my recent tests, copyPropertiesAndChildrenFrom() does what it says, but it doesn’t seem to call the listeners, which is a problem. The only solution that seemed to work for me was calling that syncValueTreeNotifyListeners()

I’d love to hear from someone on the Juce team about this.


Another option is to just do

source = destination;

which will trigger callbacks to valueTreeRedirected(), the only non-pure-virtual value-tree callback.

But I just ended up doing what you did, it just seemed simpler

Thank you for providing a solution to this problem! I was struggling to figure out how to update my GUI from an XML-loaded ValueTree until I found this post.

I made one slight change, which was needed since my ValueTree has more than one child with the same name. I replaced:

auto childType = child.getType();
auto childInDestination = destination.getChildWithName (childType);


auto childInDestination = destination.getChild(source.indexOf(child));

which ensures that the each destination child is synced to its corresponding source child (and not synced to just the first one).

Hey Hey,

Thank you so much for that method. that indeed fixes it.
I am only wondering where are you calling this exactly. I am testing in ableton and when I load a previously saved project, the flow of initialisation in juce is as follows…

pluginEditor constructor() -> getState() -> setting the new ValueTree.

After my ableton project is loaded, and I open my plugin window, the pluginEditor constructor() is not called anymore. It is af it is already called on startup, but without actually opening the window. For this reason it is initialised with the default ValueTree instead of the loaded XML one.

When I close the window and reopen it, the pluginEditor constructor() is correctly called and this time uses the updated ValueTree.

So, yes, everything works except I have to close and reopen my plugin window :stuck_out_tongue:

Ideally the plugin editor constructor should be called after the getState() method, but this is unfortunately not the case.

Any tips?