ValueTree Gui-connecting example Feedback


#1

Since I didnt knew anything about the valueTree-class, but want to use it to connect my gui with the processor, I made a little demo to learn about it.
I know, its more than answering one simple question, but I would be really happy if someone could give me feedback and point me to possible mistakes.

Its a simple Plugin, where you can add and delete tonegenerators:

screen

for the tonegenerators, i made a class called AudioClip, containing a ToneGeneratorAudioSource wich is connected to a main-mixer. In the processor there is an OwnedArray for the audioClips and an audioClipGrpValTree, wich contains all the parameters.

there is an viewport, wich is viewing an Component named audioClipViewer, this component contains an OwnedArray holding audioClipGui-Components, wich represent the audioClips with two Sliders and a remove-Button.

The processor, the audioClips and the audioClipViewer are Listeners to the ValueTree.

when the users clicks the add-Button, in the Editor there is an new valueTree-Node created, and given to the processor(function in Editor):

ValueTree audioClipTree(AUDIOCLIP);
audioClipTree.setProperty(VOLUME, gain, nullptr);
audioClipTree.setProperty(FREQ, freq, nullptr);
audioClipTree.setProperty(DELETE_FLAG, false, nullptr);
audioClipTree.setProperty(INDEX, processor.indexCount, nullptr);
processor.addAudioClipFromTree(audioClipTree);

the processor.addAudioClipFromTree()-method gets called by the editor and adds an audioClip to the OwnedArray and the Child-threeNode to the valueTree:

audioClipArray.add(new AudioClip(mixer, *audioClipGrpValTree, indexCount));
audioClipGrpValTree->addChild(valTree, indexCount, nullptr);
indexCount++;

as a result, the audioClipViewer gets notified about the change of ValueTree and adds an Gui-Element:

addAndMakeVisible(audioClipGuiArray.add(new AudioClipGui(childWhichHasBeenAdded)));

the audioClipGui-Components gets a reference to its child node, and connects the Sliders and the remove-Button to the TreeNode like this:

gainSld->getValueObject().referTo(valTreeChildToConnect.getPropertyAsValue(VOLUME, nullptr));

Now the Gui ist connected with the related threeNode, and if the Sliders are moved, the audioClips get notified about it and respond. The remove- toogle Button is connected to the DELETE_FLAG-Value, if it is set by the user, the child-tree will be removed
(valueTreePropertyChanged-Callback of AudioClip:)

if (int(treeWhosePropertyHasChanged.getProperty(INDEX)) == index)
{
	toneAudioSource.setAmplitude(treeWhosePropertyHasChanged.getProperty(VOLUME));
	toneAudioSource.setFrequency(treeWhosePropertyHasChanged.getProperty(FREQ));

	if(bool(treeWhosePropertyHasChanged.getProperty(DELETE_FLAG)) == true)
		audioClipGrpValTree.removeChild(treeWhosePropertyHasChanged, nullptr);
}

if the child-tree is removed, the audioClipViewer gets notified and removes the Gui-Element, after that the processor gets notified and removes the audioClip itself.

If the plugin gets closed and reopened in the DAW, the audioClipViewer recreates all the Elements in its Constructor:

for (int i = 0; i < valTree.getNumChildren(); i++)
{
	ValueTree& valTreeChild = valTree.getChild(i);
	//valTreeChild& = valTree.getChild(i);
	addAndMakeVisible(audioClipGuiArray.add(new AudioClipGui(valTreeChild)));
}

is there any downside of this structure, especially when a project gets bigger? If so, what are the alternatives to this?


#2

You’re going to have a bad time with race conditions all over the place if you just hook a ValueTree up to communicate between your GUI and processor.

Take a look at using AudioProcessorValueTreeState. It does what you’re trying to do in a (mostly) thread-safe and simple way (while still allowing you to manually harness the power of ValueTree if you choose to dive into the guts).

There’s a handy tutorial available as well.


#3

Ok thanks, but can I add and remove parameters after the ValueTreeState is created? Because thats what I need for my project, where new AudioClips get added and removed by the user via Gui.


#4

Adding/removing host-visible state (parameters) isn’t really supported by any host, and with ones that do you have to be extremely careful about parameter indexing. See a recent discussion about a similar issue for renaming parameters, which is rife with issues in itself (much less adding/removing, which I can’t even fathom).

In the case of AudioProcessorValueTreeState, you can’t mutate the number of parameters after you’ve set the ValueTree. So you’d be stuck to a fixed number of host aware parameters (which is appropriate for most if not all plugin types i.e. VST2). HOWEVER, you could totally add a non-host-aware set of fully modifiable state maintained internally by the plugin (and not visible to the host) which could mutate the number of audio clips.

Hopefully that helps.


#5

The thing is, i need a structure where I can hold a variable number of Soundgroups, every Soundgroup holds a variable number of ChannelStrips and each ChannelStrip holds one Audioclip.

At first I implemented this using only Arrays, but because of the Undo-function and the listener functionality of the ValueTree I wanted to combine it with my Classes.

Can I achieve this nested structure with the AudioProcessorValueTreeState class? Because I dont know how to make a structure like I need with it.


#6

One addition to this: I dont want to use the values from the ValueTree-Structure directly in the audioThread, there is always like an setter, wich copies the value from the Value Tree and for example sets the gain of an audiosource with it.

If I do this with atomic variables, is it threadsafe?