SkillAgentSearch skills...

Midifile

C++ classes for reading/writing Standard MIDI Files

Install / Use

/learn @craigsapp/Midifile
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

Midifile: C++ MIDI file parsing library

Travis Build Status AppVeyor Build Status

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:

Class organization

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

<pre> TPQ: 120 TRACKS: 3 Track 0 Tick Seconds Dur Message 0 0 ff 2f 0 Track 1 Tick Seconds Dur Message 0 0 0.5 90 48 40 120 0.5 80 48 40 120 0.5 0.5 90 48 40 240 1 80 48 40 240 1 0.5 90 4f 40 360 1.5 80 4f 40 360 1.5 0.5 90 4f 40 480 2 80 4f 40 480 2 0.5 90 51 40 600 2.5 80 51 40 600 2.5 0.5 90 51 40 720 3 80 51 40 720 3 1 90 4f 40 960 4 80 4f 40 960 4 0.5 90 4d 40 1080 4.5 80 4d 40 1080 4.5 0.5 90 4d 40 1200 5 80 4d 40 1200 5 0.5 90 4c 40 1320 5.5 80 4c 40 1320 5.5 0.5 90 4c 40 1440 6 80 4c 40 1440 6 0.5 90 4a 40 1560 6.5 80 4a 40 1560 6.5 0.5 90 4a 40 1680 7 80 4a 40 1680 7 1 90 48 40 1920 8 80 48 40 1920 8 ff 2f 0 Track 2 Tick Seconds Dur Message 0 0 0.5 90 30 40 120 0.5 80 30 40 120 0.5 0.5 90 3c 40 240 1 80 3c 40 240 1 0.5 90 40 40 360 1.5 80 40 40 360 1.5 0.5 90 3c 40 480 2 80 3c 40 480 2 0.5 90 41 40 600 2.5 80 41 40 600 2.5 0.5 90 3c 40 720 3 80 3c 40 720 3 0.5 90 40 40 840 3.5 80 40 40 840 3.5 0.5 90 3c 40 960 4 80 3c 40 960 4 0.5 90 3e 40 1080 4.5 80 3e 40 1080 4.5 0.5 90 3b 40 1200 5 80 3b 40 1200 5 0.5 90 3c 40 1320 5.5 80 3c 40
View on GitHub
GitHub Stars870
CategoryContent
Updated1d ago
Forks159

Languages

C++

Security Score

100/100

Audited on Apr 2, 2026

No findings