├── README.md ├── LICENSE └── midi_main.cpp /README.md: -------------------------------------------------------------------------------- 1 | # MIDI parser 2 | A simple .mid files parser that outputs in a plain text format MIDI events and their absolute timestamps in milliseconds (instead of relative timing between MIDI events) 3 | output format: 4 | time_in_milliseconds,track_number,channel,event_type,key,value 5 | Saved event types are: 6 | Note off - 0, 7 | Note on - 1, 8 | Aftertouch - 2 9 | Controller change - 3 10 | Program change - 4 (key is set to 255, program number stored in value field) 11 | Channel Key Pressure - 5 (key is set to 255, pressure stored in value field) 12 | Pitch Bend - 6 (key is set to 255, pitch value stored in value field as signed 16 bit integer) 13 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 ultimaterobotics 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /midi_main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #define SEND_NOTE_OFF 0b00000001 9 | #define SEND_NOTE_ON 0b00000010 10 | #define SEND_AFTERTOUCH 0b00000100 11 | #define SEND_CTRL_CHANGE 0b00001000 12 | #define SEND_PROG_CHANGE 0b00010000 13 | #define SEND_CHAN_KEYPRES 0b00100000 14 | #define SEND_PITCH_BEND 0b01000000 15 | #define SEND_TRACK_END 0b10000000 16 | 17 | enum e_event_types 18 | { 19 | evt_note_off = 0, 20 | evt_note_on, 21 | evt_aftertouch, 22 | evt_ctrl_change, 23 | evt_prog_change, 24 | evt_chan_keypress, 25 | evt_pitch_bend, 26 | evt_track_end 27 | }; 28 | 29 | int str_eq(const char *t1, const char *t2) 30 | { 31 | int x = 0; 32 | if(t1 == NULL && t2 == NULL) return 1; 33 | if(t1 == NULL || t2 == NULL) return 0; 34 | while(t1[x] != 0 && t2[x] != 0) 35 | { 36 | if(t1[x] != t2[x]) return 0; 37 | ++x; 38 | } 39 | if(t1[x] != t2[x]) return 0; 40 | return 1; 41 | } 42 | 43 | int parse_vbl(uint8_t *buf, uint32_t *res) 44 | { 45 | uint32_t val = 0; 46 | int pp = 0; 47 | while(buf[pp] & 0x80) 48 | { 49 | val += buf[pp] & 0x7F; 50 | val <<= 7; 51 | pp++; 52 | } 53 | val += buf[pp]; 54 | *res = val; 55 | return pp+1; 56 | } 57 | 58 | float ticks_to_ms = 1.0; 59 | uint32_t ticks_per_qn = 1000; 60 | uint32_t micros_per_qn = 800000; 61 | 62 | 63 | #define MAX_TEMPO_POINTS 10000 64 | int tempo_points = 0; 65 | uint32_t tempo_ms[MAX_TEMPO_POINTS]; 66 | uint32_t tempo_value[MAX_TEMPO_POINTS]; 67 | 68 | typedef struct sMIDI_event 69 | { 70 | uint8_t active; //whant to turn off some events during post processing 71 | uint32_t T; 72 | uint8_t type; 73 | uint8_t track; 74 | uint8_t channel; 75 | uint8_t key; 76 | int value; //stores also pitch bend values 77 | void set_to(sMIDI_event e) 78 | { 79 | active = e.active; 80 | T = e.T; 81 | type = e.type; 82 | track = e.track; 83 | channel = e.channel; 84 | key = e.key; 85 | value = e.value; 86 | }; 87 | }sMIDI_event; 88 | 89 | sMIDI_event *events; 90 | int events_count = 0; 91 | int events_size = 0; 92 | int event_count_memstep = 100; 93 | 94 | int zero_to_off = 0; 95 | 96 | void add_event(sMIDI_event evt) 97 | { 98 | if(events_count >= events_size) 99 | { 100 | events_size += event_count_memstep; 101 | sMIDI_event *ee = new sMIDI_event[events_size]; 102 | for(int x = 0; x < events_count; x++) 103 | ee[x].set_to(events[x]); 104 | delete events; 105 | events = ee; 106 | } 107 | events[events_count].set_to(evt); 108 | if(zero_to_off) 109 | if(events[events_count].type == evt_note_on && events[events_count].value == 0) 110 | { 111 | events[events_count].type = evt_note_off; 112 | events[events_count].value = 64; 113 | } 114 | 115 | events_count++; 116 | } 117 | 118 | void sort_events() 119 | { 120 | for(int n = 0; n < events_count; n++) 121 | { 122 | for(int n2 = n+1; n2 < events_count; n2++) 123 | { 124 | if(events[n2].T < events[n].T) 125 | { 126 | sMIDI_event ee; 127 | ee.set_to(events[n]); 128 | events[n].set_to(events[n2]); 129 | events[n2].set_to(ee); 130 | } 131 | } 132 | } 133 | } 134 | 135 | void process_overlaps(int overlap_master) 136 | { 137 | // printf("overlaps:\n"); 138 | uint8_t keys_on[255]; 139 | int keys_last_time[255]; 140 | for(int x = 0; x < 255; x++) 141 | { 142 | keys_on[x] = 0; 143 | keys_last_time[x] = -1; 144 | } 145 | int cur_events_count = events_count; 146 | for(int n = 0; n < cur_events_count; n++) 147 | { 148 | sMIDI_event *evt = events+n; 149 | if(evt->type < 2) 150 | { 151 | if(evt->T - keys_last_time[evt->key] < 1) 152 | { 153 | evt->T++; //potentially can lead to wrong events order in the output, but practically unlikely 154 | // printf("shifted at %d\n", evt->T); 155 | } 156 | keys_last_time[evt->key] = evt->T; 157 | } 158 | if(evt->type == 1 && evt->value > 0) 159 | { 160 | if(keys_on[evt->key]) 161 | { 162 | sMIDI_event e2; 163 | e2.set_to(*evt); 164 | e2.type = evt_note_off; 165 | e2.value = 0; 166 | e2.T = evt->T-1; 167 | add_event(e2); 168 | // if(evt->track == overlap_master) 169 | // keys_on[evt->key]++; 170 | // evt->active = 0; 171 | // printf("inserted cut at %d\n", e2.T); 172 | } 173 | keys_on[evt->key] = 1; 174 | } 175 | if(evt->type == 0 || evt->value == 0) 176 | { 177 | // if(keys_on[evt->key] > 1) 178 | // { 179 | // keys_on[evt->key]--; 180 | // evt->active = 0; 181 | // printf("cut at %d\n", evt->T); 182 | // } 183 | // else keys_on[evt->key] = 0; 184 | if(keys_on[evt->key] == 0) evt->active = 0; 185 | keys_on[evt->key] = 0; 186 | } 187 | } 188 | sort_events(); 189 | } 190 | 191 | int get_next_keyup(uint32_t cur_time, int key) 192 | { 193 | uint32_t min_ok_time = 0xFFFFFFFF; 194 | int id = -1; 195 | for(int n = 0; n < events_count; n++) 196 | { 197 | if(!events[n].active) continue; 198 | if(events[n].key == key && events[n].T > cur_time && events[n].T < min_ok_time) 199 | { 200 | if(events[n].type == evt_note_off || (events[n].type == evt_note_on && events[n].value == 0)) 201 | { 202 | min_ok_time = events[n].T; 203 | id = n; 204 | } 205 | } 206 | } 207 | return id; 208 | } 209 | 210 | int get_next_keydown(uint32_t cur_time, int key) 211 | { 212 | uint32_t min_ok_time = 0xFFFFFFFF; 213 | int id = -1; 214 | for(int n = 0; n < events_count; n++) 215 | { 216 | if(!events[n].active) continue; 217 | if(events[n].key == key && events[n].T > cur_time && events[n].T < min_ok_time) 218 | { 219 | if(events[n].type == evt_note_on && events[n].value > 0) 220 | { 221 | min_ok_time = events[n].T; 222 | id = n; 223 | } 224 | } 225 | } 226 | return id; 227 | } 228 | 229 | //all intervals in milliseconds 230 | #define MIN_NOTE_LENGTH 90 231 | #define MIN_NOTE_GAP 80 232 | #define MULTIPLIER_SPLIT_RELEASE_TIME 0.68 233 | #define SHORT_NOTE_MULT 2.0 234 | 235 | #define NOTE_LOW_VALUE 135 236 | #define NOTE_HIGH_VALUE 155 237 | #define NOTE_HOLD_VALUE 75 238 | #define NOTE_ON_TO_HOLD 90 239 | 240 | float key_coeffs[150]; 241 | float key_shifts[150]; 242 | 243 | void init_volume_coeffs() 244 | { 245 | for(int x = 0; x < 150; x++) 246 | { 247 | key_coeffs[x] = 1.0; 248 | key_shifts[x] = 0.0; 249 | } 250 | } 251 | void process_volume() 252 | { 253 | float vmin = NOTE_LOW_VALUE; 254 | float range = NOTE_HIGH_VALUE - NOTE_LOW_VALUE; 255 | for(int n = 0; n < events_count; n++) 256 | { 257 | if(!events[n].active) continue; 258 | if(events[n].type == evt_note_on) 259 | { 260 | float val = events[n].value; 261 | val /= 255.0; 262 | val *= key_coeffs[events[n].key]; 263 | val = vmin + val*range + key_shifts[events[n].key]; 264 | events[n].value = val; 265 | } 266 | } 267 | } 268 | 269 | void note_postprocessor() 270 | { 271 | init_volume_coeffs(); 272 | process_volume(); 273 | for(int n = 0; n < events_count; n++) 274 | { 275 | if(!events[n].active) continue; 276 | if(events[n].type == evt_note_on) 277 | { 278 | int up = get_next_keyup(events[n].T, events[n].key); 279 | if(up < 0) continue; 280 | int down = get_next_keydown(events[up].T, events[up].key); 281 | if(down < 0) continue; 282 | uint32_t gap = events[down].T - events[up].T; 283 | double dt = events[down].T - events[n].T; 284 | if(gap < MIN_NOTE_GAP) 285 | { 286 | events[up].T = events[n].T + (1.0-MULTIPLIER_SPLIT_RELEASE_TIME)*dt; 287 | uint32_t len = events[up].T - events[n].T; 288 | if(len < MIN_NOTE_LENGTH) //subject to volume increase 289 | { 290 | float coeff = (double)len / (double)MIN_NOTE_LENGTH; 291 | float val = events[n].value - NOTE_LOW_VALUE; 292 | val *= SHORT_NOTE_MULT * (1.0 - coeff)*(1.0 - coeff); 293 | val += NOTE_LOW_VALUE; 294 | if(val > 255) val = 255; 295 | events[n].value = val; 296 | } 297 | } 298 | } 299 | } 300 | 301 | int cur_events_count = events_count; 302 | for(int n = 0; n < cur_events_count; n++) 303 | { 304 | if(!events[n].active) continue; 305 | if(events[n].type == evt_note_on && events[n].value > 0) 306 | { 307 | int up = get_next_keyup(events[n].T, events[n].key); 308 | if(up < 0) 309 | continue; 310 | if(events[up].T > events[n].T + NOTE_ON_TO_HOLD) 311 | { 312 | sMIDI_event evt; 313 | evt.set_to(events[n]); 314 | evt.T = events[n].T + NOTE_ON_TO_HOLD; 315 | evt.value = NOTE_HOLD_VALUE; 316 | add_event(evt); 317 | } 318 | } 319 | } 320 | sort_events(); 321 | } 322 | 323 | void save_python_script(char *fname, uint64_t track_mask) 324 | { 325 | int handle = open(fname, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH); 326 | 327 | if(handle < 1) 328 | { 329 | fprintf(stderr, "can't open/create output file %s\n", fname); 330 | return; 331 | } 332 | 333 | char tbuf[1024]; 334 | int len; 335 | 336 | len = sprintf(tbuf, "import serial\n"); 337 | len += sprintf(tbuf+len, "import time\n"); 338 | len += sprintf(tbuf+len, "ser = serial.Serial('COM3', 115200, timeout=5)\n"); 339 | len += sprintf(tbuf+len, "time.sleep(3)\n\n"); 340 | len += sprintf(tbuf+len, "#\n"); 341 | len += sprintf(tbuf+len, "ser.write('<0,0,0,8,0,0>')\n"); 342 | write(handle, tbuf, len); 343 | for(int x = 0; x < events_count; x++) 344 | { 345 | if(!((1<')\nser.readline()\n", events[x].T, events[x].track, events[x].channel, events[x].type, events[x].key, events[x].value); 350 | if(write(handle, tbuf, len) < len) 351 | fprintf(stderr, "write %d bytes failed\n", len); 352 | 353 | } 354 | close(handle); 355 | } 356 | 357 | 358 | void save_events(char *fname, uint64_t track_mask) 359 | { 360 | int handle = open(fname, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH); 361 | 362 | if(handle < 1) 363 | { 364 | fprintf(stderr, "can't open/create output file %s\n", fname); 365 | return; 366 | } 367 | 368 | char tbuf[1024]; 369 | for(int x = 0; x < events_count; x++) 370 | { 371 | if(!((1<= 0; x--) 396 | { 397 | if(ms >= tempo_ms[x]) 398 | { 399 | // if(x > 0) return tempo_value[x-1]; 400 | return tempo_value[x]; 401 | } 402 | } 403 | return 500000; //MIDI default 404 | } 405 | 406 | double get_dt_ms(uint32_t start_ms, uint32_t ticks) 407 | { 408 | if(tempo_fixed) return ticks * ticks_to_ms; 409 | 410 | double ms = start_ms; 411 | for(uint32_t t = 0; t < ticks; t++) 412 | { 413 | double cur_tempo = get_tempo(ms); 414 | ticks_to_ms = (cur_tempo / 1000.0) / (double)(ticks_per_qn); 415 | ms += ticks_to_ms; 416 | } 417 | return ms - start_ms; 418 | } 419 | 420 | int key_map(int key) 421 | { 422 | return key; 423 | } 424 | int value_map_on(int value) 425 | { 426 | return value; 427 | // return TARGET_MIN + value * (TARGET_MAX-TARGET_MIN) / 127.0; 428 | } 429 | int value_map_off(int value) 430 | { 431 | return 0; 432 | } 433 | 434 | void parse_track(uint8_t *buf, int length, int out_process, int track_num) 435 | { 436 | int pos = 0; 437 | double rT = 0; 438 | uint32_t T = 0; 439 | int unhandled_sum = 0; 440 | int out_verbose = 1;//out_process; 441 | int send_out = out_process; 442 | 443 | int prev_msg_type = -1; 444 | int prev_msg_chan = -1; 445 | int prev_send = 0; 446 | 447 | while(pos < length) 448 | { 449 | uint32_t dt; 450 | int dpos = parse_vbl(buf+pos, &dt); 451 | pos += dpos; 452 | uint8_t type = buf[pos]>>4; 453 | uint8_t channel = buf[pos]&0x0F; 454 | uint8_t b1 = buf[pos+1]; 455 | uint8_t b2 = buf[pos+2]; 456 | int handled = 0; 457 | uint32_t cur_tempo = 0; 458 | double dt_ms = get_dt_ms(T, dt); 459 | rT += dt_ms ;//dt * ticks_to_ms; 460 | T = rT; 461 | sMIDI_event evt; 462 | evt.active = 1; 463 | evt.T = T; 464 | evt.channel = channel; 465 | evt.track = track_num; 466 | 467 | // printf("(%d, %d) ", T, dt_ms); 468 | // for(int nn = 0; nn < 16; nn++) 469 | // printf("%02X ", buf[pos-dpos+nn]); 470 | // printf("\n"); 471 | if(0)if(buf[pos] < 128 && buf[pos] > 0) 472 | { 473 | handled = 1; 474 | pos += 1; 475 | } 476 | if(1)if(prev_msg_type != -1 && buf[pos] < 127) 477 | { 478 | // printf("(%d) controller?\n", T); 479 | // pos++; 480 | evt.type = prev_msg_type; 481 | evt.key = buf[pos]; 482 | evt.channel = prev_msg_chan; 483 | evt.value = buf[pos+1]; 484 | if(prev_send) 485 | add_event(evt); 486 | handled = 1; 487 | pos++; 488 | if(prev_msg_type <= evt_ctrl_change) 489 | pos++;//= 3; 490 | // else 491 | // pos += 1; 492 | } 493 | if(type >= 0x8 && type < 0xF) 494 | { 495 | out_verbose = 0; 496 | if(type == 8 || type == 0) 497 | { 498 | prev_send = 0; 499 | if(send_out & SEND_NOTE_OFF) 500 | { 501 | prev_send = 1; 502 | evt.type = evt_note_off; 503 | evt.key = b1; 504 | evt.value = b2; 505 | add_event(evt); 506 | } 507 | pos += 3; 508 | handled = 1; 509 | prev_msg_type = evt_note_off; 510 | prev_msg_chan = channel; 511 | } 512 | if(type == 9) 513 | { 514 | prev_send = 0; 515 | if(send_out & SEND_NOTE_ON) 516 | { 517 | prev_send = 1; 518 | evt.type = evt_note_on; 519 | evt.key = b1; 520 | evt.value = b2; 521 | add_event(evt); 522 | } 523 | pos += 3; 524 | handled = 1; 525 | prev_msg_type = evt_note_on; 526 | prev_msg_chan = channel; 527 | } 528 | if(type == 0xA) 529 | { 530 | prev_send = 0; 531 | if(send_out & SEND_AFTERTOUCH) 532 | { 533 | prev_send = 1; 534 | evt.type = evt_aftertouch; 535 | evt.key = b1; 536 | evt.value = b2; 537 | add_event(evt); 538 | } 539 | if(out_verbose) printf("(%d) ch %d aft %d, v %d\n", T, channel, b1, b2); 540 | pos += 3; 541 | handled = 1; 542 | prev_msg_type = evt_aftertouch; 543 | prev_msg_chan = channel; 544 | } 545 | if(type == 0xB) 546 | { 547 | prev_send = 0; 548 | if(send_out & SEND_CTRL_CHANGE) 549 | { 550 | prev_send = 1; 551 | evt.type = evt_ctrl_change; 552 | evt.key = b1; 553 | evt.value = b2; 554 | add_event(evt); 555 | } 556 | if(out_verbose) printf("(%d) ch %d cc %d, cv %d\n", T, channel, b1, b2); 557 | pos += 3; 558 | handled = 1; 559 | prev_msg_type = evt_ctrl_change; 560 | prev_msg_chan = channel; 561 | } 562 | if(type == 0xC) 563 | { 564 | prev_send = 0; 565 | if(send_out & SEND_PROG_CHANGE) 566 | { 567 | prev_send = 1; 568 | evt.type = evt_prog_change; 569 | evt.key = 255; 570 | evt.value = b1; 571 | add_event(evt); 572 | } 573 | if(out_verbose) printf("(%d) ch %d prog %d\n", T, channel, b1); 574 | pos += 2; 575 | handled = 1; 576 | prev_msg_type = evt_prog_change; 577 | prev_msg_chan = channel; 578 | } 579 | if(type == 0xD) 580 | { 581 | prev_send = 0; 582 | if(send_out & SEND_CHAN_KEYPRES) 583 | { 584 | prev_send = 1; 585 | evt.type = evt_chan_keypress; 586 | evt.key = 255; 587 | evt.value = b1; 588 | add_event(evt); 589 | } 590 | 591 | if(out_verbose) printf("(%d) ch %d AFT %d\n", T, channel, b1); 592 | pos += 2; 593 | handled = 1; 594 | prev_msg_type = evt_chan_keypress; 595 | prev_msg_chan = channel; 596 | } 597 | if(type == 0xE) 598 | { 599 | prev_send = 0; 600 | if(send_out & SEND_PITCH_BEND) 601 | { 602 | prev_send = 1; 603 | evt.type = evt_pitch_bend; 604 | evt.key = 255; 605 | evt.value = (b2<<8) + b1; 606 | add_event(evt); 607 | } 608 | if(out_verbose) printf("(%d) ch %d pitch %d\n", T, channel, (b2<<8) + b1); 609 | pos += 3; 610 | handled = 1; 611 | prev_msg_type = evt_pitch_bend; 612 | prev_msg_chan = channel; 613 | } 614 | } 615 | if(type == 0xF) 616 | { 617 | prev_msg_type = -1; 618 | out_verbose = 1; 619 | if(channel == 0) 620 | { 621 | if(out_verbose) printf("(%d) sysex F0\n", T); 622 | handled = 1; 623 | uint32_t len = 0; 624 | int dpos = parse_vbl(buf+pos+1, &len); 625 | pos += dpos + len + 1; 626 | } 627 | if(channel == 1) 628 | { 629 | if(out_verbose) printf("(%d) MIDI Time Code Qtr. Frame\n", T); 630 | handled = 1; 631 | pos += 3; 632 | } 633 | if(channel == 2) 634 | { 635 | if(out_verbose) printf("(%d) Song Position Pointer\n", T); 636 | handled = 1; 637 | pos += 3; 638 | } 639 | if(channel == 3) 640 | { 641 | if(out_verbose) printf("(%d) Song Select\n", T); 642 | handled = 1; 643 | pos += 2; 644 | } 645 | if(channel == 6) 646 | { 647 | if(out_verbose) printf("(%d) Tune Request\n", T); 648 | handled = 1; 649 | pos += 1; 650 | } 651 | if(channel == 7) 652 | { 653 | if(out_verbose) printf("(%d) sysex F7\n", T); 654 | handled = 1; 655 | uint32_t len = 0; 656 | int dpos = parse_vbl(buf+pos+1, &len); 657 | pos += dpos + len + 1; 658 | } 659 | if(channel == 8) 660 | { 661 | if(out_verbose) printf("(%d) Timing clock\n", T); 662 | handled = 1; 663 | pos += 1; 664 | } 665 | if(channel == 0xA) 666 | { 667 | if(out_verbose) printf("(%d) Start\n", T); 668 | handled = 1; 669 | pos += 1; 670 | } 671 | if(channel == 0xB) 672 | { 673 | if(out_verbose) printf("(%d) Stop\n", T); 674 | handled = 1; 675 | pos += 1; 676 | } 677 | if(channel == 0xF) //meta event 678 | { 679 | uint32_t len = 0; 680 | if((b1 >= 1 && b1 <= 9) || b1 == 0x7F || b1 == 0x60) 681 | { 682 | int dpos = parse_vbl(buf+pos+2, &len); 683 | // printf("vbl: %d %d\n", dpos, len); 684 | pos += dpos+2; 685 | // b1 = buf[pos+1]; 686 | // b2 = buf[pos+2]; 687 | // pos++; //b1 688 | } 689 | 690 | if(b1 == 0) 691 | { 692 | if(out_verbose) printf("(%d) meta 0\n", T); 693 | handled = 1; 694 | pos += 4; 695 | } 696 | if(b1 == 1) 697 | { 698 | if(out_verbose) 699 | { 700 | printf("(%d) meta text: ", T); 701 | for(int x = 0; x < len; x++) printf("%c", buf[pos+x]); 702 | printf("\n"); 703 | } 704 | handled = 1; 705 | pos += len; 706 | } 707 | if(b1 == 2) 708 | { 709 | if(out_verbose) 710 | { 711 | printf("(%d) meta copyright: ", T); 712 | for(int x = 0; x < len; x++) printf("%c", buf[pos+x]); 713 | printf("\n"); 714 | } 715 | handled = 1; 716 | pos += len; 717 | } 718 | if(b1 == 3) 719 | { 720 | if(out_verbose) 721 | { 722 | printf("(%d) meta Track Name (%d): ", T, pos); 723 | for(int x = 0; x < len; x++) printf("%c", buf[pos+x]); 724 | printf("\n"); 725 | } 726 | handled = 1; 727 | pos += len; 728 | } 729 | if(b1 == 4) 730 | { 731 | if(out_verbose) 732 | { 733 | printf("(%d) meta Instrument Name: ", T); 734 | for(int x = 0; x < len; x++) printf("%c", buf[pos+x]); 735 | printf("\n"); 736 | } 737 | 738 | handled = 1; 739 | pos += len; 740 | } 741 | if(b1 == 5) 742 | { 743 | if(out_verbose) 744 | { 745 | printf("(%d) meta Lyrics: ", T); 746 | for(int x = 0; x < len; x++) printf("%c", buf[pos+x]); 747 | printf("\n"); 748 | } 749 | handled = 1; 750 | pos += len; 751 | } 752 | if(b1 == 6) 753 | { 754 | if(out_verbose) 755 | { 756 | printf("(%d) meta Marker: ", T); 757 | for(int x = 0; x < len; x++) printf("%c", buf[pos+x]); 758 | printf("\n"); 759 | } 760 | handled = 1; 761 | pos += len; 762 | } 763 | if(b1 == 7) 764 | { 765 | if(out_verbose) 766 | { 767 | printf("(%d) meta Cue Point: ", T); 768 | for(int x = 0; x < len; x++) printf("%c", buf[pos+x]); 769 | printf("\n"); 770 | } 771 | handled = 1; 772 | pos += len; 773 | } 774 | if(b1 == 8) 775 | { 776 | if(out_verbose) 777 | { 778 | printf("(%d) meta Program Name: ", T); 779 | for(int x = 0; x < len; x++) printf("%c", buf[pos+x]); 780 | printf("\n"); 781 | } 782 | handled = 1; 783 | pos += len; 784 | } 785 | if(b1 == 9) 786 | { 787 | if(out_verbose) 788 | { 789 | printf("(%d) meta Device Name: ", T); 790 | for(int x = 0; x < len; x++) printf("%c", buf[pos+x]); 791 | printf("\n"); 792 | } 793 | handled = 1; 794 | pos += len; 795 | } 796 | if(b1 == 0x20) 797 | { 798 | if(out_verbose) printf("(%d) meta channel prefix\n", T); 799 | handled = 1; 800 | pos += 4; 801 | } 802 | if(b1 == 0x21) 803 | { 804 | if(out_verbose) printf("(%d) meta port prefix\n", T); 805 | handled = 1; 806 | pos += 4; 807 | } 808 | if(b1 == 0x2F) 809 | { 810 | if(out_verbose) printf("(%d) meta track end\n", T); 811 | if(send_out & SEND_TRACK_END) 812 | { 813 | evt.type = evt_track_end; 814 | evt.key = 255; 815 | evt.value = 255; 816 | add_event(evt); 817 | } 818 | handled = 1; 819 | pos += 3; 820 | } 821 | if(b1 == 0x51) 822 | { 823 | uint32_t mpqn = (buf[pos+3]<<16)|(buf[pos+4]<<8)|buf[pos+5]; 824 | if(out_verbose) printf("(%d) meta tempo %d\n", T, mpqn); 825 | add_tempo_point(T, mpqn); 826 | ticks_to_ms = (float)(mpqn / 1000.0) / (float)(ticks_per_qn); 827 | 828 | handled = 1; 829 | pos += 6; 830 | } 831 | if(b1 == 0x54) 832 | { 833 | if(out_verbose) printf("(%d) meta SMTPE offset\n", T); 834 | handled = 1; 835 | pos += 8; 836 | } 837 | if(b1 == 0x58) 838 | { 839 | if(out_verbose) printf("(%d) meta Time Signature\n", T); 840 | handled = 1; 841 | pos += 7; 842 | } 843 | if(b1 == 0x59) 844 | { 845 | if(out_verbose) printf("(%d) meta Key Signature\n", T); 846 | handled = 1; 847 | pos += 5; 848 | } 849 | if(b1 == 0x60) 850 | { 851 | if(out_verbose) printf("(%d) meta XMF\n", T); 852 | handled = 1; 853 | pos += len; 854 | } 855 | if(b1 == 0x7F) 856 | { 857 | if(out_verbose) printf("(%d) meta Sequencer-Specific\n", T); 858 | handled = 1; 859 | pos += len; 860 | } 861 | if(!handled) 862 | { 863 | if(out_verbose) fprintf(stderr, "unhandled meta: %02X %02X %02X %02X %02X %02X %02X %02X\n", b1, b2, buf[pos+3], buf[pos+4], buf[pos+5], buf[pos+6], buf[pos+7], buf[pos+8]); 864 | pos += len; 865 | } 866 | } 867 | 868 | } 869 | if(!handled) 870 | { 871 | //if(out_verbose) 872 | //fprintf(stderr, "(%d) unhandled %02X %02X %02X %02X %02X %02X %02X %02X\n", T, buf[pos-2], buf[pos-1], buf[pos], buf[pos+1], buf[pos+2], buf[pos+3], buf[pos+4], buf[pos+5]); 873 | printf("(%d, %d) unhandled ", T, pos); 874 | for(int nn = 0; nn < 16; nn++) 875 | printf("%02X ", buf[pos-3+nn]); 876 | printf("\n"); 877 | 878 | unhandled_sum++; 879 | 880 | rT -= dt_ms; 881 | } 882 | } 883 | fprintf(stderr, "unhandled messages: %d\n", unhandled_sum); 884 | } 885 | 886 | void parse_midi(uint8_t *buf, int length, int send_out) 887 | { 888 | int pos = 0; 889 | uint8_t type[5]; 890 | type[4] = 0; 891 | int cur_track = 0; 892 | while(pos < length) 893 | { 894 | uint32_t len; 895 | for(int x = 0; x < 4; x++) 896 | type[x] = buf[pos + x]; 897 | len = buf[pos+4]; len <<= 8; 898 | len += buf[pos+5]; len <<= 8; 899 | len += buf[pos+6]; len <<= 8; 900 | len += buf[pos+7]; 901 | fprintf(stderr, "%s: %d\n", type, len); 902 | if(str_eq((char*)type, "MThd")) 903 | { 904 | int format = (buf[pos+8]<<8) | buf[pos+8+1]; 905 | int tracks = (buf[pos+8+2]<<8) | buf[pos+8+3]; 906 | int tpqn_type = !(buf[pos+8+4] > 0x7F); 907 | int tpqn = (buf[pos+8+4]<<8) | buf[pos+8+5]; 908 | int fps = buf[pos+8+4]&0x7F; 909 | int tpf = buf[pos+8+5]; 910 | 911 | if(tpqn_type) 912 | { 913 | fprintf(stderr, "MIDI format %d, tracks %d, tpqn %d\n", format, tracks, tpqn); 914 | ticks_per_qn = tpqn; 915 | tempo_fixed = 0; 916 | } 917 | else 918 | { 919 | fprintf(stderr, "MIDI format %d, tracks %d, fps %d, tpf %d\n", format, tracks, fps, tpf); 920 | ticks_to_ms = (float)(tpf * fps) / 1000.0; 921 | tempo_fixed = 1; 922 | } 923 | } 924 | if(str_eq((char*)type, "MTrk")) 925 | { 926 | parse_track(buf + pos + 8, len, send_out, cur_track); 927 | cur_track++; 928 | } 929 | pos += 8 + len; 930 | 931 | } 932 | } 933 | 934 | uint8_t *file_buf; 935 | int file_length = 0; 936 | 937 | void read_file(const char *fname) 938 | { 939 | int handle = open(fname, O_RDONLY); 940 | if(handle < 1) 941 | { 942 | fprintf(stderr, "can't open file!\n"); 943 | return; 944 | } 945 | lseek(handle, 0, 0); 946 | file_length = lseek(handle, 0, 2); 947 | lseek(handle, 0, 0); 948 | 949 | file_buf = new uint8_t[file_length]; 950 | if(read(handle, file_buf, file_length) != file_length) 951 | { 952 | fprintf(stderr, "file reading error\n"); 953 | } 954 | close(handle); 955 | } 956 | 957 | int main(int argc, char **argv) 958 | { 959 | if(argc < 3) 960 | { 961 | printf("\nMIDI file parser v1.0\nusage: midi_parser -flags \n"); 962 | printf("flags define which MIDI events from which tracks will and will not be stored\n"); 963 | printf("track flags starts with -t to enable track\n"); 964 | printf("-t1 -t2 will enable first and second tracks\n"); 965 | printf("-tall will enable all tracks (default option)\n"); 966 | printf("event flag starts with -e to disable, -E to enable event\n"); 967 | printf("events:\n"); 968 | printf("\tNOFF - Note Off (code %d)\n", evt_note_off); 969 | printf("\tNON - Note On (code %d)\n", evt_note_on); 970 | printf("\tAFT - Aftertouch (code %d)\n", evt_aftertouch); 971 | printf("\tCC - Controller Change (code %d)\n", evt_ctrl_change); 972 | printf("\tPC - Program Change (code %d)\n", evt_prog_change); 973 | printf("\tCKP - Channel Key Pressure (code %d)\n", evt_chan_keypress); 974 | printf("\tPB - Pitch Bend (code %d)\n", evt_pitch_bend); 975 | printf("\tTE - Track End (code %d)\n", evt_track_end); 976 | 977 | printf("\n\nAdditional options:\n"); 978 | printf("\tCUTOVP - cut overlapping notes\n"); 979 | printf("\t0toOFF - convert note on event with stroke value 0 into note off event with stroke value 0\n"); 980 | 981 | printf("\nBy default, events Note On, Note off and Track End are stored, all others ignored\n"); 982 | printf("example:\n"); 983 | 984 | printf("midi_parser -t2 -eNON -eNOFF -ECC -EPC -EPB input.mid output.txt\n"); 985 | printf("this command will store only Controller Change, Program Change and Pitch Bend events on track 2\n"); 986 | 987 | printf("\nOutput format: time in milliseconds, track, channel, type, key, value\n"); 988 | printf("For events that are not related to a specific key, key field is set to 255\n"); 989 | printf("For events that don't have valid value, it is set to 255\n"); 990 | printf("\n"); 991 | 992 | return 1; 993 | } 994 | 995 | int send_events = SEND_NOTE_ON | SEND_NOTE_OFF | SEND_TRACK_END; 996 | 997 | uint64_t track_mask = 0; 998 | int prevent_overlap = 0; 999 | int overlap_master = 1; 1000 | int need_postprocess = 0; 1001 | int make_python = 0; 1002 | 1003 | for(int a = 1; a < argc-2; a++) 1004 | { 1005 | if(str_eq(argv[a], "-eNON")) send_events &= ~SEND_NOTE_ON; 1006 | if(str_eq(argv[a], "-ENON")) send_events |= SEND_NOTE_ON; 1007 | if(str_eq(argv[a], "-eNOFF")) send_events &= ~SEND_NOTE_OFF; 1008 | if(str_eq(argv[a], "-ENOFF")) send_events |= SEND_NOTE_OFF; 1009 | if(str_eq(argv[a], "-eAFT")) send_events &= ~SEND_AFTERTOUCH; 1010 | if(str_eq(argv[a], "-EAFT")) send_events |= SEND_AFTERTOUCH; 1011 | if(str_eq(argv[a], "-eCC")) send_events &= ~SEND_CTRL_CHANGE; 1012 | if(str_eq(argv[a], "-ECC")) send_events |= SEND_CTRL_CHANGE; 1013 | if(str_eq(argv[a], "-ePC")) send_events &= ~SEND_PROG_CHANGE; 1014 | if(str_eq(argv[a], "-EPC")) send_events |= SEND_PROG_CHANGE; 1015 | if(str_eq(argv[a], "-eCKP")) send_events &= ~SEND_CHAN_KEYPRES; 1016 | if(str_eq(argv[a], "-ECKP")) send_events |= SEND_CHAN_KEYPRES; 1017 | if(str_eq(argv[a], "-ePB")) send_events &= ~SEND_PITCH_BEND; 1018 | if(str_eq(argv[a], "-EPB")) send_events |= SEND_PITCH_BEND; 1019 | if(str_eq(argv[a], "-eTE")) send_events &= ~SEND_TRACK_END; 1020 | if(str_eq(argv[a], "-ETE")) send_events |= SEND_TRACK_END; 1021 | 1022 | if(argv[a][0] == '-' && argv[a][1] == 't') 1023 | { 1024 | int tnum = 0; 1025 | if(argv[a][2] >= '0' && argv[a][2] <= '9') tnum += argv[a][2]-'0'; 1026 | if(argv[a][3] >= '0' && argv[a][3] <= '9') tnum = tnum*10 + argv[a][3]-'0'; 1027 | if(tnum > 0 && tnum < 65) track_mask |= (1<<(tnum-1)); 1028 | } 1029 | 1030 | if(str_eq(argv[a], "-CUTOVP")) prevent_overlap = 1; 1031 | if(str_eq(argv[a], "-0toOFF")) zero_to_off = 1; 1032 | 1033 | if(str_eq(argv[a], "-PYTHON")) 1034 | { 1035 | send_events = SEND_NOTE_ON | SEND_NOTE_OFF | SEND_TRACK_END; 1036 | prevent_overlap = 1; 1037 | zero_to_off = 1; 1038 | need_postprocess = 1; 1039 | make_python = 1; 1040 | } 1041 | } 1042 | if(track_mask == 0) track_mask = 0xFFFFFFFFFFFFFFFF; 1043 | 1044 | read_file(argv[argc-2]); 1045 | if(file_length < 1) return 1; 1046 | 1047 | parse_midi(file_buf, file_length, send_events); 1048 | sort_events(); 1049 | if(prevent_overlap) 1050 | process_overlaps(overlap_master); 1051 | 1052 | if(need_postprocess) 1053 | note_postprocessor(); 1054 | 1055 | if(make_python) 1056 | save_python_script(argv[argc-1], track_mask); 1057 | else 1058 | save_events(argv[argc-1], track_mask); 1059 | 1060 | delete[] file_buf; 1061 | return 0; 1062 | } 1063 | --------------------------------------------------------------------------------