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