ValueTree, Var, Value, ValueSource, AudioProcessorValueTreeState Performance and preferred usage

I’ve seen a couple discussions about these classes and the performance issues when looking up a property via this style: state[IDs::name]. Is there an official word about the performance limitations of these classes? I’d guess that if it’s good enough for WaveForm/Tracktion, it should be good enough for the rest of us, but maybe the usage of these classes within Tracktion is such that the properties of the entire tree aren’t being updated every frame at 60fps.

What is the preferred data type to be used with ValueTree-related classes? Data that isn’t constantly changing? Data that only changes once per processBlock? Data that only changes when a GUI control receives some kind of interaction?

regarding the var class, it sure seems like a whoooooole lot of extra code to just read/write to a int/float/string/etc, which is what a lot of these ValueTree/ValueSource/etc classes are built around…

2 Likes

What is updating the entire tree at 60fps?

Performance will depend on a lot of things but probably mostly on how many properties a tree has because it will need to iterate the NamedValueSet until it finds the property.

It may look like a lot of code to set a primitive but it’s really just a few function calls that are relatively cheap. The underling var is a wrapper around a primitive.

There’s the listener updates that could be time consuming if you do time consuming things in there but there’s not really a way around that… If you’re interested in the value changing, you need to be notified somehow.

If you’re doing some kind of advanced visualisation, that probably doesn’t belong in the tree.

It’s really difficult to say without a concrete use case or profile trace.

I was looking at the source code to a .musicxml file from https://www.musicxml.com/music-in-musicxml/example-set/ and even a 1-pager would result in a pretty massive valueTree. My own multi-page large ensemble scores result in musicxml files (they’re plaintext xml) that are greater than 1MB. So, if you’re scrolling around a score with a lot of staves/systems/elements or editing elements, the tree will be iterated quite often.

So, what is the ideal use-case for valueTree/Source/etc? data that doesn’t mutate very often? “Very often” meaning once every 16.667ms… i.e. you probably wouldn’t use a ValueTree to represent the way all points points that define vertices for a Path change over time in an animation

Well if you’re simply reading the data (like in most cases, especially for music notation), I would probably cache the data somehow either using a CachedValue<SomeNotationType> or I would use the ValueTreeObjectList I presented to have a set of concrete objects to use.

In the music notation example, I can’t see what would be updated at 60fps? Surely when you add a note that simply adds a tree? The parent then drawing that section can simply repaint itself? If you need this to be quicker, use a ValueTreeObjectList so you have a concrete bunch of objects.

In Waveform we use some properties that are constantly updating, modulating parameter values or the view start/end positions when scrolling etc. and these work fine.

You probably could get away with all path points stored to a tree and animate them but to be honest if you’re doing something like this you’ll probably have an object which represents the path, some kind of UI object running on a timer updating the path and then drawing it. When you hit save, you can flush the state of the path object to the tree, either in XML node form or simply as a blob of binary data (e.g. Path::writePathToStream or Path::toString).

Animations are a bit of a different use case as they’re not really the model’s state, they’re some kind of extrapolation of it. Think about saving and restoring the above gif. What does it mean? What would you expect to load when you started the app? Would it be halfway through? If so, how does the app know what frame to play next?
It’s probably better to think about it in terms of some “starting data”, then have a time animate that and display it.

Also, don’t worry too much about size, when you start dealing with plugins, multiple megabytes is not unusual for their state. It’s more about the frequency of updates and what you do in response to those. That’s why using async updaters etc. is worthwhile as I discussed in my talk.

3 Likes