Midi file to array?

midi

#1

Hi all,
I have a vague plan to convert a midi file containing a chord sequence of say whole note ( semibreve) chords into a a data structure in JUCE to use in some sort of arpeggiator/chord playing type midi plugin. In terms of C++ I assume I will need some sort of dynamic array of pointers to dynamic int arrays. It would be cool if the arrays could be stored as presets in the plugin. Perhaps JUCE can count the length of chord sequence and at least the array of pointers can be created statically. Has anyone done anything like this?
I can’t quite see how these can be used …
https://docs.juce.com/master/classMidiBuffer.html
https://docs.juce.com/master/classMidiFile.html
I also thought perhaps a (python?) script could somehow do the processing and spit the array out into the JUCE program ??
Any ideas ? Thoughts ?
Sean


#2

I am working on something similar - I use XML structures to store my MIDI events. Works great! Very rough 0.7 code (and a working - be it very limited in functionality - plugin at github .

PM me if you want details.


#3

Thanks very much tomto I will take a look at your git and try out your plugin.
Hopefully that will give some good ideas …
So generally I understand you are parsing a midifile into something like this
https://docs.juce.com/master/classXmlElement.html
and then using this to spit out midi events in JUCE .
Is that it ? Did you consider this https://www.musicxml.com/ ?

Sean


#4

I wrote this funny old C++ program to enter chords into an array of vectors.
Is assume it’s possible with a JUCE editor component to create some sort of pop-up box and just store the data structure as a preset ?

#include <iostream>
#include <vector>

int main() {
    using namespace std;
    int numChords;
    int numNotes ;
    int note;
    vector<int> chord;
    // user enters total number of chords
    cout << "Enter number of chords!" << endl;
    cin >> numChords; // variable for number of notes in the chord
    cout << "You entered " << numChords << endl;
    vector< vector<int> > chords; // array to store chord arrays

    // 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
    }

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

    return 0;
}

#5

That’s exactly how it works. Take a look at insertPatternFromFile() in the code to see how that’s done. I didn’t know about musicxml.com - I’ll check it out!


#6

It’s hard to see a solution where a chord sequence could be saved as a plugin preset.
Since the chord sequence is a dynamic structure and the plugin parameters look like they need to be statically assigned when the plugin is programmed it’s hard to figure out a solution. If I could load an XML valuetree state I could create a seperate xml creator application . Most of the examples I can find of loading binary files, text files or xml files as plugin settings assume that settings are a static structure. I also looked for ways to just run a C++ script from within a plugin to update variables but couldn’t see that. I guess I need to look more at all your code and figure it out. It would be nice if a plugin state could have a vector in it not just a float !
Sean


#7

You might just want to look at the tracktion engine for that kind of high-level task.


#8

You can save and load any data in the AudioProcessor getStateInformation and setStateInformation methods. You just need to figure out how to serialize that data into binary and deserialize it back.


#9

I do that as well Sean. Midi data is stored as xml, and is serialized in/out as state of the plugin. Works great. And since Juce makes serializing those XmlElements easy it hardly took any codeing. (actaully 2 lines: one serializing out and one serializing in).


#10

Thanks everyone for your help …
It’s hard to see what sort of Audioparameter class to store the info as …
It looks like I could save the chord sequence as a string
https://docs.juce.com/master/classAudioParameterChoice.html
say
{60,72,84,N,60,72} // N is a new chord
I could then parse the string into a vector of int vectors inside the plugin.
I could create an external program to generate the strings .
According to this tutorial it looks like the audioparameter choice is the only way to store something like that.
https://docs.juce.com/master/tutorial_audio_parameter.html
Excuse the newbie questions ! I have build a few JUCE plugins but never dealt with the plugin state …
Sean


#11

You likely can not use the audioparameters in any sensible way for that. You just need to deal with the state in some other way. Some plugins attempt to do things like have thousands or even tens of thousands of parameters to deal with states like that, but it isn’t a sensible approach to it. The binary state chunks system exist anyway…


#12

Is there a way to click a button inside a JUCE plugin and load a settings file?
I have another plugin which I build with MAX which is a Delay and a lot of people would love settings for it … It has sliders etc but the only way to save settings is to do it in the DAW.


#13

Again, look at TopiaryBeatz. It has a button to save the state, with all notes (and other midi events), to an XML file. You could easily save to a binary file but for now, during development I like to be able to inspect the state, and XML makes that easy.