Midifile
C++ classes for reading/writing Standard MIDI Files
Install / Use
/learn @craigsapp/MidifileREADME
Midifile: C++ MIDI file parsing library
Midifile is a library of C++ classes for reading/writing Standard MIDI files. The library consists of 6 classes:
<table> <tr valign="top"><td> <a href="http://midifile.sapp.org/class/MidiFile">MidiFile</a> </td><td> The main interface for dealing with MIDI files. The MidiFile class appears as a two dimensional array of MidiEvents: the first dimension is a list of tracks, and the second dimension is a list of MidiEvents. </td></tr> <tr valign="top"><td> <a href="http://midifile.sapp.org/class/MidiEventList">MidiEventList</a> </td><td> A data structure that manages the list of MidiEvents for a MIDI file track. </td></tr> <tr valign="top"><td> <a href="http://midifile.sapp.org/class/MidiEvent">MidiEvent</a> </td><td> The primary storage unit for MidiMessages in a MidiFile. The class consists of a tick timestamp (delta or absolute) and a vector of MIDI message bytes (or Standard MIDI File meta messages). </td></tr> <tr valign="top"><td> <a href="http://midifile.sapp.org/class/MidiMessage">MidiMessage</a> </td><td> The base class for MidiEvents. This is a STL vector of unsigned bytes representing a MIDI (or meta) message. </td></tr> <tr valign="top"><td> <a href="http://midifile.sapp.org/class/Binasc">Binasc</a> </td><td> A helper class for MidiFile that allows reading/writing of MIDI files in an ASCII format describing the bytes of the binary Standard MIDI Files. </td></tr> <tr valign="top"><td> <a href="http://midifile.sapp.org/class/Options">Options</a> </td><td> A optional convenience class used for parsing command-line options in the example programs. This class can be removed from the library since it is not needed for using the MidiFile class. </td></tr> </table>Here is a schematic of how the classes are used together:

The MidiFile class contains a vector of tracks stored in MidiEventList
objects. The MidiEventList is itself a vector of MidiEvents, which stores
each MIDI event in the track. MidiEvents contain a timestamp and a MidiMessage
which is a vector of unsigned char values, storing the raw bytes of a MIDI message
(or meta-message).
Documentation is under construction at http://midifile.sapp.org. Essential examples for reading and writing MIDI files are given below.
Downloading
You can download as a ZIP file from the Github page for the midifile library, or if you use git, then download with this command:
git clone https://github.com/craigsapp/midifile
This will create the midifile directory with the source code for the library.
Compiling with GCC
The library can be compiled with the command:
make library
This will create the file lib/libmidifile.a which can be used to link
to programs that use the library. Example programs can be compiled with
the command:
make programs
This will compile all example programs in the tools directory. Compiled
example programs will be stored in the bin directory. To compile both the
library and the example programs all in one step, type:
make
To compile only a single program, such as createmidifile, type:
make createmidifile
You can also place your own programs in tools, such as myprogram.cpp
and to compile type:
make myprogram
The compiled program will be bin/myprogram.
Using in your own project
The easiest way to use the midifile library in your own project is to
copy the header files in the include directory and the source-code
files in the src directory into your own project. You do not
need to copy Options.h or Options.cpp since the MidiFile class is
not dependent on them. The verovio
and midiroll projects on Github
both use this method to use the midifile library. Alternatively, you
can fork the midifile repository and build a compiled library file of
the source code that can be copied with the include directory contents
into your project.
MIDI file reading examples
The following program lists all MidiEvents in a MIDI file. The program iterates over each track, printing a list of all MIDI events in the track. For each event, the absolute tick timestamp for the performance time of the MIDI message is given, followed by the message itself as a list of hex bytes.
You can run the MidiFile::doTimeAnalysis() function to convert
the absolute tick timestamps into seconds, according to any tempo
meta-messages in the file (using a default tempo of 120 quarter notes
per minute if there are no tempo meta-messages). The absolute starting
time of the event is shown in the second column of the program's output.
The MidiFile::linkNotePairs() function can be used to match note-ons
and note-offs. When this is done, you can access the duration of the
note with MidiEvent::getDurationInSeconds() for note-on messages. The
note durations are shown in the third column of the program's output.
Note that the midifile library classes are in the smf namespace,
so using namespace smf; or smf:: prefixes are needed to access
the classes.
#include "MidiFile.h"
#include "Options.h"
#include <iostream>
#include <iomanip>
using namespace std;
using namespace smf;
int main(int argc, char** argv) {
Options options;
options.process(argc, argv);
MidiFile midifile;
if (options.getArgCount() == 0) midifile.read(cin);
else midifile.read(options.getArg(1));
midifile.doTimeAnalysis();
midifile.linkNotePairs();
int tracks = midifile.getTrackCount();
cout << "TPQ: " << midifile.getTicksPerQuarterNote() << endl;
if (tracks > 1) cout << "TRACKS: " << tracks << endl;
for (int track=0; track<tracks; track++) {
if (tracks > 1) cout << "\nTrack " << track << endl;
cout << "Tick\tSeconds\tDur\tMessage" << endl;
for (int event=0; event<midifile[track].size(); event++) {
cout << dec << midifile[track][event].tick;
cout << '\t' << dec << midifile[track][event].seconds;
cout << '\t';
if (midifile[track][event].isNoteOn())
cout << midifile[track][event].getDurationInSeconds();
cout << '\t' << hex;
for (int i=0; i<midifile[track][event].size(); i++)
cout << (int)midifile[track][event][i] << ' ';
cout << endl;
}
}
return 0;
}
The above example program will read the first filename it finds on
the command-line, or it will read from standard input if no arguments
are found. Both binary standard MIDI files and ASCII representations
of MIDI Files can be input into the program. For example, save the
following text into a file called twinkle.txt to use as input data.
This content represents the hex bytes for a standard MIDI file, which
will automatically be parsed by the MidiFile class.
4d 54 68 64 00 00 00 06 00 01 00 03 00 78 4d 54 72 6b 00 00 00 04 00 ff 2f
00 4d 54 72 6b 00 00 00 76 00 90 48 40 78 80 48 40 00 90 48 40 78 80 48 40
00 90 4f 40 78 80 4f 40 00 90 4f 40 78 80 4f 40 00 90 51 40 78 80 51 40 00
90 51 40 78 80 51 40 00 90 4f 40 81 70 80 4f 40 00 90 4d 40 78 80 4d 40 00
90 4d 40 78 80 4d 40 00 90 4c 40 78 80 4c 40 00 90 4c 40 78 80 4c 40 00 90
4a 40 78 80 4a 40 00 90 4a 40 78 80 4a 40 00 90 48 40 81 70 80 48 40 00 ff
2f 00 4d 54 72 6b 00 00 00 7d 00 90 30 40 78 80 30 40 00 90 3c 40 78 80 3c
40 00 90 40 40 78 80 40 40 00 90 3c 40 78 80 3c 40 00 90 41 40 78 80 41 40
00 90 3c 40 78 80 3c 40 00 90 40 40 78 80 40 40 00 90 3c 40 78 80 3c 40 00
90 3e 40 78 80 3e 40 00 90 3b 40 78 80 3b 40 00 90 3c 40 78 80 3c 40 00 90
39 40 78 80 39 40 00 90 35 40 78 80 35 40 00 90 37 40 78 80 37 40 00 90 30
40 81 70 80 30 40 00 ff 2f 00
Below is the output from the example program given the above input data. The
TPQ value is the ticks-per-quarter-note value from the MIDI header. In
this example, each quarter note has a duration of 120 MIDI file ticks. The
above MIDI file contains three tracks, with the first track (the expression
track, having no content other than the end-of-track meta message, ff 2f 00
in hex bytes. The second track starts with a MIDI note-on message 90 48 40
(in hex) which will start playing MIDI note 72 (C pitch one octave above
middle C) with a medium loudness (40 hex = 64 in decimal notation).
