I was looking for a simple midi file parser library, but I did not find anything that made me happy, so I decided to provide one myself. Here are my design goals:

  • minimal RAM requirements for midi with 1 track
  • incremental writing and parsing of data
  • No external dependencies: compile and run outside of Arduino with cmake
  • Using the Arduino Print API for writing data
  • For processors with a lot of RAM: provide some multitrack support

I did not want to start from scratch, so I based my work on the Midi Parser from Alexandre Bique.

Arduino Example Sketch

Here is an example sketch that shows how to parse a midi file. To reduce the number of lines of code I was using my AudioTools library, but you can use this library w/o it.

#include "AudioTools.h" // https://github.com/pschatzmann/arduino-audio-tools
#include "MidiFileParserMultiTrack.h"
#include "examples/example-midi.h"

using namespace midi;

const int write_size = 256;
MidiFileParser parser;  // Midi parser
MemoryStream midi_data(example_mid, example_mid_len); // Midi Data
StreamCopy copy(parser, midi_data, write_size); // Copy data to parser
bool debug = false;

void setup() {
  Serial.begin(115200);
  parser.begin(debug, 256 * 5);
}

void loop() {
  // Try to keep the parser filled
  if (parser.availableForWrite() > write_size) {
    copy.copy();
  }

  // Parse midi
  auto state = parser.parse(); // parseTimed() or parse();

  // Process Result
  switch (state.status)
  case MIDI_PARSER_TRACK_MIDI: {
    // process midi
    char msg[100];
    sprintf(msg, "process  time-cumulated ms: %ld status: %d [%s]   channel: %d  param1: %d   param2: %d",
            (long)state.timeInMs(), state.midi.status,
            parser.midi_status_name(state.midi.status), state.midi.channel,
            state.midi.param1, state.midi.param2);
    Serial.println(msg);
    break;
  case MIDI_PARSER_ERROR:
    Serial.println("Error\n");
  case MIDI_PARSER_EOB:
    stop();
    break;
  default:
    break;
  }
}

The parse() method is returning immediately while the parseTimed() returns the result only after taking the timing into consideration.

This (potentially updated) example can be found on Github. There you can also find more examples!

And last but not least: here is a link to the class documentation.


0 Comments

Leave a Reply

Avatar placeholder

Your email address will not be published. Required fields are marked *