1 /* 2 * MIDI file player for ALSA sequencer 3 * (type 0 only!, the library that is used doesn't support merging of tracks) 4 * 5 * Copyright (c) 1998 by Frank van de Pol <F.K.W.van.de.Pol (at) inter.nl.net> 6 * 7 * Modified so that this uses alsa-lib 8 * 1999 Jan. by Isaku Yamahata <yamahata (at) kusm.kyoto-u.ac.jp> 9 * 10 * 19990604 Takashi Iwai <iwai (at) ww.uni-erlangen.de> 11 * - use blocking mode 12 * - fix tempo event bug 13 * - add command line options 14 * 15 * 19990827 Takashi Iwai <iwai (at) ww.uni-erlangen.de> 16 * - use snd_seq_alloc_queue() 17 * 18 * 19990916 Takashi Iwai <iwai (at) ww.uni-erlangen.de> 19 * - use middle-level sequencer routines and macros 20 * 21 * This program is free software; you can redistribute it and/or modify 22 * it under the terms of the GNU General Public License as published by 23 * the Free Software Foundation; either version 2 of the License, or 24 * (at your option) any later version. 25 * 26 * This program is distributed in the hope that it will be useful, 27 * but WITHOUT ANY WARRANTY; without even the implied warranty of 28 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 29 * GNU General Public License for more details. 30 * 31 * You should have received a copy of the GNU General Public License 32 * along with this program; if not, write to the Free Software 33 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 34 * 35 */ 36 37 #include <stdio.h> 38 #include <ctype.h> 39 #include <fcntl.h> 40 #include <stdlib.h> 41 #include <sys/ioctl.h> 42 #include <unistd.h> 43 #include <errno.h> 44 #include <string.h> 45 46 #include "midifile.h" /* SMF library header */ 47 #include "midifile.c" /* SMF library code */ 48 49 #include "../include/asoundlib.h" 50 51 /* send the real-time time stamps (instead of midi ticks) to the ALSA sequencer */ 52 static int use_realtime = 0; 53 54 /* control the event buffering by using a blocking mode */ 55 static int use_blocking_mode = 1; 56 57 /* default destination queue, client and port numbers */ 58 #define DEST_CLIENT_NUMBER 65 59 #define DEST_PORT_NUMBER 0 60 61 /* event pool size */ 62 #define WRITE_POOL_SIZE 200 63 #define WRITE_POOL_SPACE 10 64 #define READ_POOL_SIZE 10 /* we need to read the pool only for echoing */ 65 66 static FILE *F; 67 static snd_seq_t *seq_handle = NULL; 68 static int ppq = 96; 69 static int slave_ppq = 96; 70 71 static double local_secs = 0; 72 static int local_ticks = 0; 73 static int local_tempo = 500000; 74 75 static int dest_queue = -1; 76 static int shared_queue = 0; 77 static int tick_offset = 0; 78 static int dest_client = DEST_CLIENT_NUMBER; 79 static int dest_port = DEST_PORT_NUMBER; 80 static int my_port = 0; 81 82 static int verbose = 0; 83 static int slave = 0; /* allow external sync */ 84 85 #define VERB_INFO 1 86 #define VERB_MUCH 2 87 #define VERB_EVENT 3 88 89 static void alsa_start_timer(void); 90 static void alsa_stop_timer(void); 91 static void wait_start(void); 92 93 94 static inline double tick2time_dbl(int tick) 95 { 96 return local_secs + ((double) (tick - local_ticks) * (double) local_tempo * 1.0E-6 / (double) ppq); 97 } 98 99 static void tick2time(snd_seq_real_time_t * tm, int tick) 100 { 101 double secs = tick2time_dbl(tick); 102 tm->tv_sec = secs; 103 tm->tv_nsec = (secs - tm->tv_sec) * 1.0E9; 104 } 105 106 static void write_ev(snd_seq_event_t *ev) 107 { 108 int rc; 109 110 if (use_blocking_mode) { 111 rc = snd_seq_event_output(seq_handle, ev); 112 if (rc < 0) { 113 printf("written = %i (%s)\n", rc, snd_strerror(rc)); 114 exit(1); 115 } 116 return; 117 } 118 while ((rc = snd_seq_event_output(seq_handle, ev)) < 0) { 119 int npfds = snd_seq_poll_descriptors_count(seq_handle, POLLOUT); 120 struct pollfd *pfds = alloca(sizeof(*pfds) * npfds); 121 snd_seq_poll_descriptors(seq_handle, pfds, npfds, POLLOUT); 122 if ((rc = poll(pfds, npfds, -1)) < 0) { 123 printf("poll error = %i (%s)\n", rc, snd_strerror(errno)); 124 exit(1); 125 } 126 } 127 } 128 129 /* read the byte */ 130 static int mygetc(void) 131 { 132 return getc(F); 133 } 134 135 /* print out the text */ 136 static void mytext(int type ATTRIBUTE_UNUSED, int leng, char *msg) 137 { 138 char *p; 139 char *ep = msg + leng; 140 141 if (verbose >= VERB_INFO) { 142 for (p = msg; p < ep; p++) 143 putchar(isprint(*p) ? *p : '?'); 144 putchar('\n'); 145 } 146 } 147 148 static void do_header(int format, int ntracks, int division) 149 { 150 snd_seq_queue_tempo_t *tempo; 151 152 if (verbose >= VERB_INFO) 153 printf("smf format %d, %d tracks, %d ppq\n", format, ntracks, division); 154 ppq = division; 155 156 if (format != 0 || ntracks != 1) { 157 printf("This player does not support merging of tracks.\n"); 158 if (! shared_queue) 159 alsa_stop_timer(); 160 exit(1); 161 } 162 /* set the ppq */ 163 snd_seq_queue_tempo_alloca(&tempo); 164 /* ppq must be set before starting the timer */ 165 if (snd_seq_get_queue_tempo(seq_handle, dest_queue, tempo) < 0) { 166 perror("get_queue_tempo"); 167 exit(1); 168 } 169 if ((slave_ppq = snd_seq_queue_tempo_get_ppq(tempo)) != ppq) { 170 snd_seq_queue_tempo_set_ppq(tempo, ppq); 171 if (snd_seq_set_queue_tempo(seq_handle, dest_queue, tempo) < 0) { 172 perror("set_queue_tempo"); 173 if (!slave && !shared_queue) 174 exit(1); 175 else 176 printf("different PPQ %d in SMF from queue PPQ %d\n", ppq, slave_ppq); 177 } else 178 slave_ppq = ppq; 179 if (verbose >= VERB_INFO) 180 printf("ALSA Timer updated, PPQ = %d\n", snd_seq_queue_tempo_get_ppq(tempo)); 181 } 182 183 /* start playing... */ 184 if (slave) { 185 if (verbose >= VERB_INFO) 186 printf("Wait till timer starts...\n"); 187 wait_start(); 188 if (verbose >= VERB_INFO) 189 printf("Go!\n"); 190 } else if (shared_queue) { 191 snd_seq_queue_status_t *stat; 192 snd_seq_queue_status_alloca(&stat); 193 snd_seq_get_queue_status(seq_handle, dest_queue, stat); 194 tick_offset = snd_seq_queue_status_get_tick_time(stat); 195 fprintf(stderr, "tick offset = %d\n", tick_offset); 196 } else { 197 alsa_start_timer(); 198 tick_offset = 0; 199 } 200 } 201 202 /* fill the event time */ 203 static void set_event_time(snd_seq_event_t *ev, unsigned int currtime) 204 { 205 if (use_realtime) { 206 snd_seq_real_time_t rtime; 207 if (ppq != slave_ppq) 208 currtime = (currtime * slave_ppq) / ppq; 209 tick2time(&rtime, currtime); 210 snd_seq_ev_schedule_real(ev, dest_queue, 0, &rtime); 211 } else { 212 if (ppq != slave_ppq) 213 currtime = (currtime * slave_ppq) / ppq; 214 currtime += tick_offset; 215 snd_seq_ev_schedule_tick(ev, dest_queue, 0, currtime); 216 } 217 } 218 219 /* fill the normal event header */ 220 static void set_event_header(snd_seq_event_t *ev) 221 { 222 snd_seq_ev_clear(ev); 223 snd_seq_ev_set_dest(ev, dest_client, dest_port); 224 snd_seq_ev_set_source(ev, my_port); 225 set_event_time(ev, Mf_currtime); 226 } 227 228 /* start the timer */ 229 static void alsa_start_timer(void) 230 { 231 snd_seq_start_queue(seq_handle, dest_queue, NULL); 232 } 233 234 /* stop the timer */ 235 static void alsa_stop_timer(void) 236 { 237 snd_seq_event_t ev; 238 set_event_header(&ev); 239 snd_seq_stop_queue(seq_handle, dest_queue, &ev); 240 } 241 242 /* change the tempo */ 243 static void do_tempo(int us) 244 { 245 snd_seq_event_t ev; 246 247 if (verbose >= VERB_MUCH) { 248 double bpm; 249 bpm = 60.0E6 / (double) us; 250 printf("Tempo %d us/beat, %.2f bpm\n", us, bpm); 251 } 252 253 /* store the new tempo and timestamp of the tempo change */ 254 local_secs = tick2time_dbl(Mf_currtime); 255 local_ticks = Mf_currtime; 256 local_tempo = us; 257 258 set_event_header(&ev); 259 if (!slave) 260 snd_seq_change_queue_tempo(seq_handle, dest_queue, us, &ev); 261 } 262 263 static void do_noteon(int chan, int pitch, int vol) 264 { 265 snd_seq_event_t ev; 266 267 if (verbose >= VERB_EVENT) 268 printf("%ld: NoteOn (%d) %d %d\n", Mf_currtime, chan, pitch, vol); 269 set_event_header(&ev); 270 snd_seq_ev_set_noteon(&ev, chan, pitch, vol); 271 write_ev(&ev); 272 } 273 274 275 static void do_noteoff(int chan, int pitch, int vol) 276 { 277 snd_seq_event_t ev; 278 279 if (verbose >= VERB_EVENT) 280 printf("%ld: NoteOff (%d) %d %d\n", Mf_currtime, chan, pitch, vol); 281 set_event_header(&ev); 282 snd_seq_ev_set_noteoff(&ev, chan, pitch, vol); 283 write_ev(&ev); 284 } 285 286 287 static void do_program(int chan, int program) 288 { 289 snd_seq_event_t ev; 290 291 if (verbose >= VERB_EVENT) 292 printf("%ld: Program (%d) %d\n", Mf_currtime, chan, program); 293 set_event_header(&ev); 294 snd_seq_ev_set_pgmchange(&ev, chan, program); 295 write_ev(&ev); 296 } 297 298 299 static void do_parameter(int chan, int control, int value) 300 { 301 snd_seq_event_t ev; 302 303 if (verbose >= VERB_EVENT) 304 printf("%ld: Control (%d) %d %d\n", Mf_currtime, chan, control, value); 305 set_event_header(&ev); 306 snd_seq_ev_set_controller(&ev, chan, control, value); 307 write_ev(&ev); 308 } 309 310 311 static void do_pitchbend(int chan, int lsb, int msb) 312 { /* !@#$% lsb & msb are in the wrong order in docs */ 313 snd_seq_event_t ev; 314 315 if (verbose >= VERB_EVENT) 316 printf("%ld: Pitchbend (%d) %d %d\n", Mf_currtime, chan, lsb, msb); 317 set_event_header(&ev); 318 snd_seq_ev_set_pitchbend(&ev, chan, (lsb + (msb << 7)) - 8192); 319 write_ev(&ev); 320 } 321 322 static void do_pressure(int chan, int pitch, int pressure) 323 { 324 snd_seq_event_t ev; 325 326 if (verbose >= VERB_EVENT) 327 printf("%ld: KeyPress (%d) %d %d\n", Mf_currtime, chan, pitch, pressure); 328 set_event_header(&ev); 329 snd_seq_ev_set_keypress(&ev, chan, pitch, pressure); 330 write_ev(&ev); 331 } 332 333 static void do_chanpressure(int chan, int pressure) 334 { 335 snd_seq_event_t ev; 336 337 if (verbose >= VERB_EVENT) 338 printf("%ld: ChanPress (%d) %d\n", Mf_currtime, chan, pressure); 339 set_event_header(&ev); 340 snd_seq_ev_set_chanpress(&ev, chan, pressure); 341 write_ev(&ev); 342 } 343 344 static void do_sysex(int len, char *msg) 345 { 346 snd_seq_event_t ev; 347 348 if (verbose >= VERB_MUCH) { 349 int c; 350 printf("%ld: Sysex, len=%d\n", Mf_currtime, len); 351 for (c = 0; c < len; c++) { 352 printf(" %02x", (unsigned char)msg[c]); 353 if (c % 16 == 15) 354 putchar('\n'); 355 } 356 if (c % 16 != 15) 357 putchar('\n'); 358 } 359 360 set_event_header(&ev); 361 snd_seq_ev_set_sysex(&ev, len, msg); 362 write_ev(&ev); 363 } 364 365 static snd_seq_event_t *wait_for_event(void) 366 { 367 int left; 368 snd_seq_event_t *input_event; 369 370 if (use_blocking_mode) { 371 /* read the event - blocked until any event is read */ 372 left = snd_seq_event_input(seq_handle, &input_event); 373 } else { 374 /* read the event - using select syscall */ 375 while ((left = snd_seq_event_input(seq_handle, &input_event)) >= 0 && 376 input_event == NULL) { 377 int npfds = snd_seq_poll_descriptors_count(seq_handle, POLLIN); 378 struct pollfd *pfds = alloca(sizeof(*pfds) * npfds); 379 snd_seq_poll_descriptors(seq_handle, pfds, npfds, POLLIN); 380 if ((left = poll(pfds, npfds, -1)) < 0) { 381 printf("poll error = %i (%s)\n", errno, snd_strerror(errno)); 382 exit(1); 383 } 384 } 385 } 386 387 if (left < 0) { 388 printf("alsa_sync error!:%s\n", snd_strerror(left)); 389 return NULL; 390 } 391 392 return input_event; 393 } 394 395 /* synchronize to the end of the event */ 396 static void alsa_sync(void) 397 { 398 /* send the echo event to the self client. */ 399 if (verbose >= VERB_MUCH) 400 printf("alsa_sync syncing...\n"); 401 /* dump the buffer */ 402 snd_seq_drain_output(seq_handle); 403 snd_seq_sync_output_queue(seq_handle); 404 if (verbose >= VERB_MUCH) 405 printf("alsa_sync synced\n"); 406 sleep(1); /* give a time for note releasing.. */ 407 } 408 409 410 /* wait for the start of the queue */ 411 static void wait_start(void) 412 { 413 snd_seq_event_t *input_event; 414 415 /* wait for the start event from the system timer */ 416 for (;;) { 417 input_event = wait_for_event(); 418 if (input_event) { 419 if (verbose >= VERB_MUCH) 420 printf("wait_start got event. type=%d, flags=%d\n", 421 input_event->type, input_event->flags); 422 if (input_event->type == SND_SEQ_EVENT_START && 423 input_event->data.queue.queue == dest_queue) { 424 snd_seq_free_event(input_event); 425 break; 426 } 427 snd_seq_free_event(input_event); 428 } 429 } 430 if (verbose >= VERB_MUCH) 431 printf("start received\n"); 432 } 433 434 435 /* print the usage */ 436 static void usage(void) 437 { 438 fprintf(stderr, "usage: playmidi1 [options] [file]\n"); 439 fprintf(stderr, " options:\n"); 440 fprintf(stderr, " -v: verbose mode\n"); 441 fprintf(stderr, " -a client:port : set destination address (default=%d:%d)\n", 442 DEST_CLIENT_NUMBER, DEST_PORT_NUMBER); 443 fprintf(stderr, " -q queue: use the specified queue\n"); 444 fprintf(stderr, " -s queue: slave mode (allow external clock synchronization)\n"); 445 fprintf(stderr, " -r : play on real-time mode\n"); 446 fprintf(stderr, " -b : play on non-blocking mode\n"); 447 } 448 449 int main(int argc, char *argv[]) 450 { 451 int tmp; 452 int c; 453 snd_seq_addr_t dest_addr; 454 const char *addr = "65:0"; 455 456 while ((c = getopt(argc, argv, "s:a:p:q:vrb")) != -1) { 457 switch (c) { 458 case 'v': 459 verbose++; 460 break; 461 case 'a': 462 case 'p': 463 addr = optarg; 464 break; 465 case 'q': 466 dest_queue = atoi(optarg); 467 if (dest_queue < 0) { 468 fprintf(stderr, "invalid queue number %d\n", dest_queue); 469 exit(1); 470 } 471 break; 472 case 's': 473 slave = 1; 474 dest_queue = atoi(optarg); 475 if (dest_queue < 0) { 476 fprintf(stderr, "invalid queue number %d\n", dest_queue); 477 exit(1); 478 } 479 break; 480 case 'r': 481 use_realtime = 1; 482 break; 483 case 'b': 484 use_blocking_mode = 0; 485 break; 486 default: 487 usage(); 488 exit(1); 489 } 490 } 491 492 if (verbose >= VERB_INFO) { 493 if (use_realtime) 494 printf("ALSA MIDI Player, feeding events to real-time queue\n"); 495 else 496 printf("ALSA MIDI Player, feeding events to song queue\n"); 497 } 498 499 /* open the sequencer device */ 500 /* Here we open the device in read/write for slave mode. */ 501 tmp = snd_seq_open(&seq_handle, "hw", slave ? SND_SEQ_OPEN_DUPLEX : SND_SEQ_OPEN_OUTPUT, 0); 502 if (tmp < 0) { 503 perror("open /dev/snd/seq"); 504 exit(1); 505 } 506 507 tmp = snd_seq_nonblock(seq_handle, !use_blocking_mode); 508 if (tmp < 0) { 509 perror("block_mode"); 510 exit(1); 511 } 512 513 /* set the name */ 514 /* set the event filter to receive only the echo event */ 515 /* if running in slave mode, also listen for a START event */ 516 if (slave) 517 snd_seq_set_client_event_filter(seq_handle, SND_SEQ_EVENT_START); 518 snd_seq_set_client_name(seq_handle, "MIDI file player"); 519 520 /* create the port */ 521 my_port = snd_seq_create_simple_port(seq_handle, "Port 0", 522 SND_SEQ_PORT_CAP_WRITE | 523 SND_SEQ_PORT_CAP_READ, 524 SND_SEQ_PORT_TYPE_MIDI_GENERIC); 525 if (my_port < 0) { 526 perror("create port"); 527 exit(1); 528 } 529 530 if (snd_seq_parse_address(seq_handle, &dest_addr, addr) < 0) { 531 perror("invalid destination address"); 532 exit(1); 533 } 534 dest_client = dest_addr.client; 535 dest_port = dest_addr.port; 536 537 /* set the queue */ 538 if (dest_queue >= 0) { 539 shared_queue = 1; 540 if (snd_seq_set_queue_usage(seq_handle, dest_queue, 1) < 0) { 541 perror("use queue"); 542 exit(1); 543 } 544 } else { 545 shared_queue = 0; 546 dest_queue = snd_seq_alloc_queue(seq_handle); 547 if (dest_queue < 0) { 548 perror("alloc queue"); 549 exit(1); 550 } 551 } 552 553 /* set the subscriber */ 554 tmp = snd_seq_connect_to(seq_handle, my_port, dest_client, dest_port); 555 if (tmp < 0) { 556 perror("subscribe"); 557 exit(1); 558 } 559 560 /* subscribe for the timer START event */ 561 if (slave) { 562 tmp = snd_seq_connect_from(seq_handle, my_port, 563 SND_SEQ_CLIENT_SYSTEM, 564 dest_queue + 16 /*snd_seq_queue_sync_port(dest_queue)*/); 565 if (tmp < 0) { 566 perror("subscribe"); 567 exit(1); 568 } 569 } 570 571 /* change the pool size */ 572 if (snd_seq_set_client_pool_output(seq_handle, WRITE_POOL_SIZE) < 0 || 573 snd_seq_set_client_pool_input(seq_handle, READ_POOL_SIZE) < 0 || 574 snd_seq_set_client_pool_output_room(seq_handle, WRITE_POOL_SPACE) < 0) { 575 perror("pool"); 576 exit(1); 577 } 578 579 if (optind < argc) { 580 F = fopen(argv[optind], "r"); 581 if (F == NULL) { 582 fprintf(stderr, "playmidi1: can't open file %s\n", argv[optind]); 583 exit(1); 584 } 585 } else 586 F = stdin; 587 588 Mf_header = do_header; 589 Mf_tempo = do_tempo; 590 Mf_getc = mygetc; 591 Mf_text = mytext; 592 593 Mf_noteon = do_noteon; 594 Mf_noteoff = do_noteoff; 595 Mf_program = do_program; 596 Mf_parameter = do_parameter; 597 Mf_pitchbend = do_pitchbend; 598 Mf_pressure = do_pressure; 599 Mf_chanpressure = do_chanpressure; 600 Mf_sysex = do_sysex; 601 602 /* go.. go.. go.. */ 603 mfread(); 604 605 alsa_sync(); 606 if (! shared_queue) 607 alsa_stop_timer(); 608 609 snd_seq_close(seq_handle); 610 611 if (verbose >= VERB_INFO) { 612 printf("Stopping at %f s, tick %f\n", 613 tick2time_dbl(Mf_currtime + 1), (double) (Mf_currtime + 1)); 614 } 615 616 exit(0); 617 } 618