Giter Club home page Giter Club logo

midifile's Introduction

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:

MidiFile 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.
MidiEventList A data structure that manages the list of MidiEvents for a MIDI file track.
MidiEvent 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).
MidiMessage The base class for MidiEvents. This is a STL vector of unsigned bytes representing a MIDI (or meta) message.
Binasc 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.
Options 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.

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

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
1320	5.5	0.5	90 39 40
1440	6		80 39 40
1440	6	0.5	90 35 40
1560	6.5		80 35 40
1560	6.5	0.5	90 37 40
1680	7		80 37 40
1680	7	1	90 30 40
1920	8		80 30 40
1920	8		ff 2f 0

The default behavior of the MidiFile class is to store the absolute tick times of MIDI events, available in MidiEvent::tick, which is the tick time from the start of the file to the current event. In standard MIDI files, tick are stored as delta values, where the tick indicates the duration to wait since the previous message in a track. To access the delta tick values, you can either (1) subtrack the current tick time from the previous tick time in the list, or call MidiFile::makeDeltaTime() to convert the absolute tick values into delta tick values.

The MidiFile::joinTracks() function can be used to convert multi-track data into a single time sequence. The joinTrack() operation can be reversed by calling the MidiFile::splitTracks() function. Here is a sample of program that joins the MidiEvents into a single track so that the data can be processed in a single loop:

#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(options.getArg(1));
   else midifile.read(cin);
   cout << "TPQ: " << midifile.getTicksPerQuarterNote() << endl;
   cout << "TRACKS: " << midifile.getTrackCount() << endl;
   midifile.joinTracks();
   // midifile.getTrackCount() will now return "1", but original
   // track assignments can be seen in .track field of MidiEvent.
   cout << "TICK    DELTA   TRACK   MIDI MESSAGE\n";
   cout << "____________________________________\n";
   MidiEvent* mev;
   int deltatick;
   for (int event=0; event < midifile[0].size(); event++) {
      mev = &midifile[0][event];
      if (event == 0) deltatick = mev->tick;
      else deltatick = mev->tick - midifile[0][event-1].tick;
      cout << dec << mev->tick;
      cout << '\t' << deltatick;
      cout << '\t' << mev->track;
      cout << '\t' << hex;
      for (int i=0; i < mev->size(); i++)
         cout << (int)(*mev)[i] << ' ';
      cout << endl;
   }
   return 0;
}

Below is the new single-track output. The first column is the absolute tick timestamp of the message; the second column is the delta tick value; the third column is the original track value; and the last column contains the MIDI message (in hex bytes).

TPQ: 120
TRACKS: 3
TICK    DELTA   TRACK   MIDI MESSAGE
____________________________________
0	0	1	90 48 40
0	0	2	90 30 40
0	0	0	ff 2f 0
120	120	1	80 48 40
120	0	2	80 30 40
120	0	2	90 3c 40
120	0	1	90 48 40
240	120	2	80 3c 40
240	0	1	80 48 40
240	0	2	90 40 40
240	0	1	90 4f 40
360	120	2	80 40 40
360	0	1	80 4f 40
360	0	1	90 4f 40
360	0	2	90 3c 40
480	120	2	80 3c 40
480	0	1	80 4f 40
480	0	2	90 41 40
480	0	1	90 51 40
600	120	2	80 41 40
600	0	1	80 51 40
600	0	1	90 51 40
600	0	2	90 3c 40
720	120	1	80 51 40
720	0	2	80 3c 40
720	0	2	90 40 40
720	0	1	90 4f 40
840	120	2	80 40 40
840	0	2	90 3c 40
960	120	2	80 3c 40
960	0	1	80 4f 40
960	0	2	90 3e 40
960	0	1	90 4d 40
1080	120	1	80 4d 40
1080	0	2	80 3e 40
1080	0	2	90 3b 40
1080	0	1	90 4d 40
1200	120	1	80 4d 40
1200	0	2	80 3b 40
1200	0	2	90 3c 40
1200	0	1	90 4c 40
1320	120	1	80 4c 40
1320	0	2	80 3c 40
1320	0	1	90 4c 40
1320	0	2	90 39 40
1440	120	1	80 4c 40
1440	0	2	80 39 40
1440	0	1	90 4a 40
1440	0	2	90 35 40
1560	120	1	80 4a 40
1560	0	2	80 35 40
1560	0	2	90 37 40
1560	0	1	90 4a 40
1680	120	1	80 4a 40
1680	0	2	80 37 40
1680	0	2	90 30 40
1680	0	1	90 48 40
1920	240	1	80 48 40
1920	0	2	80 30 40
1920	0	1	ff 2f 0
1920	0	2	ff 2f 0

MIDI file writing example

Below is an example program to create a MIDI file. This program will generate a random sequence of notes and append them to the end of the track. By default a MidiFile object contains a single track and will be written as a type-0 MIDI file unless more tracks are added. After adding notes to the track, it must be sorted into time sequence before being written to a file.

#include "MidiFile.h"
#include "Options.h"
#include <random>
#include <iostream>

using namespace std;
using namespace smf;

int main(int argc, char** argv) {
   Options options;
   options.define("n|note-count=i:10", "How many notes to randomly play");
   options.define("o|output-file=s",   "Output filename (stdout if none)");
   options.define("i|instrument=i:0",  "General MIDI instrument number");
   options.define("x|hex=b",           "Hex byte-code output");
   options.process(argc, argv);

   random_device rd;
   mt19937 mt(rd());
   uniform_int_distribution<int> starttime(0, 100);
   uniform_int_distribution<int> duration(1, 8);
   uniform_int_distribution<int> pitch(36, 84);
   uniform_int_distribution<int> velocity(40, 100);

   MidiFile midifile;
   int track   = 0;
   int channel = 0;
   int instr   = options.getInteger("instrument");
   midifile.addTimbre(track, 0, channel, instr);

   int tpq     = midifile.getTPQ();
   int count   = options.getInteger("note-count");
   for (int i=0; i<count; i++) {
      int starttick = int(starttime(mt) / 4.0 * tpq);
      int key       = pitch(mt);
      int endtick   = starttick + int(duration(mt) / 4.0 * tpq);
      midifile.addNoteOn (track, starttick, channel, key, velocity(mt));
      midifile.addNoteOff(track, endtick,   channel, key);
   }
   midifile.sortTracks();  // Need to sort tracks since added events are
                           // appended to track in random tick order.
   string filename = options.getString("output-file");
   if (filename.empty()) {
      if (options.getBoolean("hex")) midifile.writeHex(cout);
      else cout << midifile;
   } else
      midifile.write(filename);

   return 0;
}

If no output file is specified, the MIDI file contents will be printed in the Binasc format to standard output, which can be read back into a MidiFile object and converted into a Standard MIDI file (see the read/write example further down the page for how to do that):

"MThd"			; MIDI header chunk marker
4'6			; bytes to follow in header chunk
2'0			; file format: Type-0 (single track)
2'1			; number of tracks
2'120			; ticks per quarter note

;;; TRACK 0 ----------------------------------
"MTrk"			; MIDI track chunk marker
4'89			; bytes to follow in track chunk
v30	90 '74 '72	; note-on D5
v150	90 '68 '88	; note-on G#4
v0	90 '79 '83	; note-on G5
v60	90 '74 '0	; note-off D5
v150	90 '79 '0	; note-off G5
v30	90 '68 '0	; note-off G#4
v990	90 '60 '100	; note-on C4
v90	90 '60 '0	; note-off C4
v630	90 '83 '69	; note-on B5
v60	90 '83 '0	; note-off B5
v30	90 '56 '51	; note-on G#3
v90	90 '56 '0	; note-off G#3
v390	90 '78 '46	; note-on F#5
v30	90 '60 '78	; note-on C4
v90	90 '78 '0	; note-off F#5
v0	90 '70 '56	; note-on A#4
v60	90 '76 '100	; note-on E5
v90	90 '60 '0	; note-off C4
v30	90 '76 '0	; note-off E5
v60	90 '70 '0	; note-off A#4
v0	ff 2f v0	; end-of-track

Here is the MIDI data visualized with the example program mid2svg:

10 random nots

The -x option can be used to output the data as hex byte-codes, the -n option controls the number of notes, and -i # specifies the instrument number to be used:

myprogram -n 100 -x -i 24

produces the hex byte-code MIDI file:

4d 54 68 64 00 00 00 06 00 00 00 01 00 78 4d 54 72 6b 00 00 03 27 00 c0 18
1e 90 4d 2f 1e 90 31 5e 00 90 40 42 1e 90 47 55 1e 90 47 00 00 90 31 00 00
90 32 62 1e 90 43 2d 1e 90 43 00 00 90 3f 5f 1e 90 32 00 1e 90 4d 00 00 90
47 38 1e 90 51 33 1e 90 40 00 00 90 31 31 00 90 35 3a 1e 90 24 41 00 90 4d
4f 00 90 4e 32 1e 90 31 00 00 90 51 00 1e 90 4e 00 00 90 48 51 1e 90 3f 00
00 90 24 00 1e 90 47 00 1e 90 35 00 00 90 2c 61 1e 90 4d 63 3c 90 4d 00 00
90 48 00 00 90 33 30 1e 90 2c 00 00 90 4d 00 00 90 40 5f 00 90 45 5f 00 90
3e 58 00 90 3f 45 00 90 24 4a 1e 90 33 00 00 90 3c 3c 1e 90 32 38 1e 90 39
40 1e 90 53 43 1e 90 40 00 00 90 3f 00 00 90 3e 00 00 90 45 00 00 90 4d 62
1e 90 24 00 00 90 32 00 00 90 30 42 00 90 2d 28 1e 90 3c 00 00 90 4d 00 00
90 53 00 00 90 2a 45 3c 90 36 51 1e 90 39 00 00 90 2a 00 00 90 36 4b 3c 90
36 00 00 90 3e 5c 1e 90 2d 00 1e 90 30 00 00 90 3e 00 3c 90 41 48 00 90 37
3f 00 90 36 3a 00 90 41 51 00 90 46 38 3c 90 36 00 1e 90 36 00 00 90 46 00
00 90 36 58 1e 90 41 00 00 90 32 44 00 90 47 2a 1e 90 37 00 00 90 45 2b 1e
90 41 53 00 90 3e 2d 1e 90 3e 00 00 90 33 28 00 90 29 4b 1e 90 41 00 00 90
41 00 1e 90 29 00 00 90 49 51 1e 90 47 00 00 90 35 49 00 90 49 43 1e 90 35
00 00 90 45 00 00 90 36 00 00 90 27 5c 1e 90 32 00 1e 90 49 00 00 90 28 4d
1e 90 49 00 00 90 33 00 00 90 2e 44 1e 90 29 2b 3c 90 27 00 00 90 24 3e 00
90 28 53 00 90 52 51 1e 90 4d 4f 00 90 26 5c 1e 90 28 00 00 90 29 00 00 90
27 32 1e 90 28 00 00 90 2e 00 00 90 4d 00 1e 90 2f 28 1e 90 4a 5a 00 90 47
43 1e 90 4a 00 00 90 52 00 00 90 24 00 00 90 34 2f 1e 90 2f 00 00 90 3c 5e
00 90 28 4f 00 90 32 2d 1e 90 26 00 00 90 3c 00 00 90 27 00 00 90 53 63 1e
90 47 00 1e 90 32 00 00 90 44 5d 00 90 32 40 1e 90 28 00 00 90 46 46 1e 90
34 00 1e 90 2a 3e 1e 90 53 00 00 90 3a 3f 00 90 53 31 1e 90 28 5f 1e 90 28
00 00 90 46 00 00 90 53 00 00 90 2a 00 1e 90 32 00 00 90 3a 00 00 90 44 00
3c 90 33 4d 1e 90 53 57 00 90 54 30 1e 90 38 45 1e 90 2f 46 1e 90 2f 00 00
90 33 00 1e 90 3a 61 00 90 38 40 1e 90 54 00 00 90 27 37 1e 90 3a 00 00 90
53 00 00 90 32 29 1e 90 38 00 00 90 40 2b 00 90 36 41 1e 90 38 00 00 90 34
46 1e 90 27 00 5a 90 36 00 00 90 32 00 00 90 40 00 00 90 48 4a 5a 90 34 00
00 90 48 00 1e 90 29 62 00 90 3e 4d 1e 90 39 3e 00 90 4a 2d 00 90 40 2d 3c
90 39 00 00 90 4a 00 00 90 25 58 1e 90 29 00 00 90 41 37 00 90 45 4c 00 90
4d 64 1e 90 41 00 00 90 3e 00 1e 90 4d 00 3c 90 40 00 00 90 25 00 00 90 39
4a 3c 90 32 43 1e 90 45 4a 1e 90 45 00 3c 90 45 00 3c 90 32 00 00 90 39 00
00 ff 2f 00

Visualization with bin/mid2svg -s 6 -a 12 -v:

100 random notes

Read/Write example

Here is an example minimal program that converts the above hex byte-codes into a standard MIDI file:

#include "MidiFile.h"
#include <iostream>

using namespace std;
using namespace smf;

int main(int argc, char** argv) {
   if (argc != 3) return 1;
   MidiFile midifile;
   midifile.read(argv[1]);
   if (midifile.status()) midifile.write(argv[2]);
   else cerr << "Problem reading MIDI file " << argv[1] << endl;
}

The MidiFile::read() function will automatically identify if the input is a binary standard MIDI file, a hex byte-code representation, or a generalized binasc syntax file (which includes byte-codes). The MidiFile::status() function can be checked after reading a MIDI file to determine if the file was read without problems.

Code snippets

How to process multiple input files and get duration of MIDI files

This example uses the MidiFile::getFileDurationInSeconds() to calculate the duration of a MIDI file. Also, this example shows how to process multiple input files when using the Options class.

#include "MidiFile.h"
#include "Options.h"
#include <iostream>
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);
      cout << midifile.getFileDurationInSeconds() << " seconds" << endl;
   } else {
      int count = options.getArgCount();
      for (int i=0; i<count; i++) {
         string filename = options.getArg(i+1);
         if (count > 1) cout << filename << "\t";
         midifile.read(filename);
         cout << midifile.getFileDurationInSeconds() << " seconds" << endl;
      }
   }
   return 0;
}

How to extract text meta-messages from a MIDI file.

The MidiMessage::isText() function will return true if the message is a text meta-message. The following program merges all tracks into a single list and does one loop checking for text meta-messages, printing them out when found. The MidiMessage::getMetaContent() function extracts the text string of the message from the raw MIDI file bytes.

#include "MidiFile.h"
#include <iostream>

using namespace std;
using namespace smf;

int main(int argc, char** argv) {
   MidiFile midifile;
   if (argc == 1) midifile.read(cin);
   else midifile.read(argv[1]);
   if (!midifile.status()) {
      cerr << "Problem reading MIDI file" << endl;
      return 1;
   }

   midifile.joinTracks();
   for (int i=0; i<midifile[0].getEventCount(); i++) {
      if (midifile[0][i].isText()) {
         string content = midifile[0][i].getMetaContent();
         cout << content << endl;
      }
   }

   return 0;
}

Extracting lyrics would work the same by using .isLyricText() instead of .isText(), and a track-name meta-message is identified by .isTrackName().

How to convert a Type-1 MIDI file into a Type-0 MIDI file

Here is a demonstration of converting a multi-track MIDI file into a single-track MIDI file:

#include "MidiFile.h"
#include <iostream>
using namespace std;
using namespace smf;

int main(int argc, char** argv) {
   if (argc != 3) {
      cerr << "Usage: " << argv[0] << " input output" << endl;
      return 1;
   }
   MidiFile midifile;
   midifile.read(argv[1]);
   if (!midifile.status()) {
      cerr << "Problem reading MIDI file" << endl;
      return 1;
   }

   midifile.joinTracks();
   midifile.write(argv[2]);

   return 0;
}

The .joinTracks() function merges all tracks into a single track. And if a MidiFile object has only one track when it is being written, it will be written as a type-0 (single-track) MIDI file.

How to check for a drum track in a MIDI file

In General MIDI files, the drum track is on the 10th channel, which is represented by the integer 9. The following example searches through the MIDI events in each track until it finds a note on channel 9:

#include "MidiFile.h"
#include <iostream>
using namespace std;
using namespace smf;

int main(int argc, char** argv) {
   MidiFile midifile;
   if (argc == 1) midifile.read(cin);
   else midifile.read(argv[1]);
   if (!midifile.status()) {
      cerr << "Problem reading MIDI file" << endl;
      return 1;
   }

   bool found = false;
   for (int i=0; i<midifile.getTrackCount(); i++) {
      for (int j=0; j<midifile[i].getEventCount(); j++) {
         if (midifile[i][j].isNote()) {
            int channel = midifile[i][j].getChannelNibble();
            if (channel == 9) {
               found = true;
               break;
            }
         }
      }
      if (found == true) break;
   }
   if (found) cout << "Has a percussion part." << endl;
   else cout << "Does not have a percussion part." << endl;

   return 0;
}

How to delete percussion notes in a MIDI file

For some music-analysis applications, it is useful to remove percussion notes from a MIDI file. Here is an example of how that can be done with the midifile library.

#include "MidiFile.h"
#include <iostream>
using namespace std;
using namespace smf;

int main(int argc, char** argv) {
   if (argc != 3) {
      cerr << "Usage: " << argv[0] << " input output" << endl;
      return 1;
   }
   MidiFile midifile;
   midifile.read(argv[1]);
   if (!midifile.status()) {
      cerr << "Problem reading MIDI file" << endl;
      return 1;
   }

   for (int i=0; i<midifile.getTrackCount(); i++) {
      for (int j=0; j<midifile[i].getEventCount(); j++) {
         if (midifile[i][j].isNote()) {
            int channel = midifile[i][j].getChannelNibble();
            if (channel == 9) {
               midifile[i][j].clear();
            }
         }
      }
   }

   midifile.removeEmpties();  // optional
   midifile.write(argv[2]);
   return 0;
}

To delete a MIDI message, clear its vector base class. This will leave an empty MidiEvent in the track, but the MidiFile::write() function will ignore any empty MidiMessages. The MidiFile::removeEmpties() function can be called to explicitly remove any empty MidiEvents from the track.

How to transpose pitches in a MIDI file

This example shows how to transpose notes in a MIDI file. Care should be taken to avoid transposing channel 10 in General MIDI, since this is reserved for the drum track (and most MIDI files use the General MIDI convention).

#include "MidiFile.h"
#include "Options.h"
#include <iostream>

using namespace std;
using namespace smf;

int main(int argc, char** argv) {
   Options options;
   options.define("t|transpose=i:0", "Semitones to transpose by");
   options.process(argc, argv);

   MidiFile midifile;
   if (options.getArgCount() == 0) midifile.read(cin);
   else midifile.read(options.getArg(1));
   if (!midifile.status()) {
      cerr << "Could not read MIDI file" << endl;
      return 1;
   }

   int transpose = options.getInteger("transpose");
   for (int i=0; i<midifile.getTrackCount(); i++) {
      for (int j=0; j<midifile[i].getEventCount(); j++) {
         if (!midifile[i][j].isNote()) continue;
         if (midifile[i][j].getChannel() == 9) continue;
         int newkey = transpose + midifile[i][j].getP1();
         midifile[i][j].setP1(newkey);
      }
   }

   if (options.getArgCount() < 2) cout << midifile;
   else midifile.write(options.getArg(2));
   return 0;
}

How to list instrument numbers used in a MIDI file

The following example lists all of the instrument numbers used in a MIDI file. It does not analyze the drum track.

#include "MidiFile.h"
#include "Options.h"
#include <set>
#include <utility>
#include <iostream>

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));
   if (!midifile.status()) {
      cerr << "Could not read MIDI file" << endl;
      return 1;
   }

   pair<int, int> trackinst;
   set<pair<int, int>> iset;
   for (int i=0; i<midifile.getTrackCount(); i++) {
      for (int j=0; j<midifile[i].getEventCount(); j++) {
         if (midifile[i][j].isTimbre()) {
            trackinst.first = i;
            trackinst.second = midifile[i][j].getP1();
            iset.insert(trackinst);
         }
      }
   }
   for (auto it : iset)
      cout << "Track:" << it.first << "\tInstrument:" << it.second << endl;
   return 0;
}

How to emulate temperaments in a MIDI file

If you want to simulate temperaments in a Standard MIDI file without a synthesizer that specifically knows about temperaments, then this example is useful. Each pitch-class is placed into a separate track and MIDI channel. A pitch-bend message is then added to the start of each track in each channel to control the temperament. Care is taken to avoid MIDI channel 10, which is reserved for percussion timbres in General MIDI.

#include "MidiFile.h"
#include <iostream>
using namespace std;
using namespace smf;

int main(int argc, char** argv) {
   if (argc != 3) {
      cerr << "Usage: " << argv[0] << " input output" << endl;
      return 1;
   }
   MidiFile midifile;
   midifile.read(argv[1]);
   if (!midifile.status()) {
      cerr << "Problem reading MIDI file" << endl;
      return 1;
   }

   midifile.joinTracks();
   for (int i=0; i<midifile[0].getEventCount(); i++) {
      midifile[0][i].seq = 2;
      if (!midifile[0][i].isNote()) {
         midifile[0][i].track = 0;
         continue;
      }
      int pc = midifile[0][i].getP1() % 12;
      int channel = midifile[0][i].getChannelNibble();
      if (channel != 9) {
         midifile[0][i].track = pc + 1;
         if (pc >= 9) pc++;
         midifile[0][i].setChannelNibble(pc);
      } else midifile[0][i].track = 13;
   }
   midifile.splitTracks();

   double maxbend = 200.0;  // typical pitch-bend depth in cents on synthesizers
   // pythagorean tuning deviations from equal temperament in cents.
   vector<double> pythagorean = {-3.91, 9.78, 0.00, -9.78, 3.91, -5.87, 7.82,
         -1.96, -11.73, 1.96, -7.82, 5.87};

   for (int i=0; i<12; i++) {
      int maxtrack = midifile.getTrackCount();
      int track = i+1;
      if (track >= maxtrack) break;
      int channel = i;
      if (i >= 9) channel++;
      double bend = pythagorean[i] / maxbend;
      MidiEvent* me = midifile.addPitchBend(track, 0, channel, bend);
      me->seq = 1;
   }

   midifile.sortTracks();
   midifile.write(argv[2]);

   return 0;
}

The MidiFile::splitTracks() function will generate 13 or 14 tracks. Track 0 will contain all non-note MIDI messages from the original file, while tracks 1 to 12 will contain notes of a specific pitch-class on MIDI channels 1-12, skipping channel 10 (the General MIDI percussion channel). Percussion notes will be placed in track 13, but remain on channel 10.

The use of MidiEvent::seq being set to 1 and 2 in the program is used to force the first notes at tick time 0 to be placed after the pitch bend messages inserted at the same timestamp when MidiFile::sortTracks() is called (events with a lower sequence number will be placed before those with a higher number if they occur at the same time in a track when sorting the events in the track). The pitch-bend messages would probably be sorted before the notes anyway, but using seq should guarantee they are placed before the first notes.

Try this program on Bach's Well-Tempered Clavier, Book I, Fugue No. 4 in C-sharp minor:

4d 54 68 64 00 00 00 06 00 01 00 06 00 78 4d 54 72 6b 00 00 00 13 00 ff 51 03 08 8e 6c 00 ff 58 04 02 01 30 08 00 ff 2f
00 4d 54 72 6b 00 00 09 bd b2 50 90 49 40 81 70 80 49 40 00 90 48 40 81 70 80 48 40 00 90 4c 40 81 70 80 4c 40 00 90 4b
40 83 60 80 4b 40 00 90 49 40 82 68 80 49 40 00 90 4b 40 78 80 4b 40 00 90 4c 40 78 80 4c 40 00 90 4b 40 78 80 4b 40 00
90 49 40 81 70 80 49 40 00 90 47 40 81 70 80 47 40 00 90 49 40 81 70 80 49 40 00 90 4b 40 81 70 80 4b 40 82 68 90 4c 40
78 80 4c 40 00 90 4b 40 78 80 4b 40 00 90 49 40 78 80 49 40 00 90 47 40 78 80 47 40 00 90 4b 40 78 80 4b 40 00 90 50 40
82 68 80 50 40 00 90 4e 40 78 80 4e 40 00 90 50 40 78 80 50 40 00 90 51 40 78 80 51 40 00 90 53 40 84 58 80 53 40 00 90
51 40 78 80 51 40 00 90 50 40 78 80 50 40 00 90 4e 40 78 80 4e 40 00 90 50 40 3c 80 50 40 00 90 4e 40 3c 80 4e 40 00 90
4c 40 3c 80 4c 40 00 90 4b 40 3c 80 4b 40 00 90 49 40 83 60 80 49 40 00 90 47 40 82 68 80 47 40 00 90 49 40 78 80 49 40
00 90 47 40 78 80 47 40 00 90 45 40 78 80 45 40 00 90 44 40 81 70 80 44 40 00 90 46 40 78 80 46 40 00 90 47 40 78 80 47
40 00 90 49 40 81 70 80 49 40 00 90 47 40 83 60 80 47 40 00 90 46 40 81 70 80 46 40 00 90 47 40 84 58 80 47 40 00 90 49
40 78 80 49 40 00 90 4b 40 78 80 4b 40 00 90 4c 40 78 80 4c 40 00 90 4c 40 81 70 80 4c 40 00 90 4b 40 81 70 80 4b 40 00
90 4c 40 78 80 4c 40 00 90 4b 40 78 80 4b 40 00 90 4c 40 78 80 4c 40 00 90 4e 40 78 80 4e 40 00 90 50 40 3c 80 50 40 00
90 4e 40 3c 80 4e 40 00 90 50 40 3c 80 50 40 00 90 51 40 3c 80 51 40 00 90 50 40 3c 80 50 40 00 90 4e 40 3c 80 4e 40 00
90 4c 40 3c 80 4c 40 00 90 50 40 3c 80 50 40 00 90 4e 40 3c 80 4e 40 00 90 4c 40 3c 80 4c 40 00 90 4e 40 3c 80 4e 40 00
90 50 40 3c 80 50 40 00 90 4e 40 3c 80 4e 40 00 90 4c 40 3c 80 4c 40 00 90 4b 40 3c 80 4b 40 00 90 4e 40 3c 80 4e 40 00
90 4c 40 3c 80 4c 40 00 90 4b 40 3c 80 4b 40 00 90 4c 40 3c 80 4c 40 00 90 4e 40 3c 80 4e 40 00 90 4c 40 3c 80 4c 40 00
90 4b 40 3c 80 4b 40 00 90 49 40 3c 80 49 40 00 90 4c 40 3c 80 4c 40 00 90 4b 40 3c 80 4b 40 00 90 49 40 3c 80 49 40 00
90 4b 40 3c 80 4b 40 00 90 4c 40 3c 80 4c 40 00 90 4b 40 3c 80 4b 40 00 90 49 40 3c 80 49 40 00 90 47 40 3c 80 47 40 00
90 4b 40 3c 80 4b 40 00 90 49 40 3c 80 49 40 00 90 47 40 3c 80 47 40 00 90 49 40 3c 80 49 40 00 90 4b 40 3c 80 4b 40 00
90 49 40 3c 80 49 40 00 90 47 40 3c 80 47 40 00 90 46 40 3c 80 46 40 00 90 49 40 3c 80 49 40 00 90 47 40 82 2c 80 47 40
00 90 49 40 3c 80 49 40 00 90 4b 40 3c 80 4b 40 00 90 47 40 3c 80 47 40 00 90 49 40 82 68 80 49 40 00 90 4c 40 78 80 4c
40 00 90 4b 40 82 68 80 4b 40 00 90 4e 40 78 80 4e 40 00 90 4c 40 84 58 80 4c 40 00 90 4b 40 81 70 80 4b 40 00 90 49 40
81 70 80 49 40 00 90 48 40 3c 80 48 40 00 90 46 40 3c 80 46 40 00 90 48 40 78 80 48 40 00 90 4b 40 78 80 4b 40 00 90 50
40 3c 80 50 40 00 90 4e 40 3c 80 4e 40 00 90 50 40 3c 80 50 40 00 90 51 40 3c 80 51 40 00 90 50 40 3c 80 50 40 00 90 4e
40 3c 80 4e 40 00 90 4c 40 3c 80 4c 40 00 90 50 40 3c 80 50 40 00 90 4e 40 3c 80 4e 40 00 90 4c 40 3c 80 4c 40 00 90 4e
40 3c 80 4e 40 00 90 50 40 3c 80 50 40 00 90 4e 40 3c 80 4e 40 00 90 4c 40 3c 80 4c 40 00 90 4b 40 3c 80 4b 40 00 90 4e
40 3c 80 4e 40 00 90 4d 40 81 70 80 4d 40 00 90 51 40 81 70 80 51 40 00 90 50 40 84 58 80 50 40 00 90 4e 40 3c 80 4e 40
00 90 4c 40 3c 80 4c 40 00 90 4a 40 81 70 80 4a 40 78 90 49 40 78 80 49 40 00 90 4e 40 78 80 4e 40 00 90 4e 40 78 80 4e
40 00 90 4e 40 78 80 4e 40 00 90 4c 40 3c 80 4c 40 00 90 4a 40 3c 80 4a 40 00 90 4c 40 82 68 80 4c 40 00 90 4a 40 3c 80
4a 40 00 90 49 40 3c 80 49 40 00 90 4a 40 83 60 80 4a 40 00 90 49 40 81 70 80 49 40 00 90 4e 40 81 70 80 4e 40 00 90 4c
40 81 70 80 4c 40 00 90 4c 40 81 34 80 4c 40 00 90 4e 40 3c 80 4e 40 00 90 4c 40 3c 80 4c 40 00 90 4a 40 3c 80 4a 40 00
90 49 40 3c 80 49 40 00 90 4c 40 3c 80 4c 40 00 90 4a 40 3c 80 4a 40 00 90 49 40 3c 80 49 40 00 90 4a 40 3c 80 4a 40 00
90 4c 40 3c 80 4c 40 00 90 4a 40 3c 80 4a 40 00 90 49 40 3c 80 49 40 00 90 47 40 3c 80 47 40 00 90 4a 40 3c 80 4a 40 00
90 49 40 83 60 80 49 40 00 90 48 40 81 70 80 48 40 00 90 4c 40 81 70 80 4c 40 00 90 4b 40 84 58 80 4b 40 00 90 44 40 78
80 44 40 00 90 49 40 78 80 49 40 00 90 49 40 78 80 49 40 00 90 49 40 78 80 49 40 00 90 47 40 3c 80 47 40 00 90 45 40 3c
80 45 40 00 90 47 40 83 60 80 47 40 00 90 45 40 81 70 80 45 40 00 90 44 40 81 70 80 44 40 81 70 90 4b 40 83 60 80 4b 40
00 90 4a 40 81 70 80 4a 40 00 90 4e 40 81 70 80 4e 40 00 90 4d 40 81 70 80 4d 40 00 90 4c 40 81 70 80 4c 40 00 90 4b 40
3c 80 4b 40 00 90 49 40 3c 80 49 40 00 90 4b 40 3c 80 4b 40 00 90 4c 40 3c 80 4c 40 00 90 4b 40 3c 80 4b 40 00 90 49 40
3c 80 49 40 00 90 47 40 3c 80 47 40 00 90 4b 40 3c 80 4b 40 00 90 49 40 3c 80 49 40 00 90 47 40 3c 80 47 40 00 90 49 40
3c 80 49 40 00 90 4b 40 3c 80 4b 40 00 90 49 40 3c 80 49 40 00 90 4c 40 3c 80 4c 40 00 90 4b 40 3c 80 4b 40 00 90 49 40
3c 80 49 40 00 90 48 40 81 70 80 48 40 00 90 47 40 81 70 80 47 40 00 90 46 40 81 70 80 46 40 00 90 45 40 81 70 80 45 40
00 90 44 40 81 70 80 44 40 89 30 90 49 40 83 60 80 49 40 00 90 48 40 81 70 80 48 40 00 90 4c 40 81 70 80 4c 40 00 90 4b
40 85 50 80 4b 40 00 90 49 40 83 60 80 49 40 00 90 48 40 81 70 80 48 40 78 90 49 40 3c 80 49 40 00 90 4b 40 3c 80 4b 40
00 90 4c 40 78 80 4c 40 00 90 4e 40 78 80 4e 40 00 90 50 40 3c 80 50 40 00 90 4e 40 3c 80 4e 40 00 90 50 40 3c 80 50 40
00 90 51 40 3c 80 51 40 00 90 50 40 3c 80 50 40 00 90 4e 40 3c 80 4e 40 00 90 4c 40 3c 80 4c 40 00 90 50 40 3c 80 50 40
00 90 4e 40 3c 80 4e 40 00 90 4c 40 3c 80 4c 40 00 90 4e 40 3c 80 4e 40 00 90 50 40 3c 80 50 40 00 90 4e 40 3c 80 4e 40
00 90 4c 40 3c 80 4c 40 00 90 4b 40 3c 80 4b 40 00 90 4e 40 3c 80 4e 40 00 90 4c 40 3c 80 4c 40 00 90 4b 40 3c 80 4b 40
00 90 4c 40 3c 80 4c 40 00 90 4e 40 3c 80 4e 40 00 90 4c 40 3c 80 4c 40 00 90 4a 40 3c 80 4a 40 00 90 49 40 3c 80 49 40
00 90 4c 40 3c 80 4c 40 00 90 4a 40 3c 80 4a 40 00 90 49 40 3c 80 49 40 00 90 4a 40 3c 80 4a 40 00 90 4c 40 3c 80 4c 40
00 90 4a 40 3c 80 4a 40 00 90 49 40 3c 80 49 40 00 90 47 40 3c 80 47 40 00 90 4a 40 3c 80 4a 40 00 90 49 40 3c 80 49 40
00 90 47 40 3c 80 47 40 00 90 49 40 3c 80 49 40 00 90 4a 40 3c 80 4a 40 00 90 49 40 3c 80 49 40 00 90 47 40 3c 80 47 40
00 90 45 40 3c 80 45 40 00 90 49 40 3c 80 49 40 00 90 47 40 3c 80 47 40 00 90 45 40 3c 80 45 40 00 90 47 40 3c 80 47 40
00 90 49 40 3c 80 49 40 00 90 47 40 3c 80 47 40 00 90 45 40 3c 80 45 40 00 90 44 40 3c 80 44 40 00 90 47 40 3c 80 47 40
00 90 45 40 81 70 80 45 40 81 70 90 49 40 83 60 80 49 40 00 90 48 40 81 70 80 48 40 00 90 4c 40 81 70 80 4c 40 00 90 4b
40 84 58 80 4b 40 00 90 49 40 78 80 49 40 00 90 50 40 78 80 50 40 00 90 50 40 78 80 50 40 00 90 50 40 78 80 50 40 00 90
4e 40 3c 80 4e 40 00 90 4c 40 3c 80 4c 40 00 90 4e 40 81 70 80 4e 40 00 90 4c 40 83 60 80 4c 40 00 90 4b 40 81 70 80 4b
40 00 90 4f 40 81 70 80 4f 40 00 90 4e 40 81 70 80 4e 40 00 90 42 40 81 70 80 42 40 00 90 41 40 81 70 80 41 40 00 90 45
40 81 70 80 45 40 00 90 44 40 78 80 44 40 83 60 90 48 40 78 80 48 40 00 90 4e 40 78 80 4e 40 00 90 4e 40 78 80 4e 40 00
90 4e 40 78 80 4e 40 00 90 4c 40 3c 80 4c 40 00 90 4b 40 3c 80 4b 40 00 90 4c 40 78 80 4c 40 00 90 4b 40 3c 80 4b 40 00
90 49 40 3c 80 49 40 00 90 4b 40 78 80 4b 40 00 90 48 40 78 80 48 40 00 90 49 40 85 50 80 49 40 00 90 48 40 81 70 80 48
40 00 90 47 40 81 70 80 47 40 00 90 46 40 81 70 80 46 40 00 90 45 40 81 70 80 45 40 00 90 44 40 83 60 80 44 40 00 90 46
40 81 70 80 46 40 00 90 48 40 81 70 80 48 40 00 90 49 40 83 60 80 49 40 00 90 48 40 81 70 80 48 40 00 90 4c 40 83 60 80
4c 40 00 90 4b 40 78 80 4b 40 00 90 49 40 78 80 49 40 00 90 48 40 81 70 80 48 40 00 90 49 40 83 60 80 49 40 00 90 48 40
81 70 80 48 40 00 90 49 40 8f 00 80 49 40 77 90 00 00 00 ff 2f 00 4d 54 72 6b 00 00 09 40 ab 10 91 44 40 81 70 81 44 40
00 91 41 40 81 70 81 41 40 00 91 45 40 81 70 81 45 40 00 91 44 40 81 70 81 44 40 00 91 42 40 83 60 81 42 40 00 91 49 40
83 60 81 49 40 00 91 47 40 83 60 81 47 40 00 91 45 40 81 70 81 45 40 00 91 44 40 81 70 81 44 40 00 91 45 40 82 68 81 45
40 00 91 44 40 78 81 44 40 00 91 42 40 78 81 42 40 00 91 40 40 78 81 40 40 00 91 3f 40 81 70 81 3f 40 00 91 44 40 81 70
81 44 40 00 91 44 40 81 70 81 44 40 00 91 43 40 81 70 81 43 40 00 91 44 40 81 70 81 44 40 00 91 3b 40 81 70 81 3b 40 00
91 3d 40 82 68 81 3d 40 00 91 3d 40 78 81 3d 40 00 91 3f 40 78 81 3f 40 00 91 3d 40 78 81 3d 40 00 91 3f 40 78 81 3f 40
00 91 41 40 78 81 41 40 00 91 42 40 81 70 81 42 40 00 91 45 40 81 70 81 45 40 00 91 44 40 81 70 81 44 40 3c 91 47 40 3c
81 47 40 00 91 45 40 3c 81 45 40 00 91 44 40 3c 81 44 40 00 91 42 40 78 81 42 40 00 91 45 40 78 81 45 40 00 91 44 40 78
81 44 40 00 91 42 40 78 81 42 40 00 91 41 40 81 70 81 41 40 00 91 42 40 82 68 81 42 40 00 91 40 40 84 58 81 40 40 00 91
3f 40 81 70 81 3f 40 00 91 40 40 84 58 81 40 40 00 91 3f 40 78 81 3f 40 00 91 40 40 78 81 40 40 00 91 42 40 3c 81 42 40
00 91 44 40 3c 81 44 40 00 91 42 40 81 70 81 42 40 00 91 47 40 82 68 81 47 40 00 91 49 40 78 81 49 40 00 91 47 40 78 81
47 40 00 91 45 40 78 81 45 40 00 91 44 40 81 70 81 44 40 a1 60 91 49 40 81 70 81 49 40 00 91 48 40 81 70 81 48 40 00 91
4c 40 81 70 81 4c 40 00 91 4b 40 85 50 81 4b 40 00 91 49 40 83 60 81 49 40 00 91 48 40 78 81 48 40 00 91 47 40 81 34 81
47 40 00 91 47 40 3c 81 47 40 00 91 49 40 3c 81 49 40 00 91 4a 40 3c 81 4a 40 00 91 49 40 3c 81 49 40 00 91 47 40 3c 81
47 40 00 91 45 40 3c 81 45 40 00 91 49 40 3c 81 49 40 00 91 47 40 3c 81 47 40 00 91 45 40 3c 81 45 40 00 91 47 40 3c 81
47 40 00 91 49 40 3c 81 49 40 00 91 47 40 3c 81 47 40 00 91 45 40 3c 81 45 40 00 91 44 40 3c 81 44 40 00 91 47 40 3c 81
47 40 00 91 45 40 82 2c 81 45 40 00 91 49 40 3c 81 49 40 00 91 47 40 3c 81 47 40 00 91 45 40 3c 81 45 40 00 91 44 40 81
70 81 44 40 87 40 91 45 40 81 70 81 45 40 00 91 44 40 81 70 81 44 40 00 91 49 40 81 70 81 49 40 00 91 47 40 84 58 81 47
40 00 91 40 40 78 81 40 40 00 91 45 40 78 81 45 40 00 91 45 40 78 81 45 40 00 91 45 40 78 81 45 40 00 91 44 40 3c 81 44
40 00 91 42 40 3c 81 42 40 00 91 44 40 82 68 81 44 40 00 91 3d 40 3c 81 3d 40 00 91 3f 40 3c 81 3f 40 00 91 40 40 78 81
40 40 00 91 42 40 78 81 42 40 00 91 44 40 3c 81 44 40 00 91 42 40 3c 81 42 40 00 91 44 40 3c 81 44 40 00 91 45 40 3c 81
45 40 00 91 44 40 3c 81 44 40 00 91 42 40 3c 81 42 40 00 91 40 40 3c 81 40 40 00 91 44 40 3c 81 44 40 00 91 42 40 3c 81
42 40 00 91 40 40 3c 81 40 40 00 91 42 40 3c 81 42 40 00 91 44 40 3c 81 44 40 00 91 42 40 3c 81 42 40 00 91 40 40 3c 81
40 40 00 91 3f 40 3c 81 3f 40 00 91 42 40 3c 81 42 40 00 91 40 40 3c 81 40 40 00 91 3f 40 3c 81 3f 40 00 91 40 40 3c 81
40 40 00 91 42 40 3c 81 42 40 00 91 40 40 3c 81 40 40 00 91 3f 40 3c 81 3f 40 00 91 3d 40 3c 81 3d 40 00 91 40 40 3c 81
40 40 00 91 3f 40 3c 81 3f 40 00 91 3d 40 3c 81 3d 40 00 91 3f 40 3c 81 3f 40 00 91 40 40 3c 81 40 40 00 91 3e 40 3c 81
3e 40 00 91 3d 40 3c 81 3d 40 00 91 3b 40 3c 81 3b 40 00 91 3e 40 3c 81 3e 40 00 91 3d 40 3c 81 3d 40 00 91 3b 40 3c 81
3b 40 00 91 3d 40 3c 81 3d 40 00 91 3e 40 3c 81 3e 40 00 91 3d 40 3c 81 3d 40 00 91 40 40 3c 81 40 40 00 91 3f 40 3c 81
3f 40 00 91 3d 40 3c 81 3d 40 00 91 48 40 81 70 81 48 40 00 91 3d 40 81 70 81 3d 40 00 91 3f 40 78 81 3f 40 00 91 3f 40
78 81 3f 40 00 91 44 40 3c 81 44 40 00 91 46 40 3c 81 46 40 00 91 47 40 81 70 81 47 40 00 91 46 40 78 81 46 40 00 91 4b
40 78 81 4b 40 00 91 4b 40 78 81 4b 40 00 91 4b 40 78 81 4b 40 00 91 49 40 3c 81 49 40 00 91 48 40 3c 81 48 40 00 91 49
40 83 60 81 49 40 00 91 47 40 81 70 81 47 40 00 91 46 40 81 70 81 46 40 00 91 45 40 82 68 81 45 40 00 91 3f 40 78 81 3f
40 00 91 44 40 78 81 44 40 00 91 44 40 81 70 81 44 40 00 91 42 40 3c 81 42 40 00 91 41 40 3c 81 41 40 00 91 42 40 83 60
81 42 40 00 91 40 40 81 70 81 40 40 00 91 3f 40 81 70 81 3f 40 00 91 3d 40 81 70 81 3d 40 00 91 3f 40 83 60 81 3f 40 84
58 91 44 40 78 81 44 40 00 91 49 40 78 81 49 40 00 91 49 40 78 81 49 40 00 91 49 40 78 81 49 40 00 91 48 40 3c 81 48 40
00 91 46 40 3c 81 46 40 00 91 48 40 3c 81 48 40 00 91 49 40 3c 81 49 40 00 91 4b 40 3c 81 4b 40 00 91 48 40 3c 81 48 40
00 91 44 40 3c 81 44 40 00 91 42 40 3c 81 42 40 00 91 44 40 3c 81 44 40 00 91 45 40 3c 81 45 40 00 91 44 40 3c 81 44 40
00 91 42 40 3c 81 42 40 00 91 40 40 3c 81 40 40 00 91 44 40 3c 81 44 40 00 91 42 40 3c 81 42 40 00 91 40 40 3c 81 40 40
00 91 42 40 3c 81 42 40 00 91 44 40 3c 81 44 40 00 91 42 40 3c 81 42 40 00 91 40 40 3c 81 40 40 00 91 3f 40 3c 81 3f 40
00 91 42 40 3c 81 42 40 00 91 40 40 3c 81 40 40 00 91 44 40 3c 81 44 40 00 91 45 40 3c 81 45 40 00 91 47 40 3c 81 47 40
00 91 49 40 3c 81 49 40 00 91 4b 40 3c 81 4b 40 00 91 48 40 3c 81 48 40 00 91 49 40 3c 81 49 40 00 91 4b 40 78 81 4b 40
8b 20 91 42 40 78 81 42 40 00 91 47 40 78 81 47 40 00 91 47 40 78 81 47 40 00 91 47 40 78 81 47 40 00 91 45 40 3c 81 45
40 00 91 44 40 3c 81 44 40 00 91 45 40 81 70 81 45 40 00 91 44 40 84 1c 81 44 40 00 91 44 40 3c 81 44 40 00 91 42 40 3c
81 42 40 00 91 41 40 3c 81 41 40 00 91 42 40 81 70 81 42 40 00 91 44 40 82 2c 81 44 40 00 91 44 40 3c 81 44 40 00 91 42
40 3c 81 42 40 00 91 40 40 3c 81 40 40 00 91 3f 40 3c 81 3f 40 00 91 45 40 3c 81 45 40 00 91 44 40 3c 81 44 40 00 91 42
40 3c 81 42 40 00 91 40 40 3c 81 40 40 00 91 44 40 3c 81 44 40 00 91 49 40 3c 81 49 40 00 91 47 40 3c 81 47 40 00 91 45
40 3c 81 45 40 00 91 44 40 3c 81 44 40 00 91 45 40 3c 81 45 40 00 91 42 40 3c 81 42 40 00 91 44 40 82 68 81 44 40 00 91
49 40 3c 81 49 40 00 91 48 40 3c 81 48 40 00 91 49 40 82 68 81 49 40 00 91 46 40 78 81 46 40 00 91 4b 40 78 81 4b 40 00
91 4b 40 78 81 4b 40 00 91 4b 40 78 81 4b 40 00 91 49 40 3c 81 49 40 00 91 47 40 3c 81 47 40 00 91 49 40 81 70 81 49 40
00 91 47 40 81 70 81 47 40 00 91 47 40 81 70 81 47 40 00 91 46 40 81 70 81 46 40 00 91 4a 40 81 70 81 4a 40 00 91 49 40
83 60 81 49 40 78 91 44 40 78 81 44 40 00 91 49 40 78 81 49 40 00 91 49 40 78 81 49 40 00 91 49 40 78 81 49 40 00 91 48
40 3c 81 48 40 00 91 46 40 3c 81 46 40 00 91 48 40 3c 81 48 40 00 91 49 40 3c 81 49 40 00 91 4b 40 81 70 81 4b 40 00 91
49 40 3c 81 49 40 00 91 48 40 3c 81 48 40 00 91 49 40 81 70 81 49 40 00 91 42 40 81 70 81 42 40 00 91 44 40 83 60 81 44
40 00 91 42 40 82 68 81 42 40 82 68 91 44 40 78 81 44 40 00 91 42 40 3c 81 42 40 00 91 40 40 3c 81 40 40 00 91 42 40 78
81 42 40 00 91 42 40 78 81 42 40 00 91 42 40 78 81 42 40 00 91 40 40 3c 81 40 40 00 91 3f 40 3c 81 3f 40 00 91 40 40 82
68 81 40 40 00 91 42 40 3c 81 42 40 00 91 44 40 3c 81 44 40 00 91 45 40 78 81 45 40 00 91 44 40 81 70 81 44 40 00 91 40
40 78 81 40 40 00 91 45 40 78 81 45 40 00 91 45 40 78 81 45 40 00 91 45 40 78 81 45 40 00 91 44 40 3c 81 44 40 00 91 42
40 3c 81 42 40 00 91 44 40 78 81 44 40 00 91 46 40 3c 81 46 40 00 91 48 40 3c 81 48 40 00 91 49 40 81 70 81 49 40 00 91
46 40 81 70 81 46 40 00 91 44 40 81 70 81 44 40 00 91 44 40 85 50 81 44 40 00 91 44 40 81 70 81 44 40 00 91 42 40 81 70
81 42 40 00 91 41 40 81 70 81 41 40 00 91 45 40 81 70 81 45 40 00 91 44 40 87 40 81 44 40 77 90 00 00 00 ff 2f 00 4d 54
72 6b 00 00 08 ba 98 30 92 3d 40 81 70 82 3d 40 00 92 3c 40 81 70 82 3c 40 00 92 40 40 81 70 82 40 40 00 92 3f 40 83 60
82 3f 40 00 92 3d 40 81 70 82 3d 40 00 92 42 40 82 68 82 42 40 00 92 40 40 78 82 40 40 00 92 3f 40 78 82 3f 40 00 92 3d
40 78 82 3d 40 00 92 3d 40 81 70 82 3d 40 00 92 3b 40 81 70 82 3b 40 00 92 3d 40 81 70 82 3d 40 00 92 42 40 82 68 82 42
40 00 92 40 40 78 82 40 40 00 92 3f 40 78 82 3f 40 00 92 3d 40 78 82 3d 40 00 92 3f 40 81 70 82 3f 40 00 92 44 40 81 70
82 44 40 78 92 45 40 78 82 45 40 00 92 44 40 78 82 44 40 00 92 42 40 78 82 42 40 00 92 41 40 78 82 41 40 00 92 3d 40 78
82 3d 40 00 92 42 40 81 70 82 42 40 00 92 40 40 85 50 82 40 40 00 92 44 40 81 70 82 44 40 00 92 46 40 81 70 82 46 40 92
60 92 3d 40 81 70 82 3d 40 00 92 3c 40 81 70 82 3c 40 00 92 40 40 81 70 82 40 40 00 92 3f 40 83 60 82 3f 40 00 92 3d 40
87 40 82 3d 40 00 92 36 40 78 82 36 40 00 92 38 40 78 82 38 40 00 92 3a 40 78 82 3a 40 00 92 3b 40 78 82 3b 40 00 92 3d
40 83 60 82 3d 40 81 70 92 40 40 81 70 82 40 40 00 92 3f 40 81 70 82 3f 40 00 92 44 40 81 70 82 44 40 00 92 42 40 83 60
82 42 40 00 92 40 40 81 70 82 40 40 8b 20 92 44 40 81 70 82 44 40 00 92 43 40 81 70 82 43 40 00 92 47 40 81 70 82 47 40
00 92 46 40 84 58 82 46 40 00 92 3f 40 78 82 3f 40 00 92 44 40 82 68 82 44 40 00 92 42 40 3c 82 42 40 00 92 40 40 3c 82
40 40 00 92 42 40 82 68 82 42 40 00 92 40 40 3c 82 40 40 00 92 42 40 3c 82 42 40 00 92 44 40 89 30 82 44 40 8c 18 92 3d
40 78 82 3d 40 00 92 42 40 78 82 42 40 00 92 42 40 78 82 42 40 00 92 42 40 78 82 42 40 00 92 41 40 3c 82 41 40 00 92 3f
40 3c 82 3f 40 00 92 41 40 81 70 82 41 40 00 92 42 40 78 82 42 40 00 92 36 40 3c 82 36 40 00 92 38 40 3c 82 38 40 00 92
39 40 78 82 39 40 00 92 3b 40 78 82 3b 40 00 92 3d 40 3c 82 3d 40 00 92 3b 40 3c 82 3b 40 00 92 3d 40 3c 82 3d 40 00 92
3e 40 3c 82 3e 40 00 92 3d 40 3c 82 3d 40 00 92 3b 40 3c 82 3b 40 00 92 39 40 3c 82 39 40 00 92 3d 40 3c 82 3d 40 00 92
3b 40 3c 82 3b 40 00 92 39 40 3c 82 39 40 00 92 3b 40 3c 82 3b 40 00 92 3d 40 3c 82 3d 40 00 92 3b 40 3c 82 3b 40 00 92
39 40 3c 82 39 40 00 92 38 40 3c 82 38 40 00 92 3b 40 3c 82 3b 40 00 92 39 40 3c 82 39 40 00 92 38 40 3c 82 38 40 00 92
39 40 3c 82 39 40 00 92 3b 40 3c 82 3b 40 00 92 39 40 3c 82 39 40 00 92 3b 40 3c 82 3b 40 00 92 3d 40 3c 82 3d 40 00 92
3e 40 3c 82 3e 40 00 92 40 40 3c 82 40 40 00 92 3e 40 3c 82 3e 40 00 92 40 40 3c 82 40 40 00 92 42 40 3c 82 42 40 00 92
40 40 3c 82 40 40 00 92 3e 40 3c 82 3e 40 00 92 3d 40 3c 82 3d 40 00 92 40 40 3c 82 40 40 00 92 3e 40 3c 82 3e 40 00 92
3d 40 3c 82 3d 40 00 92 3e 40 3c 82 3e 40 00 92 40 40 3c 82 40 40 00 92 3e 40 3c 82 3e 40 00 92 3d 40 3c 82 3d 40 00 92
3b 40 3c 82 3b 40 00 92 3e 40 3c 82 3e 40 00 92 3d 40 3c 82 3d 40 00 92 3b 40 3c 82 3b 40 00 92 3d 40 3c 82 3d 40 00 92
3e 40 3c 82 3e 40 00 92 3d 40 3c 82 3d 40 00 92 3b 40 3c 82 3b 40 00 92 39 40 3c 82 39 40 00 92 3d 40 3c 82 3d 40 00 92
3b 40 83 60 82 3b 40 00 92 39 40 3c 82 39 40 00 92 38 40 3c 82 38 40 00 92 36 40 3c 82 36 40 00 92 34 40 3c 82 34 40 00
92 33 40 3c 82 33 40 00 92 31 40 3c 82 31 40 00 92 30 40 3c 82 30 40 00 92 31 40 3c 82 31 40 00 92 33 40 81 70 82 33 40
8e 08 92 31 40 78 82 31 40 00 92 36 40 78 82 36 40 00 92 36 40 78 82 36 40 00 92 36 40 78 82 36 40 00 92 34 40 3c 82 34
40 00 92 33 40 3c 82 33 40 00 92 34 40 81 70 82 34 40 00 92 37 40 81 70 82 37 40 00 92 38 40 81 70 82 38 40 00 92 35 40
78 82 35 40 87 40 92 33 40 78 82 33 40 00 92 38 40 78 82 38 40 00 92 38 40 78 82 38 40 00 92 38 40 78 82 38 40 00 92 36
40 3c 82 36 40 00 92 34 40 3c 82 34 40 00 92 36 40 82 2c 82 36 40 00 92 39 40 3c 82 39 40 00 92 38 40 3c 82 38 40 00 92
36 40 3c 82 36 40 00 92 35 40 3c 82 35 40 00 92 33 40 3c 82 33 40 00 92 35 40 3c 82 35 40 00 92 31 40 3c 82 31 40 00 92
36 40 3c 82 36 40 00 92 35 40 3c 82 35 40 00 92 36 40 3c 82 36 40 00 92 38 40 3c 82 38 40 00 92 39 40 3c 82 39 40 00 92
38 40 3c 82 38 40 00 92 39 40 3c 82 39 40 00 92 3b 40 3c 82 3b 40 00 92 3d 40 3c 82 3d 40 00 92 3c 40 3c 82 3c 40 00 92
3d 40 3c 82 3d 40 00 92 3f 40 3c 82 3f 40 00 92 40 40 3c 82 40 40 00 92 3f 40 3c 82 3f 40 00 92 40 40 3c 82 40 40 00 92
42 40 3c 82 42 40 00 92 44 40 3c 82 44 40 00 92 42 40 3c 82 42 40 00 92 44 40 3c 82 44 40 00 92 45 40 3c 82 45 40 00 92
44 40 3c 82 44 40 00 92 42 40 3c 82 42 40 00 92 40 40 3c 82 40 40 00 92 44 40 3c 82 44 40 00 92 42 40 3c 82 42 40 00 92
40 40 3c 82 40 40 00 92 42 40 3c 82 42 40 00 92 44 40 3c 82 44 40 00 92 42 40 3c 82 42 40 00 92 40 40 3c 82 40 40 00 92
3f 40 3c 82 3f 40 00 92 42 40 3c 82 42 40 00 92 40 40 3c 82 40 40 00 92 3f 40 3c 82 3f 40 00 92 40 40 3c 82 40 40 00 92
42 40 3c 82 42 40 00 92 40 40 3c 82 40 40 00 92 3f 40 3c 82 3f 40 00 92 3d 40 3c 82 3d 40 00 92 40 40 3c 82 40 40 00 92
3f 40 81 70 82 3f 40 91 68 92 38 40 78 82 38 40 00 92 3d 40 78 82 3d 40 00 92 3d 40 78 82 3d 40 00 92 3d 40 78 82 3d 40
00 92 3c 40 3c 82 3c 40 00 92 3a 40 3c 82 3a 40 00 92 3c 40 81 70 82 3c 40 00 92 3d 40 83 60 82 3d 40 00 92 3b 40 82 68
82 3b 40 00 92 42 40 78 82 42 40 00 92 41 40 81 70 82 41 40 00 92 42 40 81 70 82 42 40 00 92 3b 40 81 70 82 3b 40 00 92
3d 40 84 1c 82 3d 40 00 92 3d 40 3c 82 3d 40 00 92 3b 40 3c 82 3b 40 00 92 39 40 3c 82 39 40 00 92 38 40 83 60 82 38 40
93 58 92 3b 40 78 82 3b 40 00 92 40 40 78 82 40 40 00 92 40 40 78 82 40 40 00 92 40 40 78 82 40 40 00 92 3e 40 3c 82 3e
40 00 92 3d 40 3c 82 3d 40 00 92 3b 40 81 70 82 3b 40 78 92 3d 40 78 82 3d 40 00 92 42 40 78 82 42 40 00 92 42 40 78 82
42 40 00 92 42 40 78 82 42 40 00 92 40 40 3c 82 40 40 00 92 3f 40 3c 82 3f 40 00 92 40 40 81 70 82 40 40 00 92 42 40 83
24 82 42 40 00 92 44 40 3c 82 44 40 00 92 45 40 78 82 45 40 00 92 44 40 3c 82 44 40 00 92 42 40 3c 82 42 40 00 92 44 40
78 82 44 40 00 92 42 40 3c 82 42 40 00 92 40 40 3c 82 40 40 00 92 3f 40 81 70 82 3f 40 00 92 40 40 83 60 82 40 40 00 92
3f 40 78 82 3f 40 00 92 3d 40 78 82 3d 40 00 92 3f 40 78 82 3f 40 00 92 41 40 3c 82 41 40 00 92 42 40 3c 82 42 40 00 92
44 40 78 82 44 40 00 92 44 40 78 82 44 40 78 92 3d 40 78 82 3d 40 00 92 3f 40 78 82 3f 40 00 92 3d 40 78 82 3d 40 00 92
3c 40 81 70 82 3c 40 00 92 3d 40 83 60 82 3d 40 00 92 3f 40 81 70 82 3f 40 00 92 3d 40 78 82 3d 40 00 92 3d 40 78 82 3d
40 00 92 42 40 78 82 42 40 00 92 42 40 78 82 42 40 00 92 42 40 78 82 42 40 00 92 40 40 3c 82 40 40 00 92 3f 40 3c 82 3f
40 00 92 40 40 78 82 40 40 00 92 42 40 3c 82 42 40 00 92 44 40 3c 82 44 40 00 92 46 40 81 70 82 46 40 00 92 3f 40 83 60
82 3f 40 00 92 40 40 81 70 82 40 40 00 92 3f 40 82 68 82 3f 40 00 92 40 40 3c 82 40 40 00 92 42 40 3c 82 42 40 00 92 41
40 78 82 41 40 00 92 3d 40 83 60 82 3d 40 00 92 3d 40 78 82 3d 40 00 92 42 40 78 82 42 40 00 92 42 40 78 82 42 40 00 92
42 40 81 70 82 42 40 00 92 41 40 78 82 41 40 00 92 3f 40 78 82 3f 40 00 92 41 40 83 60 82 41 40 77 90 00 00 00 ff 2f 00
4d 54 72 6b 00 00 07 ac 8b 20 93 38 40 83 60 83 38 40 00 93 37 40 81 70 83 37 40 00 93 3b 40 81 70 83 3b 40 00 93 3a 40
83 60 83 3a 40 00 93 38 40 81 70 83 38 40 00 93 39 40 82 68 83 39 40 00 93 38 40 3c 83 38 40 00 93 36 40 3c 83 36 40 00
93 38 40 78 83 38 40 00 93 3d 40 78 83 3d 40 00 93 36 40 78 83 36 40 00 93 38 40 3c 83 38 40 00 93 39 40 3c 83 39 40 00
93 3b 40 82 68 83 3b 40 00 93 39 40 78 83 39 40 00 93 38 40 78 83 38 40 00 93 36 40 78 83 36 40 00 93 38 40 81 70 83 38
40 00 93 36 40 78 83 36 40 00 93 34 40 78 83 34 40 00 93 33 40 82 68 83 33 40 00 93 32 40 78 83 32 40 00 93 31 40 87 40
83 31 40 90 70 93 38 40 81 70 83 38 40 00 93 37 40 81 70 83 37 40 00 93 3b 40 81 70 83 3b 40 00 93 3a 40 83 60 83 3a 40
00 93 38 40 78 83 38 40 00 93 39 40 78 83 39 40 00 93 38 40 78 83 38 40 00 93 36 40 78 83 36 40 00 93 35 40 81 70 83 35
40 00 93 39 40 81 70 83 39 40 00 93 38 40 83 60 83 38 40 00 93 36 40 84 58 83 36 40 00 93 38 40 3c 83 38 40 00 93 36 40
3c 83 36 40 00 93 34 40 78 83 34 40 00 93 36 40 3c 83 36 40 00 93 38 40 3c 83 38 40 00 93 39 40 78 83 39 40 00 93 36 40
78 83 36 40 00 93 38 40 81 70 83 38 40 00 93 31 40 89 30 83 31 40 00 93 36 40 81 70 83 36 40 00 93 34 40 78 83 34 40 00
93 33 40 78 83 33 40 00 93 34 40 78 83 34 40 00 93 36 40 78 83 36 40 00 93 38 40 78 83 38 40 00 93 36 40 78 83 36 40 00
93 38 40 78 83 38 40 00 93 39 40 78 83 39 40 00 93 3b 40 89 30 83 3b 40 00 93 3d 40 81 70 83 3d 40 00 93 3c 40 81 70 83
3c 40 00 93 40 40 81 70 83 40 40 00 93 3f 40 83 60 83 3f 40 00 93 3d 40 84 58 83 3d 40 00 93 3b 40 78 83 3b 40 00 93 3a
40 78 83 3a 40 00 93 38 40 81 70 83 38 40 00 93 37 40 3c 83 37 40 00 93 35 40 3c 83 35 40 00 93 37 40 81 70 83 37 40 00
93 38 40 3c 83 38 40 00 93 3a 40 3c 83 3a 40 00 93 38 40 3c 83 38 40 00 93 37 40 3c 83 37 40 00 93 38 40 3c 83 38 40 00
93 3a 40 3c 83 3a 40 00 93 3b 40 3c 83 3b 40 00 93 38 40 3c 83 38 40 00 93 39 40 3c 83 39 40 00 93 3b 40 3c 83 3b 40 00
93 39 40 3c 83 39 40 00 93 38 40 3c 83 38 40 00 93 3a 40 3c 83 3a 40 00 93 3b 40 3c 83 3b 40 00 93 3d 40 3c 83 3d 40 00
93 3a 40 3c 83 3a 40 00 93 3b 40 3c 83 3b 40 00 93 3d 40 3c 83 3d 40 00 93 3b 40 3c 83 3b 40 00 93 3a 40 3c 83 3a 40 00
93 3c 40 3c 83 3c 40 00 93 3d 40 3c 83 3d 40 00 93 3f 40 3c 83 3f 40 00 93 3c 40 3c 83 3c 40 00 93 3d 40 83 60 83 3d 40
98 30 93 36 40 81 70 83 36 40 00 93 35 40 81 70 83 35 40 00 93 39 40 81 70 83 39 40 00 93 38 40 83 60 83 38 40 00 93 36
40 83 60 83 36 40 93 58 93 38 40 78 83 38 40 00 93 3d 40 78 83 3d 40 00 93 3d 40 78 83 3d 40 00 93 3d 40 78 83 3d 40 00
93 3c 40 3c 83 3c 40 00 93 3a 40 3c 83 3a 40 00 93 3c 40 81 70 83 3c 40 00 93 3d 40 81 70 83 3d 40 00 93 39 40 81 70 83
39 40 00 93 36 40 81 70 83 36 40 00 93 38 40 81 70 83 38 40 00 93 35 40 81 70 83 35 40 00 93 36 40 81 70 83 36 40 00 93
38 40 83 60 83 38 40 00 93 33 40 83 60 83 33 40 9b 18 93 2c 40 78 83 2c 40 00 93 31 40 78 83 31 40 00 93 31 40 78 83 31
40 00 93 31 40 78 83 31 40 00 93 30 40 3c 83 30 40 00 93 2e 40 3c 83 2e 40 00 93 30 40 81 70 83 30 40 00 93 31 40 81 70
83 31 40 90 70 93 31 40 83 60 83 31 40 00 93 30 40 81 70 83 30 40 00 93 34 40 81 70 83 34 40 00 93 33 40 83 60 83 33 40
00 93 31 40 78 83 31 40 00 93 34 40 78 83 34 40 00 93 39 40 78 83 39 40 00 93 39 40 78 83 39 40 00 93 39 40 78 83 39 40
00 93 38 40 3c 83 38 40 00 93 36 40 3c 83 36 40 00 93 38 40 83 60 83 38 40 00 93 36 40 81 70 83 36 40 00 93 38 40 83 60
83 38 40 00 93 39 40 81 70 83 39 40 00 93 36 40 82 2c 83 36 40 00 93 36 40 3c 83 36 40 00 93 34 40 3c 83 34 40 00 93 33
40 3c 83 33 40 00 93 34 40 78 83 34 40 00 93 31 40 78 83 31 40 00 93 38 40 83 60 83 38 40 00 93 36 40 81 70 83 36 40 00
93 33 40 81 70 83 33 40 00 93 34 40 3c 83 34 40 00 93 33 40 3c 83 33 40 00 93 34 40 3c 83 34 40 00 93 36 40 3c 83 36 40
00 93 34 40 3c 83 34 40 00 93 33 40 3c 83 33 40 00 93 31 40 3c 83 31 40 00 93 34 40 3c 83 34 40 00 93 33 40 3c 83 33 40
00 93 31 40 3c 83 31 40 00 93 33 40 3c 83 33 40 00 93 34 40 3c 83 34 40 00 93 33 40 3c 83 33 40 00 93 31 40 3c 83 31 40
00 93 30 40 3c 83 30 40 00 93 33 40 3c 83 33 40 00 93 31 40 78 83 31 40 00 93 34 40 78 83 34 40 00 93 39 40 78 83 39 40
00 93 39 40 78 83 39 40 00 93 39 40 78 83 39 40 00 93 37 40 3c 83 37 40 00 93 36 40 3c 83 36 40 00 93 34 40 81 70 83 34
40 78 93 36 40 78 83 36 40 00 93 3b 40 78 83 3b 40 00 93 3b 40 78 83 3b 40 00 93 3b 40 78 83 3b 40 00 93 39 40 3c 83 39
40 00 93 38 40 3c 83 38 40 00 93 39 40 3c 83 39 40 00 93 38 40 3c 83 38 40 00 93 36 40 3c 83 36 40 00 93 34 40 3c 83 34
40 00 93 33 40 81 70 83 33 40 78 93 38 40 78 83 38 40 00 93 3f 40 78 83 3f 40 00 93 3f 40 78 83 3f 40 00 93 3f 40 78 83
3f 40 00 93 3d 40 3c 83 3d 40 00 93 3c 40 3c 83 3c 40 00 93 3d 40 83 60 83 3d 40 00 93 3c 40 81 70 83 3c 40 00 93 40 40
82 68 83 40 40 00 93 31 40 78 83 31 40 00 93 36 40 78 83 36 40 00 93 36 40 78 83 36 40 00 93 36 40 78 83 36 40 00 93 35
40 3c 83 35 40 00 93 33 40 3c 83 33 40 00 93 31 40 83 60 83 31 40 00 93 33 40 82 68 83 33 40 00 93 33 40 78 83 33 40 00
93 38 40 78 83 38 40 00 93 38 40 78 83 38 40 00 93 38 40 78 83 38 40 00 93 36 40 3c 83 36 40 00 93 34 40 3c 83 34 40 00
93 36 40 78 83 36 40 00 93 36 40 78 83 36 40 00 93 36 40 78 83 36 40 00 93 34 40 3c 83 34 40 00 93 33 40 3c 83 33 40 00
93 34 40 78 83 34 40 00 93 33 40 3c 83 33 40 00 93 31 40 3c 83 31 40 00 93 33 40 78 83 33 40 00 93 2c 40 78 83 2c 40 00
93 31 40 78 83 31 40 00 93 31 40 78 83 31 40 00 93 31 40 78 83 31 40 00 93 2f 40 3c 83 2f 40 00 93 2e 40 3c 83 2e 40 00
93 33 40 82 2c 83 33 40 00 93 34 40 3c 83 34 40 00 93 36 40 81 34 83 36 40 00 93 34 40 3c 83 34 40 00 93 33 40 3c 83 33
40 00 93 31 40 3c 83 31 40 00 93 38 40 83 60 83 38 40 00 93 39 40 82 68 83 39 40 00 93 38 40 3c 83 38 40 00 93 39 40 3c
83 39 40 00 93 3b 40 78 83 3b 40 00 93 39 40 78 83 39 40 00 93 38 40 78 83 38 40 00 93 36 40 78 83 36 40 00 93 3d 40 78
83 3d 40 00 93 3b 40 3c 83 3b 40 00 93 39 40 3c 83 39 40 00 93 38 40 78 83 38 40 00 93 36 40 78 83 36 40 00 93 38 40 83
60 83 38 40 77 90 00 00 00 ff 2f 00 4d 54 72 6b 00 00 07 cd 00 90 31 40 83 60 80 31 40 00 90 30 40 81 70 80 30 40 00 90
34 40 81 70 80 34 40 00 90 33 40 83 60 80 33 40 00 90 31 40 78 80 31 40 00 90 33 40 78 80 33 40 00 90 34 40 82 68 80 34
40 00 90 33 40 3c 80 33 40 00 90 31 40 3c 80 31 40 00 90 33 40 78 80 33 40 00 90 38 40 78 80 38 40 00 90 31 40 78 80 31
40 00 90 33 40 3c 80 33 40 00 90 34 40 3c 80 34 40 00 90 36 40 82 68 80 36 40 00 90 34 40 78 80 34 40 00 90 33 40 78 80
33 40 00 90 31 40 78 80 31 40 00 90 33 40 81 70 80 33 40 00 90 31 40 82 68 80 31 40 00 90 2f 40 78 80 2f 40 00 90 2d 40
78 80 2d 40 00 90 2c 40 78 80 2c 40 00 90 2d 40 81 70 80 2d 40 00 90 2e 40 81 70 80 2e 40 00 90 30 40 81 70 80 30 40 00
90 31 40 81 70 80 31 40 00 90 2c 40 78 80 2c 40 00 90 2d 40 78 80 2d 40 00 90 2f 40 82 68 80 2f 40 00 90 2d 40 78 80 2d
40 00 90 2c 40 78 80 2c 40 00 90 2a 40 78 80 2a 40 00 90 31 40 81 70 80 31 40 00 90 2d 40 82 68 80 2d 40 00 90 2c 40 78
80 2c 40 00 90 2a 40 78 80 2a 40 00 90 28 40 78 80 28 40 00 90 2a 40 81 70 80 2a 40 00 90 2c 40 81 70 80 2c 40 00 90 2d
40 78 80 2d 40 00 90 2c 40 78 80 2c 40 00 90 2d 40 78 80 2d 40 00 90 2f 40 78 80 2f 40 00 90 31 40 78 80 31 40 00 90 2f
40 78 80 2f 40 00 90 31 40 78 80 31 40 00 90 33 40 78 80 33 40 00 90 34 40 81 70 80 34 40 00 90 31 40 82 68 80 31 40 00
90 2f 40 78 80 2f 40 00 90 2e 40 78 80 2e 40 00 90 2c 40 78 80 2c 40 00 90 31 40 81 70 80 31 40 00 90 33 40 81 70 80 33
40 00 90 2c 40 81 70 80 2c 40 9a 20 90 2f 40 81 70 80 2f 40 00 90 2e 40 81 70 80 2e 40 00 90 33 40 81 70 80 33 40 00 90
31 40 83 60 80 31 40 00 90 2f 40 84 58 80 2f 40 00 90 38 40 78 80 38 40 00 90 36 40 78 80 36 40 00 90 34 40 78 80 34 40
00 90 3b 40 81 70 80 3b 40 00 90 2f 40 81 70 80 2f 40 00 90 34 40 81 70 80 34 40 00 90 39 40 81 70 80 39 40 00 90 38 40
81 70 80 38 40 00 90 3d 40 83 60 80 3d 40 00 90 3c 40 81 70 80 3c 40 00 90 3d 40 81 70 80 3d 40 95 48 90 31 40 3c 80 31
40 00 90 33 40 3c 80 33 40 00 90 34 40 78 80 34 40 00 90 36 40 78 80 36 40 00 90 38 40 3c 80 38 40 00 90 36 40 3c 80 36
40 00 90 38 40 3c 80 38 40 00 90 39 40 3c 80 39 40 00 90 38 40 3c 80 38 40 00 90 36 40 3c 80 36 40 00 90 34 40 3c 80 34
40 00 90 38 40 3c 80 38 40 00 90 36 40 3c 80 36 40 00 90 34 40 3c 80 34 40 00 90 36 40 3c 80 36 40 00 90 38 40 3c 80 38
40 00 90 36 40 3c 80 36 40 00 90 34 40 3c 80 34 40 00 90 33 40 3c 80 33 40 00 90 36 40 3c 80 36 40 00 90 34 40 3c 80 34
40 00 90 33 40 3c 80 33 40 00 90 34 40 3c 80 34 40 00 90 36 40 3c 80 36 40 00 90 34 40 3c 80 34 40 00 90 39 40 3c 80 39
40 00 90 38 40 3c 80 38 40 00 90 39 40 3c 80 39 40 00 90 33 40 3c 80 33 40 00 90 31 40 3c 80 31 40 00 90 33 40 3c 80 33
40 00 90 34 40 3c 80 34 40 00 90 33 40 3c 80 33 40 00 90 38 40 3c 80 38 40 00 90 36 40 3c 80 36 40 00 90 38 40 3c 80 38
40 00 90 31 40 81 70 80 31 40 95 48 90 34 40 78 80 34 40 00 90 39 40 78 80 39 40 00 90 39 40 78 80 39 40 00 90 39 40 78
80 39 40 00 90 38 40 3c 80 38 40 00 90 36 40 3c 80 36 40 00 90 38 40 81 70 80 38 40 00 90 39 40 81 70 80 39 40 00 90 36
40 81 70 80 36 40 00 90 2f 40 81 70 80 2f 40 00 90 34 40 81 70 80 34 40 00 90 2d 40 83 60 80 2d 40 00 90 2c 40 81 70 80
2c 40 91 68 90 2c 40 78 80 2c 40 00 90 31 40 78 80 31 40 00 90 31 40 78 80 31 40 00 90 31 40 78 80 31 40 00 90 2f 40 3c
80 2f 40 00 90 2e 40 3c 80 2e 40 00 90 2f 40 3c 80 2f 40 00 90 2e 40 3c 80 2e 40 00 90 2c 40 3c 80 2c 40 00 90 2f 40 3c
80 2f 40 00 90 2e 40 3c 80 2e 40 00 90 2c 40 3c 80 2c 40 00 90 2e 40 3c 80 2e 40 00 90 2f 40 3c 80 2f 40 00 90 2e 40 3c
80 2e 40 00 90 2c 40 3c 80 2c 40 00 90 2a 40 3c 80 2a 40 00 90 2e 40 3c 80 2e 40 00 90 2c 40 3c 80 2c 40 00 90 2a 40 3c
80 2a 40 00 90 2c 40 3c 80 2c 40 00 90 2e 40 3c 80 2e 40 00 90 2c 40 3c 80 2c 40 00 90 2f 40 3c 80 2f 40 00 90 2e 40 3c
80 2e 40 00 90 2c 40 3c 80 2c 40 00 90 2b 40 81 70 80 2b 40 00 90 2c 40 81 70 80 2c 40 00 90 2e 40 81 70 80 2e 40 00 90
33 40 81 70 80 33 40 00 90 2c 40 81 70 80 2c 40 85 50 90 25 40 83 60 80 25 40 00 90 30 40 81 70 80 30 40 00 90 28 40 81
70 80 28 40 00 90 27 40 83 60 80 27 40 00 90 25 40 78 80 25 40 00 90 25 40 3c 80 25 40 00 90 27 40 3c 80 27 40 00 90 28
40 78 80 28 40 00 90 2a 40 78 80 2a 40 00 90 2c 40 3c 80 2c 40 00 90 2a 40 3c 80 2a 40 00 90 2c 40 3c 80 2c 40 00 90 2d
40 3c 80 2d 40 00 90 2c 40 3c 80 2c 40 00 90 2a 40 3c 80 2a 40 00 90 28 40 3c 80 28 40 00 90 2c 40 3c 80 2c 40 00 90 2a
40 3c 80 2a 40 00 90 28 40 3c 80 28 40 00 90 2a 40 3c 80 2a 40 00 90 2c 40 3c 80 2c 40 00 90 2a 40 3c 80 2a 40 00 90 28
40 3c 80 28 40 00 90 27 40 3c 80 27 40 00 90 2a 40 3c 80 2a 40 00 90 28 40 78 80 28 40 00 90 34 40 78 80 34 40 00 90 39
40 78 80 39 40 00 90 39 40 78 80 39 40 00 90 39 40 78 80 39 40 00 90 38 40 3c 80 38 40 00 90 36 40 3c 80 36 40 00 90 38
40 78 80 38 40 00 90 2c 40 78 80 2c 40 00 90 31 40 78 80 31 40 00 90 2f 40 78 80 2f 40 00 90 2d 40 81 70 80 2d 40 00 90
2c 40 78 80 2c 40 8f 00 90 31 40 78 80 31 40 00 90 36 40 78 80 36 40 00 90 36 40 78 80 36 40 00 90 36 40 78 80 36 40 00
90 35 40 3c 80 35 40 00 90 33 40 3c 80 33 40 00 90 35 40 81 70 80 35 40 00 90 36 40 81 70 80 36 40 86 48 90 2c 40 78 80
2c 40 00 90 31 40 78 80 31 40 00 90 31 40 78 80 31 40 00 90 31 40 78 80 31 40 00 90 30 40 3c 80 30 40 00 90 2e 40 3c 80
2e 40 00 90 30 40 3c 80 30 40 00 90 31 40 3c 80 31 40 00 90 33 40 3c 80 33 40 00 90 30 40 3c 80 30 40 00 90 28 40 81 70
80 28 40 78 90 2d 40 78 80 2d 40 00 90 27 40 81 70 80 27 40 78 90 2c 40 78 80 2c 40 00 90 25 40 78 80 25 40 8c 18 90 31
40 81 70 80 31 40 00 90 30 40 81 70 80 30 40 00 90 34 40 81 70 80 34 40 00 90 33 40 83 60 80 33 40 00 90 31 40 78 80 31
40 00 90 34 40 78 80 34 40 00 90 39 40 78 80 39 40 00 90 39 40 78 80 39 40 00 90 39 40 78 80 39 40 00 90 38 40 3c 80 38
40 00 90 36 40 3c 80 36 40 00 90 34 40 3c 80 34 40 00 90 33 40 3c 80 33 40 00 90 31 40 3c 80 31 40 00 90 2f 40 3c 80 2f
40 00 90 2e 40 81 70 80 2e 40 00 90 2d 40 82 68 80 2d 40 00 90 2c 40 3c 80 2c 40 00 90 2a 40 3c 80 2a 40 00 90 29 40 81
70 80 29 40 00 90 2a 40 83 60 80 2a 40 00 90 2c 40 8f 00 80 2c 40 00 90 2b 40 83 60 80 2b 40 00 90 2c 40 87 40 80 2c 40
00 90 31 40 8f 00 80 31 40 77 90 00 00 00 ff 2f 00

How to split MIDI tracks into separate MIDI files

The following program takes a multi-track MIDI file with three or more tracks, and splits out each track into a separate MIDI file. The expression track of the original MIDI file is copied into the 0th track of the new MIDI files, and the individual tracks of the first MIDI file are copied to the 1st track of the output MIDI files.

#include "MidiFile.h"
#include <iostream>
#include <vector>
using namespace std;
using namespace smf;

int main(int argc, char** argv) {
   if (argc != 3) {
      cerr << "Usage: " << argv[0] << " input output" << endl;
      return 1;
   }
   MidiFile midifile(argv[1]);
   if (!midifile.status()) {
      cerr << "Problem reading input" << endl;
      return 1;
   }
   if (midifile.getTrackCount() < 3) {
      cerr << "Not enough tracks to split" << endl;
      return 1;
   }
   string basename = argv[2];
   if (basename.substr(basename.size() - 4) == ".mid")
      basename = basename.substr(0, basename.size() - 4);
   int outcount = midifile.getTrackCount() - 1;
   vector<MidiFile> outputs(outcount);
   for (int i=0; i<outcount; i++) {
      outputs[i].addTrack();
      for (int j=0; j<midifile[0].getEventCount(); j++)
         outputs[i].addEvent(midifile[0][j]);
      for (int j=0; j<midifile[i+1].getEventCount(); j++)
         outputs[i].addEvent(1, midifile[i+1][j]);
   }
   for (int i=0; i<outcount; i++)
      outputs[i].write(basename + "-" + to_string(i+1) + ".mid");
   return 0;
}

Here is the first file extracted from the MIDI file input for the temperament example:

4d 54 68 64 00 00 00 06 00 01 00 02 00 78 4d 54 72 6b 00 00 00 13 00 ff 51
03 08 8e 6c 00 ff 58 04 02 01 30 08 00 ff 2f 00 4d 54 72 6b 00 00 09 bd b2
50 90 49 40 81 70 80 49 40 00 90 48 40 81 70 80 48 40 00 90 4c 40 81 70 80
4c 40 00 90 4b 40 83 60 80 4b 40 00 90 49 40 82 68 80 49 40 00 90 4b 40 78
80 4b 40 00 90 4c 40 78 80 4c 40 00 90 4b 40 78 80 4b 40 00 90 49 40 81 70
80 49 40 00 90 47 40 81 70 80 47 40 00 90 49 40 81 70 80 49 40 00 90 4b 40
81 70 80 4b 40 82 68 90 4c 40 78 80 4c 40 00 90 4b 40 78 80 4b 40 00 90 49
40 78 80 49 40 00 90 47 40 78 80 47 40 00 90 4b 40 78 80 4b 40 00 90 50 40
82 68 80 50 40 00 90 4e 40 78 80 4e 40 00 90 50 40 78 80 50 40 00 90 51 40
78 80 51 40 00 90 53 40 84 58 80 53 40 00 90 51 40 78 80 51 40 00 90 50 40
78 80 50 40 00 90 4e 40 78 80 4e 40 00 90 50 40 3c 80 50 40 00 90 4e 40 3c
80 4e 40 00 90 4c 40 3c 80 4c 40 00 90 4b 40 3c 80 4b 40 00 90 49 40 83 60
80 49 40 00 90 47 40 82 68 80 47 40 00 90 49 40 78 80 49 40 00 90 47 40 78
80 47 40 00 90 45 40 78 80 45 40 00 90 44 40 81 70 80 44 40 00 90 46 40 78
80 46 40 00 90 47 40 78 80 47 40 00 90 49 40 81 70 80 49 40 00 90 47 40 83
60 80 47 40 00 90 46 40 81 70 80 46 40 00 90 47 40 84 58 80 47 40 00 90 49
40 78 80 49 40 00 90 4b 40 78 80 4b 40 00 90 4c 40 78 80 4c 40 00 90 4c 40
81 70 80 4c 40 00 90 4b 40 81 70 80 4b 40 00 90 4c 40 78 80 4c 40 00 90 4b
40 78 80 4b 40 00 90 4c 40 78 80 4c 40 00 90 4e 40 78 80 4e 40 00 90 50 40
3c 80 50 40 00 90 4e 40 3c 80 4e 40 00 90 50 40 3c 80 50 40 00 90 51 40 3c
80 51 40 00 90 50 40 3c 80 50 40 00 90 4e 40 3c 80 4e 40 00 90 4c 40 3c 80
4c 40 00 90 50 40 3c 80 50 40 00 90 4e 40 3c 80 4e 40 00 90 4c 40 3c 80 4c
40 00 90 4e 40 3c 80 4e 40 00 90 50 40 3c 80 50 40 00 90 4e 40 3c 80 4e 40
00 90 4c 40 3c 80 4c 40 00 90 4b 40 3c 80 4b 40 00 90 4e 40 3c 80 4e 40 00
90 4c 40 3c 80 4c 40 00 90 4b 40 3c 80 4b 40 00 90 4c 40 3c 80 4c 40 00 90
4e 40 3c 80 4e 40 00 90 4c 40 3c 80 4c 40 00 90 4b 40 3c 80 4b 40 00 90 49
40 3c 80 49 40 00 90 4c 40 3c 80 4c 40 00 90 4b 40 3c 80 4b 40 00 90 49 40
3c 80 49 40 00 90 4b 40 3c 80 4b 40 00 90 4c 40 3c 80 4c 40 00 90 4b 40 3c
80 4b 40 00 90 49 40 3c 80 49 40 00 90 47 40 3c 80 47 40 00 90 4b 40 3c 80
4b 40 00 90 49 40 3c 80 49 40 00 90 47 40 3c 80 47 40 00 90 49 40 3c 80 49
40 00 90 4b 40 3c 80 4b 40 00 90 49 40 3c 80 49 40 00 90 47 40 3c 80 47 40
00 90 46 40 3c 80 46 40 00 90 49 40 3c 80 49 40 00 90 47 40 82 2c 80 47 40
00 90 49 40 3c 80 49 40 00 90 4b 40 3c 80 4b 40 00 90 47 40 3c 80 47 40 00
90 49 40 82 68 80 49 40 00 90 4c 40 78 80 4c 40 00 90 4b 40 82 68 80 4b 40
00 90 4e 40 78 80 4e 40 00 90 4c 40 84 58 80 4c 40 00 90 4b 40 81 70 80 4b
40 00 90 49 40 81 70 80 49 40 00 90 48 40 3c 80 48 40 00 90 46 40 3c 80 46
40 00 90 48 40 78 80 48 40 00 90 4b 40 78 80 4b 40 00 90 50 40 3c 80 50 40
00 90 4e 40 3c 80 4e 40 00 90 50 40 3c 80 50 40 00 90 51 40 3c 80 51 40 00
90 50 40 3c 80 50 40 00 90 4e 40 3c 80 4e 40 00 90 4c 40 3c 80 4c 40 00 90
50 40 3c 80 50 40 00 90 4e 40 3c 80 4e 40 00 90 4c 40 3c 80 4c 40 00 90 4e
40 3c 80 4e 40 00 90 50 40 3c 80 50 40 00 90 4e 40 3c 80 4e 40 00 90 4c 40
3c 80 4c 40 00 90 4b 40 3c 80 4b 40 00 90 4e 40 3c 80 4e 40 00 90 4d 40 81
70 80 4d 40 00 90 51 40 81 70 80 51 40 00 90 50 40 84 58 80 50 40 00 90 4e
40 3c 80 4e 40 00 90 4c 40 3c 80 4c 40 00 90 4a 40 81 70 80 4a 40 78 90 49
40 78 80 49 40 00 90 4e 40 78 80 4e 40 00 90 4e 40 78 80 4e 40 00 90 4e 40
78 80 4e 40 00 90 4c 40 3c 80 4c 40 00 90 4a 40 3c 80 4a 40 00 90 4c 40 82
68 80 4c 40 00 90 4a 40 3c 80 4a 40 00 90 49 40 3c 80 49 40 00 90 4a 40 83
60 80 4a 40 00 90 49 40 81 70 80 49 40 00 90 4e 40 81 70 80 4e 40 00 90 4c
40 81 70 80 4c 40 00 90 4c 40 81 34 80 4c 40 00 90 4e 40 3c 80 4e 40 00 90
4c 40 3c 80 4c 40 00 90 4a 40 3c 80 4a 40 00 90 49 40 3c 80 49 40 00 90 4c
40 3c 80 4c 40 00 90 4a 40 3c 80 4a 40 00 90 49 40 3c 80 49 40 00 90 4a 40
3c 80 4a 40 00 90 4c 40 3c 80 4c 40 00 90 4a 40 3c 80 4a 40 00 90 49 40 3c
80 49 40 00 90 47 40 3c 80 47 40 00 90 4a 40 3c 80 4a 40 00 90 49 40 83 60
80 49 40 00 90 48 40 81 70 80 48 40 00 90 4c 40 81 70 80 4c 40 00 90 4b 40
84 58 80 4b 40 00 90 44 40 78 80 44 40 00 90 49 40 78 80 49 40 00 90 49 40
78 80 49 40 00 90 49 40 78 80 49 40 00 90 47 40 3c 80 47 40 00 90 45 40 3c
80 45 40 00 90 47 40 83 60 80 47 40 00 90 45 40 81 70 80 45 40 00 90 44 40
81 70 80 44 40 81 70 90 4b 40 83 60 80 4b 40 00 90 4a 40 81 70 80 4a 40 00
90 4e 40 81 70 80 4e 40 00 90 4d 40 81 70 80 4d 40 00 90 4c 40 81 70 80 4c
40 00 90 4b 40 3c 80 4b 40 00 90 49 40 3c 80 49 40 00 90 4b 40 3c 80 4b 40
00 90 4c 40 3c 80 4c 40 00 90 4b 40 3c 80 4b 40 00 90 49 40 3c 80 49 40 00
90 47 40 3c 80 47 40 00 90 4b 40 3c 80 4b 40 00 90 49 40 3c 80 49 40 00 90
47 40 3c 80 47 40 00 90 49 40 3c 80 49 40 00 90 4b 40 3c 80 4b 40 00 90 49
40 3c 80 49 40 00 90 4c 40 3c 80 4c 40 00 90 4b 40 3c 80 4b 40 00 90 49 40
3c 80 49 40 00 90 48 40 81 70 80 48 40 00 90 47 40 81 70 80 47 40 00 90 46
40 81 70 80 46 40 00 90 45 40 81 70 80 45 40 00 90 44 40 81 70 80 44 40 89
30 90 49 40 83 60 80 49 40 00 90 48 40 81 70 80 48 40 00 90 4c 40 81 70 80
4c 40 00 90 4b 40 85 50 80 4b 40 00 90 49 40 83 60 80 49 40 00 90 48 40 81
70 80 48 40 78 90 49 40 3c 80 49 40 00 90 4b 40 3c 80 4b 40 00 90 4c 40 78
80 4c 40 00 90 4e 40 78 80 4e 40 00 90 50 40 3c 80 50 40 00 90 4e 40 3c 80
4e 40 00 90 50 40 3c 80 50 40 00 90 51 40 3c 80 51 40 00 90 50 40 3c 80 50
40 00 90 4e 40 3c 80 4e 40 00 90 4c 40 3c 80 4c 40 00 90 50 40 3c 80 50 40
00 90 4e 40 3c 80 4e 40 00 90 4c 40 3c 80 4c 40 00 90 4e 40 3c 80 4e 40 00
90 50 40 3c 80 50 40 00 90 4e 40 3c 80 4e 40 00 90 4c 40 3c 80 4c 40 00 90
4b 40 3c 80 4b 40 00 90 4e 40 3c 80 4e 40 00 90 4c 40 3c 80 4c 40 00 90 4b
40 3c 80 4b 40 00 90 4c 40 3c 80 4c 40 00 90 4e 40 3c 80 4e 40 00 90 4c 40
3c 80 4c 40 00 90 4a 40 3c 80 4a 40 00 90 49 40 3c 80 49 40 00 90 4c 40 3c
80 4c 40 00 90 4a 40 3c 80 4a 40 00 90 49 40 3c 80 49 40 00 90 4a 40 3c 80
4a 40 00 90 4c 40 3c 80 4c 40 00 90 4a 40 3c 80 4a 40 00 90 49 40 3c 80 49
40 00 90 47 40 3c 80 47 40 00 90 4a 40 3c 80 4a 40 00 90 49 40 3c 80 49 40
00 90 47 40 3c 80 47 40 00 90 49 40 3c 80 49 40 00 90 4a 40 3c 80 4a 40 00
90 49 40 3c 80 49 40 00 90 47 40 3c 80 47 40 00 90 45 40 3c 80 45 40 00 90
49 40 3c 80 49 40 00 90 47 40 3c 80 47 40 00 90 45 40 3c 80 45 40 00 90 47
40 3c 80 47 40 00 90 49 40 3c 80 49 40 00 90 47 40 3c 80 47 40 00 90 45 40
3c 80 45 40 00 90 44 40 3c 80 44 40 00 90 47 40 3c 80 47 40 00 90 45 40 81
70 80 45 40 81 70 90 49 40 83 60 80 49 40 00 90 48 40 81 70 80 48 40 00 90
4c 40 81 70 80 4c 40 00 90 4b 40 84 58 80 4b 40 00 90 49 40 78 80 49 40 00
90 50 40 78 80 50 40 00 90 50 40 78 80 50 40 00 90 50 40 78 80 50 40 00 90
4e 40 3c 80 4e 40 00 90 4c 40 3c 80 4c 40 00 90 4e 40 81 70 80 4e 40 00 90
4c 40 83 60 80 4c 40 00 90 4b 40 81 70 80 4b 40 00 90 4f 40 81 70 80 4f 40
00 90 4e 40 81 70 80 4e 40 00 90 42 40 81 70 80 42 40 00 90 41 40 81 70 80
41 40 00 90 45 40 81 70 80 45 40 00 90 44 40 78 80 44 40 83 60 90 48 40 78
80 48 40 00 90 4e 40 78 80 4e 40 00 90 4e 40 78 80 4e 40 00 90 4e 40 78 80
4e 40 00 90 4c 40 3c 80 4c 40 00 90 4b 40 3c 80 4b 40 00 90 4c 40 78 80 4c
40 00 90 4b 40 3c 80 4b 40 00 90 49 40 3c 80 49 40 00 90 4b 40 78 80 4b 40
00 90 48 40 78 80 48 40 00 90 49 40 85 50 80 49 40 00 90 48 40 81 70 80 48
40 00 90 47 40 81 70 80 47 40 00 90 46 40 81 70 80 46 40 00 90 45 40 81 70
80 45 40 00 90 44 40 83 60 80 44 40 00 90 46 40 81 70 80 46 40 00 90 48 40
81 70 80 48 40 00 90 49 40 83 60 80 49 40 00 90 48 40 81 70 80 48 40 00 90
4c 40 83 60 80 4c 40 00 90 4b 40 78 80 4b 40 00 90 49 40 78 80 49 40 00 90
48 40 81 70 80 48 40 00 90 49 40 83 60 80 49 40 00 90 48 40 81 70 80 48 40
00 90 49 40 8f 00 80 49 40 77 90 00 00 00 ff 2f 00

How to create vibrato with pitch-bend messages in a MIDI file

This example demonstrates the generation of a constant vibrato for notes in a MIDI file (on a particular channel). The program adds an extra track at the end of the file to store the pitch bends. The vibrato rate is constant regardless of the tempo setting for the MIDI file, since the vibrato is calculated in physical time rather than tick time. The MidiFile::getAbsoluteTickTime() function calculates the conversion between physical time in seconds and tick time in the MIDI file.

#include "MidiFile.h"
#include "Options.h"
#include <iostream>
#include <utility>
#include <cmath>
using namespace std;
using namespace smf;

int main(int argc, char** argv) {
   Options options;
   options.define("f|frequency=d:4.0",     "vibrato frequency");
   options.define("d|depth=d:20.0",        "vibrato depth in cents");
   options.define("b|bend-max=d:200.0",    "pitch bend depth");
   options.define("s|sample-rate=d:100.0", "sample rate");
   options.define("o|output-file=s",       "output filename");
   options.define("c|channel=i:0",         "output channel");
   options.process(argc, argv);

   MidiFile midifile;
   if (options.getArgCount() == 0) midifile.read(cin);
   else midifile.read(options.getArg(1));
   if (!midifile.status()) {
      cerr << "Problem reading file" << endl;
      return 1;
   }

   string filename  = options.getString("output-file");
   int    channel   = options.getInteger("channel");
   double freq      = options.getDouble("frequency");
   double depth     = options.getDouble("depth");
   double bend      = options.getDouble("bend-max");
   double srate     = options.getDouble("sample-rate");
   double phase     = 0.0;
   double twopi     = 2.0 * M_PI;
   double increment = twopi * freq / srate;
   double maxtime   = midifile.getFileDurationInSeconds();
   midifile.addTrack(); // store vibrato in separate track
   pair<int, double> tickbend;
   vector<pair<double, double>> storage;
   int count = maxtime * srate;
   storage.reserve(maxtime * srate + 1000);
   for (int i=0; i<count; i++) {
      tickbend.first = int(midifile.getAbsoluteTickTime(i/srate) + 0.5);
      tickbend.second = depth/bend * sin(phase);
      if ((storage.size() > 0) && (tickbend.first == 0)) break;
      storage.push_back(tickbend);
      phase += increment;
      if (phase > twopi) phase -= twopi;
   }
   int track = midifile.getTrackCount() - 1;
   for (int i=0; i<(int)storage.size(); i++)
      midifile.addPitchBend(track, storage[i].first, channel, storage[i].second);
   if (filename.empty()) cout << midifile;
   else midifile.write(filename);
   return 0;
}

Polyrhythm generator

Here is a program that generates polyrhythm patterns. Command line options are:

option default value meaning
-a 2 first instrument's division of the cycle
-b 3 first instrument's division of the cycle
-c 10 number of cycles
-d 2.0 duration of each cycle
--key1 76 percussion key number for first instrument
--key2 77 percussion key number for first instrument
-o output filename
#include "MidiFile.h"
#include "Options.h"
#include <iostream>
#include <utility>
#include <cmath>
using namespace std;
using namespace smf;

int main(int argc, char** argv) {
   Options options;
   options.define("a=i:2",           "cycle division 1");
   options.define("b=i:3",           "cycle division 2");
   options.define("c|cycle=i:10",    "cycle count");
   options.define("d|dur=d:2.0",     "duration of cycle in seconds");
   options.define("key1=i:76",       "first percussion key number");
   options.define("key2=i:77",       "second percussion key number");
   options.define("o|output-file=s", "output filename");
   options.process(argc, argv);

   int a = options.getInteger("a");
   int b = options.getInteger("b");
   int c = options.getInteger("cycle");
   int key1 = options.getInteger("key1");
   int key2 = options.getInteger("key2");
   double dur = options.getDouble("dur");
   double tempo = 60.0 / dur;

   MidiFile midifile;
   midifile.setTPQ(a*b);
   midifile.addTempo(0, 0, tempo);
   midifile.addTracks(2);
   for (int i=0; i<b*c + 1; i++) {
      midifile.addNoteOn(1, i*a, 9, key1, 64);
      midifile.addNoteOff(1, (i+1)*a, 9, key1);
   }
   for (int i=0; i<a*c + 1; i++) {
      midifile.addNoteOn(2, i*b, 9, key2, 64);
      midifile.addNoteOff(2, (i+1)*b, 9, key2);
   }

   string filename  = options.getString("output-file");
   if (filename.empty()) cout << midifile;
   else midifile.write(filename);
   return 0;
}

This program demonstrates how to set the ticks-per-quarter-note value in the MIDI header. In this case it is set to the factor of a*b which is the duration of one cycle (so each cycle has the duration of a quarter note). A tempo meta-message is also calculated based on the desired duration of a cycle.

For example, try the options -a 3 -b 4 -c 200 -d 1 -o 3x4.mid, which will play a 3-against-4 pattern for 200 cycles with each cycle lasting 1 second. Or here is 11-against-13 for 100 cycles: -a 11 -b 13 -c 100 -d 5 -o 11x13.mid.

midifile's People

Contributors

alpha0010 avatar craigsapp avatar derselbst avatar folkertvanheusden avatar gocha avatar jacqueslorentz avatar justinharding avatar lpugin avatar quiasmo avatar refi64 avatar reidtreharne avatar rettinghaus avatar sommern avatar zlaski avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

midifile's Issues

Error parsing MIDI file

I'm having trouble loading the attached MIDI:
Good Bye.zip
The error is "Expecting 'M' at first byte in track but got '133'"
The MIDI plays fine in Foobar2000.
I checked in a HEX editor and found that in one case the command "FF 2F 00" (End of track) isn't followed directly by "MTrk" - I think that causes the error. I wonder what commands are there between the end of track and the start of the next one? Is this a normal situation or is it invalid syntax?

Infinite loop

While reading a particular type of files, the library enters the infinite loop. The problem can be reproduced with a file consisting of 1025 or more null symbols. In order to get the minimal example, call python -c "with open('data.mid', 'wb') as f: f.write('\x00' * 1025)" and then open it with main.cpp as Midifile("data.mid").

It happens in the following loop:
https://github.com/craigsapp/midifile/blob/master/src/Binasc.cpp#L270
The problem occurs when getline reads an empty string. The file cursor does not move, and eof never gets reached.

I am not sure what behavior is supposed in the midi-format but it seems that one could just include && inputLine[0] != '\0' into the condition of the cycle.

My main problem now is that I can't validate input file because the infinite loop occurs before I have any ability to check status.

The 'midicat' program conflicts with sndio

Installing midifile-g20200602...
pkg-static: midifile-g20200602 conflicts with sndio-1.7.0.20201210 (installs files into the same place).  Problematic file: /usr/local/bin/midicat
*** Error code 1

Please consider renaming it, or better rename all programs by adding the prefix midifile-.

doTimeAnalysis not correct(durations.cpp )

First thanks the sample

double duration;

I am trying to get MIDIEvent's start time and duration
the twinkle twinkle little star mid I try to parse is from
https://www.8notes.com/scores/2904.asp?ftype=midi

below is the result
QTRS DUR TRACK NOTE

0 0.6 1 60
0 1.2 1 48
0.6 0.6 1 60
1.2 0.6 1 67
1.2 1.2 1 52
1.8 0.6 1 67
2.4 0.6 1 69
2.4 1.2 1 53
3 0.6 1 69
3.6 1.2 1 67
3.6 1.2 1 52
4.8 0.6 1 65
4.8 1.2 1 50
5.4 0.6 1 65
6 0.6 1 64
6 1.2 1 48
6.6 0.6 1 64
7.2 0.6 1 62
7.2 0.6 1 53
7.8 0.6 1 62
7.8 0.6 1 55
8.4 1.2 1 60
8.4 0.6 1 52
9 0.6 1 48
9.6 0.6 1 67
9.6 1.2 1 52
10.2 0.6 1 67
10.8 0.6 1 65
10.8 1.2 1 53
11.4 0.6 1 65
12 0.6 1 64
12 1.2 1 55
12.6 0.6 1 64
13.2 1.2 1 62
13.2 1.2 1 55
14.4 0.6 1 67
14.4 1.2 1 52
15 0.6 1 67
15.6 0.6 1 65
15.6 1.2 1 53
16.2 0.6 1 65
16.8 0.6 1 64
16.8 1.2 1 55
17.4 0.6 1 64
18 1.2 1 62
18 1.2 1 55
19.2 0.6 1 60
19.2 1.2 1 48
19.8 0.6 1 60
20.4 0.6 1 67
20.4 1.2 1 52
21 0.6 1 67
21.6 0.6 1 69
21.6 1.2 1 53
22.2 0.6 1 69
22.8 1.2 1 67
22.8 1.2 1 52
24 0.6 1 65
24 1.2 1 50
24.6 0.6 1 65
25.2 0.6 1 64
25.2 1.2 1 48
25.8 0.6 1 64
26.4 0.6 1 62
26.4 0.6 1 53
27 0.6 1 62
27 0.6 1 55
27.6 1.2 1 60
27.6 1.2 1 48

some event's start time seems wrong,could you please check this or give some advice for somewhere I can check to fix this

thx :)

while(1)

when i want to read file context {0x00 0x00 .....}
MidiFile::read
int Binasc::writeToBinary
will while(1)

[Suggestion] linking 'sustain on(127)' and 'sustain off(0)' midievents in a function

Hi Craig,

Currently we can get a note-off event of specific note-on event by using linkNotePairs() and getLinkedEvent(). They're very useful.
How about having similar utility function for linking a sustain-on(127) event and a sustain-off(0) event which is placed at the closest next position after the sustain-on event on the same channel, and vice versa.
In that case, some exceptional situations need to be considered. For example,

  1. In a channel which doesn't use any sustain-on event except a initial sustain-off event, we can't get linked sustain-on event of initial sustain-off event.
  2. In a channel which ends without sustain-off event(if that's possible), we can't get linked sustain-off event of the last sustain-on event.

Sustain midi messages are very important articulation especially in keyboard instruments and they logically can be considered as on-and-off pairs if they're used properly.
Perhaps you could find more midi messages can be treated as pairs.

Thanks in advance.

Kind regards,

Peter

How to copy tempo track,key track,and meter track from one midifile to an empty midifile?

1
I use MUSICSTD to check midifiles ,from it i can see three tracks that store tempo,key,and meter. However i'm not sure whether there were 3 tracks that actually exist in midifile or it was just one track that contains all 3 kinds of data.I tried to use the following code to do the function but it failed.

	MidiFile midifile_changed;
	midifile_changed.addTrack();
	for (int j = 0; j<midifile[0].getEventCount(); j++)
		midifile_changed.addEvent(midifile[0][j]);
	midifile_changed.addTrack();
	for (int j = 0; j<midifile[1].getEventCount(); j++)
		midifile_changed.addEvent(midifile[1][j]);

When I only copy track[0],the tempo track dosen't exist in MUSICSTD .
And when I copy both these two tracks,the tempo track exist,but sometimes it copys the sound track of the original midifile.
Not sure how to do now...

Move headers so that project is submodule-friendly

I would like to send a PR that does the following:

  1. Move the headers from include/*.h into include/midifile/*.h
  2. Change code to include as e.g. #include "midifile/MidiEvent.h"
  3. Change CMakeLists.txt file to to use target_include_directories in accordance with modern CMake style.

This will make the project more modular and friendly when used as a submodule in a larger project and is in accordance with standard procedure. Do you have any issues with this? If not then let me know and I will send a pull request. Thanks

Allow static and shared builds

Will a shared library also be supported?

If you remove the STATIC argument from add_library() in CMakeLists.txt then the user can decide to build either a static or shared library bu supplying cmake parameter -DBUILD_SHARED_LIBS:BOOL=OFF or -DBUILD_SHARED_LIBS:BOOL=ON respectively.

Note that to support building a shared library (DLL) on Windows you will need to add the necessary __declspec(dllexport) and __declspec(dllimport) stuff for exported classes.

Binasc.h missing two required headers for it to compile with MinGW

Unless these includes are added to Binasc.h:

#include <cstdlib>
#include <stdlib.h>

Then you get compile errors like this:

src-library/Binasc.cpp:1273:53: error: 'atof' was not declared in this scope
       double doubleOutput = atof(&word[quoteIndex+1]);

src-library/Binasc.cpp:1307:52: error: 'atoi' was not declared in this scope
          long tempLong = atoi(&word[quoteIndex + 1]);

src-library/Binasc.cpp:1445:61: error: 'strtol' was not declared in this scope
    outputByte = (uchar)strtol(word.c_str(), (char**)NULL, 16);

src-library/Binasc.cpp:1677:40: error: 'strtod' was not declared in this scope
    double value = strtod(&word[1], NULL);

Writing past the end of a vector in MidiFile::mergeTracks

In the function MidiFile::mergeTracks there are two lines near the bottom that read:

m_events[length] = NULL;
m_events.resize(length-1);

Since length is the number of tracks the first line writes past the end of the m_events vector and corrupts memory. This should be:

m_events[length-1] = NULL;
m_events.resize(length-1);

Meta event parse error

The structure of Meta event is:
0xFF <type byte> <var len> data ...
and in MidiFile.cpp line 2599:

metai = MidiFile::readByte(input); // meta type
array.push_back(metai);
for (uchar j=0; j<metai; j++) {
    byte = MidiFile::readByte(input); // meta type
    array.push_back(byte);
}

use 1 byte metai as the var len.

If a mid file contains a meta event which is larger than 127 bytes
etc: I will save a custom text event to track who play this song in my app.
This file will read failed.

Documentation source code links to the wrong lines

The links to the source code from the documentation don't match with the source code of the current version of Midifile. I'm up for taking care of this, but might I also recommend something like Doxygen to help with documentation generation?

Memory leak in MidiFile::operator=

Hello, I am running the midifile library under ASAN (Address Sanitizer) and it is telling me that there are some memory leaks.

One of them appears to be caused by using MidiFile move assignment operator under certain circumstances. On the first line of that function there appears to be a problem:

m_events = std::move(other.m_events);

but the problem is, the pointers stored in m_events (before the move) won't be freed, and you have a leak. The vector's destructor will be called, but it won't free raw pointers. It appears that the issue goes away when I insert these lines at the top of the function:

    clear();
    if (m_events[0] != NULL) {
        delete m_events[0];
        m_events[0] = NULL;
    }
    ...

Could you please fix this? By the way, I also had a look in the MidiFile copy assignment operator and it also looks dubious, in particular you are reserving space in the m_events array and then adding new events onto the end of it, when you should probably be freeing the events in that vector, then resizing it to zero, then reserving, then finally adding new elements (note that calling reserve will not change the size of the vector).

Overall, I would really recommend avoiding to use raw pointers that own memory; the fact that you are using naked new and delete statements throughout is a red flag... I am thus honestly not surprised to find these memory leaks. If you have a pointer that owns memory the default choice is std::unique_ptr which will handle memory management for you so that you never have to worry about calling delete at the right time.

Thanks
David
P.S. I have a pull request pending about restructuring the include folders in this repository, can you please respond? :-)

[Suggestion] Additional condition(s) on sortTrack...

Hello,

In 'eventcompare', we have some extra condition for sorting midi messages when there're noteon and pitchbend at the same time(tick). I think it needs to be applied to program change message too, as below:

   else if (((aevent[0] & 0xf0) == 0xe0) && ((bevent[0] & 0xf0) == 0x90)) {
      // pitch bend placed before note on messages
      return -1;
   } else if (((aevent[0] & 0xf0) == 0x90) && ((bevent[0] & 0xf0) == 0xe0)) {
      // pitch bend placed before note on messages
      return +1;
   } else if (((aevent[0] & 0xf0) == 0xc0) && ((bevent[0] & 0xf0) == 0x90)) {
       // program change placed before note on messages
       return -1;
   } else if (((aevent[0] & 0xf0) == 0x90) && ((bevent[0] & 0xf0) == 0xc0)) {
       // program change placed before note on messages
       return +1;
   } 

I have same idea about placing tempo change and signature change midi messages before any noteon message which is at the same tick, but they aren't channel specific so I'm not sure if that also should be considered or not.

Please check this and thanks in advance.

Kind regards,
Peter

Events are not linked

In the latest version, duration is always zero. I have tried doing time analysis first.

smf::MidiFile midi_parser(in);
midi_parser.linkNotePairs();
midi_parser.doTimeAnalysis();

In the loop:

if (event.isNoteOn()) {
  double duration = event.getDurationInSeconds();
  double start = event.seconds;
  int pitch = event.getKeyNumber();
  log("NOTE ON %i, %f, %f", pitch, start, duration);
} else if (event.isNoteOff()) {
  log("NOTE OFF %i, %f", event.getKeyNumber(), event.seconds);
}

Sample output:
NOTE ON 49, 272.571792, 0.000000
NOTE ON 53, 272.571792, 0.000000
NOTE ON 56, 272.571792, 0.000000
NOTE OFF 49, 275.013760
NOTE OFF 53, 275.013760
NOTE OFF 56, 275.013760

2 Indexing Errors, already fixed them.

I found two indexing errors in joinTracks(); and splitTracks();, both errors involved going out of bounds on the vector, I already fixed the errors after some reading up on the documentation for vectors, and will leave the updated MidiFile.cpp attached to this ticket. Note the commenting for info.

MidiFile.cpp.zip

writeHex doesn't write to the output stream

Instead it calls printf directly, causing the output to go to the console instead of being written inside the file you pass.

My fix was to do something like this:

 // save default formatting (in the beginning of the function)
 ios init(0);
 init.copyfmt(out);

 out << hex << setw(2) << setfill('0') << right << value;

 // restore default formatting (at the end of the function)
 out.copyfmt(init);

Such a great library! Thank you very much for sharing it, and the Options class is the best I've used.

Compiling in windows

Just a heads up. When compiling in Windows using the "visual-studio" fix, the process fails. MidiMessage.cpp is missing "#include ". It has to be added manually in order to generate the library file.

p.s. - this library is awesome

EDIT: I'm getting undefined refrence errors with MidiFile inclusion

Code:

#include "MidiFile.h"
#include "Options.h"
#include <iostream>

using namespace std;

int main(int argc, char** argv)
{
    MidiFile outTrack; //Declares a midi obj named seed track

    //Controls
    int totalTracks = 60; //sets desired number of output tracks

    outTrack.read("orig.mid"); //Assigns file to outTrack obj. Contents of file is transfered to obj. File must be named "orig".

    int eventsTot = outTrack.getEventCount(0); //Gets the total number of events from original midi file

    for(int a = 1; a <= totalTracks ; a++){ //Main Track Loop. Loops through the desired number of tracks

        outTrack.addTrack();


        for(int i=0;i<=eventsTot;i++){ //Main Event Loop. Loops through each event of the orig track


        }

    }

    cout << "Hello world!" << endl;
    return 0;
}

Errors:

||=== Build: Debug in midiii (compiler: GNU GCC Compiler) ===|
obj\Debug\main.o||In function main':| C:\Users\Desktop\New folder\midiii\main.cpp|9|undefined reference toMidiFile::MidiFile()'|
C:\Users\Desktop\New folder\midiii\main.cpp|14|undefined reference to MidiFile::read(char const*)'| C:\Users\Desktop\New folder\midiii\main.cpp|16|undefined reference toMidiFile::getEventCount(int)'|
C:\Users\Desktop\New folder\midiii\main.cpp|20|undefined reference to MidiFile::addTrack()'| C:\Users\Desktop\New folder\midiii\main.cpp|31|undefined reference toMidiFile::~MidiFile()'|
C:\Users\Desktop\New folder\midiii\main.cpp|31|undefined reference to `MidiFile::~MidiFile()'|
||error: ld returned 1 exit status|
||=== Build failed: 7 error(s), 0 warning(s) (0 minute(s), 0 second(s)) ===|

Multiple bugs

the MidiEvent::linkEvent function in src-library/MidiEvent.cpp in midifile through 2017-03-16 can cause a denial of service(invalid memory read and application crash) via a crafted mid file.

./mid2mtb midifile_invalid_memory_read_1.mid

----debug info:----
Program received signal SIGSEGV, Segmentation fault.
0x0000000000405e57 in MidiEvent::linkEvent (this=0x21, mev=0x643610)
    at src-library/MidiEvent.cpp:184
184	   if (eventlink != NULL) {
(gdb) bt
#0  0x0000000000405e57 in MidiEvent::linkEvent (this=0x21, mev=0x643610)
    at src-library/MidiEvent.cpp:184
#1  0x0000000000407555 in MidiEventList::linkNotePairs (this=0x641e30)
    at src-library/MidiEventList.cpp:316
#2  0x00000000004135b2 in MidiFile::linkNotePairs (this=0x7fffffffde60)
    at src-library/MidiFile.cpp:2232
#3  0x0000000000402f4c in convertMidiFile (midifile=..., 
    matlab=std::vector of length 0, capacity 100000)
    at src-programs/mid2mtb.cpp:65
#4  0x0000000000402eca in main (argc=2, argv=0x7fffffffdfc8)
    at src-programs/mid2mtb.cpp:49
(gdb) disassemble 
Dump of assembler code for function MidiEvent::linkEvent(MidiEvent*):
   0x0000000000405e2a <+0>:	push   %rbp
   0x0000000000405e2b <+1>:	mov    %rsp,%rbp
   0x0000000000405e2e <+4>:	sub    $0x10,%rsp
   0x0000000000405e32 <+8>:	mov    %rdi,-0x8(%rbp)
   0x0000000000405e36 <+12>:	mov    %rsi,-0x10(%rbp)
   0x0000000000405e3a <+16>:	mov    -0x10(%rbp),%rax
   0x0000000000405e3e <+20>:	mov    0x30(%rax),%rax
   0x0000000000405e42 <+24>:	test   %rax,%rax
   0x0000000000405e45 <+27>:	je     0x405e53 <MidiEvent::linkEvent(MidiEvent*)+41>
   0x0000000000405e47 <+29>:	mov    -0x10(%rbp),%rax
   0x0000000000405e4b <+33>:	mov    %rax,%rdi
   0x0000000000405e4e <+36>:	callq  0x405de8 <MidiEvent::unlinkEvent()>
   0x0000000000405e53 <+41>:	mov    -0x8(%rbp),%rax
=> 0x0000000000405e57 <+45>:	mov    0x30(%rax),%rax
   0x0000000000405e5b <+49>:	test   %rax,%rax
   0x0000000000405e5e <+52>:	je     0x405e70 <MidiEvent::linkEvent(MidiEvent*)+70>
   0x0000000000405e60 <+54>:	mov    -0x8(%rbp),%rax
   0x0000000000405e64 <+58>:	mov    0x30(%rax),%rax
   0x0000000000405e68 <+62>:	mov    %rax,%rdi
   0x0000000000405e6b <+65>:	callq  0x405de8 <MidiEvent::unlinkEvent()>
---Type <return> to continue, or q <return> to quit---q
Quit
(gdb) i r
rax            0x21	33
rbx            0x42	66
rcx            0x644dc0	6573504
rdx            0x643610	6567440
rsi            0x643610	6567440
rdi            0x21	33
rbp            0x7fffffffdc60	0x7fffffffdc60
rsp            0x7fffffffdc50	0x7fffffffdc50
r8             0x0	0
r9             0x2	2
r10            0x7ffff78b97b8	140737346508728
r11            0x7ffff78b9701	140737346508545
r12            0x402d60	4205920
r13            0x7fffffffdfc0	140737488347072
r14            0x0	0
r15            0x0	0
rip            0x405e57	0x405e57 <MidiEvent::linkEvent(MidiEvent*)+45>
eflags         0x10246	[ PF ZF IF RF ]
cs             0x33	51
ss             0x2b	43
ds             0x0	0
es             0x0	0
fs             0x0	0
---Type <return> to continue, or q <return> to quit---
gs             0x0	0
(gdb)

=================================================================
==7038== ERROR: AddressSanitizer: heap-use-after-free on address 0x605a000123d0 at pc 0x40b51d bp 0x7ffc56c2b7a0 sp 0x7ffc56c2b798
READ of size 8 at 0x605a000123d0 thread T0
    #0 0x40b51c in std::vector<MidiEvent*, std::allocator<MidiEvent*> >::push_back(MidiEvent* const&) /usr/include/c++/4.8/bits/stl_vector.h:903
    #1 0x40a391 in MidiEventList::linkNotePairs() /home/a/Downloads/midifile-master/src-library/MidiEventList.cpp:309
    #2 0x41e632 in MidiFile::linkNotePairs() /home/a/Downloads/midifile-master/src-library/MidiFile.cpp:2232
    #3 0x403545 in convertMidiFile(MidiFile&, std::vector<std::vector<double, std::allocator<double> >, std::allocator<std::vector<double, std::allocator<double> > > >&) /home/a/Downloads/midifile-master/src-programs/mid2mtb.cpp:65
    #4 0x403476 in main /home/a/Downloads/midifile-master/src-programs/mid2mtb.cpp:49
    #5 0x7fa7aabe4ec4 (/lib/x86_64-linux-gnu/libc.so.6+0x21ec4)
    #6 0x4032f8 in _start (/home/a/Downloads/midifile-master/bin/mid2mtb+0x4032f8)
0x605a000123d0 is located 1360 bytes inside of 3072-byte region [0x605a00011e80,0x605a00012a80)
freed by thread T0 here:
    #0 0x7fa7ab4b39da (/usr/lib/x86_64-linux-gnu/libasan.so.0+0x119da)
    #1 0x410889 in __gnu_cxx::new_allocator<std::vector<MidiEvent*, std::allocator<MidiEvent*> > >::deallocate(std::vector<MidiEvent*, std::allocator<MidiEvent*> >*, unsigned long) /usr/include/c++/4.8/ext/new_allocator.h:110
    #2 0x40f741 in std::_Vector_base<std::vector<MidiEvent*, std::allocator<MidiEvent*> >, std::allocator<std::vector<MidiEvent*, std::allocator<MidiEvent*> > > >::_M_deallocate(std::vector<MidiEvent*, std::allocator<MidiEvent*> >*, unsigned long) /usr/include/c++/4.8/bits/stl_vector.h:174
    #3 0x40e061 in std::_Vector_base<std::vector<MidiEvent*, std::allocator<MidiEvent*> >, std::allocator<std::vector<MidiEvent*, std::allocator<MidiEvent*> > > >::~_Vector_base() /usr/include/c++/4.8/bits/stl_vector.h:160
    #4 0x40bb5d in std::vector<std::vector<MidiEvent*, std::allocator<MidiEvent*> >, std::allocator<std::vector<MidiEvent*, std::allocator<MidiEvent*> > > >::~vector() /usr/include/c++/4.8/bits/stl_vector.h:416
    #5 0x4111d1 in void std::_Destroy<std::vector<std::vector<MidiEvent*, std::allocator<MidiEvent*> >, std::allocator<std::vector<MidiEvent*, std::allocator<MidiEvent*> > > > >(std::vector<std::vector<MidiEvent*, std::allocator<MidiEvent*> >, std::allocator<std::vector<MidiEvent*, std::allocator<MidiEvent*> > > >*) /usr/include/c++/4.8/bits/stl_construct.h:93
    #6 0x41067d in void std::_Destroy_aux<false>::__destroy<std::vector<std::vector<MidiEvent*, std::allocator<MidiEvent*> >, std::allocator<std::vector<MidiEvent*, std::allocator<MidiEvent*> > > >*>(std::vector<std::vector<MidiEvent*, std::allocator<MidiEvent*> >, std::allocator<std::vector<MidiEvent*, std::allocator<MidiEvent*> > > >*, std::vector<std::vector<MidiEvent*, std::allocator<MidiEvent*> >, std::allocator<std::vector<MidiEvent*, std::allocator<MidiEvent*> > > >*) /usr/include/c++/4.8/bits/stl_construct.h:103
    #7 0x40f3d2 in void std::_Destroy<std::vector<std::vector<MidiEvent*, std::allocator<MidiEvent*> >, std::allocator<std::vector<MidiEvent*, std::allocator<MidiEvent*> > > >*>(std::vector<std::vector<MidiEvent*, std::allocator<MidiEvent*> >, std::allocator<std::vector<MidiEvent*, std::allocator<MidiEvent*> > > >*, std::vector<std::vector<MidiEvent*, std::allocator<MidiEvent*> >, std::allocator<std::vector<MidiEvent*, std::allocator<MidiEvent*> > > >*) /usr/include/c++/4.8/bits/stl_construct.h:126
    #8 0x40ced4 in void std::_Destroy<std::vector<std::vector<MidiEvent*, std::allocator<MidiEvent*> >, std::allocator<std::vector<MidiEvent*, std::allocator<MidiEvent*> > > >*, std::vector<std::vector<MidiEvent*, std::allocator<MidiEvent*> >, std::allocator<std::vector<MidiEvent*, std::allocator<MidiEvent*> > > > >(std::vector<std::vector<MidiEvent*, std::allocator<MidiEvent*> >, std::allocator<std::vector<MidiEvent*, std::allocator<MidiEvent*> > > >*, std::vector<std::vector<MidiEvent*, std::allocator<MidiEvent*> >, std::allocator<std::vector<MidiEvent*, std::allocator<MidiEvent*> > > >*, std::allocator<std::vector<std::vector<MidiEvent*, std::allocator<MidiEvent*> >, std::allocator<std::vector<MidiEvent*, std::allocator<MidiEvent*> > > > >&) /usr/include/c++/4.8/bits/stl_construct.h:151
    #9 0x40b657 in std::vector<std::vector<std::vector<MidiEvent*, std::allocator<MidiEvent*> >, std::allocator<std::vector<MidiEvent*, std::allocator<MidiEvent*> > > >, std::allocator<std::vector<std::vector<MidiEvent*, std::allocator<MidiEvent*> >, std::allocator<std::vector<MidiEvent*, std::allocator<MidiEvent*> > > > > >::~vector() /usr/include/c++/4.8/bits/stl_vector.h:415
    #10 0x40ab52 in MidiEventList::linkNotePairs() /home/a/Downloads/midifile-master/src-library/MidiEventList.cpp:348
    #11 0x41e632 in MidiFile::linkNotePairs() /home/a/Downloads/midifile-master/src-library/MidiFile.cpp:2232
    #12 0x403545 in convertMidiFile(MidiFile&, std::vector<std::vector<double, std::allocator<double> >, std::allocator<std::vector<double, std::allocator<double> > > >&) /home/a/Downloads/midifile-master/src-programs/mid2mtb.cpp:65
    #13 0x403476 in main /home/a/Downloads/midifile-master/src-programs/mid2mtb.cpp:49
    #14 0x7fa7aabe4ec4 (/lib/x86_64-linux-gnu/libc.so.6+0x21ec4)
previously allocated by thread T0 here:
    #0 0x7fa7ab4b381a (/usr/lib/x86_64-linux-gnu/libasan.so.0+0x1181a)
    #1 0x410811 in __gnu_cxx::new_allocator<std::vector<MidiEvent*, std::allocator<MidiEvent*> > >::allocate(unsigned long, void const*) /usr/include/c++/4.8/ext/new_allocator.h:104
    #2 0x40f6b8 in std::_Vector_base<std::vector<MidiEvent*, std::allocator<MidiEvent*> >, std::allocator<std::vector<MidiEvent*, std::allocator<MidiEvent*> > > >::_M_allocate(unsigned long) /usr/include/c++/4.8/bits/stl_vector.h:168
    #3 0x40d596 in std::vector<std::vector<MidiEvent*, std::allocator<MidiEvent*> >, std::allocator<std::vector<MidiEvent*, std::allocator<MidiEvent*> > > >::_M_default_append(unsigned long) /usr/include/c++/4.8/bits/vector.tcc:549
    #4 0x40b82e in std::vector<std::vector<MidiEvent*, std::allocator<MidiEvent*> >, std::allocator<std::vector<MidiEvent*, std::allocator<MidiEvent*> > > >::resize(unsigned long) /usr/include/c++/4.8/bits/stl_vector.h:667
    #5 0x40945a in MidiEventList::linkNotePairs() /home/a/Downloads/midifile-master/src-library/MidiEventList.cpp:228
    #6 0x41e632 in MidiFile::linkNotePairs() /home/a/Downloads/midifile-master/src-library/MidiFile.cpp:2232
    #7 0x403545 in convertMidiFile(MidiFile&, std::vector<std::vector<double, std::allocator<double> >, std::allocator<std::vector<double, std::allocator<double> > > >&) /home/a/Downloads/midifile-master/src-programs/mid2mtb.cpp:65
    #8 0x403476 in main /home/a/Downloads/midifile-master/src-programs/mid2mtb.cpp:49
    #9 0x7fa7aabe4ec4 (/lib/x86_64-linux-gnu/libc.so.6+0x21ec4)
SUMMARY: AddressSanitizer: heap-use-after-free /usr/include/c++/4.8/bits/stl_vector.h:903 std::vector<MidiEvent*, std::allocator<MidiEvent*> >::push_back(MidiEvent* const&)
Shadow bytes around the buggy address:
  0x0c0bbfffa420: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x0c0bbfffa430: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x0c0bbfffa440: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x0c0bbfffa450: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x0c0bbfffa460: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
=>0x0c0bbfffa470: fd fd fd fd fd fd fd fd fd fd[fd]fd fd fd fd fd
  0x0c0bbfffa480: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x0c0bbfffa490: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x0c0bbfffa4a0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x0c0bbfffa4b0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x0c0bbfffa4c0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:     fa
  Heap righ redzone:     fb
  Freed Heap region:     fd
  Stack left redzone:    f1
  Stack mid redzone:     f2
  Stack right redzone:   f3
  Stack partial redzone: f4
  Stack after return:    f5
  Stack use after scope: f8
  Global redzone:        f9
  Global init order:     f6
  Poisoned by user:      f7
  ASan internal:         fe
==7038== ABORTING

POC:midifile_invalid_memory_read_1.mid
This vulnerability has been assigned as CVE-2017-12656.
the MidiEventList::reserve function in src-library/MidiEventList.cpp:157 in midifile through 2017-03-16 can cause a denial of service(memory allocation error and application crash) via a crafted mid file.

./mid2mtb midifile_memory_allcation_error_1.mid

----debug info:----
terminate called after throwing an instance of 'std::bad_alloc'
  what():  std::bad_alloc

Program received signal SIGABRT, Aborted.
0x00007ffff7531cc9 in __GI_raise (sig=sig@entry=6)
    at ../nptl/sysdeps/unix/sysv/linux/raise.c:56
56	../nptl/sysdeps/unix/sysv/linux/raise.c: No such file or directory.
(gdb) bt
#0  0x00007ffff7531cc9 in __GI_raise (sig=sig@entry=6)
    at ../nptl/sysdeps/unix/sysv/linux/raise.c:56
#1  0x00007ffff75350d8 in __GI_abort () at abort.c:89
#2  0x00007ffff7b36535 in __gnu_cxx::__verbose_terminate_handler() ()
   from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#3  0x00007ffff7b346d6 in ?? () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#4  0x00007ffff7b34703 in std::terminate() ()
   from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#5  0x00007ffff7b34922 in __cxa_throw ()
   from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#6  0x00007ffff7b34e0d in operator new(unsigned long) ()
   from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#7  0x000000000040b1a2 in __gnu_cxx::new_allocator<MidiEvent*>::allocate (
    this=0x641e50, __n=959807488)
    at /usr/include/c++/4.8/ext/new_allocator.h:104
#8  0x000000000040a2cd in std::_Vector_base<MidiEvent*, std::allocator<MidiEvent*> >::_M_allocate (this=0x641e50, __n=959807488)
    at /usr/include/c++/4.8/bits/stl_vector.h:168
#9  0x0000000000408868 in std::vector<MidiEvent*, std::allocator<MidiEvent*> >::_M_allocate_and_copy<std::move_iterator<MidiEvent**> > (this=0x641e50, 
    __n=959807488, __first=..., __last=...)
    at /usr/include/c++/4.8/bits/stl_vector.h:1138
#10 0x0000000000407c39 in std::vector<MidiEvent*, std::allocator<MidiEvent*> >::---Type <return> to continue, or q <return> to quit---
reserve (this=0x641e50, __n=959807488)
    at /usr/include/c++/4.8/bits/vector.tcc:75
#11 0x0000000000406cb8 in MidiEventList::reserve (this=0x641e50, 
    rsize=959807488) at src-library/MidiEventList.cpp:157
#12 0x000000000040f28c in MidiFile::read (this=0x7fffffffde60, input=...)
    at src-library/MidiFile.cpp:471
#13 0x000000000040e1d4 in MidiFile::read (this=0x7fffffffde60, 
    filename="/home/a/Documents/file.mid")
    at src-library/MidiFile.cpp:230
#14 0x000000000040d95b in MidiFile::MidiFile (this=0x7fffffffde60, 
    filename="/home/a/Documents/file.mid")
    at src-library/MidiFile.cpp:90
#15 0x0000000000402eb9 in main (argc=2, argv=0x7fffffffdfc8)
    at src-programs/mid2mtb.cpp:48
(gdb) disassemble 
Dump of assembler code for function __GI_raise:
   0x00007ffff7531c90 <+0>:	mov    %fs:0x2d4,%eax
   0x00007ffff7531c98 <+8>:	mov    %eax,%ecx
   0x00007ffff7531c9a <+10>:	mov    %fs:0x2d0,%esi
   0x00007ffff7531ca2 <+18>:	test   %esi,%esi
   0x00007ffff7531ca4 <+20>:	jne    0x7ffff7531cd8 <__GI_raise+72>
   0x00007ffff7531ca6 <+22>:	mov    $0xba,%eax
   0x00007ffff7531cab <+27>:	syscall 
   0x00007ffff7531cad <+29>:	mov    %eax,%ecx
   0x00007ffff7531caf <+31>:	mov    %eax,%fs:0x2d0
   0x00007ffff7531cb7 <+39>:	mov    %eax,%esi
   0x00007ffff7531cb9 <+41>:	movslq %edi,%rdx
   0x00007ffff7531cbc <+44>:	movslq %esi,%rsi
   0x00007ffff7531cbf <+47>:	movslq %ecx,%rdi
   0x00007ffff7531cc2 <+50>:	mov    $0xea,%eax
   0x00007ffff7531cc7 <+55>:	syscall 
=> 0x00007ffff7531cc9 <+57>:	cmp    $0xfffffffffffff000,%rax
   0x00007ffff7531ccf <+63>:	ja     0x7ffff7531cea <__GI_raise+90>
   0x00007ffff7531cd1 <+65>:	repz retq 
   0x00007ffff7531cd3 <+67>:	nopl   0x0(%rax,%rax,1)
   0x00007ffff7531cd8 <+72>:	test   %eax,%eax
   0x00007ffff7531cda <+74>:	jg     0x7ffff7531cb9 <__GI_raise+41>
   0x00007ffff7531cdc <+76>:	mov    %eax,%ecx
---Type <return> to continue, or q <return> to quit---q
Quit
(gdb) i r
rax            0x0	0
rbx            0x7ffff78ba868	140737346513000
rcx            0x7ffff7531cc9	140737342807241
rdx            0x6	6
rsi            0xc106	49414
rdi            0xc106	49414
rbp            0x7ffff7b948a2	0x7ffff7b948a2
rsp            0x7fffffffd6f8	0x7fffffffd6f8
r8             0xa	10
r9             0x7ffff7fda780	140737353983872
r10            0x8	8
r11            0x246	582
r12            0x7ffff0000950	140737219922256
r13            0x7fffffffdfc0	140737488347072
r14            0x0	0
r15            0x0	0
rip            0x7ffff7531cc9	0x7ffff7531cc9 <__GI_raise+57>
eflags         0x246	[ PF ZF IF ]
cs             0x33	51
ss             0x2b	43
ds             0x0	0
es             0x0	0
fs             0x0	0
---Type <return> to continue, or q <return> to quit---
gs             0x0	0
(gdb) 

==7041== ERROR: AddressSanitizer failed to allocate 0x1c9ac2000 (7678468096) bytes of LargeMmapAllocator: Cannot allocate memory
==7041== Process memory map follows:
	0x000000400000-0x000000461000	/home/a/Downloads/midifile-master/bin/mid2mtb
	0x000000660000-0x000000661000	/home/a/Downloads/midifile-master/bin/mid2mtb
	0x000000661000-0x000000665000	/home/a/Downloads/midifile-master/bin/mid2mtb
	0x00007fff7000-0x00008fff7000	
	0x00008fff7000-0x02008fff7000	
	0x02008fff7000-0x10007fff8000	
	0x600000000000-0x600400000000	
	0x600400000000-0x600400010000	
	0x600400010000-0x600600000000	
	0x600600000000-0x600600010000	
	0x600600010000-0x600800000000	
	0x600800000000-0x600800010000	
	0x600800010000-0x600c00000000	
	0x600c00000000-0x600c00010000	
	0x600c00010000-0x600e00000000	
	0x600e00000000-0x600e00010000	
	0x600e00010000-0x603600000000	
	0x603600000000-0x603600020000	
	0x603600020000-0x603e00000000	
	0x603e00000000-0x603e00020000	
	0x603e00020000-0x605200000000	
	0x605200000000-0x605200020000	
	0x605200020000-0x607200000000	
	0x607200000000-0x607200030000	
	0x607200030000-0x60a600000000	
	0x60a600000000-0x60a600090000	
	0x60a600090000-0x610000000000	
	0x610000000000-0x610000005000	
	0x7f3d8aee9000-0x7f3d8b135000	
	0x7f3d8b135000-0x7f3d8b23a000	/lib/x86_64-linux-gnu/libm-2.19.so
	0x7f3d8b23a000-0x7f3d8b439000	/lib/x86_64-linux-gnu/libm-2.19.so
	0x7f3d8b439000-0x7f3d8b43a000	/lib/x86_64-linux-gnu/libm-2.19.so
	0x7f3d8b43a000-0x7f3d8b43b000	/lib/x86_64-linux-gnu/libm-2.19.so
	0x7f3d8b43b000-0x7f3d8b43e000	/lib/x86_64-linux-gnu/libdl-2.19.so
	0x7f3d8b43e000-0x7f3d8b63d000	/lib/x86_64-linux-gnu/libdl-2.19.so
	0x7f3d8b63d000-0x7f3d8b63e000	/lib/x86_64-linux-gnu/libdl-2.19.so
	0x7f3d8b63e000-0x7f3d8b63f000	/lib/x86_64-linux-gnu/libdl-2.19.so
	0x7f3d8b63f000-0x7f3d8b658000	/lib/x86_64-linux-gnu/libpthread-2.19.so
	0x7f3d8b658000-0x7f3d8b857000	/lib/x86_64-linux-gnu/libpthread-2.19.so
	0x7f3d8b857000-0x7f3d8b858000	/lib/x86_64-linux-gnu/libpthread-2.19.so
	0x7f3d8b858000-0x7f3d8b859000	/lib/x86_64-linux-gnu/libpthread-2.19.so
	0x7f3d8b859000-0x7f3d8b85d000	
	0x7f3d8b85d000-0x7f3d8ba18000	/lib/x86_64-linux-gnu/libc-2.19.so
	0x7f3d8ba18000-0x7f3d8bc17000	/lib/x86_64-linux-gnu/libc-2.19.so
	0x7f3d8bc17000-0x7f3d8bc1b000	/lib/x86_64-linux-gnu/libc-2.19.so
	0x7f3d8bc1b000-0x7f3d8bc1d000	/lib/x86_64-linux-gnu/libc-2.19.so
	0x7f3d8bc1d000-0x7f3d8bc22000	
	0x7f3d8bc22000-0x7f3d8bc38000	/lib/x86_64-linux-gnu/libgcc_s.so.1
	0x7f3d8bc38000-0x7f3d8be37000	/lib/x86_64-linux-gnu/libgcc_s.so.1
	0x7f3d8be37000-0x7f3d8be38000	/lib/x86_64-linux-gnu/libgcc_s.so.1
	0x7f3d8be38000-0x7f3d8bf1e000	/usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.19
	0x7f3d8bf1e000-0x7f3d8c11d000	/usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.19
	0x7f3d8c11d000-0x7f3d8c125000	/usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.19
	0x7f3d8c125000-0x7f3d8c127000	/usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.19
	0x7f3d8c127000-0x7f3d8c13c000	
	0x7f3d8c13c000-0x7f3d8c164000	/usr/lib/x86_64-linux-gnu/libasan.so.0.0.0
	0x7f3d8c164000-0x7f3d8c364000	/usr/lib/x86_64-linux-gnu/libasan.so.0.0.0
	0x7f3d8c364000-0x7f3d8c365000	/usr/lib/x86_64-linux-gnu/libasan.so.0.0.0
	0x7f3d8c365000-0x7f3d8c366000	/usr/lib/x86_64-linux-gnu/libasan.so.0.0.0
	0x7f3d8c366000-0x7f3d8f0cb000	
	0x7f3d8f0cb000-0x7f3d8f0ee000	/lib/x86_64-linux-gnu/ld-2.19.so
	0x7f3d8f2bc000-0x7f3d8f2d3000	
	0x7f3d8f2d8000-0x7f3d8f2e1000	
	0x7f3d8f2e3000-0x7f3d8f2ed000	
	0x7f3d8f2ed000-0x7f3d8f2ee000	/lib/x86_64-linux-gnu/ld-2.19.so
	0x7f3d8f2ee000-0x7f3d8f2ef000	/lib/x86_64-linux-gnu/ld-2.19.so
	0x7f3d8f2ef000-0x7f3d8f2f0000	
	0x7ffd996dc000-0x7ffd996fd000	[stack]
	0x7ffd99712000-0x7ffd99714000	[vvar]
	0x7ffd99714000-0x7ffd99716000	[vdso]
	0xffffffffff600000-0xffffffffff601000	[vsyscall]
==7041== End of process memory map.
==7041== AddressSanitizer CHECK failed: ../../../../src/libsanitizer/sanitizer_common/sanitizer_posix.cc:70 "(("unable to mmap" && 0)) != (0)" (0x0, 0x0)
    #0 0x7f3d8c14e31d (/usr/lib/x86_64-linux-gnu/libasan.so.0+0x1231d)
    #1 0x7f3d8c155133 (/usr/lib/x86_64-linux-gnu/libasan.so.0+0x19133)
    #2 0x7f3d8c1576d3 (/usr/lib/x86_64-linux-gnu/libasan.so.0+0x1b6d3)
    #3 0x7f3d8c145078 (/usr/lib/x86_64-linux-gnu/libasan.so.0+0x9078)
    #4 0x7f3d8c14d849 (/usr/lib/x86_64-linux-gnu/libasan.so.0+0x11849)
    #5 0x41039a in __gnu_cxx::new_allocator<MidiEvent*>::allocate(unsigned long, void const*) /usr/include/c++/4.8/ext/new_allocator.h:104
    #6 0x40f00e in std::_Vector_base<MidiEvent*, std::allocator<MidiEvent*> >::_M_allocate(unsigned long) /usr/include/c++/4.8/bits/stl_vector.h:168
    #7 0x40c1fd in MidiEvent** std::vector<MidiEvent*, std::allocator<MidiEvent*> >::_M_allocate_and_copy<std::move_iterator<MidiEvent**> >(unsigned long, std::move_iterator<MidiEvent**>, std::move_iterator<MidiEvent**>) /usr/include/c++/4.8/bits/stl_vector.h:1138
    #8 0x40b003 in std::vector<MidiEvent*, std::allocator<MidiEvent*> >::reserve(unsigned long) /usr/include/c++/4.8/bits/vector.tcc:75
    #9 0x40921f in MidiEventList::reserve(int) /home/a/Downloads/midifile-master/src-library/MidiEventList.cpp:157
    #10 0x41698d in MidiFile::read(std::istream&) /home/a/Downloads/midifile-master/src-library/MidiFile.cpp:471
    #11 0x41513c in MidiFile::read(std::string const&) /home/a/Downloads/midifile-master/src-library/MidiFile.cpp:230
    #12 0x413d21 in MidiFile::MidiFile(std::string const&) /home/a/Downloads/midifile-master/src-library/MidiFile.cpp:90
    #13 0x403462 in main /home/a/Downloads/midifile-master/src-programs/mid2mtb.cpp:48
    #14 0x7f3d8b87eec4 (/lib/x86_64-linux-gnu/libc.so.6+0x21ec4)
    #15 0x4032f8 in _start (/home/a/Downloads/midifile-master/bin/mid2mtb+0x4032f8)

POC:midifile_memory_allcation_error_1.mid
This vulnerability has been assigned as CVE-2017-12661.
the MidiEventList::linkNotePairs function in src-library/MidiEventList.cpp in midifile through 2017-03-16 can cause a denial of service(invalid free and application crash) via a crafted mid file.

./mid2mtb midifile_invalid_free.mid

----debug info:----
Expecting 'M' at first byte in track, but found nothing.
*** Error in `/home/a/Downloads/midifile-master/bin/mid2mtb': free(): invalid pointer: 0x00000000006abf08 ***

Program received signal SIGABRT, Aborted.
0x00007ffff7531cc9 in __GI_raise (sig=sig@entry=6)
    at ../nptl/sysdeps/unix/sysv/linux/raise.c:56
56	../nptl/sysdeps/unix/sysv/linux/raise.c: No such file or directory.
(gdb) bt
#0  0x00007ffff7531cc9 in __GI_raise (sig=sig@entry=6)
    at ../nptl/sysdeps/unix/sysv/linux/raise.c:56
#1  0x00007ffff75350d8 in __GI_abort () at abort.c:89
#2  0x00007ffff756e394 in __libc_message (do_abort=do_abort@entry=1, 
    fmt=fmt@entry=0x7ffff767cb28 "*** Error in `%s': %s: 0x%s ***\n")
    at ../sysdeps/posix/libc_fatal.c:175
#3  0x00007ffff757a66e in malloc_printerr (ptr=<optimized out>, 
    str=0x7ffff7678c19 "free(): invalid pointer", action=1) at malloc.c:4996
#4  _int_free (av=<optimized out>, p=<optimized out>, have_lock=0)
    at malloc.c:3840
#5  0x000000000040a328 in __gnu_cxx::new_allocator<MidiEvent*>::deallocate (
    this=0x6456f0, __p=0x6abf08)
    at /usr/include/c++/4.8/ext/new_allocator.h:110
#6  0x0000000000408906 in std::_Vector_base<MidiEvent*, std::allocator<MidiEvent*> >::_M_deallocate (this=0x6456f0, __p=0x6abf08, __n=18446744073708677151)
    at /usr/include/c++/4.8/bits/stl_vector.h:174
#7  0x0000000000408787 in std::_Vector_base<MidiEvent*, std::allocator<MidiEvent*> >::~_Vector_base (this=0x6456f0, __in_chrg=<optimized out>)
    at /usr/include/c++/4.8/bits/stl_vector.h:160
#8  0x0000000000407b7b in std::vector<MidiEvent*, std::allocator<MidiEvent*> >::~vector (this=0x6456f0, __in_chrg=<optimized out>)
    at /usr/include/c++/4.8/bits/stl_vector.h:416
#9  0x000000000040c038 in std::_Destroy<std::vector<MidiEvent*, std::allocator<M---Type <return> to continue, or q <return> to quit---
idiEvent*> > > (__pointer=0x6456f0)
    at /usr/include/c++/4.8/bits/stl_construct.h:93
#10 0x000000000040b73e in std::_Destroy_aux<false>::__destroy<std::vector<MidiEvent*, std::allocator<MidiEvent*> >*> (__first=0x6456f0, __last=0x6459c0)
    at /usr/include/c++/4.8/bits/stl_construct.h:103
#11 0x000000000040ac1b in std::_Destroy<std::vector<MidiEvent*, std::allocator<MidiEvent*> >*> (__first=0x644dc0, __last=0x6459c0)
    at /usr/include/c++/4.8/bits/stl_construct.h:126
#12 0x0000000000409a3b in std::_Destroy<std::vector<MidiEvent*, std::allocator<MidiEvent*> >*, std::vector<MidiEvent*, std::allocator<MidiEvent*> > > (
    __first=0x644dc0, __last=0x6459c0)
    at /usr/include/c++/4.8/bits/stl_construct.h:151
#13 0x0000000000408363 in std::vector<std::vector<MidiEvent*, std::allocator<MidiEvent*> >, std::allocator<std::vector<MidiEvent*, std::allocator<MidiEvent*> > > >::~vector (this=0x644038, __in_chrg=<optimized out>)
    at /usr/include/c++/4.8/bits/stl_vector.h:415
#14 0x000000000040bd3c in std::_Destroy<std::vector<std::vector<MidiEvent*, std::allocator<MidiEvent*> >, std::allocator<std::vector<MidiEvent*, std::allocator<MidiEvent*> > > > > (__pointer=0x644038)
    at /usr/include/c++/4.8/bits/stl_construct.h:93
#15 0x000000000040b3ae in std::_Destroy_aux<false>::__destroy<std::vector<std::vector<MidiEvent*, std::allocator<MidiEvent*> >, std::allocator<std::vector<MidiEvent*, std::allocator<MidiEvent*> > > >*> (__first=0x644038, __last=0x6441a0)
---Type <return> to continue, or q <return> to quit---
    at /usr/include/c++/4.8/bits/stl_construct.h:103
#16 0x000000000040a603 in std::_Destroy<std::vector<std::vector<MidiEvent*, std::allocator<MidiEvent*> >, std::allocator<std::vector<MidiEvent*, std::allocator<MidiEvent*> > > >*> (__first=0x644020, __last=0x6441a0)
    at /usr/include/c++/4.8/bits/stl_construct.h:126
#17 0x0000000000409043 in std::_Destroy<std::vector<std::vector<MidiEvent*, std::allocator<MidiEvent*> >, std::allocator<std::vector<MidiEvent*, std::allocator<MidiEvent*> > > >*, std::vector<std::vector<MidiEvent*, std::allocator<MidiEvent*> >, std::allocator<std::vector<MidiEvent*, std::allocator<MidiEvent*> > > > >
    (__first=0x644020, __last=0x6441a0)
    at /usr/include/c++/4.8/bits/stl_construct.h:151
#18 0x0000000000407fe9 in std::vector<std::vector<std::vector<MidiEvent*, std::allocator<MidiEvent*> >, std::allocator<std::vector<MidiEvent*, std::allocator<MidiEvent*> > > >, std::allocator<std::vector<std::vector<MidiEvent*, std::allocator<MidiEvent*> >, std::allocator<std::vector<MidiEvent*, std::allocator<MidiEvent*> > > > > >::~vector (this=0x7fffffffdcd0, __in_chrg=<optimized out>)
    at /usr/include/c++/4.8/bits/stl_vector.h:415
#19 0x0000000000407926 in MidiEventList::linkNotePairs (this=0x641e30)
    at src-library/MidiEventList.cpp:348
#20 0x00000000004135b2 in MidiFile::linkNotePairs (this=0x7fffffffde60)
    at src-library/MidiFile.cpp:2232
#21 0x0000000000402f4c in convertMidiFile (midifile=..., 
    matlab=std::vector of length 0, capacity 100000)
---Type <return> to continue, or q <return> to quit---
    at src-programs/mid2mtb.cpp:65
#22 0x0000000000402eca in main (argc=2, argv=0x7fffffffdfc8)
    at src-programs/mid2mtb.cpp:49
(gdb) disassemble 
Dump of assembler code for function __GI_raise:
   0x00007ffff7531c90 <+0>:	mov    %fs:0x2d4,%eax
   0x00007ffff7531c98 <+8>:	mov    %eax,%ecx
   0x00007ffff7531c9a <+10>:	mov    %fs:0x2d0,%esi
   0x00007ffff7531ca2 <+18>:	test   %esi,%esi
   0x00007ffff7531ca4 <+20>:	jne    0x7ffff7531cd8 <__GI_raise+72>
   0x00007ffff7531ca6 <+22>:	mov    $0xba,%eax
   0x00007ffff7531cab <+27>:	syscall 
   0x00007ffff7531cad <+29>:	mov    %eax,%ecx
   0x00007ffff7531caf <+31>:	mov    %eax,%fs:0x2d0
   0x00007ffff7531cb7 <+39>:	mov    %eax,%esi
   0x00007ffff7531cb9 <+41>:	movslq %edi,%rdx
   0x00007ffff7531cbc <+44>:	movslq %esi,%rsi
   0x00007ffff7531cbf <+47>:	movslq %ecx,%rdi
   0x00007ffff7531cc2 <+50>:	mov    $0xea,%eax
   0x00007ffff7531cc7 <+55>:	syscall 
=> 0x00007ffff7531cc9 <+57>:	cmp    $0xfffffffffffff000,%rax
   0x00007ffff7531ccf <+63>:	ja     0x7ffff7531cea <__GI_raise+90>
   0x00007ffff7531cd1 <+65>:	repz retq 
   0x00007ffff7531cd3 <+67>:	nopl   0x0(%rax,%rax,1)
   0x00007ffff7531cd8 <+72>:	test   %eax,%eax
   0x00007ffff7531cda <+74>:	jg     0x7ffff7531cb9 <__GI_raise+41>
   0x00007ffff7531cdc <+76>:	mov    %eax,%ecx
---Type <return> to continue, or q <return> to quit---q
Quit
(gdb) i r
rax            0x0	0
rbx            0x6e	110
rcx            0x7ffff7531cc9	140737342807241
rdx            0x6	6
rsi            0xc3c9	50121
rdi            0xc3c9	50121
rbp            0x7fffffffd9d0	0x7fffffffd9d0
rsp            0x7fffffffd638	0x7fffffffd638
r8             0x3830666261363030	4048848637729845296
r9             0x69666964696d2f73	7594873701593329523
r10            0x8	8
r11            0x246	582
r12            0x7fffffffd7e0	140737488345056
r13            0x7	7
r14            0x6e	110
r15            0x7	7
rip            0x7ffff7531cc9	0x7ffff7531cc9 <__GI_raise+57>
eflags         0x246	[ PF ZF IF ]
cs             0x33	51
ss             0x2b	43
ds             0x0	0
es             0x0	0
fs             0x0	0
---Type <return> to continue, or q <return> to quit---
gs             0x0	0
(gdb) 

=================================================================
==7044== ERROR: AddressSanitizer: heap-use-after-free on address 0x605a000126b8 at pc 0x40b51d bp 0x7ffeac076a70 sp 0x7ffeac076a68
READ of size 8 at 0x605a000126b8 thread T0
    #0 0x40b51c in std::vector<MidiEvent*, std::allocator<MidiEvent*> >::push_back(MidiEvent* const&) /usr/include/c++/4.8/bits/stl_vector.h:903
    #1 0x40a391 in MidiEventList::linkNotePairs() /home/a/Downloads/midifile-master/src-library/MidiEventList.cpp:309
    #2 0x41e632 in MidiFile::linkNotePairs() /home/a/Downloads/midifile-master/src-library/MidiFile.cpp:2232
    #3 0x403545 in convertMidiFile(MidiFile&, std::vector<std::vector<double, std::allocator<double> >, std::allocator<std::vector<double, std::allocator<double> > > >&) /home/a/Downloads/midifile-master/src-programs/mid2mtb.cpp:65
    #4 0x403476 in main /home/a/Downloads/midifile-master/src-programs/mid2mtb.cpp:49
    #5 0x7f67d7af2ec4 (/lib/x86_64-linux-gnu/libc.so.6+0x21ec4)
    #6 0x4032f8 in _start (/home/a/Downloads/midifile-master/bin/mid2mtb+0x4032f8)
0x605a000126b8 is located 2104 bytes inside of 3072-byte region [0x605a00011e80,0x605a00012a80)
freed by thread T0 here:
    #0 0x7f67d83c19da (/usr/lib/x86_64-linux-gnu/libasan.so.0+0x119da)
    #1 0x410889 in __gnu_cxx::new_allocator<std::vector<MidiEvent*, std::allocator<MidiEvent*> > >::deallocate(std::vector<MidiEvent*, std::allocator<MidiEvent*> >*, unsigned long) /usr/include/c++/4.8/ext/new_allocator.h:110
    #2 0x40f741 in std::_Vector_base<std::vector<MidiEvent*, std::allocator<MidiEvent*> >, std::allocator<std::vector<MidiEvent*, std::allocator<MidiEvent*> > > >::_M_deallocate(std::vector<MidiEvent*, std::allocator<MidiEvent*> >*, unsigned long) /usr/include/c++/4.8/bits/stl_vector.h:174
    #3 0x40e061 in std::_Vector_base<std::vector<MidiEvent*, std::allocator<MidiEvent*> >, std::allocator<std::vector<MidiEvent*, std::allocator<MidiEvent*> > > >::~_Vector_base() /usr/include/c++/4.8/bits/stl_vector.h:160
    #4 0x40bb5d in std::vector<std::vector<MidiEvent*, std::allocator<MidiEvent*> >, std::allocator<std::vector<MidiEvent*, std::allocator<MidiEvent*> > > >::~vector() /usr/include/c++/4.8/bits/stl_vector.h:416
    #5 0x4111d1 in void std::_Destroy<std::vector<std::vector<MidiEvent*, std::allocator<MidiEvent*> >, std::allocator<std::vector<MidiEvent*, std::allocator<MidiEvent*> > > > >(std::vector<std::vector<MidiEvent*, std::allocator<MidiEvent*> >, std::allocator<std::vector<MidiEvent*, std::allocator<MidiEvent*> > > >*) /usr/include/c++/4.8/bits/stl_construct.h:93
    #6 0x41067d in void std::_Destroy_aux<false>::__destroy<std::vector<std::vector<MidiEvent*, std::allocator<MidiEvent*> >, std::allocator<std::vector<MidiEvent*, std::allocator<MidiEvent*> > > >*>(std::vector<std::vector<MidiEvent*, std::allocator<MidiEvent*> >, std::allocator<std::vector<MidiEvent*, std::allocator<MidiEvent*> > > >*, std::vector<std::vector<MidiEvent*, std::allocator<MidiEvent*> >, std::allocator<std::vector<MidiEvent*, std::allocator<MidiEvent*> > > >*) /usr/include/c++/4.8/bits/stl_construct.h:103
    #7 0x40f3d2 in void std::_Destroy<std::vector<std::vector<MidiEvent*, std::allocator<MidiEvent*> >, std::allocator<std::vector<MidiEvent*, std::allocator<MidiEvent*> > > >*>(std::vector<std::vector<MidiEvent*, std::allocator<MidiEvent*> >, std::allocator<std::vector<MidiEvent*, std::allocator<MidiEvent*> > > >*, std::vector<std::vector<MidiEvent*, std::allocator<MidiEvent*> >, std::allocator<std::vector<MidiEvent*, std::allocator<MidiEvent*> > > >*) /usr/include/c++/4.8/bits/stl_construct.h:126
    #8 0x40ced4 in void std::_Destroy<std::vector<std::vector<MidiEvent*, std::allocator<MidiEvent*> >, std::allocator<std::vector<MidiEvent*, std::allocator<MidiEvent*> > > >*, std::vector<std::vector<MidiEvent*, std::allocator<MidiEvent*> >, std::allocator<std::vector<MidiEvent*, std::allocator<MidiEvent*> > > > >(std::vector<std::vector<MidiEvent*, std::allocator<MidiEvent*> >, std::allocator<std::vector<MidiEvent*, std::allocator<MidiEvent*> > > >*, std::vector<std::vector<MidiEvent*, std::allocator<MidiEvent*> >, std::allocator<std::vector<MidiEvent*, std::allocator<MidiEvent*> > > >*, std::allocator<std::vector<std::vector<MidiEvent*, std::allocator<MidiEvent*> >, std::allocator<std::vector<MidiEvent*, std::allocator<MidiEvent*> > > > >&) /usr/include/c++/4.8/bits/stl_construct.h:151
    #9 0x40b657 in std::vector<std::vector<std::vector<MidiEvent*, std::allocator<MidiEvent*> >, std::allocator<std::vector<MidiEvent*, std::allocator<MidiEvent*> > > >, std::allocator<std::vector<std::vector<MidiEvent*, std::allocator<MidiEvent*> >, std::allocator<std::vector<MidiEvent*, std::allocator<MidiEvent*> > > > > >::~vector() /usr/include/c++/4.8/bits/stl_vector.h:415
    #10 0x40ab52 in MidiEventList::linkNotePairs() /home/a/Downloads/midifile-master/src-library/MidiEventList.cpp:348
    #11 0x41e632 in MidiFile::linkNotePairs() /home/a/Downloads/midifile-master/src-library/MidiFile.cpp:2232
    #12 0x403545 in convertMidiFile(MidiFile&, std::vector<std::vector<double, std::allocator<double> >, std::allocator<std::vector<double, std::allocator<double> > > >&) /home/a/Downloads/midifile-master/src-programs/mid2mtb.cpp:65
    #13 0x403476 in main /home/a/Downloads/midifile-master/src-programs/mid2mtb.cpp:49
    #14 0x7f67d7af2ec4 (/lib/x86_64-linux-gnu/libc.so.6+0x21ec4)
previously allocated by thread T0 here:
    #0 0x7f67d83c181a (/usr/lib/x86_64-linux-gnu/libasan.so.0+0x1181a)
    #1 0x410811 in __gnu_cxx::new_allocator<std::vector<MidiEvent*, std::allocator<MidiEvent*> > >::allocate(unsigned long, void const*) /usr/include/c++/4.8/ext/new_allocator.h:104
    #2 0x40f6b8 in std::_Vector_base<std::vector<MidiEvent*, std::allocator<MidiEvent*> >, std::allocator<std::vector<MidiEvent*, std::allocator<MidiEvent*> > > >::_M_allocate(unsigned long) /usr/include/c++/4.8/bits/stl_vector.h:168
    #3 0x40d596 in std::vector<std::vector<MidiEvent*, std::allocator<MidiEvent*> >, std::allocator<std::vector<MidiEvent*, std::allocator<MidiEvent*> > > >::_M_default_append(unsigned long) /usr/include/c++/4.8/bits/vector.tcc:549
    #4 0x40b82e in std::vector<std::vector<MidiEvent*, std::allocator<MidiEvent*> >, std::allocator<std::vector<MidiEvent*, std::allocator<MidiEvent*> > > >::resize(unsigned long) /usr/include/c++/4.8/bits/stl_vector.h:667
    #5 0x40945a in MidiEventList::linkNotePairs() /home/a/Downloads/midifile-master/src-library/MidiEventList.cpp:228
    #6 0x41e632 in MidiFile::linkNotePairs() /home/a/Downloads/midifile-master/src-library/MidiFile.cpp:2232
    #7 0x403545 in convertMidiFile(MidiFile&, std::vector<std::vector<double, std::allocator<double> >, std::allocator<std::vector<double, std::allocator<double> > > >&) /home/a/Downloads/midifile-master/src-programs/mid2mtb.cpp:65
    #8 0x403476 in main /home/a/Downloads/midifile-master/src-programs/mid2mtb.cpp:49
    #9 0x7f67d7af2ec4 (/lib/x86_64-linux-gnu/libc.so.6+0x21ec4)
SUMMARY: AddressSanitizer: heap-use-after-free /usr/include/c++/4.8/bits/stl_vector.h:903 std::vector<MidiEvent*, std::allocator<MidiEvent*> >::push_back(MidiEvent* const&)
Shadow bytes around the buggy address:
  0x0c0bbfffa480: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x0c0bbfffa490: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x0c0bbfffa4a0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x0c0bbfffa4b0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x0c0bbfffa4c0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
=>0x0c0bbfffa4d0: fd fd fd fd fd fd fd[fd]fd fd fd fd fd fd fd fd
  0x0c0bbfffa4e0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x0c0bbfffa4f0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x0c0bbfffa500: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x0c0bbfffa510: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x0c0bbfffa520: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:     fa
  Heap righ redzone:     fb
  Freed Heap region:     fd
  Stack left redzone:    f1
  Stack mid redzone:     f2
  Stack right redzone:   f3
  Stack partial redzone: f4
  Stack after return:    f5
  Stack use after scope: f8
  Global redzone:        f9
  Global init order:     f6
  Poisoned by user:      f7
  ASan internal:         fe
==7044== ABORTING

POC:midifile_invalid_free.mid
This vulnerability has been assigned as CVE-2017-12660.
the MidiEventList::linkNotePairs in src-library/MidiEventList.cpp:314 in midifile through 2017-03-16 can cause a denial of service(invalid memory read and application crash) via a crafted mid file.

./mid2mtb midifile_invalid_memory_read_2.mid

----debug info:----
Program received signal SIGSEGV, Segmentation fault.
0x00000000004074fb in MidiEventList::linkNotePairs (this=0x641e30)
    at src-library/MidiEventList.cpp:314
314	            noteon = noteons[channel][key].back();
(gdb) bt
#0  0x00000000004074fb in MidiEventList::linkNotePairs (this=0x641e30)
    at src-library/MidiEventList.cpp:314
#1  0x00000000004135b2 in MidiFile::linkNotePairs (this=0x7fffffffde50)
    at src-library/MidiFile.cpp:2232
#2  0x0000000000402f4c in convertMidiFile (midifile=..., 
    matlab=std::vector of length 0, capacity 100000)
    at src-programs/mid2mtb.cpp:65
#3  0x0000000000402eca in main (argc=2, argv=0x7fffffffdfb8)
    at src-programs/mid2mtb.cpp:49
(gdb) disassemble 0x00000000004074e8,0x000000000040750e
Dump of assembler code from 0x4074e8 to 0x40750e:
   0x00000000004074e8 <MidiEventList::linkNotePairs()+1822>:	mov    %rbx,%rsi
   0x00000000004074eb <MidiEventList::linkNotePairs()+1825>:	mov    %rax,%rdi
   0x00000000004074ee <MidiEventList::linkNotePairs()+1828>:	callq  0x408460 <std::vector<std::vector<MidiEvent*, std::allocator<MidiEvent*> >, std::allocator<std::vector<MidiEvent*, std::allocator<MidiEvent*> > > >::operator[](unsigned long)>
   0x00000000004074f3 <MidiEventList::linkNotePairs()+1833>:	mov    %rax,%rdi
   0x00000000004074f6 <MidiEventList::linkNotePairs()+1836>:	callq  0x407e2e <std::vector<MidiEvent*, std::allocator<MidiEvent*> >::back()>
=> 0x00000000004074fb <MidiEventList::linkNotePairs()+1841>:	mov    (%rax),%rax
   0x00000000004074fe <MidiEventList::linkNotePairs()+1844>:	mov    %rax,-0xa0(%rbp)
   0x0000000000407505 <MidiEventList::linkNotePairs()+1851>:	mov    -0xc8(%rbp),%eax
   0x000000000040750b <MidiEventList::linkNotePairs()+1857>:	movslq %eax,%rbx
End of assembler dump.
(gdb) i r
rax            0x3fffffff9	17179869177
rbx            0x97	151
rcx            0x644de0	6573536
rdx            0x3fffffff9	17179869177
rsi            0x7fffffffdc08	140737488346120
rdi            0x7fffffffdc40	140737488346176
rbp            0x7fffffffdd50	0x7fffffffdd50
rsp            0x7fffffffdc60	0x7fffffffdc60
r8             0x0	0
r9             0x2	2
r10            0x7ffff78b97b8	140737346508728
r11            0x7ffff7682c01	140737344187393
r12            0x402d60	4205920
r13            0x7fffffffdfb0	140737488347056
r14            0x0	0
r15            0x0	0
rip            0x4074fb	0x4074fb <MidiEventList::linkNotePairs()+1841>
eflags         0x10207	[ CF PF IF RF ]
cs             0x33	51
ss             0x2b	43
ds             0x0	0
es             0x0	0
fs             0x0	0
---Type <return> to continue, or q <return> to quit---
gs             0x0	0
(gdb) x/20x 0x3fffffff9
0x3fffffff9:	Cannot access memory at address 0x3fffffff9
(gdb) 

POC:midifile_invalid_memory_read_2.mid
This vulnerability has been assigned as CVE-2017-12658.
the MidiEventList::linkNotePairs function in src-library/MidiEventList.cpp:309 in midifile through 2017-03-16 can cause a denial of service(memory allocation error and application crash) via a crafted mid file.

./mid2mtb midifile_memory_allcation_error_2.mid

----debug info:----
Program received signal SIGSEGV, Segmentation fault.
0x000000000040b338 in __gnu_cxx::new_allocator<MidiEvent*>::construct<MidiEvent*<MidiEvent* const&> > (this=0x6b28a0, __p=0xc11)
    at /usr/include/c++/4.8/ext/new_allocator.h:120
120		{ ::new((void *)__p) _Up(std::forward<_Args>(__args)...); }
(gdb) bt
#0  0x000000000040b338 in __gnu_cxx::new_allocator<MidiEvent*>::construct<MidiEvent*<MidiEvent* const&> > (this=0x6b28a0, __p=0xc11)
    at /usr/include/c++/4.8/ext/new_allocator.h:120
#1  0x000000000040a551 in std::allocator_traits<std::allocator<MidiEvent*> >::_S_construct<MidiEvent*<MidiEvent* const&> >(std::allocator<MidiEvent*>&, std::allocator_traits<std::allocator<MidiEvent*> >::__construct_helper*, (MidiEvent*<MidiEvent* const&>&&)...) (__a=..., __p=0xc11)
    at /usr/include/c++/4.8/bits/alloc_traits.h:254
#2  0x0000000000408d8e in std::allocator_traits<std::allocator<MidiEvent*> >::construct<MidiEvent*<MidiEvent* const&> >(std::allocator<MidiEvent*>&, MidiEvent*<MidiEvent* const&>*, (MidiEvent*<MidiEvent* const&>&&)...) (__a=..., __p=0xc11)
    at /usr/include/c++/4.8/bits/alloc_traits.h:393
#3  0x0000000000407f6e in std::vector<MidiEvent*, std::allocator<MidiEvent*> >::push_back (this=0x6b28a0, __x=@0x7fffffffdcb8: 0x643c30)
    at /usr/include/c++/4.8/bits/stl_vector.h:905
#4  0x0000000000407434 in MidiEventList::linkNotePairs (this=0x641e30)
    at src-library/MidiEventList.cpp:309
#5  0x00000000004135b2 in MidiFile::linkNotePairs (this=0x7fffffffde50)
    at src-library/MidiFile.cpp:2232
#6  0x0000000000402f4c in convertMidiFile (midifile=..., 
    matlab=std::vector of length 0, capacity 100000)
    at src-programs/mid2mtb.cpp:65
#7  0x0000000000402eca in main (argc=2, argv=0x7fffffffdfb8)
---Type <return> to continue, or q <return> to quit---
    at src-programs/mid2mtb.cpp:49
(gdb) disassemble 
Dump of assembler code for function _ZN9__gnu_cxx13new_allocatorIP9MidiEventE9constructIS2_IRKS2_EEEvPT_DpOT0_:
   0x000000000040b2fe <+0>:	push   %rbp
   0x000000000040b2ff <+1>:	mov    %rsp,%rbp
   0x000000000040b302 <+4>:	push   %rbx
   0x000000000040b303 <+5>:	sub    $0x28,%rsp
   0x000000000040b307 <+9>:	mov    %rdi,-0x18(%rbp)
   0x000000000040b30b <+13>:	mov    %rsi,-0x20(%rbp)
   0x000000000040b30f <+17>:	mov    %rdx,-0x28(%rbp)
   0x000000000040b313 <+21>:	mov    -0x28(%rbp),%rax
   0x000000000040b317 <+25>:	mov    %rax,%rdi
   0x000000000040b31a <+28>:	callq  0x407f20 <std::forward<MidiEvent* const&>(std::remove_reference<MidiEvent* const&>::type&)>
   0x000000000040b31f <+33>:	mov    (%rax),%rbx
   0x000000000040b322 <+36>:	mov    -0x20(%rbp),%rax
   0x000000000040b326 <+40>:	mov    %rax,%rsi
   0x000000000040b329 <+43>:	mov    $0x8,%edi
   0x000000000040b32e <+48>:	callq  0x403f2f <operator new(unsigned long, void*)>
   0x000000000040b333 <+53>:	test   %rax,%rax
   0x000000000040b336 <+56>:	je     0x40b33b <_ZN9__gnu_cxx13new_allocatorIP9MidiEventE9constructIS2_IRKS2_EEEvPT_DpOT0_+61>
=> 0x000000000040b338 <+58>:	mov    %rbx,(%rax)
---Type <return> to continue, or q <return> to quit---
   0x000000000040b33b <+61>:	add    $0x28,%rsp
   0x000000000040b33f <+65>:	pop    %rbx
   0x000000000040b340 <+66>:	pop    %rbp
   0x000000000040b341 <+67>:	retq   
End of assembler dump.
(gdb) i r 
rax            0xc11	3089
rbx            0x643c30	6569008
rcx            0xc11	3089
rdx            0x7fffffffdcb8	140737488346296
rsi            0xc11	3089
rdi            0x8	8
rbp            0x7fffffffdbd0	0x7fffffffdbd0
rsp            0x7fffffffdba0	0x7fffffffdba0
r8             0x0	0
r9             0x2	2
r10            0x7ffff78b97b8	140737346508728
r11            0x7ffff78b9701	140737346508545
r12            0x402d60	4205920
r13            0x7fffffffdfb0	140737488347056
r14            0x0	0
r15            0x0	0
rip            0x40b338	0x40b338 <_ZN9__gnu_cxx13new_allocatorIP9MidiEventE9constructIS2_IRKS2_EEEvPT_DpOT0_+58>
eflags         0x10206	[ PF IF RF ]
cs             0x33	51
ss             0x2b	43
ds             0x0	0
es             0x0	0
---Type <return> to continue, or q <return> to quit---
fs             0x0	0
gs             0x0	0
(gdb)

=================================================================
==7030== ERROR: AddressSanitizer: heap-buffer-overflow on address 0x605a00009b88 at pc 0x40b51d bp 0x7fff6f0f91f0 sp 0x7fff6f0f91e8
READ of size 8 at 0x605a00009b88 thread T0
    #0 0x40b51c in std::vector<MidiEvent*, std::allocator<MidiEvent*> >::push_back(MidiEvent* const&) /usr/include/c++/4.8/bits/stl_vector.h:903
    #1 0x40a391 in MidiEventList::linkNotePairs() /home/a/Downloads/midifile-master/src-library/MidiEventList.cpp:309
    #2 0x41e632 in MidiFile::linkNotePairs() /home/a/Downloads/midifile-master/src-library/MidiFile.cpp:2232
    #3 0x403545 in convertMidiFile(MidiFile&, std::vector<std::vector<double, std::allocator<double> >, std::allocator<std::vector<double, std::allocator<double> > > >&) /home/a/Downloads/midifile-master/src-programs/mid2mtb.cpp:65
    #4 0x403476 in main /home/a/Downloads/midifile-master/src-programs/mid2mtb.cpp:49
    #5 0x7f0bc8a7cec4 (/lib/x86_64-linux-gnu/libc.so.6+0x21ec4)
    #6 0x4032f8 in _start (/home/a/Downloads/midifile-master/bin/mid2mtb+0x4032f8)
0x605a00009b88 is located 8 bytes to the right of 3072-byte region [0x605a00008f80,0x605a00009b80)
allocated by thread T0 here:
    #0 0x7f0bc934b81a (/usr/lib/x86_64-linux-gnu/libasan.so.0+0x1181a)
    #1 0x410811 in __gnu_cxx::new_allocator<std::vector<MidiEvent*, std::allocator<MidiEvent*> > >::allocate(unsigned long, void const*) /usr/include/c++/4.8/ext/new_allocator.h:104
    #2 0x40f6b8 in std::_Vector_base<std::vector<MidiEvent*, std::allocator<MidiEvent*> >, std::allocator<std::vector<MidiEvent*, std::allocator<MidiEvent*> > > >::_M_allocate(unsigned long) /usr/include/c++/4.8/bits/stl_vector.h:168
    #3 0x40d596 in std::vector<std::vector<MidiEvent*, std::allocator<MidiEvent*> >, std::allocator<std::vector<MidiEvent*, std::allocator<MidiEvent*> > > >::_M_default_append(unsigned long) /usr/include/c++/4.8/bits/vector.tcc:549
    #4 0x40b82e in std::vector<std::vector<MidiEvent*, std::allocator<MidiEvent*> >, std::allocator<std::vector<MidiEvent*, std::allocator<MidiEvent*> > > >::resize(unsigned long) /usr/include/c++/4.8/bits/stl_vector.h:667
    #5 0x40945a in MidiEventList::linkNotePairs() /home/a/Downloads/midifile-master/src-library/MidiEventList.cpp:228
    #6 0x41e632 in MidiFile::linkNotePairs() /home/a/Downloads/midifile-master/src-library/MidiFile.cpp:2232
    #7 0x403545 in convertMidiFile(MidiFile&, std::vector<std::vector<double, std::allocator<double> >, std::allocator<std::vector<double, std::allocator<double> > > >&) /home/a/Downloads/midifile-master/src-programs/mid2mtb.cpp:65
    #8 0x403476 in main /home/a/Downloads/midifile-master/src-programs/mid2mtb.cpp:49
    #9 0x7f0bc8a7cec4 (/lib/x86_64-linux-gnu/libc.so.6+0x21ec4)
SUMMARY: AddressSanitizer: heap-buffer-overflow /usr/include/c++/4.8/bits/stl_vector.h:903 std::vector<MidiEvent*, std::allocator<MidiEvent*> >::push_back(MidiEvent* const&)
Shadow bytes around the buggy address:
  0x0c0bbfff9320: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c0bbfff9330: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c0bbfff9340: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c0bbfff9350: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c0bbfff9360: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x0c0bbfff9370: fa[fa]fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c0bbfff9380: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c0bbfff9390: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c0bbfff93a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c0bbfff93b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c0bbfff93c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:     fa
  Heap righ redzone:     fb
  Freed Heap region:     fd
  Stack left redzone:    f1
  Stack mid redzone:     f2
  Stack right redzone:   f3
  Stack partial redzone: f4
  Stack after return:    f5
  Stack use after scope: f8
  Global redzone:        f9
  Global init order:     f6
  Poisoned by user:      f7
  ASan internal:         fe
==7030== ABORTING

POC:midifile_memory_allcation_error_2.mid
This vulnerability has been assigned as CVE-2017-12659.
the MidiEvent::unlinkEvent function in src-library/MidiEvent.cpp in midifile through 2017-03-16 can cause a denial of service(invalid memory read and application crash) via a crafted mid file.

./mid2mtb midifile_invalid_memory_read_3.mid

----debug info:----
Program received signal SIGSEGV, Segmentation fault.
0x0000000000405df8 in MidiEvent::unlinkEvent (this=0x21)
    at src-library/MidiEvent.cpp:162
162	   if (eventlink == NULL) {
(gdb) bt
#0  0x0000000000405df8 in MidiEvent::unlinkEvent (this=0x21)
    at src-library/MidiEvent.cpp:162
#1  0x0000000000405e27 in MidiEvent::unlinkEvent (this=0x642778)
    at src-library/MidiEvent.cpp:167
#2  0x00000000004073b1 in MidiEventList::linkNotePairs (this=0x641840)
    at src-library/MidiEventList.cpp:304
#3  0x00000000004135b2 in MidiFile::linkNotePairs (this=0x7fffffffde60)
    at src-library/MidiFile.cpp:2232
#4  0x0000000000402f4c in convertMidiFile (midifile=..., 
    matlab=std::vector of length 0, capacity 100000)
    at src-programs/mid2mtb.cpp:65
#5  0x0000000000402eca in main (argc=2, argv=0x7fffffffdfc8)
    at src-programs/mid2mtb.cpp:49
(gdb) disassemble 
Dump of assembler code for function MidiEvent::unlinkEvent():
   0x0000000000405de8 <+0>:	push   %rbp
   0x0000000000405de9 <+1>:	mov    %rsp,%rbp
   0x0000000000405dec <+4>:	sub    $0x20,%rsp
   0x0000000000405df0 <+8>:	mov    %rdi,-0x18(%rbp)
   0x0000000000405df4 <+12>:	mov    -0x18(%rbp),%rax
=> 0x0000000000405df8 <+16>:	mov    0x30(%rax),%rax
   0x0000000000405dfc <+20>:	test   %rax,%rax
   0x0000000000405dff <+23>:	jne    0x405e03 <MidiEvent::unlinkEvent()+27>
   0x0000000000405e01 <+25>:	jmp    0x405e27 <MidiEvent::unlinkEvent()+63>
   0x0000000000405e03 <+27>:	mov    -0x18(%rbp),%rax
   0x0000000000405e07 <+31>:	mov    0x30(%rax),%rax
   0x0000000000405e0b <+35>:	mov    %rax,-0x8(%rbp)
   0x0000000000405e0f <+39>:	mov    -0x18(%rbp),%rax
   0x0000000000405e13 <+43>:	movq   $0x0,0x30(%rax)
   0x0000000000405e1b <+51>:	mov    -0x8(%rbp),%rax
   0x0000000000405e1f <+55>:	mov    %rax,%rdi
   0x0000000000405e22 <+58>:	callq  0x405de8 <MidiEvent::unlinkEvent()>
   0x0000000000405e27 <+63>:	leaveq 
   0x0000000000405e28 <+64>:	retq   
End of assembler dump.
(gdb) i r
rax            0x21	33
rbx            0x0	0
rcx            0x0	0
rdx            0x88	136
rsi            0x11	17
rdi            0x21	33
rbp            0x7fffffffdc30	0x7fffffffdc30
rsp            0x7fffffffdc10	0x7fffffffdc10
r8             0x0	0
r9             0x6b4ee0	7032544
r10            0x7ffff78b97b8	140737346508728
r11            0x7ffff7682c70	140737344187504
r12            0x402d60	4205920
r13            0x7fffffffdfc0	140737488347072
r14            0x0	0
r15            0x0	0
rip            0x405df8	0x405df8 <MidiEvent::unlinkEvent()+16>
eflags         0x10202	[ IF RF ]
cs             0x33	51
ss             0x2b	43
ds             0x0	0
es             0x0	0
fs             0x0	0
---Type <return> to continue, or q <return> to quit---
gs             0x0	0
(gdb)

=================================================================
==7035== ERROR: AddressSanitizer: attempting free on address which was not malloc()-ed: 0x60040000cb78
    #0 0x7fa5838ca9da (/usr/lib/x86_64-linux-gnu/libasan.so.0+0x119da)
    #1 0x40f069 in __gnu_cxx::new_allocator<MidiEvent*>::deallocate(MidiEvent**, unsigned long) /usr/include/c++/4.8/ext/new_allocator.h:110
    #2 0x40c29f in std::_Vector_base<MidiEvent*, std::allocator<MidiEvent*> >::_M_deallocate(MidiEvent**, unsigned long) /usr/include/c++/4.8/bits/stl_vector.h:174
    #3 0x40c0d2 in std::_Vector_base<MidiEvent*, std::allocator<MidiEvent*> >::~_Vector_base() /usr/include/c++/4.8/bits/stl_vector.h:160
    #4 0x40aeb1 in std::vector<MidiEvent*, std::allocator<MidiEvent*> >::~vector() /usr/include/c++/4.8/bits/stl_vector.h:416
    #5 0x411549 in void std::_Destroy<std::vector<MidiEvent*, std::allocator<MidiEvent*> > >(std::vector<MidiEvent*, std::allocator<MidiEvent*> >*) /usr/include/c++/4.8/bits/stl_construct.h:93
    #6 0x410a1d in void std::_Destroy_aux<false>::__destroy<std::vector<MidiEvent*, std::allocator<MidiEvent*> >*>(std::vector<MidiEvent*, std::allocator<MidiEvent*> >*, std::vector<MidiEvent*, std::allocator<MidiEvent*> >*) /usr/include/c++/4.8/bits/stl_construct.h:103
    #7 0x40fc34 in void std::_Destroy<std::vector<MidiEvent*, std::allocator<MidiEvent*> >*>(std::vector<MidiEvent*, std::allocator<MidiEvent*> >*, std::vector<MidiEvent*, std::allocator<MidiEvent*> >*) /usr/include/c++/4.8/bits/stl_construct.h:126
    #8 0x40e0a4 in void std::_Destroy<std::vector<MidiEvent*, std::allocator<MidiEvent*> >*, std::vector<MidiEvent*, std::allocator<MidiEvent*> > >(std::vector<MidiEvent*, std::allocator<MidiEvent*> >*, std::vector<MidiEvent*, std::allocator<MidiEvent*> >*, std::allocator<std::vector<MidiEvent*, std::allocator<MidiEvent*> > >&) /usr/include/c++/4.8/bits/stl_construct.h:151
    #9 0x40bb51 in std::vector<std::vector<MidiEvent*, std::allocator<MidiEvent*> >, std::allocator<std::vector<MidiEvent*, std::allocator<MidiEvent*> > > >::~vector() /usr/include/c++/4.8/bits/stl_vector.h:415
    #10 0x4111d1 in void std::_Destroy<std::vector<std::vector<MidiEvent*, std::allocator<MidiEvent*> >, std::allocator<std::vector<MidiEvent*, std::allocator<MidiEvent*> > > > >(std::vector<std::vector<MidiEvent*, std::allocator<MidiEvent*> >, std::allocator<std::vector<MidiEvent*, std::allocator<MidiEvent*> > > >*) /usr/include/c++/4.8/bits/stl_construct.h:93
    #11 0x41067d in void std::_Destroy_aux<false>::__destroy<std::vector<std::vector<MidiEvent*, std::allocator<MidiEvent*> >, std::allocator<std::vector<MidiEvent*, std::allocator<MidiEvent*> > > >*>(std::vector<std::vector<MidiEvent*, std::allocator<MidiEvent*> >, std::allocator<std::vector<MidiEvent*, std::allocator<MidiEvent*> > > >*, std::vector<std::vector<MidiEvent*, std::allocator<MidiEvent*> >, std::allocator<std::vector<MidiEvent*, std::allocator<MidiEvent*> > > >*) /usr/include/c++/4.8/bits/stl_construct.h:103
    #12 0x40f3d2 in void std::_Destroy<std::vector<std::vector<MidiEvent*, std::allocator<MidiEvent*> >, std::allocator<std::vector<MidiEvent*, std::allocator<MidiEvent*> > > >*>(std::vector<std::vector<MidiEvent*, std::allocator<MidiEvent*> >, std::allocator<std::vector<MidiEvent*, std::allocator<MidiEvent*> > > >*, std::vector<std::vector<MidiEvent*, std::allocator<MidiEvent*> >, std::allocator<std::vector<MidiEvent*, std::allocator<MidiEvent*> > > >*) /usr/include/c++/4.8/bits/stl_construct.h:126
    #13 0x40ced4 in void std::_Destroy<std::vector<std::vector<MidiEvent*, std::allocator<MidiEvent*> >, std::allocator<std::vector<MidiEvent*, std::allocator<MidiEvent*> > > >*, std::vector<std::vector<MidiEvent*, std::allocator<MidiEvent*> >, std::allocator<std::vector<MidiEvent*, std::allocator<MidiEvent*> > > > >(std::vector<std::vector<MidiEvent*, std::allocator<MidiEvent*> >, std::allocator<std::vector<MidiEvent*, std::allocator<MidiEvent*> > > >*, std::vector<std::vector<MidiEvent*, std::allocator<MidiEvent*> >, std::allocator<std::vector<MidiEvent*, std::allocator<MidiEvent*> > > >*, std::allocator<std::vector<std::vector<MidiEvent*, std::allocator<MidiEvent*> >, std::allocator<std::vector<MidiEvent*, std::allocator<MidiEvent*> > > > >&) /usr/include/c++/4.8/bits/stl_construct.h:151
    #14 0x40b657 in std::vector<std::vector<std::vector<MidiEvent*, std::allocator<MidiEvent*> >, std::allocator<std::vector<MidiEvent*, std::allocator<MidiEvent*> > > >, std::allocator<std::vector<std::vector<MidiEvent*, std::allocator<MidiEvent*> >, std::allocator<std::vector<MidiEvent*, std::allocator<MidiEvent*> > > > > >::~vector() /usr/include/c++/4.8/bits/stl_vector.h:415
    #15 0x40ab52 in MidiEventList::linkNotePairs() /home/a/Downloads/midifile-master/src-library/MidiEventList.cpp:348
    #16 0x41e632 in MidiFile::linkNotePairs() /home/a/Downloads/midifile-master/src-library/MidiFile.cpp:2232
    #17 0x403545 in convertMidiFile(MidiFile&, std::vector<std::vector<double, std::allocator<double> >, std::allocator<std::vector<double, std::allocator<double> > > >&) /home/a/Downloads/midifile-master/src-programs/mid2mtb.cpp:65
    #18 0x403476 in main /home/a/Downloads/midifile-master/src-programs/mid2mtb.cpp:49
    #19 0x7fa582ffbec4 (/lib/x86_64-linux-gnu/libc.so.6+0x21ec4)
0x60040000cb78 is located 5 bytes to the right of 3-byte region [0x60040000cb70,0x60040000cb73)
allocated by thread T0 here:
    #0 0x7fa5838ca81a (/usr/lib/x86_64-linux-gnu/libasan.so.0+0x1181a)
    #1 0x41039a in __gnu_cxx::new_allocator<MidiEvent*>::allocate(unsigned long, void const*) /usr/include/c++/4.8/ext/new_allocator.h:104
    #2 0x40f00e in std::_Vector_base<MidiEvent*, std::allocator<MidiEvent*> >::_M_allocate(unsigned long) /usr/include/c++/4.8/bits/stl_vector.h:168
    #3 0x40cad5 in void std::vector<MidiEvent*, std::allocator<MidiEvent*> >::_M_emplace_back_aux<MidiEvent* const&>(MidiEvent* const&) /usr/include/c++/4.8/bits/vector.tcc:404
    #4 0x40b5bf in std::vector<MidiEvent*, std::allocator<MidiEvent*> >::push_back(MidiEvent* const&) /usr/include/c++/4.8/bits/stl_vector.h:911
    #5 0x40a391 in MidiEventList::linkNotePairs() /home/a/Downloads/midifile-master/src-library/MidiEventList.cpp:309
    #6 0x41e632 in MidiFile::linkNotePairs() /home/a/Downloads/midifile-master/src-library/MidiFile.cpp:2232
    #7 0x403545 in convertMidiFile(MidiFile&, std::vector<std::vector<double, std::allocator<double> >, std::allocator<std::vector<double, std::allocator<double> > > >&) /home/a/Downloads/midifile-master/src-programs/mid2mtb.cpp:65
    #8 0x403476 in main /home/a/Downloads/midifile-master/src-programs/mid2mtb.cpp:49
    #9 0x7fa582ffbec4 (/lib/x86_64-linux-gnu/libc.so.6+0x21ec4)
SUMMARY: AddressSanitizer: bad-free ??:0 ??
==7035== ABORTING

POC:midifile_invalid_memory_read_3.mid
This vulnerability has been assigned as CVE-2017-12657.

poc.zip

MidiFile::mergeTracks needs to fix track field in all events that are moved

As mergeTracks moves the event lists upward to get rid of aTrack2 it doesn't update the track field of the events being moved. The loop is

for (int i=aTrack2; i<length-1; i++) {
	m_events[i] = m_events[i+1];
}

After this loop all the events in m_events[aTrack2] on up will have track fields with their old track indices instead of their new ones.

variable length values must not be >4 bytes

Why are you writing up to 5 bytes in MidiFile::writeVLValue? I don't think this is correct according to Midi 1.1 spec:

The largest number which is allowed is 0FFFFFFF so that the variable-length representations must fit in 32 bits in a routine to write variable-length numbers.

I.e. that aValue == 0x0FFFFFFF gives VLValue of 0x7FFFFFFF. Fluidsynth's midi parser actually complains when reading midi files written with this library.

makeNoteOff wrong value (addNoteOff)

I was playing with the library and I noticed that the value for the note off was wrong.

It was previously on 90 but the correct value is 0x80 as following

void MidiMessage::makeNoteOff(int channel, int key) {
   resize(3);
   (*this)[0] = 0x80 | (0x0f & channel);    // was previously 0x90
   (*this)[1] = key & 0x7f;
   (*this)[2] = 0x00;
}

Same for

void MidiMessage::makeNoteOff(void) {
   if (!isNoteOn()) {
      resize(3);
      (*this)[0] = 0x80;                // was  previously 0x90
      (*this)[1] = 0;
      (*this)[2] = 0;
   } else {
      (*this)[2] = 0;
   }
}

In any case the library is a very good wrapper to work with MIDI. Thanks!

Receiving `reset` message > 1 byte

When reading in midi files (tested with various midi files from various different sources) and then looking at the individual messages from the MidiEvent object there always seems to be a few messages such as:

ff 51 03 07 a1 20

in particular at the start of the file, but my understanding is that a 0xff status byte means "reset" and should not be followed by any other bytes in the message (and sure enough, when I send the midi event to a softsynth it complains that it can't parse it). Is this a problem with the midifile library? Thanks

Status when reading a file

When I try to read a file with the midifile.read() function ( in MidiFile.cpp ) there are three possible outcomes:

  1. File exists and is a valid MIDI file
  2. File exists and is not a valid MIDI file
  3. File doesn't exist

Cases 1 & 2 work fine but for case 3 the variable rwstatus is not set so the subsequent midifile.status() call returns the incorrect value. Was this the intention?

I can work round this by checking the return value from the read call rather than explicitly checking the status afterwards.

How to copy tracks?

for example, I want to copy Track 1 twice and add the new tracks in the end of the midi

        int tb = A.getNumTracks();
	A.addTracks(times);

	for (int i = tb; i < tb + times; ++i)
		A[i] = A[channel];
	A.sortTracks();
	A.write(filepath);

But however, the output file is the same as the origin midi
How can I fix?

documentation question

Hi,
Where I can find documentation to add and manage in file creation
bars, measures, repeats, tempos 4/3 3/4 and such ,

Can't compile the visual-studio project

Hi! I have VS2015, and in the developer prompt when i type

set "PLATFORM=" and "msbuild" I get the following:

C:\Users\Joel\Downloads\craigsapp-midifile-55a68db>cd visual-studio

C:\Users\Joel\Downloads\craigsapp-midifile-55a68db\visual-studio>set "PLATFORM="

C:\Users\Joel\Downloads\craigsapp-midifile-55a68db\visual-studio>msbuild
Microsoft (R) Build Engine version 14.0.23107.0
Copyright (C) Microsoft Corporation. All rights reserved.

Build started 2016-03-07 13:15:43.
The target "AfterGenerateAppxManifest" listed in an AfterTargets attribute at "C:\Program Files (x8 6)\MSBuild\Microsoft.NetNative\Microsoft.Net.CoreRuntime.targets (68,11)" does not exist in the pr oject, and will be ignored.
The target "_GeneratePrisForPortableLibraries" listed in a BeforeTargets attribute at "C:\Program F iles (x86)\MSBuild\Microsoft.NetNative\Microsoft.Net.CoreRuntime.targets (177,11)" does not exist
in the project, and will be ignored.
The target "AfterGenerateAppxManifest" listed in an AfterTargets attribute at "C:\Program Files (x8 6)\MSBuild\Microsoft.NetNative\Microsoft.NetNative.targets (126,11)" does not exist in the project , and will be ignored.
The target "AfterGenerateAppxManifest" listed in an AfterTargets attribute at "C:\Program Files (x8 6)\MSBuild\Microsoft.NetNative\Microsoft.NetNative.targets (174,11)" does not exist in the project , and will be ignored.
The target "BeforeGenerateProjectPriFile" listed in a BeforeTargets attribute at "C:\Program Files
(x86)\MSBuild\Microsoft\NuGet\Microsoft.NuGet.targets (149,61)" does not exist in the project, and
will be ignored.
Project "C:\Users\Joel\Downloads\craigsapp-midifile-55a68db\visual-studio\midifile.vcxproj" on node 1 (default targets).
InitializeBuildStatus:
Creating "Debug\midifile.tlog\unsuccessfulbuild" because "AlwaysCreate" was specified.
FinalizeBuildStatus:
Deleting file "Debug\midifile.tlog\unsuccessfulbuild".
Touching "Debug\midifile.tlog\midifile.lastbuildstate".
Done Building Project "C:\Users\Joel\Downloads\craigsapp-midifile-55a68db\visual-studio\midifile.vc xproj" (default targets).

Build succeeded.
0 Warning(s)
0 Error(s)

I'm not getting anything useful out of it :( Thanks!

How to get MIDI Type

Hi!

How can MIDI Type be detected (0, 1, 2)?
Like midifile.GetMIDIType()

I see that it is loaded in MidiFile::read, but seems that it is not stored as class member variable. Possible solution is to convert type variable to a member variable.

// Header parameter #1: format type
int type;
shortdata = readLittleEndian2Bytes(input);
switch (shortdata) {
	case 0:
		type = 0;
		break;
	case 1:
		type = 1;
		break;
	case 2:
		// Type-2 MIDI files should probably be allowed as well,
		// but I have never seen one in the wild to test with.
	default:
		est.Format("Error: cannot handle a type-%hu MIDI file.", shortdata);
		m_rwstatus = false; return m_rwstatus;
}

// Header parameter #2: track count
int tracks;
shortdata = readLittleEndian2Bytes(input);
if (type == 0 && shortdata != 1) {
	est.Format("Error: Type 0 MIDI file can only contain one track. Instead track count is: %hu", shortdata);
	m_rwstatus = false; return m_rwstatus;
} else {
	tracks = shortdata;
}

Bad Midi file when velocity==10

Hello,
Thank you for this very useful library.
There is a weird issue when trying to export a Midi file if one value==10, for example the velocity.
Only with a value of 10 .... The rest works as expected from what I tested.
I attach you the Midi files. They contain a single note.
The one with the velocity==12 is fine, the one with the velocity==10 has an extra Hex value and then gets corrupted.

I had a lot of variables in my code but it looks as simple as that :

   MidiMessage midiMsg;
    midiMsg.makeNoteOn(60, 10, 0);
    outputFile.addEvent(0, 0, midiMsg);
    midiMsg.makeNoteOff(60, 10, 0);
    outputFile.addEvent(0, 2, midiMsg);

Cheers,

files.zip

Unresolved external references when including midifile with my progam..

Hi, maybe a rookie question but i want to use the midifile source code and include it in a project but i'm having difficulties with 8 unresolved external references, similar to this one:

Severity    Code    Description Project File    Line
Error   LNK2019 unresolved external symbol "public: int __thiscall MidiFile::addEvent(int,int,class std::vector<unsigned char,class std::allocator<unsigned char> > &)" (?addEvent@MidiFile@@QAEHHHAAV?$vector@EV?$allocator@E@std@@@std@@@Z) referenced in function "void __cdecl CREATE_MIDI(void)" (?CREATE_MIDI@@YAXXZ) SPMA - Assignment 1 - 4591930 EPM   C:\Users\Paul\Desktop\Uni Stuff - YEAR 2\SOFTWARE PROGRAMMING\Assignments\Assignment 1\SPMA - Assignment 1 - 4591930 EPM\Main.obj   1

I want my midifile to be a subfolder in my project so i have #include "midifile/include/MidiFile.h" in my code and the following code i adapted a bit from the create midi files section of the midifile app on here: https://github.com/craigsapp/midifile/blob/master/src-programs/createmidifile.cpp

// FUNCTION: CREATE MIDI DATA..
void CREATE_MIDI()
{
    MidiFile outputfile;        // CREATE AN EMPTY MIDI FILE WITH ONE TRACK..
    outputfile.absoluteTicks();  // TIME INFO STORED AS ABSOLUTE TIME..
    outputfile.addTrack(number_of_melodies -1);     // ADD ALL CURRENT MELODIES (-1 AS WE ALREADY HAVE ONE TRACK)..
    vector<uchar> midievent;     // TEMP STORAGE FOR MIDI EVENTS..
    midievent.resize(3);        // SET THE ARRAY SIZE TO 3 BYTES..
    int tpq = 120;              // default value in MIDI file is 48
    outputfile.setTicksPerQuarterNote(tpq);

    // store a melody line in track 1 (track 0 left empty for conductor info)
    int i = 0;
    double actiontime = 0;      // temporary storage for MIDI event time
    midievent[2] = 64;       // store attack/release velocity for note command..

    // FOR: LOOP AROUND NUMBER OF MELODIES..
    for (counter i = 0; i < number_of_melodies; ++i)
    {
        // FOR: LOOP ROUND NUMBER OF NOTES IN EACH MELODY..
        for (counter j = 0; j < noteOUT.note_value[i].size(); ++j)
        {
            midievent[i] = 0x90;     // STORE 'NOTE-ON' COMMAND (ON MIDI CHANNEL 1)..
            midievent[i+1] = noteOUT.midi_number[i][j]; // ADD MELODY MIDI NUMBER INFO..
            outputfile.addEvent(1, actiontime, midievent);  // APPEND THE MIDI EVENT TO THE FILE..
            actiontime += tpq * noteOUT.note_length_MS[i][j];       // CALCULATE TIMINGS AND APPEND FOR EACH NOTE..     
            midievent[i] = 0x80;     // STORE 'NOTE-OFF' COMMAND (ON MIDI CHANNEL 1)..
            outputfile.addEvent(1, actiontime, midievent);  // APPEND THE MIDI EVENT TO THE FILE..
            actiontime = 0; //RESET ACTIONTIME..
        }
        // END FOR..
    }
    // END FOR..

    outputfile.sortTracks();         // ORGANISE DATA INTO CORRECT ORDER..
    outputfile.write(fileX.full_path_midi); // WRITE STANDARD MIDI FILE..
}
// END FUNCTION..

My program won't compile, I can't interperet the error messages other than they seem to mention spme of the midifile functions, like they're undefined or something, so something is amiss in my folder structures or implemenation into my program.

Any ideas what could be causing this? And how am i supposed to properly include and be able to use the midifile stuff?

Thanks,

Paul..

meta message length inconsistency

There are two ways to create meta messages using either MidiFile or MidiMessage.
The latter however does not use a VLV for the data length and the generated meta messages differ.

Furthermore MidiFile::write already adds the VLV length automatically for some messages, so it can be omitted when creating specific messages.

I think this would be useful for meta messages as well. The VLV length is really only needed for reading / writing MIDI files. When working with the data vector<uchar> contains all the information needed.

One more thing (not worth a separate issue): There is a typo in "until"...

getSpelling missing case?

When I first tried using this, I got a dump and tracked it back to this:

In MidiMessage.cpp at approximately line 1089, the case 4 for base12pc, there is no case 0 contained in it. Each other has a case 1, 0/2, 3. This one omits the 0. In music output from Musescore with more or less default settings, I had a note 76 at velocity 80, which causes on exit accidental to be set to 123456.

I think all that is needed is to add case 0, e.g.

    case 2: base7pc = 2; accidental =  0; break;  // E

becomes

    case 0:   case 2: base7pc = 2; accidental =  0; break;  // E

I did not dig deeply to see if there is some underlying reason that case 4 should never have a velocity low order bits of 0, but Musescore certainly output it, so I believe it is more likely just an omission in this code.

I'm going to give a shot at submitting a PR but am rather a beginner at git, so apologies if I cannot get that to happen properly.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.