BOOST XML JUCE

I have a question about @Xenakios’s example code. Doesn’t the "note"+String(i) method inside setProperty() result in constructing a new Identifier every iteration, which the documentation warns us is sub-optimal?

Asking because I’ve taken steps to avoid this, and I’m wondering if it was unnecessary.

I made no claims of efficiency or correctness for the code. It was just meant to illustrate one typically needs some helper functions when dealing with the ValueTrees. (There are also use cases where it’s not feasible to preconstruct the identifiers anyway. This maybe isn’t one of them because one could consider for example a chord of 127 notes or something to be the maximum amount needed.)

I’m interested though as to what the best way of accomplishing this would be. My thought was either 1: create a large bank of preconstructed Identifiers (note1, note2 etc.) and then have a function which builds more if they are ever required. Or 2: Make each note a child instead of a property, and then access them by index number. Is there a better method than either of these?

Edit: Looking into the var class, I see it can store arrays as well, so maybe this is the way to go…

Hi all,
I just spent a few hours looking at the examples and tutorials.
I am confused how to change the value tree from within the editor.
The examples in the tutorials create an audioprocessor::valuetreestate and then use audioprocessor::addparameter to add components to the valuetree that gets created by the constructor ( that’s how I understand it ). A separate listener is automatically created which looks for changes of state.
How would I add the custom build valuetree to be editable buy the GUI ?
The audioparameter classes dont seem to fit a valuetree with Children that are a list of ints …
Should I just declare a valuetree and then add a listener too it seperate to the one already included in the audioprocessor class ?
https://docs.juce.com/master/classValueTree_1_1Listener.html#details

Following on from @Xenakios great help above should I try

vt::addListener ( Listener * chordsChanged ) 

(https://docs.juce.com/master/classValueTree_1_1Listener.html) * listener )

I am guessing the listener could be declared as a public member of the AudioProcessor class ( in PluginProcessor.h )

Pretty confused how to implement this !

It’s not clear how to fudge the default AudioProcessorEditor class into something that has “parameters” that are not standard …

Thanks for your advice.
Sean

Just add your custom tree to the “state” member of your plugin’s AudioProcessorValueTreeState. Since you will need a custom GUI, you will however need to handle that somehow yourself in the AudioProcessorEditor, probably with a custom component.

You are of course not obligated to use the ValueTrees at all. But if your plugin is already based on AudioProcessorValueTreeState, it’s probably the cleanest way to deal with it. The GUI will be about as complicated to do either way. And like I already mentioned, the GUI should have as little to do with it all as possible. The plugin should completely work even if there is no GUI. So first figure out how your data structures (for example the ValueTree) are going to work, then figure out the how the GUI works with that.

1 Like

Thanks @Xenakios
I never tried editing the juce library code but I guess it’s never too late to start doing that …
I can see in the juce_AudioProcessorValueTreeState.h there is a member :

ValueTree state; 

Are you suggesting adding a child to that member called “chords” ?
I mean first create the value tree vt using something like your code above and then

state.addChild(vt, -1, nullptr);

After that you suggest hacking into or replacing the juce_AudioProcessorEditor and/or the generic editor to create with a custom gui …

Sounds like a big job but doable…
Sean

There is no need to edit anything in JUCE itself for your use case. You should almost never do that anyway.

The GenericAudioProcessorEditor is useless by itself when you need something more complicated than simple numeric parameters. You need to inherit from AudioProcessorEditor to implement your custom GUI. You could maybe use GenericAudioProcessorEditor in that as a child component to deal with the numeric parameters of your AudioProcessor, but for the chord editing you need to do something else. (Maybe a TextEditor will work at least for testing purposes to enter the chords as lines of text…)

Thanks Xeniakos,
I spend hours on this forum mostly because all the tutorials don’t use the classes that the vst plugin automatically generates.
For example.
This tutorial declares it’s own valuetree state called “parameters”
https://docs.juce.com/master/tutorial_audio_processor_value_tree_state.html
In an attempt to fiddle and learn I tried setting up a value tree in the prepare to play block

void WayloChorder2AudioProcessor::prepareToPlay (double sampleRate, int samplesPerBlock)
{
    // Use this method as the place to do any pre-playback
    // initialisation that you need..
    // initialise array to keep track of playing notes 
    for (int i = 0; i < 127 ; i++ ){
        playing[i]= 0;
    }
    // create a dummy chord progression in a globally declared value tree 
    vt.addChild(makeChordValueTree("Cmaj", {60,64,67}), -1, nullptr);
    vt.addChild(makeChordValueTree("Cmin", {60,63,67}), -1, nullptr);
    
    
    
   
    
}

My next step would be something along the lines of

  this.state.addChild(vt, -1, nullptr);

If I wanted to


"Just add your custom tree to the “state” member of your plugin’s AudioProcessorValueTreeState."

How would I access that “state” member from inside the WayloChorder2AudioProcessor::prepareToPlay function ?
I thought the word “Just” was inappropriately utilized in that sentence :wink:
Maybe CLION would be better at Xcode in helping me find that member …

Sorry beginner C++ question but the JUCE classes hierarchy is a bit of a maze to me .
Sean

Assuming your AudioProcessor (that is, your plugin’s processing part) has a member

AudioProcessorValueTreeState parameters;

You can add your custom state with :

parameters.state.addChild...

You probably shouldn’t add the children in the prepareToPlay method because that can be called multiple times and you would be adding the children multiple times. (Unless you check that the children haven’t already been added…) The AudioProcessor’s constructor is a better place to add your default and/or test states.

Thanks Xeniakos for all your kind help!
I am using the projucer “audio plug in” template.
Xcode ( and clion ) cant find a variable “parameters” or “state”.
I am not sure whether they are created by default. I searched and searched through various constructors in the heirarchy but cant find them declared anywhere.
I would seem I would have to declare that myself ?
If that’s the case I have to figure out how to convert the structure in the plugin tutorial to use one in the audio plugin template.
I did think the constructor was a better place to add the children …
That should be simple enough to do.

Look for a member of type AudioProcessorValueTreeState in the AudioProcessor subclass. If it’s not there, then you need to add it yourself. (Projucer does not add it by default because there are multiple ways to deal with the plugin parameters/states.) But if you are following the AudioProcessorValueTreeState plugin tutorial, the tutorial class should have it…

1 Like

The AudioProcessorValueTreeState is an optional class, that is intended to enhance the AudioProcessor’s handling of Parameters exposed to the host, as well as providing a public ValueTree member, where your additional parameters, that are not automated by the host (e.g. because they are of a kind the host wouldn’t understand, like in your case).
This makes it easy to serialise the plugin’s state in one go for the host to save and restore it later using getStateInformation and setStateInformation.

To use the AudioProcessorValueTreeState, create one member of this type in your AudioProcessor (this procedure is called aggregation).

The way, how the automated parameters are added was recently changed, have a look in this thread: “AudioProcessorValueTreeState Improvements”.

After that to add your own information to the state member of that AudioProcessorValueTreeState, like @Xenakios explained.

1 Like

Thanks Senseis @xenakios and @daniel !
That should keep me going for a while!

I have been on tour away from all this …
At the moment my constructor looks like this

WayloChorder3AudioProcessor::WayloChorder3AudioProcessor()
#ifndef JucePlugin_PreferredChannelConfigurations
     : AudioProcessor (BusesProperties()
                     #if ! JucePlugin_IsMidiEffect
                      #if ! JucePlugin_IsSynth
                       .withInput  ("Input",  AudioChannelSet::stereo(), true)
                      #endif
                       .withOutput ("Output", AudioChannelSet::stereo(), true)
                     #endif
                       )
#endif
{
    AudioProcessorValueTreeState parameters(*this, nullptr);
    parameters.state.addChild(makeChordValueTree("Cmaj", {60,64,67}), -1, nullptr);
    parameters.state.addChild(makeChordValueTree("Cmin", {60,63,67}), -1, nullptr);
   
}

WayloChorder3AudioProcessor::~WayloChorder3AudioProcessor()
{
}

It uses a method I added :

ValueTree WayloChorder3AudioProcessor::makeChordValueTree(String name, std::initializer_list<int> notes)
{
    ValueTree result(name);
    for (size_t i=0;i<notes.size();++i)
        result.setProperty("note_"+String(i), *(notes.begin()+i), nullptr);
    return result;
}

I just instantiated that member class directly in the constructor without declaring it in the header file.

I assume I will now be able to see that data structure from inside the process block and use it.

Do I need a pointer to it in the editor class to access it from over there ?

Is that what you folks suggested ?

The tutorial on the AudioProcessorValueTreeState didn’t help much …

Thanks for all your help !
Sean

No. How would that work? The AudioProcessorValueTreeState you added is a local variable in the constructor. For object scoped variables (that is, to be visible in the class’s methods) you need to have them as class members.

Thanks Xeniakos,
I cant figure out how to make that object a class member.
More of a C++ question than a JUCE question.
Perhaps I should head over to stackexchange !
I looked at this
https://www.learncpp.com/cpp-tutorial/103-aggregation/
It’s not clear at all to me how I would initialize the AudioProcessorValueTreeState as a member of
the AudioProcessor class.

How does this look?

WayloChorder3AudioProcessor::WayloChorder3AudioProcessor()

     //: AudioProcessorValueTreeState parameters(*this, nullptr);
#ifndef JucePlugin_PreferredChannelConfigurations
     : AudioProcessor (BusesProperties()
                     #if ! JucePlugin_IsMidiEffect
                      #if ! JucePlugin_IsSynth
                       .withInput  ("Input",  AudioChannelSet::stereo(), true)
                      #endif
                       .withOutput ("Output", AudioChannelSet::stereo(), true)
                     #endif
                       )
     , parameters(*this, nullptr)
#endif

{
    

    for (int i = 0; i < 127 ; i++ ){
        playing[i]= 0;
    }
 
    ValueTree vt("chords");
    parameters.state.addChild(vt, -1,nullptr);
    vt.addChild(makeChordValueTree("Cmaj", {60,64,67}), -1, nullptr);
    vt.addChild(makeChordValueTree("Cmin", {60,63,67}), -1, nullptr);
    
   
}

My PluginProcessor.h has this in it …

private:
    //==============================================================================
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (WayloChorder3AudioProcessor)
    AudioProcessorValueTreeState parameters;

Do I also need to declare a pointer to it in the editor ?

Sean

I have really no idea how I would use this data structure in my plugin. When not using the ValueTree I had a 2D Vector and a position index.
In the tutorial these things are single memory locations. In the tutorial a pointer is pointed to the memory location in the Audio Processor constructor and dereferenced to find the value.

How to do this with a dynamic structure is a mystery to me.
I don’t see how I can dynamically create pointers to all the memory locations in a ValueTree …

It’s also not clear to me how I would access members in the Value tree stored in this way. It’s all very different to the JUCE examples.

For example in the code above how would I access the value of the 2nd note in the 2nd chord ( i.e Cmin 63 ) .

It seems like the way to access the data members of the valuetree is via the string name. Perhaps I can create a queue with the chord names in it and iterate through that to get to the next chord in the sequence or something …

Thanks for your replies.

Sean

It’s kind of beginning to look like it might be better if you just use your initial std::vector<std::vector<int>> to store your chords…The ValueTree doesn’t really necessarily give you any benefits for your use case but complicates things a lot. On the other hand, without the ValueTree you would need to figure out a way to serialize and deserialize the chords anyway…Well, programming is complicated, what else can I say?

Anyway, here’s a code example that gets the chord notes from the ValueTree :

void testValueTreeChords()
{
	ValueTree chords("chords");
	chords.addChild(makeChordValueTree("cmajor",{60, 64, 67}),-1,nullptr);
	chords.addChild(makeChordValueTree("cminor", { 60, 63, 67 }), -1, nullptr);
	for (int i = 0; i < 8; ++i)
	{
		ValueTree chord = chords.getChild(i % chords.getNumChildren()); // cycle through the chords
		for (int j = 0; j < chord.getNumProperties(); ++j)
		{
			std::cout << (int)chord.getProperty("note_" + String(j)) << " ";
		}
		std::cout << "\n";
	}
}

That is, because it is mixing two things:

  • AudioProcessorValueTreeState:
    a class that is aggregated to the AudioProcessor, that handles the state of the plugin, so it can be easily saved and restored. The state is made up by two things: the parameters, that are exposed to the host and many other data, that is not needed in the host, but still should be restored

  • ValueTree:
    Is a tree of data, similar to XML. The AudioProcessorValueTreeState offers a ValueTreeState, that you can use to add your own data. It is not visible to the host, but still it is saved and easy to restore in the getStateInformation().

Most of the examples only talk about the parameters exposed to the host.

Thanks for your replies,
Programming is indeed challenging but fun.

That nice code Xeniakos posted gets the chord values but it’s still hard for me to see how to dynamically create pointers to all the values in the audioprocessor class .

Just thinking aloud can I just somehow employ BOOST and have a button in the GUI that loads an xml file and parses it to populate the 2d std:vector ?
I have the boost file working standalone.


I see other folks have used BOOST

I would assume it’s possible for a callback in the GUI to start a process of overwriting the std:vector member in the audioprocessor class .
Is that idea too naughty ?
The thing is that none of this stuff needs to happen while the audio thread is running . You just need to be able to create chord sequences and load em up and play them with the midi callbacks.
Shouldn’t it be relatively easy for a JUCE plugin to at least run some C++ code pretty much in the background ?
Sean