How to use the ValueTree to restore an application state?

#1

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?

0 Likes

#2

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);
    }
}
0 Likes

ValueTree fromXml() and Listeners
#3

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

0 Likes

#4

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.

2 Likes