BOOST XML JUCE


#1

If I export an xml from a C++ program using the boost library will I be able to import it into JUCE ?
Something like this …


Thanks for your replies.


#2

Is there some particular reason for you to use Boost? Juce itself has Xml classes…Anyway, the point of Xml is that the data would be interchangeable.


#3

Just a side note, like @Xenakios said, the XmlElement and XmlDocument should work. Although, JUCE has no DTD checks and all these XML grammar workflows (XSLT).

Even though ValueTree stores into XML, it cannot process all XML, only a subset. The main difference is, that XML tags can have a content, which the ValueTree doesn’t support.


#4

Thanks for your replies !!
I wrote this program to store a chord progression as a 2D dynamic vector.
I have created a JUCE chord playing VST plugin which works with a 2D std::vector declared globally.

Ideally it would be possible to run a program like this from within JUCE but with all the looped input I am not sure how it’s going to work within the processblock and the JUCE gui callback.

It would be lovely if I could use the JUCE pianocomponent for input etc …

I assume with a VST plugin the audio/midi thread and the GUI have to be started at the outset when the plugin gets loaded and started.

This seemed like a simple solution.
I did think of just trying to write a seperate standalone application in JUCE which did much the same thing that used the JUCE xml classes.

I looked at the documentation and scoured the forum and although it’s a relatively simple problem I can’t easily see how I would save an array as an xml file in JUCE and then reimport it.

#include <iostream>
#include <vector>
#include <iostream>
#include <fstream>
#include <boost/serialization/serialization.hpp>
#include <boost/serialization/vector.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>

using namespace std;

int main() {
    using namespace std;
    int numChords;

    vector<vector<int> > chords; // array to store chord arrays

    int numNotes;
    int note;
    vector<int> chord;
    // DISPLAY MIDI NOTE NUMBERS
    cout << "Waylo Chorder Utility" << endl;
    cout << endl;
    cout << "MIDI NOTE NUMBERS : 60 is MIDDLE C !" << endl;
    cout << endl;
    cout << "     C# 25      D# 27           F#30     G# 32      A# 34" << endl;
    cout << "C0 24 	    D 26       E 28 F 29      G 31      A 33       B 35" << endl;
    cout << endl;
    cout << "     C# 37      D# 39           F# 42    G# 44      A# 46" << endl;
    cout << "C1 36      D 38       E 40 F 41      G 43      A 45       B 47" << endl;
    cout << endl;
    cout << "     C# 49      D# 51           F# 54    G# 56      A# 58" << endl;
    cout << "C2 48      D 50       E 52 F 53      G 55      A 57       B 59" << endl;
    cout << " " << endl;
    cout << "     C# 61      D# 63           F# 66    G# 6       A# 70" << endl;
    cout << "C3 60      D 62       E 64 F 65      G 67      A 69       B 71" << endl;
    cout << endl;
    cout << "     C# 73      D# 75           F# 78    G#80       A#82" << endl;
    cout << "C4 72      D 74       E 76 F 77      G 79      A 81       B 83 " << endl;

    cout << "Enter number of chords!" << endl;
    cin >> numChords; // variable for number of notes in the chord
    cout << "You entered " << numChords << endl;


// store notes for each chord in array
    for (int i = 0; i < numChords; i++) {
        cout << "enter number of notes in chord " << i + 1 << endl;
        cin >> numNotes;
        for (int j = 0; j < numNotes; j++) {
            cout << " enter chord " << i + 1 << " note number " << j + 1 << endl;
            cin >> note;
            chord.push_back(note); // store this note in array for this chord
        }
        chords.push_back(chord); // store the created chord in the chord array
        chord.clear(); // clear the temp chord and set it to null so next chord can be entered
    }

    
    // print the array
    cout << endl << "you entered: " << endl;
    // print the results
    for (int i = 0; i < numChords; i++) {
        for (int j = 0; j < chords[i].size(); j++) {
            cout << chords[i][j] << ",";
        }
        cout << endl;
    }

    {
        // store the array to a file
        std::ofstream ofs("dump.dat");
        boost::archive::text_oarchive oa(ofs);
        oa & chords;
    }

    chords.clear(); // clear the original array

    {
        // restore the array from the file
        std::ifstream ifs("dump.dat");
        boost::archive::text_iarchive ia(ifs);
        ia & chords;
    }

    cout << endl << "you saved: " << endl;
    // print the restored array
    for (int i = 0; i < numChords; i++) {
        for (int j = 0; j < chords[i].size(); j++) {
            cout << chords[i][j] << ",";
        }
        cout << endl;
    }

    return 0;
}

I wonder if this file generated by BOOST can be easily parsed by JUCE ?

Thanks for your help!
Sean


#5

I don’t know about Boost, but here are some functions for inspiration to do it with the Juce classes (there is no error checking nor optimizations attempted here) :


#6

wonderful !!! Thanks so much I will play with those !!


#7

For what it’s worth, I found using ValueTree’s when possible to be super useful. Getting the XML read/write for free, undo/redo and being a great data model container (for all the GUI and controllers to listen to). ValueTree’s would be my first choice in what you are doing.


#8

Thanks for all the suggestions … I don’t think I can use an audioparameter float for each midi note in a dynamically created chord progression. Lets say there are 30 chords with 10 notes in them.

I looked at this class
ValueTree::ValueTree ( const [Identifier] & type ) explicit

Can I really declare a value true like this ?:

ValueTree chordsequence ( std::vector < std::vector > )

It would seem like a lot of messy coding to try and declare a value tree to hold the chords, children for each chord and then granchildren for each note in each chord dynamically in a value tree …

It seems like those classes are really just designed to hold some big static data structure with floats and bools for plugin parameters.

Wouldn’t a simple string text input box in the GUI that was parsed and converted into a data structure be a lot simpler?
Sean


#9

The GUI should have nothing to do with it. You should design your code so that you are able to implement the GUI in any kind of manner. (The code should also work without any GUI objects around, if it is to be used in a plugin.)

Using ValueTrees for the chords isn’t too messy if you just have some helper functions, like :


ValueTree 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;
}

ValueTree vt("chords");
vt.addChild(makeChordValueTree("Cmaj", {60,64,67}), -1, nullptr);
vt.addChild(makeChordValueTree("Cmin", {60,63,67}), -1, nullptr);
std::unique_ptr<XmlElement> xml(vt.createXml());
xml->writeToFile(File("/Users/name/chords1.xml"), "");

The ValueTrees are a very powerful data structure. (And there’s nothing “static” about them, you can add and remove stuff dynamically just fine.) They might seem like overkill for your particular use case at first, but they might prove to be more useful later when your software gets more complicated. But it’s of course up to you to decide if you want to deal with the initial complexity of ValueTrees.


#10

that’s very cool Xeniakos that certainly looks like the way to go ! I owe you a libation or 2 !!


#11

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.


#12

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.)


#13

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…


#14

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


#15

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.


#16

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


#17

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…)


#18

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


#19

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.


#20

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.