I add a track using:
edit->ensureNumberOfAudioTracks (getAudioTracks (*edit).size() + 1);
However, when I listen to the edit via valueTreeChildAdded, the TRACK children get added in two different ways randomly.
Way 1: valueTreeChildAdded is called with and empty TRACK node first
Way 2: valueTreeChildAdded is called with children first and is called with the populated TRACK node
Is this expected behavior? If so, why is this happening?
Is this in the same application run using the same function call both times?
Usually you’d see this difference depending on when you add your listener. The empty
TRACK node gets added with the
Edit::insertTrack call and then
TrackList::createNewObject gets called to initialise it as an audio track.
You best bet is to do anything you need to asynchronously as the track will be guaranteed to have been created at that point.
It is the same application (RecordingDemo example).
I am trying to pass on the edit changes via listening to the edit’s state as they come through.
Do you mean use juce::AsyncUpdater?
That’s not really possible as the Tracks will be initialised via ValueTree::Listeners as well. As the order of
ValueTree::Listener callbacks isn’t well defined, you can’t know if your listener will be called before the Tracktion Engine one or not.
So if you listen to the state, you need to use an
juce::AsyncUpdater to find the object with that state asynchronously. Then it’s fully initialised and safe to use. E.g. you can use this function:
Track* findTrackForState (const Edit&, const juce::ValueTree&);
In Waveform what we tend to do for UI is just have a class that listens to the state and then triggers an async update if something changes e.g. a track is added/removed/moved or a clip is added/removed or a clip position is moved. Then depending on what thing happened, in the async callback we can update our track UI or reposition clip components etc. That saves updating the whole UI every time something changes.