1 /* $NetBSD: midirecord.c,v 1.10 2015/09/23 05:31:01 mrg Exp $ */ 2 3 /* 4 * Copyright (c) 2014 Matthew R. Green 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 /* 30 * midirecord(1), similar to audiorecord(1). 31 */ 32 33 #include <sys/cdefs.h> 34 35 #ifndef lint 36 __RCSID("$NetBSD: midirecord.c,v 1.10 2015/09/23 05:31:01 mrg Exp $"); 37 #endif 38 39 #include <sys/param.h> 40 #include <sys/midiio.h> 41 #include <sys/ioctl.h> 42 #include <sys/time.h> 43 #include <sys/uio.h> 44 45 #include <err.h> 46 #include <errno.h> 47 #include <ctype.h> 48 #include <fcntl.h> 49 #include <paths.h> 50 #include <signal.h> 51 #include <stdio.h> 52 #include <stdlib.h> 53 #include <string.h> 54 #include <unistd.h> 55 #include <util.h> 56 #include <assert.h> 57 #include <stdbool.h> 58 59 #include "libaudio.h" 60 61 static const char *midi_device; 62 static unsigned *filt_devnos = NULL; 63 static unsigned *filt_chans = NULL; 64 static unsigned num_filt_devnos, num_filt_chans; 65 static char *raw_output; 66 static int midifd; 67 static int aflag, qflag, oflag; 68 static bool debug = false; 69 int verbose; 70 static int outfd, rawfd = -1; 71 static ssize_t data_size; 72 static struct timeval record_time; 73 static struct timeval start_time; 74 static int tempo = 120; 75 static unsigned round_beats = 1; 76 static unsigned notes_per_beat = 24; 77 static bool ignore_timer_fail = false; 78 static bool stdout_mode = false; 79 80 static void debug_log(const char *, size_t, const char *, ...) 81 __printflike(3, 4); 82 static size_t midi_event_local_to_output(seq_event_t, u_char *, size_t); 83 static size_t midi_event_timer_wait_abs_to_output(seq_event_t, u_char *, 84 size_t); 85 static size_t midi_event_timer_to_output(seq_event_t, u_char *, size_t); 86 static size_t midi_event_chn_common_to_output(seq_event_t, u_char *, size_t); 87 static size_t midi_event_chn_voice_to_output(seq_event_t, u_char *, size_t); 88 static size_t midi_event_sysex_to_output(seq_event_t, u_char *, size_t); 89 static size_t midi_event_fullsize_to_output(seq_event_t, u_char *, size_t); 90 static size_t midi_event_to_output(seq_event_t, u_char *, size_t); 91 static int timeleft(struct timeval *, struct timeval *); 92 static bool filter_array(unsigned, unsigned *, size_t); 93 static bool filter_dev(unsigned); 94 static bool filter_chan(unsigned); 95 static bool filter_devchan(unsigned, unsigned); 96 static void parse_ints(const char *, unsigned **, unsigned *, const char *); 97 static void cleanup(int) __dead; 98 static void rewrite_header(void); 99 static void write_midi_header(void); 100 static void write_midi_trailer(void); 101 static void usage(void) __dead; 102 103 #define PATH_DEV_MUSIC "/dev/music" 104 105 int 106 main(int argc, char *argv[]) 107 { 108 u_char *buffer; 109 size_t bufsize = 0; 110 int ch, no_time_limit = 1; 111 112 while ((ch = getopt(argc, argv, "aB:c:Dd:f:hn:oqr:t:T:V")) != -1) { 113 switch (ch) { 114 case 'a': 115 aflag++; 116 break; 117 case 'B': 118 bufsize = strsuftoll("read buffer size", optarg, 119 1, UINT_MAX); 120 break; 121 case 'c': 122 parse_ints(optarg, &filt_chans, &num_filt_chans, 123 "channels"); 124 break; 125 case 'D': 126 debug = true; 127 break; 128 case 'd': 129 parse_ints(optarg, &filt_devnos, &num_filt_devnos, 130 "devices"); 131 break; 132 case 'f': 133 midi_device = optarg; 134 ignore_timer_fail = true; 135 break; 136 case 'n': 137 decode_uint(optarg, ¬es_per_beat); 138 break; 139 case 'o': 140 oflag++; /* time stamp starts at proc start */ 141 break; 142 case 'q': 143 qflag++; 144 break; 145 case 'r': 146 raw_output = optarg; 147 break; 148 case 'R': 149 decode_uint(optarg, &round_beats); 150 if (round_beats == 0) 151 errx(1, "-R <round_beats> must be a positive integer"); 152 break; 153 case 't': 154 no_time_limit = 0; 155 decode_time(optarg, &record_time); 156 break; 157 case 'T': 158 decode_int(optarg, &tempo); 159 break; 160 case 'V': 161 verbose++; 162 break; 163 /* case 'h': */ 164 default: 165 usage(); 166 /* NOTREACHED */ 167 } 168 } 169 argc -= optind; 170 argv += optind; 171 172 if (argc != 1) 173 usage(); 174 175 /* 176 * work out the buffer size to use, and allocate it. don't allow it 177 * to be too small. 178 */ 179 if (bufsize < 32) 180 bufsize = 32 * 1024; 181 buffer = malloc(bufsize); 182 if (buffer == NULL) 183 err(1, "couldn't malloc buffer of %d size", (int)bufsize); 184 185 /* 186 * open the music device 187 */ 188 if (midi_device == NULL && (midi_device = getenv("MIDIDEVICE")) == NULL) 189 midi_device = PATH_DEV_MUSIC; 190 midifd = open(midi_device, O_RDONLY); 191 if (midifd < 0) 192 err(1, "failed to open %s", midi_device); 193 194 /* open the output file */ 195 if (argv[0][0] != '-' || argv[0][1] != '\0') { 196 int mode = O_CREAT|(aflag ? O_APPEND : O_TRUNC)|O_WRONLY; 197 198 outfd = open(*argv, mode, 0666); 199 if (outfd < 0) 200 err(1, "could not open %s", *argv); 201 } else { 202 stdout_mode = true; 203 outfd = STDOUT_FILENO; 204 } 205 206 /* open the raw output file */ 207 if (raw_output) { 208 int mode = O_CREAT|(aflag ? O_APPEND : O_TRUNC)|O_WRONLY; 209 210 rawfd = open(raw_output, mode, 0666); 211 if (rawfd < 0) 212 err(1, "could not open %s", raw_output); 213 } 214 215 /* start the midi timer */ 216 if (ioctl(midifd, SEQUENCER_TMR_START, NULL) < 0) { 217 if (ignore_timer_fail) 218 warn("failed to start midi timer"); 219 else 220 err(1, "failed to start midi timer"); 221 } 222 223 /* set the timebase */ 224 if (ioctl(midifd, SEQUENCER_TMR_TIMEBASE, ¬es_per_beat) < 0) { 225 if (ignore_timer_fail) 226 warn("SEQUENCER_TMR_TIMEBASE: notes_per_beat %d", 227 notes_per_beat); 228 else 229 err(1, "SEQUENCER_TMR_TIMEBASE: notes_per_beat %d", 230 notes_per_beat); 231 } 232 233 /* set the tempo */ 234 if (ioctl(midifd, SEQUENCER_TMR_TEMPO, &tempo) < 0) { 235 if (ignore_timer_fail) 236 warn("SEQUENCER_TMR_TIMEBASE: tempo %d", tempo); 237 else 238 err(1, "SEQUENCER_TMR_TIMEBASE: tempo %d", tempo); 239 } 240 241 signal(SIGINT, cleanup); 242 243 data_size = 0; 244 245 if (verbose) 246 fprintf(stderr, "tempo=%d notes_per_beat=%u\n", 247 tempo, notes_per_beat); 248 249 if (!no_time_limit && verbose) 250 fprintf(stderr, "recording for %lu seconds, %lu microseconds\n", 251 (u_long)record_time.tv_sec, (u_long)record_time.tv_usec); 252 253 /* Create a midi header. */ 254 write_midi_header(); 255 256 (void)gettimeofday(&start_time, NULL); 257 while (no_time_limit || timeleft(&start_time, &record_time)) { 258 seq_event_t e; 259 size_t wrsize; 260 size_t rdsize; 261 262 rdsize = (size_t)read(midifd, &e, sizeof e); 263 if (rdsize == 0) 264 break; 265 266 if (rdsize != sizeof e) 267 err(1, "read failed"); 268 269 if (rawfd != -1 && write(rawfd, &e, sizeof e) != sizeof e) 270 err(1, "write to raw file failed"); 271 272 /* convert 'e' into something useful for output */ 273 wrsize = midi_event_to_output(e, buffer, bufsize); 274 275 if (wrsize) { 276 if ((size_t)write(outfd, buffer, wrsize) != wrsize) 277 err(1, "write failed"); 278 data_size += wrsize; 279 } 280 } 281 cleanup(0); 282 } 283 284 static void 285 debug_log(const char *file, size_t line, const char *fmt, ...) 286 { 287 va_list ap; 288 289 if (!debug) 290 return; 291 fprintf(stderr, "%s:%zu: ", file, line); 292 va_start(ap, fmt); 293 vfprintf(stderr, fmt, ap); 294 va_end(ap); 295 fprintf(stderr, "\n"); 296 } 297 298 #define LOG(fmt...) \ 299 debug_log(__func__, __LINE__, fmt) 300 301 302 /* 303 * handle a SEQ_LOCAL event. NetBSD /dev/music doesn't generate these. 304 */ 305 static size_t 306 midi_event_local_to_output(seq_event_t e, u_char *buffer, size_t bufsize) 307 { 308 size_t size = 0; 309 310 LOG("UNHANDLED SEQ_LOCAL"); 311 312 return size; 313 } 314 315 /* 316 * convert a midi absolute time event to a variable length delay 317 */ 318 static size_t 319 midi_event_timer_wait_abs_to_output( 320 seq_event_t e, 321 u_char *buffer, 322 size_t bufsize) 323 { 324 static unsigned prev_div; 325 static int prev_leftover; 326 unsigned cur_div; 327 unsigned val = 0, xdiv; 328 int vallen = 0, i; 329 330 if (prev_div == 0 && !oflag) 331 prev_div = e.t_WAIT_ABS.divisions; 332 cur_div = e.t_WAIT_ABS.divisions; 333 334 xdiv = cur_div - prev_div + prev_leftover; 335 if (round_beats != 1) { 336 // round to closest 337 prev_leftover = xdiv % round_beats; 338 xdiv -= prev_leftover; 339 if (verbose) 340 fprintf(stderr, "adjusted beat value to %x (leftover = %d)\n", 341 xdiv, prev_leftover); 342 } 343 if (xdiv) { 344 while (xdiv) { 345 uint32_t extra = val ? 0x80 : 0; 346 347 val <<= 8; 348 val |= (xdiv & 0x7f) | extra; 349 xdiv >>= 7; 350 vallen++; 351 } 352 } else 353 vallen = 1; 354 355 for (i = 0; i < vallen; i++) { 356 buffer[i] = val & 0xff; 357 val >>= 8; 358 } 359 for (; i < 4; i++) 360 buffer[i] = 0; 361 LOG("TMR_WAIT_ABS: new div %x (cur %x prev %x): bufval (len=%u): " 362 "%02x:%02x:%02x:%02x", 363 cur_div - prev_div, cur_div, prev_div, 364 vallen, buffer[0], buffer[1], buffer[2], buffer[3]); 365 366 prev_div = cur_div; 367 368 return vallen; 369 } 370 371 /* 372 * handle a SEQ_TIMING event. 373 */ 374 static size_t 375 midi_event_timer_to_output(seq_event_t e, u_char *buffer, size_t bufsize) 376 { 377 size_t size = 0; 378 379 LOG("SEQ_TIMING"); 380 switch (e.timing.op) { 381 case TMR_WAIT_REL: 382 /* NetBSD /dev/music doesn't generate these. */ 383 LOG("UNHANDLED TMR_WAIT_REL: divisions: %x", e.t_WAIT_REL.divisions); 384 break; 385 386 case TMR_WAIT_ABS: 387 size = midi_event_timer_wait_abs_to_output(e, buffer, bufsize); 388 break; 389 390 case TMR_STOP: 391 case TMR_START: 392 case TMR_CONTINUE: 393 case TMR_TEMPO: 394 case TMR_ECHO: 395 case TMR_CLOCK: 396 case TMR_SPP: 397 case TMR_TIMESIG: 398 /* NetBSD /dev/music doesn't generate these. */ 399 LOG("UNHANDLED timer op: %x", e.timing.op); 400 break; 401 402 default: 403 LOG("unknown timer op: %x", e.timing.op); 404 break; 405 } 406 407 return size; 408 } 409 410 /* 411 * handle a SEQ_CHN_COMMON event. 412 */ 413 static size_t 414 midi_event_chn_common_to_output(seq_event_t e, u_char *buffer, size_t bufsize) 415 { 416 size_t size = 0; 417 418 assert(e.common.channel < 16); 419 LOG("SEQ_CHN_COMMON"); 420 421 if (filter_devchan(e.common.device, e.common.channel)) 422 return 0; 423 424 switch (e.common.op) { 425 case MIDI_CTL_CHANGE: 426 buffer[0] = MIDI_CTL_CHANGE | e.c_CTL_CHANGE.channel; 427 buffer[1] = e.c_CTL_CHANGE.controller; 428 buffer[2] = e.c_CTL_CHANGE.value; 429 LOG("MIDI_CTL_CHANGE: channel %x ctrl %x val %x", 430 e.c_CTL_CHANGE.channel, e.c_CTL_CHANGE.controller, 431 e.c_CTL_CHANGE.value); 432 size = 3; 433 break; 434 435 case MIDI_PGM_CHANGE: 436 buffer[0] = MIDI_PGM_CHANGE | e.c_PGM_CHANGE.channel; 437 buffer[1] = e.c_PGM_CHANGE.program; 438 LOG("MIDI_PGM_CHANGE: channel %x program %x", 439 e.c_PGM_CHANGE.channel, e.c_PGM_CHANGE.program); 440 size = 2; 441 break; 442 443 case MIDI_CHN_PRESSURE: 444 buffer[0] = MIDI_CHN_PRESSURE | e.c_CHN_PRESSURE.channel; 445 buffer[1] = e.c_CHN_PRESSURE.pressure; 446 LOG("MIDI_CHN_PRESSURE: channel %x pressure %x", 447 e.c_CHN_PRESSURE.channel, e.c_CHN_PRESSURE.pressure); 448 size = 2; 449 break; 450 451 case MIDI_PITCH_BEND: 452 buffer[0] = MIDI_PITCH_BEND | e.c_PITCH_BEND.channel; 453 /* 14 bits split over 2 data bytes, lsb first */ 454 buffer[1] = e.c_PITCH_BEND.value & 0x7f; 455 buffer[2] = (e.c_PITCH_BEND.value >> 7) & 0x7f; 456 LOG("MIDI_PITCH_BEND: channel %x val %x", 457 e.c_PITCH_BEND.channel, e.c_PITCH_BEND.value); 458 size = 3; 459 break; 460 461 default: 462 LOG("unknown common op: %x", e.voice.op); 463 break; 464 } 465 466 return size; 467 } 468 469 /* 470 * handle a SEQ_CHN_VOICE event. 471 */ 472 static size_t 473 midi_event_chn_voice_to_output(seq_event_t e, u_char *buffer, size_t bufsize) 474 { 475 size_t size = 0; 476 477 assert(e.common.channel < 16); 478 LOG("SEQ_CHN_VOICE"); 479 480 if (filter_devchan(e.voice.device, e.voice.channel)) 481 return 0; 482 483 switch (e.voice.op) { 484 case MIDI_NOTEOFF: 485 buffer[0] = MIDI_NOTEOFF | e.c_NOTEOFF.channel; 486 buffer[1] = e.c_NOTEOFF.key; 487 buffer[2] = e.c_NOTEOFF.velocity; 488 489 LOG("MIDI_NOTEOFF: channel %x key %x velocity %x", 490 e.c_NOTEOFF.channel, e.c_NOTEOFF.key, e.c_NOTEOFF.velocity); 491 size = 3; 492 break; 493 494 case MIDI_NOTEON: 495 buffer[0] = MIDI_NOTEON | e.c_NOTEON.channel; 496 buffer[1] = e.c_NOTEON.key; 497 buffer[2] = e.c_NOTEON.velocity; 498 499 LOG("MIDI_NOTEON: channel %x key %x velocity %x", 500 e.c_NOTEON.channel, e.c_NOTEON.key, e.c_NOTEON.velocity); 501 size = 3; 502 break; 503 504 case MIDI_KEY_PRESSURE: 505 buffer[0] = MIDI_KEY_PRESSURE | e.c_KEY_PRESSURE.channel; 506 buffer[1] = e.c_KEY_PRESSURE.key; 507 buffer[2] = e.c_KEY_PRESSURE.pressure; 508 509 LOG("MIDI_KEY_PRESSURE: channel %x key %x pressure %x", 510 e.c_KEY_PRESSURE.channel, e.c_KEY_PRESSURE.key, 511 e.c_KEY_PRESSURE.pressure); 512 size = 3; 513 break; 514 515 default: 516 LOG("unknown voice op: %x", e.voice.op); 517 break; 518 } 519 520 return size; 521 } 522 523 /* 524 * handle a SEQ_SYSEX event. NetBSD /dev/music doesn't generate these. 525 */ 526 static size_t 527 midi_event_sysex_to_output(seq_event_t e, u_char *buffer, size_t bufsize) 528 { 529 size_t size = 0; 530 531 LOG("UNHANDLED SEQ_SYSEX"); 532 533 return size; 534 } 535 536 /* 537 * handle a SEQ_FULLSIZE event. NetBSD /dev/music doesn't generate these. 538 */ 539 static size_t 540 midi_event_fullsize_to_output(seq_event_t e, u_char *buffer, size_t bufsize) 541 { 542 size_t size = 0; 543 544 LOG("UNHANDLED SEQ_FULLSIZE"); 545 546 return size; 547 } 548 549 /* 550 * main handler for MIDI events. 551 */ 552 static size_t 553 midi_event_to_output(seq_event_t e, u_char *buffer, size_t bufsize) 554 { 555 size_t size = 0; 556 557 /* XXX so far we only process 4 byte returns */ 558 assert(bufsize >= 4); 559 560 LOG("event: %02x:%02x:%02x:%02x %02x:%02x:%02x:%02x", e.tag, 561 e.unknown.byte[0], e.unknown.byte[1], 562 e.unknown.byte[2], e.unknown.byte[3], 563 e.unknown.byte[4], e.unknown.byte[5], 564 e.unknown.byte[6]); 565 566 switch (e.tag) { 567 case SEQ_LOCAL: 568 size = midi_event_local_to_output(e, buffer, bufsize); 569 break; 570 571 case SEQ_TIMING: 572 size = midi_event_timer_to_output(e, buffer, bufsize); 573 break; 574 575 case SEQ_CHN_COMMON: 576 size = midi_event_chn_common_to_output(e, buffer, bufsize); 577 break; 578 579 case SEQ_CHN_VOICE: 580 size = midi_event_chn_voice_to_output(e, buffer, bufsize); 581 break; 582 583 case SEQ_SYSEX: 584 size = midi_event_sysex_to_output(e, buffer, bufsize); 585 break; 586 587 case SEQ_FULLSIZE: 588 size = midi_event_fullsize_to_output(e, buffer, bufsize); 589 break; 590 591 default: 592 errx(1, "don't understand midi tag %x", e.tag); 593 } 594 595 return size; 596 } 597 598 static bool 599 filter_array(unsigned val, unsigned *array, size_t arraylen) 600 { 601 602 if (array == NULL) 603 return false; 604 605 for (; arraylen; arraylen--) 606 if (array[arraylen - 1] == val) 607 return false; 608 609 return true; 610 } 611 612 static bool 613 filter_dev(unsigned device) 614 { 615 616 if (filter_array(device, filt_devnos, num_filt_devnos)) 617 return true; 618 619 return false; 620 } 621 622 static bool 623 filter_chan(unsigned channel) 624 { 625 626 if (filter_array(channel, filt_chans, num_filt_chans)) 627 return true; 628 629 return false; 630 } 631 632 static bool 633 filter_devchan(unsigned device, unsigned channel) 634 { 635 636 if (filter_dev(device) || filter_chan(channel)) 637 return true; 638 639 return false; 640 } 641 642 static int 643 timeleft(struct timeval *start_tvp, struct timeval *record_tvp) 644 { 645 struct timeval now, diff; 646 647 (void)gettimeofday(&now, NULL); 648 timersub(&now, start_tvp, &diff); 649 timersub(record_tvp, &diff, &now); 650 651 return (now.tv_sec > 0 || (now.tv_sec == 0 && now.tv_usec > 0)); 652 } 653 654 static void 655 parse_ints(const char *str, unsigned **arrayp, unsigned *sizep, const char *msg) 656 { 657 unsigned count = 1, u, longest = 0, c = 0; 658 unsigned *ip; 659 const char *s, *os; 660 char *num_buf; 661 662 /* 663 * count all the comma separated values, and figre out 664 * the longest one. 665 */ 666 for (s = str; *s; s++) { 667 c++; 668 if (*s == ',') { 669 count++; 670 if (c > longest) 671 longest = c; 672 c = 0; 673 } 674 } 675 *sizep = count; 676 677 num_buf = malloc(longest + 1); 678 ip = malloc(sizeof(*ip) * count); 679 if (!ip || !num_buf) 680 errx(1, "malloc failed"); 681 682 for (count = 0, s = os = str, u = 0; *s; s++) { 683 if (*s == ',') { 684 num_buf[u] = '\0'; 685 decode_uint(num_buf, &ip[count++]); 686 os = s + 1; 687 u = 0; 688 } else 689 num_buf[u++] = *s; 690 } 691 num_buf[u] = '\0'; 692 decode_uint(num_buf, &ip[count++]); 693 *arrayp = ip; 694 695 if (verbose) { 696 fprintf(stderr, "Filtering %s in:", msg); 697 for (size_t i = 0; i < *sizep; i++) 698 fprintf(stderr, " %u", ip[i]); 699 fprintf(stderr, "\n"); 700 } 701 702 free(num_buf); 703 } 704 705 static void 706 cleanup(int signo) 707 { 708 709 write_midi_trailer(); 710 rewrite_header(); 711 712 if (ioctl(midifd, SEQUENCER_TMR_STOP, NULL) < 0) { 713 if (ignore_timer_fail) 714 warn("failed to stop midi timer"); 715 else 716 err(1, "failed to stop midi timer"); 717 } 718 719 close(outfd); 720 close(midifd); 721 if (signo != 0) 722 (void)raise_default_signal(signo); 723 724 exit(0); 725 } 726 727 static void 728 rewrite_header(void) 729 { 730 731 /* can't do this here! */ 732 if (stdout_mode) 733 return; 734 735 if (lseek(outfd, (off_t)0, SEEK_SET) == (off_t)-1) 736 err(1, "could not seek to start of file for header rewrite"); 737 write_midi_header(); 738 } 739 740 #define BYTE1(x) ((x) & 0xff) 741 #define BYTE2(x) (((x) >> 8) & 0xff) 742 #define BYTE3(x) (((x) >> 16) & 0xff) 743 #define BYTE4(x) (((x) >> 24) & 0xff) 744 745 static void 746 write_midi_header(void) 747 { 748 unsigned char header[] = { 749 'M', 'T', 'h', 'd', 750 0, 0, 0, 6, 751 0, 1, 752 0, 0, /* ntracks */ 753 0, 0, /* notes per beat */ 754 }; 755 /* XXX only support one track so far */ 756 unsigned ntracks = 1; 757 unsigned char track[] = { 758 'M', 'T', 'r', 'k', 759 0, 0, 0, 0, 760 }; 761 unsigned char bpm[] = { 762 0, 0xff, 0x51, 0x3, 763 0, 0, 0, /* inverse tempo */ 764 }; 765 unsigned total_size = data_size + sizeof header + sizeof track + sizeof bpm; 766 767 header[10] = BYTE2(ntracks); 768 header[11] = BYTE1(ntracks); 769 header[12] = BYTE2(notes_per_beat); 770 header[13] = BYTE1(notes_per_beat); 771 772 track[4] = BYTE4(total_size); 773 track[5] = BYTE3(total_size); 774 track[6] = BYTE2(total_size); 775 track[7] = BYTE1(total_size); 776 777 #define TEMPO_INV(x) (60000000UL / (x)) 778 bpm[4] = BYTE3(TEMPO_INV(tempo)); 779 bpm[5] = BYTE2(TEMPO_INV(tempo)); 780 bpm[6] = BYTE1(TEMPO_INV(tempo)); 781 782 if (write(outfd, header, sizeof header) != sizeof header) 783 err(1, "write of header failed"); 784 if (write(outfd, track, sizeof track) != sizeof track) 785 err(1, "write of track header failed"); 786 if (write(outfd, bpm, sizeof bpm) != sizeof bpm) 787 err(1, "write of bpm header failed"); 788 789 LOG("wrote header: ntracks=%u notes_per_beat=%u tempo=%d total_size=%u", 790 ntracks, notes_per_beat, tempo, total_size); 791 } 792 793 static void 794 write_midi_trailer(void) 795 { 796 unsigned char trailer[] = { 797 0, 0xff, 0x2f, 0, 798 }; 799 800 if (write(outfd, trailer, sizeof trailer) != sizeof trailer) 801 err(1, "write of trailer failed"); 802 } 803 804 static void 805 usage(void) 806 { 807 808 fprintf(stderr, "Usage: %s [-aDfhqV] [options] {outfile|-}\n", 809 getprogname()); 810 fprintf(stderr, "Options:\n" 811 "\t-B buffer size\n" 812 "\t-c channels\n" 813 "\t-d devices\n" 814 "\t-f sequencerdev\n" 815 "\t-n notesperbeat\n" 816 "\t-r raw_output\n" 817 "\t-T tempo\n" 818 "\t-t recording time\n"); 819 exit(EXIT_FAILURE); 820 } 821