Value Tree looses Listener, after use

Hello,

Disclaimer: This is my first post, please let me know if I do any mistakes. It was not my intention.

I’m learning the big Value Tree topic in Juce at the moment. So far it actually was working out well. I was able to track states of my classes, so that I was well able to connect my model with my components.
I’m working on a feature that I can load files into a track. I actually copied much of the logic from the audio player tutorial since there is a lot of code I’m able to use in my code. Now, after I loaded some tracks and played them, I click again the open button and load more files and play them.

I designed my code that the Value Tree takes care of the several states. Actually most of the states from the tutorial I’m still using since they make sense. Here is the issue I can’t find the reason for: When I load again files in the track, my Value Tree isn’t sending the change to all the listeners, actually not even the class in which I change the property gets notified.

Here is a snippet of the code:

void TrackComponent::openButtonClicked()
{
	chooser = std::make_unique<juce::FileChooser>("Select a Wave file to play...",
		juce::File{},
		"*.wav");
	auto chooserFlags = juce::FileBrowserComponent::openMode
		| juce::FileBrowserComponent::canSelectMultipleItems;

	chooser->launchAsync(chooserFlags, [this](const juce::FileChooser& fc)
		{
			files_.addArray(fc.getResults());
			for (int i = 0; i < files_.size(); ++i)
			{
				juce::Identifier fileProperty("File" + juce::String(i));
				juce::ValueTree fileTree(propertyFiles_);
				fileTree.setProperty(fileProperty, files_[i].getFullPathName(), nullptr);
				channelNode_.addChild(fileTree, i, nullptr);
				fileViewComponent_.addFile(files_[i].getFileName());
			};
			bool outputSelected = channelNode_.hasProperty(propertyOutput_);
			bool inputSelected = channelNode_.hasProperty(propertyInput_);
			bool filesSelected = !files_.isEmpty();
			if (filesSelected && outputSelected && inputSelected)
			{
				channelNode_.setProperty(propertyState_, "Preparing", nullptr);
				channelNode_.setProperty(propertyState_, "Stopped", nullptr);
			}
			if (filesSelected && !outputSelected && !inputSelected)
				channelNode_.setProperty(propertyState_, "Preparing", nullptr);
		});
}

What I don’t understand is, that this part fires well:

			if (filesSelected && !outputSelected && !inputSelected)
				channelNode_.setProperty(propertyState_, "Preparing", nullptr);

but the other if statement,

			if (filesSelected && outputSelected && inputSelected)
			{
				channelNode_.setProperty(propertyState_, "Preparing", nullptr);
				channelNode_.setProperty(propertyState_, "Stopped", nullptr);
			}

which is the one, which should let the app move on.It doesn’t send notification or sends the notification to another node but if so how and why? I checked with debugger that the IF-Statement gets entered and I also checked other points where the App should move on but I tracked it back that no notification is send actually. At least not for the Value Tree which every class is listening to.

I struggle a bit with debugging the value tree. I always have the feeling something strange is happening in the background (I hope it’s only my paranoia^^). I saw that @cpr2323 has a value tree debugger in his github repo but it’s a little old and I don’t know if it is still intended to be used. While I’m waiting on an answer here, I will give the debugger a try. Thanks for sharing in advance :slight_smile:

And here is a snippet of the XML how I think it could be wise to use the value tree but I was always wondering if this approach is good:

<Channel_0 ChannelNumber="1" State="Preparing" Output="0" Input="0">
  <Files File0="C:\Path\to\File\Audiophile0.wav"/>
  <Files File1="C:\Path\to\File\Audiophile1.wav"/>
  <Files File2="C:\Path\to\File\Audiophile2.wav"/>
  <Files File3="C:\Path\to\File\Audiophile3.wav"/>
  <Files File4="C:\Path\to\File\Audiophile4.wav"/>
  <Files File5="C:\Path\to\File\Audiophile5.wav"/>
  <Files File6="C:\Path\to\File\Audiophile6.wav"/>
</Channel_0>

This is how it should look when everything is implemented well. I’m aware of that, with only the for loop I can’t get the XML as shown but I get close, only the numbers are wrong in the property so far.

Also when I understand the Value Tree correct I would really like to help making a more interactive and detailed tutorial for it. The tutorial is totally understandable but I feel alike others here that it could be a bit more detailed about using the value tree in a bigger project.

Diclaimer: I didn’t carefully read your code, I’ll just throw a couple of tips out in case it can help.

For debugging Value Trees, I use GitHub - jcredland/juce-toys: Debugging utilities in a JUCE Module, plus NatVis and LLDB customizations, it’s a lifesaver!

I found Value Trees a little confusing at first. The main things I needed to understand was that Value Trees are a way of accesning a hidden underlying source data, which is reference counted so the Value Tree objects can pop in and out of existence no problem. Listeners are attached to a Value Tree but not the underlying object. Listeners will only hear about changes made using that Value Tree and not all changes to the underlying source data, so that Value Tree needs to exist as long as the listener needs to listen.

Sorry if you’re already on top of all that, but if not, I hope it helps track down the problem.

1 Like

Thanks @AdamVenn you definetly mention some good Infos here, I’ll check that out. So the Juce Debugger is still up to date :slight_smile:

I think I found the issue. If I set the Tree to the same property again,no change will be send actually isn’t?

That’s correct (and APVTS also has the same feature)

Thanks, so I think the topic can be closed. Thank you very much for your help :slight_smile: