1 //
2 // Programmer:    Craig Stuart Sapp <craig@ccrma.stanford.edu>
3 // Creation Date: Tue Jan 22 22:09:46 PST 2002
4 // Last Modified: Thu Nov 20 17:09:08 PST 2003
5 // Last Modified: Mon Sep  6 23:21:17 PDT 2004 Changed pow(2) to pow(2.0).
6 // Last Modified: Fri Jul 23 12:32:31 PDT 2010 Generalized tempo parsing.
7 // Last Modified: Mon Feb  9 21:17:36 PST 2015 Updated for C++11.
8 // Filename:      ...sig/examples/all/mid2mat.cpp
9 // Web Address:   http://sig.sapp.org/examples/museinfo/midi/mid2mat.cpp
10 // Syntax:        C++; museinfo
11 //
12 // Description:   Converts a MIDI file into a text-based note matrix.
13 //
14 // directives:
15 //    note    = note data
16 //    tempo   = tempo change
17 //    control = continuous controller
18 //    tpq     = ticks per quarter note
19 //
20 
21 #include "MidiFile.h"
22 #include "Options.h"
23 
24 #include <ctype.h>
25 #include <string.h>
26 #include <stdio.h>
27 #include <math.h>
28 #include <vector>
29 #include <iostream>
30 #include <iomanip>
31 
32 using namespace std;
33 using namespace smf;
34 
35 // Four types of event time display:
36 #define TICK 1            /* time units are MIDI file ticks (absolute)     */
37 #define BEAT 2            /* time units are Beats (quarter note, absolute) */
38 #define SEC  3            /* time units are seconds (absolute)             */
39 #define MSEC 4            /* time units are millisecodns (absolute)        */
40 
41 // Data which can be found in the final data array:
42 #define OP_NOTE    1000   /* Note Event                  */
43 #define OP_CONTROL 2000   /* Continuous-Controller Event */
44 #define OP_INSTR   3000   /* Instrument Change Event     */
45 #define OP_TEMPO   4000   /* Tempo Meta Event            */
46 #define OP_METER   5000   /* Meter Meta Event            */
47 #define OP_KEYSIG  6000   /* Key Signature Event         */
48 
49 #define OP_NOTE_NAME    "NOTE"
50 #define OP_CONTROL_NAME "CONT"
51 #define OP_CONT_NAME    "CONT"
52 #define OP_INSTR_NAME   "INSTR"
53 #define OP_TEMPO_NAME   "TEMPO"
54 #define OP_METER_NAME   "METER"
55 #define OP_KEYSIG_NAME  "KEYSIG"
56 
57 
58 // General MIDI instrument names:
59 const char *GMinstrument[128] = {
60    "acpiano",   "britepno",  "synpiano",  "honkytonk", "epiano1",   "epiano2",
61    "hrpschrd",  "clavinet",  "celeste",   "glocken",   "musicbox",  "vibes",
62    "marimba",   "xylophon",  "tubebell",  "santur",    "homeorg",   "percorg",
63    "rockorg",   "churchorg", "reedorg",   "accordn",   "harmonica", "concrtna",
64    "nyguitar",  "acguitar",  "jazzgtr",   "cleangtr",  "mutegtr",   "odguitar",
65    "distgtr",   "gtrharm",   "acbass",    "fngrbass",  "pickbass",  "fretless",
66    "slapbas1",  "slapbas2",  "synbass1",  "synbass2",  "violin",    "viola",
67    "cello",     "contraba",  "marcato",   "pizzcato",  "harp",      "timpani",
68    "marcato",   "slowstr",   "synstr1",   "synstr2",   "choir",     "doo",
69    "voices",    "orchhit",   "trumpet",   "trombone",  "tuba",      "mutetrum",
70    "frenchorn", "hitbrass",  "synbras1",  "synbras2",  "sprnosax",  "altosax",
71    "tenorsax",  "barisax",   "oboe",      "englhorn",  "bassoon",   "clarinet",
72    "piccolo",   "flute",     "recorder",  "woodflut",  "bottle",    "shakazul",
73    "whistle",   "ocarina",   "sqrwave",   "sawwave",   "calliope",  "chiflead",
74    "charang",   "voxlead",   "lead5th",   "basslead",  "fantasia",  "warmpad",
75    "polysyn",   "ghostie",   "bowglass",  "metalpad",  "halopad",   "sweeper",
76    "aurora",    "soundtrk",  "crystal",   "atmosphr",  "freshair",  "unicorn",
77    "sweeper",   "startrak",  "sitar",     "banjo",     "shamisen",  "koto",
78    "kalimba",   "bagpipes",  "fiddle",    "shannai",   "carillon",  "agogo",
79    "steeldrum", "woodblock", "taiko",     "toms",      "syntom",    "revcymb",
80    "fx-fret",   "fx-blow",   "seashore",  "jungle",    "telephone", "helicptr",
81    "applause",  "ringwhsl"
82 };
83 
84 vector<int> legend_instr;
85 vector<int> legend_opcode;
86 vector<int> legend_controller;
87 
88 // user interface variables
89 Options options;
90 int     debugQ   = 0;           // use with --debug option
91 int     verboseQ = 0;           // used with -v option
92 int     tickQ    = 0;           // used with -t option
93 int     beatQ    = 0;           // used with -b option
94 int     secQ     = 0;           // used with -s option
95 int     msecQ    = 0;           // used with -m option
96 double  unused   = -1000.0;     // used with -u option
97 char    arrayname[1024] = {0};  // used with -n option
98 int     timetype = SEC;
99 int     numQ     = 0;
100 double  tempo    = 60.0;
101 int     maxcount = 100000;
102 vector<vector<double> > matlabarray;
103 
104 // function declarations:
105 void      convertMidiFile       (MidiFile& midifile,
106                                  vector<vector<double> >& matlab);
107 //void    setTempo              (MidiFile& midifile, int index, double& tempo);
108 void      checkOptions          (Options& opts, int argc, char** argv);
109 void      example               (void);
110 void      usage                 (const char* command);
111 double    getTime               (int ticks, MidiFile& midifile);
112 void      processMetaEvent      (MidiFile& midifile, int i,
113                                  vector<double>& event);
114 void      printEvent            (vector<double>& event);
115 void      printLegend           (MidiFile& midifile);
116 void      printMatlabArray      (MidiFile& midifile,
117                                  vector<vector<double> >& matlab);
118 void      sortArray             (vector<vector<double> >& matlab);
119 int       eventcmp              (const void* a, const void* b);
120 void      printOpcodeVariables  (vector<int> opcodes);
121 void      printOpName           (int code);
122 
123 
124 //////////////////////////////////////////////////////////////////////////
125 
main(int argc,char * argv[])126 int main(int argc, char* argv[]) {
127    matlabarray.reserve(100000);
128    matlabarray.clear();
129 
130    legend_instr.resize(128);
131    legend_opcode.resize(128);
132    legend_controller.resize(128);
133 
134    checkOptions(options, argc, argv);
135    MidiFile midifile(options.getArg(1));
136 
137    convertMidiFile(midifile, matlabarray);
138    if (!verboseQ) {
139       printMatlabArray(midifile, matlabarray);
140    }
141    return 0;
142 }
143 
144 //////////////////////////////////////////////////////////////////////////
145 
146 
147 //////////////////////////////
148 //
149 // printOpcodeVariables -- create variables for each type of
150 //  data found in the following array (for readability).
151 //
152 
printOpcodeVariables(vector<int> opcodes)153 void printOpcodeVariables(vector<int> opcodes) {
154    int i;
155    for (i=0; i<(int)opcodes.size(); i++) {
156       if (!opcodes[i]) {
157          continue;
158       }
159       switch (i) {
160          case 1:
161             cout << OP_NOTE_NAME << " = "    << OP_NOTE    << ";" << endl;
162             break;
163          case 2:
164             cout << OP_CONTROL_NAME << " = " << OP_CONTROL << ";" << endl;
165             break;
166          case 3:
167             cout << OP_INSTR_NAME << " = "   << OP_INSTR   << ";" << endl;
168             break;
169          case 4:
170             cout << OP_TEMPO_NAME << " = "   << OP_TEMPO   << ";" << endl;
171             break;
172          case 5:
173             cout << OP_METER_NAME << " = "   << OP_METER   << ";" << endl;
174             break;
175          case 6:
176             cout << OP_KEYSIG_NAME << " = "  << OP_KEYSIG  << ";" << endl;
177             break;
178       }
179    }
180 }
181 
182 
183 
184 //////////////////////////////
185 //
186 // convertMidiFile --
187 //
188 
convertMidiFile(MidiFile & midifile,vector<vector<double>> & matlab)189 void convertMidiFile(MidiFile& midifile, vector<vector<double> >& matlab) {
190    midifile.absoluteTicks();
191    midifile.joinTracks();
192    if (secQ || msecQ) {
193       midifile.doTimeAnalysis();
194    }
195    vector<double> event(7);
196    vector<double> ontimes(128);
197    vector<int> onvelocities(128);
198    int i;
199    for (i=0; i<128; i++) {
200       ontimes[i] = -1.0;
201       onvelocities[i] = -1;
202    }
203 
204    double offtime = 0.0;
205 
206    int key = 0;
207    int vel = 0;
208 
209    if (verboseQ) {
210       cout << "-1\ttpq\t" << midifile.getTicksPerQuarterNote() << endl;
211    }
212 
213    for (i=0; i<midifile.getNumEvents(0); i++) {
214       event.assign(event.size(), unused);
215       int command = midifile[0][i][0] & 0xf0;
216       if (command == 0xf0) {
217          command = midifile[0][i][0];
218       }
219       if (command == 0x90 && midifile[0][i][2] != 0) {
220          // store note-on velocity and time
221          key = midifile[0][i][1];
222          vel = midifile[0][i][2];
223          ontimes[key] = getTime(midifile[0][i].tick, midifile);
224 
225          onvelocities[key] = vel;
226       } else if (command == 0x90 || command == 0x80) {
227          // note off command write to output
228          key = midifile[0][i][1];
229          offtime = getTime(midifile[0][i].tick, midifile);
230          legend_opcode[OP_NOTE/1000] = 1;
231 
232          if (verboseQ) {
233             cout
234               << ontimes[key]
235               << "\tnote"
236               << "\tdur=" << offtime - ontimes[key]
237               << "\tpch=" << key
238               << "\tvel=" << onvelocities[key]
239               << "\tch="  << (midifile[0][i][0] & 0x0f)
240               << "\ttrack=" << midifile[0][i].track
241               << endl;
242          } else {
243             event[0] = ontimes[key];
244             event[1] = OP_NOTE;
245             event[2] = offtime - ontimes[key];
246             event[3] = key;
247             event[4] = onvelocities[key];
248             event[5] = (midifile[0][i][0] & 0x0f);
249             event[6] = midifile[0][i].track;
250          }
251       } else if (command == 0xb0) {
252          legend_controller[midifile[0][i][1]] = 1;
253          legend_opcode[OP_CONTROL/1000] = 1;
254 
255          if (verboseQ) {
256             cout << getTime(midifile[0][i].tick, midifile)
257                  << "\tcontrol"
258                  << "\ttype="  << (int)midifile[0][i][1]
259                  << "\tval="   << (int)midifile[0][i][2]
260                  << "\tch="    << (midifile[0][i][0] & 0x0f)
261                  << "\ttrack=" << midifile[0][i].track
262                  << "\n";
263          } else {
264             event[0] = getTime(midifile[0][i].tick, midifile);
265             event[1] = OP_CONTROL;
266             event[2] = (int)midifile[0][i][1];
267             event[3] = (int)midifile[0][i][2];
268             event[5] = (midifile[0][i][0] & 0x0f);
269             event[6] = midifile[0][i].track;
270          }
271       } else if (command == 0xc0) {
272          legend_instr[midifile[0][i][1]] = 1;
273          legend_opcode[OP_INSTR/1000] = 1;
274 
275          if (verboseQ) {
276          cout << getTime(midifile[0][i].tick, midifile)
277               << "\tinstr"
278               << "\tname="  << GMinstrument[midifile[0][i][1]]
279               << "\tnum="   << (int)midifile[0][i][1]
280               << "\tch="    << (midifile[0][i][0] & 0x0f)
281               << "\ttrack=" << midifile[0][i].track
282               << "\n";
283          } else {
284             event[0] = getTime(midifile[0][i].tick, midifile);
285             event[1] = OP_INSTR;
286             event[2] = (int)midifile[0][i][1];
287             event[5] = (midifile[0][i][0] & 0x0f);
288             event[6] = midifile[0][i].track;
289          }
290       } else if (command == 0xff) {
291          if (verboseQ) {
292             cout << getTime(midifile[0][i].tick, midifile)
293                  << "\t";
294          } else {
295             event[0] = getTime(midifile[0][i].tick, midifile);
296          }
297          processMetaEvent(midifile, i, event);
298          if (verboseQ) {
299             cout << "\n";
300          }
301       }
302 
303       /* no longer needed
304       // check for tempo indication
305       if (midifile[0][i][0] == 0xff &&
306                  midifile[0][i][1] == 0x51) {
307          setTempo(midifile, i, tempo);
308 
309       }
310       */
311 
312       if (event[1] != unused) {
313          matlab.push_back(event);
314       }
315    }
316 
317 }
318 
319 
320 
321 //////////////////////////////
322 //
323 // processMetaEvent -- Handle meta events.
324 //
325 
processMetaEvent(MidiFile & midifile,int i,vector<double> & event)326 void processMetaEvent(MidiFile& midifile, int i, vector<double>& event) {
327    MidiEvent& mfevent = midifile[0][i];
328 
329    switch (mfevent[1]) {
330       case 0x51:  // tempo change
331          legend_opcode[OP_TEMPO/1000] = 1;
332          event[1] = OP_TEMPO;
333          event[2] = mfevent.getTempoBPM();
334          break;
335 
336       case 0x58:  // time signature
337          // 58 04 nn dd cc bb
338          //  nn=numerator of time sig.
339          //  dd=denominator of time sig. 2=quarter
340          //  3=eighth, etc.
341          //  cc=number of ticks in metronome click
342          //  bb=number of 32nd notes to the quarter note
343          if (verboseQ) {
344             cout << "%meter\t" << (int)mfevent[2] << "/" << pow(2.0, mfevent[3]);
345          } else {
346             legend_opcode[OP_METER/1000] = 1;
347             event[1] = OP_METER;
348             event[2] = (int)mfevent[2];
349             event[3] = pow(2.0, mfevent[3]);
350          }
351          break;
352 
353       case 0x59:  // key signature
354          // 59 02 sf mi
355          // sf=sharps/flats (-7=7 flats, 0=key of C, 7=7 sharps)
356          // mi=major/minor (0=major, 1=minor)
357          if (verboseQ) {
358             cout << "%keysig\t";
359             if (mfevent[3]==0) {
360                switch (mfevent[2]) {
361                   case 0: cout << "C-major"; break;
362                   case 1: cout << "G-major"; break;
363                   case 2: cout << "D-major"; break;
364                   case 3: cout << "A-major"; break;
365                   case 4: cout << "E-major"; break;
366                   case 5: cout << "B-major"; break;
367                   case 6: cout << "F-sharp-major"; break;
368                   case 7: cout << "C-sharp-major"; break;
369                }
370             } else {
371                switch (mfevent[2]) {
372                   case 0: cout << "A-minor"; break;
373                   case 1: cout << "E-minor"; break;
374                   case 2: cout << "B-minor"; break;
375                   case 3: cout << "F-minor"; break;
376                   case 4: cout << "C-sharp-minor"; break;
377                   case 5: cout << "G-sharp-minor"; break;
378                   case 6: cout << "D-sharp-minor"; break;
379                   case 7: cout << "A-sharp-minor"; break;
380                }
381             }
382          } else {
383             legend_opcode[OP_KEYSIG/1000] = 1;
384             event[1] = OP_KEYSIG;
385             event[2] = (int)mfevent[2];
386             event[3] = (int)mfevent[3];
387          }
388          break;
389       default:
390          if (verboseQ) {
391             cout << "%meta\t0x" << hex << (int)mfevent[1] << dec;
392          }
393    }
394 }
395 
396 
397 
398 //////////////////////////////
399 //
400 // getTime -- return the time in command-line specified time unit
401 //
402 
getTime(int ticks,MidiFile & midifile)403 double getTime(int ticks, MidiFile& midifile) {
404    int tpq = midifile.getTicksPerQuarterNote();
405    switch (timetype) {
406       case TICK:
407          return ticks;
408       case BEAT:
409          return (double)ticks/tpq;
410       case SEC:
411          return midifile.getTimeInSeconds(ticks);
412       case MSEC:
413          return 1000 * midifile.getTimeInSeconds(ticks);
414    }
415    return 0.0;
416 }
417 
418 
419 
420 /* obsolete function
421 //////////////////////////////
422 //
423 // setTempo -- set the current tempo
424 //
425 
426 void setTempo(MidiFile& midifile, int index, double& tempo) {
427    double newtempo = 0.0;
428    static int count = 0;
429    count++;
430    vector<double> event;
431    event.assign(7, unused);
432 
433    MidiEvent& mididata = midifile[0][index];
434 
435    int microseconds = 0;
436    microseconds = microseconds | (mididata.data[3] << 16);
437    microseconds = microseconds | (mididata.data[4] << 8);
438    microseconds = microseconds | (mididata.data[5] << 0);
439 
440    newtempo = 60.0 / microseconds * 1000000.0;
441    if (count <= 1) {
442       tempo = newtempo;
443    } else if (tempo != newtempo) {
444       if (verboseQ) {
445          cout << getTime(midifile[0][index].tick, midifile);
446               << "\t"
447               << "tempo\t" << newtempo << endl;
448       } else {
449          legend_opcode[OP_TEMPO/1000] = 1;
450          event[0] = getTime(midifile[0][index].tick, midifile);
451          event[1] = OP_TEMPO;
452          event[2] = newtempo;
453          matlabarray.push_back(event);
454       }
455    }
456    tempo = newtempo;
457 }
458 */
459 
460 
461 
462 //////////////////////////////
463 //
464 // checkOptions --
465 //
466 
checkOptions(Options & opts,int argc,char * argv[])467 void checkOptions(Options& opts, int argc, char* argv[]) {
468    opts.define("u|unused=d:-1000.0",             "unused parameter indicator");
469    opts.define("n|name=s:data",                     "name for data array");
470    opts.define("t|ticks|tick=b",                    "display time in ticks");
471    opts.define("s|sec|second|seconds=b",            "display time in seconds");
472    opts.define("m|msec|millisecond|milliseconds=b", "display time in msec");
473    opts.define("b|beat|beats=b",                    "display time in beats");
474    opts.define("num=b",                        "display opcodes as numbers");
475    opts.define("v|verbose=b",                       "display verbose data");
476 
477    opts.define("author=b",  "author of program");
478    opts.define("version=b", "compilation info");
479    opts.define("example=b", "example usages");
480    opts.define("h|help=b",  "short description");
481 
482    opts.define("debug=b",  "debug mode to find errors in input file");
483    opts.define("max=i:100000", "maximum number of notes expected in input");
484 
485    opts.process(argc, argv);
486 
487    // handle basic options:
488    if (opts.getBoolean("author")) {
489       cout << "Written by Craig Stuart Sapp, "
490            << "craig@ccrma.stanford.edu, 22 Jan 2002" << endl;
491       exit(0);
492    } else if (opts.getBoolean("version")) {
493       cout << argv[0] << ", version: 12 Nov 2003" << endl;
494       cout << "compiled: " << __DATE__ << endl;
495       exit(0);
496    } else if (opts.getBoolean("help")) {
497       usage(opts.getCommand().c_str());
498       exit(0);
499    } else if (opts.getBoolean("example")) {
500       example();
501       exit(0);
502    }
503 
504    unused   = opts.getDouble("unused");
505    debugQ   = opts.getBoolean("debug");
506    maxcount = opts.getInteger("max");
507    numQ     = opts.getBoolean("num");
508 
509    if (opts.getArgCount() != 1) {
510       usage(opts.getCommand().c_str());
511       exit(1);
512    }
513 
514    tickQ = opts.getBoolean("ticks");
515    secQ  = opts.getBoolean("seconds");
516    msecQ = opts.getBoolean("milliseconds");
517    beatQ = opts.getBoolean("beats");
518    strcpy(arrayname, opts.getString("name").c_str());
519 
520    if (tickQ) {
521       timetype = TICK;
522       if (verboseQ) {
523          cout << "-1\ttunit\tticks\n";
524       }
525    } else if (beatQ) {
526       timetype = BEAT;
527       if (verboseQ) {
528          cout << "-1\ttunit\tbeat\n";
529       }
530    } else if (secQ) {
531       timetype = SEC;
532       if (verboseQ) {
533          cout << "-1\ttunit\tseconds\n";
534       }
535    } else if (msecQ) {
536       timetype = MSEC;
537       if (verboseQ) {
538          cout << "-1\ttunit\tmilliseconds\n";
539       }
540    } else {
541       timetype = BEAT;
542       if (verboseQ) {
543          cout << "-1\ttunit\tseconds\n";
544       }
545    }
546 }
547 
548 
549 
550 //////////////////////////////
551 //
552 // example --
553 //
554 
example(void)555 void example(void) {
556 
557 }
558 
559 
560 
561 //////////////////////////////
562 //
563 // usage --
564 //
565 
usage(const char * command)566 void usage(const char* command) {
567    cout << "Usage: " << command << " midifile" << endl;
568 }
569 
570 
571 
572 //////////////////////////////
573 //
574 // printLegend -- print a legend of the codes in the data.
575 //
576 
577 const char *GMcontrollers[128] = {
578    "  0   Bank Select (coarse)               0..127",
579    "  1   Modulation Wheel (coarse)          0..127",
580    "  2   Breath Control (coarse)            0..127",
581    "  3   Continuous controller #3           0..127",
582    "  4   Foot Controller (coarse)           0..127",
583    "  5   Portamento Time (coarse)           0..127",
584    "  6   Data Entry Slider (coarse)         0..127",
585    "  7   Main Volume (coarse)               0..127",
586    "  8   Stereo Balance (coarse)            0..127",
587    "  9   Continuous controller #9           0..127",
588    " 10   Pan (coarse)                       0=left 127=right",
589    " 11   Expression (sub-Volume) (coarse)   0..127",
590    " 12   Effect Control 1 (coarse)          0..127",
591    " 13   Effect Control 2 (coarse)          0..127",
592    " 14   Continuous controller #14          0..127",
593    " 15   Continuous controller #15          0..127",
594    " 16   General Purpose Slider 1           0..127",
595    " 17   General Purpose Slider 2           0..127",
596    " 18   General Purpose Slider 3           0..127",
597    " 19   General Purpose Slider 4           0..127",
598    " 20   Continuous controller #20          0..127",
599    " 21   Continuous controller #21          0..127",
600    " 22   Continuous controller #22          0..127",
601    " 23   Continuous controller #23          0..127",
602    " 24   Continuous controller #24          0..127",
603    " 25   Continuous controller #25          0..127",
604    " 26   Continuous controller #26          0..127",
605    " 27   Continuous controller #27          0..127",
606    " 28   Continuous controller #28          0..127",
607    " 29   Continuous controller #29          0..127",
608    " 30   Continuous controller #30          0..127",
609    " 31   Continuous controller #31          0..127",
610    " 32   Bank Select (fine)                 0..127 usu.ignored",
611    " 33   Modulation Wheel (fine)            0..127",
612    " 34   Breath Control (fine)              0..127",
613    " 35   Continuous controller #3 (fine)    0..127",
614    " 36   Foot Controller (fine)             0..127",
615    " 37   Portamento Time (fine)             0..127",
616    " 38   Data Entry Slider (fine)           0..127",
617    " 39   Main Volume (fine)                 0..127 usu. ignored",
618    " 40   Stereo Balance (fine)              0..127",
619    " 41   Continuous controller #9 (fine)    0..127",
620    " 42   Pan (fine)                         0..127 usu. ignored",
621    " 43   Expression (sub-Volume) (fine)     0..127 usu. ignored",
622    " 44   Effect Control 1 (fine)            0..127",
623    " 45   Effect Control 2 (fine)            0..127",
624    " 46   Continuous controller #14 (fine)   0..127",
625    " 47   Continuous controller #15 (fine)   0..127",
626    " 48   Continuous controller #16          0..127",
627    " 49   Continuous controller #17          0..127",
628    " 50   Continuous controller #18          0..127",
629    " 51   Continuous controller #19          0..127",
630    " 52   Continuous controller #20 (fine)   0..127",
631    " 53   Continuous controller #21 (fine)   0..127",
632    " 54   Continuous controller #22 (fine)   0..127",
633    " 55   Continuous controller #23 (fine)   0..127",
634    " 56   Continuous controller #24 (fine)   0..127",
635    " 57   Continuous controller #25 (fine)   0..127",
636    " 58   Continuous controller #26 (fine)   0..127",
637    " 59   Continuous controller #27 (fine)   0..127",
638    " 60   Continuous controller #28 (fine)   0..127",
639    " 61   Continuous controller #29 (fine)   0..127",
640    " 62   Continuous controller #30 (fine)   0..127",
641    " 63   Continuous controller #31 (fine)   0..127",
642    " 64   Hold pedal (Sustain) on/off        0..63=off  64..127=on",
643    " 65   Portamento on/off                  0..63=off  64..127=on",
644    " 66   Sustenuto Pedal on/off             0..63=off  64..127=on",
645    " 67   Soft Pedal on/off                  0..63=off  64..127=on",
646    " 68   Legato Pedal on/off                0..63=off  64..127=on",
647    " 69   Hold Pedal 2 on/off                0..63=off  64..127=on",
648    " 70   Sound Variation                    0..127",
649    " 71   Sound Timbre                       0..127",
650    " 72   Sound Release Time                 0..127",
651    " 73   Sound Attack Time                  0..127",
652    " 74   Sound Brighness                    0..127",
653    " 75   Sound Control 6                    0..127",
654    " 76   Sound Control 7                    0..127",
655    " 77   Sound Control 8                    0..127",
656    " 78   Sound Control 9                    0..127",
657    " 79   Sound Control 10                   0..127",
658    " 80   General Purpose Button             0..63=off 64..127=on",
659    " 81   General Purpose Button             0..63=off 64..127=on",
660    " 82   General Purpose Button             0..63=off 64..127=on",
661    " 83   General Purpose Button             0..63=off 64..127=on",
662    " 84   Undefined on/off                   0..63=off 64..127=on",
663    " 85   Undefined on/off                   0..63=off 64..127=on",
664    " 86   Undefined on/off                   0..63=off 64..127=on",
665    " 87   Undefined on/off                   0..63=off 64..127=on",
666    " 88   Undefined on/off                   0..63=off 64..127=on",
667    " 89   Undefined on/off                   0..63=off 64..127=on",
668    " 90   Undefined on/off                   0..63=off 64..127=on",
669    " 91   Effects Level                      0..127",
670    " 92   Tremulo Level                      0..127",
671    " 93   Chorus Level                       0..127",
672    " 94   Celeste (Detune) Level             0..127",
673    " 95   Phaser Level                       0..127",
674    " 96   Data entry +1                      ignored",
675    " 97   Data entry -1                      ignored",
676    " 98   Non-Registered Parameter Number (coarse)0..127",
677    " 99   Non-Registered Parameter Number (fine)  0..127",
678    "100   Registered Parameter Number (coarse)    0..127",
679    "101   Registered Parameter Number (fine) 0..127",
680    "102   Undefined                          ?",
681    "103   Undefined                          ?",
682    "104   Undefined                          ?",
683    "105   Undefined                          ?",
684    "106   Undefined                          ?",
685    "107   Undefined                          ?",
686    "108   Undefined                          ?",
687    "109   Undefined                          ?",
688    "110   Undefined                          ?",
689    "111   Undefined                          ?",
690    "112   Undefined                          ?",
691    "113   Undefined                          ?",
692    "114   Undefined                          ?",
693    "115   Undefined                          ?",
694    "116   Undefined                          ?",
695    "117   Undefined                          ?",
696    "118   Undefined                          ?",
697    "119   Undefined                          ?",
698    "120   All Sound Off                      ignored",
699    "121   All Controllers Off                ignored",
700    "122   Local Keyboard On/Off              0..63=off 64..127=on",
701    "123   All Notes Off                      ignored",
702    "124   Omni Mode Off                      ignored",
703    "125   Omni Mode On                       ignored",
704    "126   Monophonic Mode On                 **",
705    "127   Polyphonic Mode On (mono=off)      ignored"
706 };
707 
708 
printLegend(MidiFile & midifile)709 void printLegend(MidiFile& midifile) {
710    int sum = 0;
711    int i;
712 
713    cout << "\n";
714    cout << "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n";
715    cout << "%% DATA LEGEND                                               %%\n";
716    cout << "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n";
717    cout << "%%Filename: " << midifile.getFilename() << endl;
718    cout << "%%Ticks per quarter note: " << midifile.getTicksPerQuarterNote()
719         << "\n";
720    cout << "%%Time units used in column 1: ";
721    switch (timetype) {
722       case TICK: cout << "ticks\n";         break;
723       case BEAT: cout << "beat\n";          break;
724       case SEC:  cout << "seconds\n";       break;
725       case MSEC: cout << "milliseconds\n";  break;
726       default:   cout << "unknown\n";
727 
728    }
729    // cout << "% unused parameter marker: " << unused << "\n";
730    // check for opcodes used in data:
731    sum = 0;
732    for (i=0; i<(int)legend_opcode.size(); i++) {
733       sum += legend_opcode[i];
734    }
735    if (sum > 0) {
736       cout << "% " << sum << " opcodes are present in the data:\n";
737       for (i=0; i<(int)legend_opcode.size(); i++) {
738          if (legend_opcode[i]) {
739             switch (i*1000) {
740                case OP_NOTE:
741                   cout << "%\topcode " << OP_NOTE << "\t= note\n";
742                   cout << "%\t   column 1 = start time of note\n";
743                   cout << "%\t   column 2 = opcode for note\n";
744                   cout << "%\t   column 3 = duration of note\n";
745                   cout << "%\t   column 4 = MIDI key number\n";
746                   cout << "%\t   column 5 = MIDI attack velocity\n";
747                   cout << "%\t   column 6 = MIDI channel\n";
748                   cout << "%\t   column 7 = MIDI-file track number\n";
749                   break;
750                case OP_TEMPO:
751                   cout << "%\topcode " << OP_TEMPO << "\t= tempo change\n";
752                   cout << "%\t   column 1 = start time of tempo\n";
753                   cout << "%\t   column 2 = opcode for tempo\n";
754                   cout << "%\t   column 3 = number of beats per minute\n";
755                   cout << "%\t   column 4-7 = unused\n";
756                   break;
757                case OP_CONTROL:
758                   cout << "%\topcode " << OP_CONTROL
759                        << "\t= continuous controller\n";
760                   cout << "%\t   column 1 = action time of controller\n";
761                   cout << "%\t   column 2 = opcode for controller\n";
762                   cout << "%\t   column 3 = controller number\n";
763                   cout << "%\t   column 4 = controller value\n";
764                   cout << "%\t   column 5 = unused\n";
765                   cout << "%\t   column 6 = MIDI channel\n";
766                   cout << "%\t   column 7 = MIDI-file track number\n";
767                   break;
768                case OP_INSTR:
769                   cout << "%\topcode " << OP_INSTR << "\t= instrument\n";
770                   cout << "%\t   column 1 = start time of instrument on channel\n";
771                   cout << "%\t   column 2 = opcode for instrument\n";
772                   cout << "%\t   column 3 = instrument number\n";
773                   cout << "%\t   column 4-5 = unused\n";
774                   cout << "%\t   column 6 = MIDI channel\n";
775                   cout << "%\t   column 7 = MIDI-file track number\n";
776                   break;
777                case OP_METER:
778                   cout << "%\topcode " << OP_METER << "\t= meter signature\n";
779                   cout << "%\t   column 1 = start time of meter signature\n";
780                   cout << "%\t   column 2 = opcode for meter\n";
781                   cout << "%\t   column 3 = numerator of meter\n";
782                   cout << "%\t   column 4 = denominator of meter\n";
783                   cout << "%\t   column 5-7 = unused\n";
784                   break;
785                case OP_KEYSIG:
786                   cout << "%\topcode " << OP_KEYSIG << "\t= key signature\n";
787                   cout << "%\t   column 1 = start time of key signature\n";
788                   cout << "%\t   column 2 = opcode for key signature\n";
789                   cout << "%\t   column 3 = number of sharps (positive) or flats (negative)\n";
790                   cout << "%\t   column 4 = mode (0=major, 1=minor)\n";
791                   cout << "%\t   column 5-7 = unused\n";
792                   break;
793                default:
794                   cout << "%\topcode " << i*1000 << "\t= unknown\n";
795             }
796          }
797       }
798    }
799 
800 
801    // check for instruments to list:
802    sum = 0;
803    for (i=0; i<(int)legend_instr.size(); i++) {
804       sum += legend_instr[i];
805    }
806    if (sum > 0) {
807       if (sum == 1) {
808          cout << "% " << sum << " instrument timbre is present in the data:\n";
809       } else {
810          cout << "% " << sum << " instrument timbres are present in the data:\n";
811       }
812       for (i=0; i<(int)legend_instr.size(); i++) {
813          if (legend_instr[i]) {
814             cout << "%\tinstrument number " << i << "\t= "
815                  << GMinstrument[i] << "\n";
816          }
817       }
818    }
819 
820    // check for controllers to list:
821    sum = 0;
822    for (i=0; i<(int)legend_controller.size(); i++) {
823       sum += legend_controller[i];
824    }
825    if (sum > 0) {
826       if (sum == 1) {
827       cout << "% " << sum << " type of controller is present in the data:\n";
828       } else {
829       cout << "% " << sum << " types of controllers are present in the data:\n";
830       }
831       for (i=0; i<(int)legend_controller.size(); i++) {
832          if (legend_controller[i]) {
833             cout << "%\tcontroller " << GMcontrollers[i] << "\n";
834          }
835       }
836    }
837 
838    cout << "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n";
839    cout << endl;
840 
841 }
842 
843 
844 
845 //////////////////////////////
846 //
847 // printMatlabArray -- print the Matlab array representing the MIDI file.
848 //
849 
printMatlabArray(MidiFile & midifile,vector<vector<double>> & matlab)850 void printMatlabArray(MidiFile& midifile, vector<vector<double> >& matlab) {
851    int i;
852    sortArray(matlab);
853    printLegend(midifile);
854    if (!numQ) {
855       printOpcodeVariables(legend_opcode);
856    }
857    cout << arrayname << " = [\n";
858    for (i=0; i<(int)matlab.size(); i++) {
859       printEvent(matlab[i]);
860    }
861    cout << "];\n";
862 }
863 
864 
865 
866 //////////////////////////////
867 //
868 // sortArray -- sort the input file into time order because
869 //   the notes may be slightly out of time order.
870 //
871 
sortArray(vector<vector<double>> & matlab)872 void sortArray(vector<vector<double> >& matlab) {
873    qsort(matlab.data(), matlab.size(), sizeof(vector<double>), eventcmp);
874 }
875 
876 
877 
878 //////////////////////////////
879 //
880 // eventcmp -- compare two events and determine which should come
881 //    first in time.
882 //
883 
eventcmp(const void * a,const void * b)884 int eventcmp(const void* a, const void* b) {
885    vector<double>& A = *((vector<double>*)a);
886    vector<double>& B = *((vector<double>*)b);
887 
888    if (A[0] < B[0]) {
889       return -1;
890    } else if (A[0] > B[0]) {
891       return 1;
892    } else {
893       return 0;   // there is a tie if they come at the same time.
894    }
895 }
896 
897 
898 
899 //////////////////////////////
900 //
901 // printOpName -- print the OpCode's symbolic name for better
902 // readability.
903 //
904 
printOpName(int code)905 void printOpName(int code) {
906    switch (code) {
907 
908       case OP_NOTE:
909          cout << OP_NOTE_NAME;
910          break;
911       case OP_CONTROL:
912          cout << OP_CONT_NAME;
913          break;
914       case OP_INSTR:
915          cout << OP_INSTR_NAME;
916          break;
917       case OP_TEMPO:
918          cout << OP_TEMPO_NAME;
919          break;
920       case OP_METER:
921          cout << OP_METER_NAME;
922          break;
923       case OP_KEYSIG:
924          cout << OP_KEYSIG_NAME;
925          break;
926       default:
927          cout << code;
928 
929    }
930 }
931 
932 
933 
934 //////////////////////////////
935 //
936 // printEvent -- print the event
937 //
938 
printEvent(vector<double> & event)939 void printEvent(vector<double>& event) {
940    int i;
941    for (i=0; i<(int)event.size(); i++) {
942       if ((i == 1) && (!numQ)) {
943          printOpName((int)event[i]);
944          cout << ",\t";
945          continue;
946       }
947       cout << event[i];
948       // if ((i==0) && (event[i] - (int)event[i] == 0.0)) {
949       //    cout << ".0000";
950       //    if (event[i] < 10) {
951       //       cout << "0";
952       //    }
953       // }
954       if (i<(int)event.size()-1) {
955          cout << ",\t";
956       }
957    }
958    cout << ";\n";
959 }
960 
961 
962 
963