Lines Matching defs:*
2 * MIDI file player for ALSA sequencer
3 * (type 0 only!, the library that is used doesn't support merging of tracks)
5 * Copyright (c) 1998 by Frank van de Pol <F.K.W.van.de.Pol@inter.nl.net>
7 * Modified so that this uses alsa-lib
8 * 1999 Jan. by Isaku Yamahata <yamahata@kusm.kyoto-u.ac.jp>
10 * 19990604 Takashi Iwai <iwai@ww.uni-erlangen.de>
11 * - use blocking mode
12 * - fix tempo event bug
13 * - add command line options
15 * 19990827 Takashi Iwai <iwai@ww.uni-erlangen.de>
16 * - use snd_seq_alloc_queue()
18 * 19990916 Takashi Iwai <iwai@ww.uni-erlangen.de>
19 * - use middle-level sequencer routines and macros
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.
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.
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
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>
46 #include "midifile.h" /* SMF library header */
47 #include "midifile.c" /* SMF library code */
49 #include "../include/asoundlib.h"
51 /* send the real-time time stamps (instead of midi ticks) to the ALSA sequencer */
52 static int use_realtime = 0;
54 /* control the event buffering by using a blocking mode */
55 static int use_blocking_mode = 1;
57 /* default destination queue, client and port numbers */
58 #define DEST_CLIENT_NUMBER 65
59 #define DEST_PORT_NUMBER 0
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 */
66 static FILE *F;
67 static snd_seq_t *seq_handle = NULL;
68 static int ppq = 96;
69 static int slave_ppq = 96;
71 static double local_secs = 0;
72 static int local_ticks = 0;
73 static int local_tempo = 500000;
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;
82 static int verbose = 0;
83 static int slave = 0; /* allow external sync */
85 #define VERB_INFO 1
86 #define VERB_MUCH 2
87 #define VERB_EVENT 3
89 static void alsa_start_timer(void);
90 static void alsa_stop_timer(void);
91 static void wait_start(void);
94 static inline double tick2time_dbl(int tick)
96 return local_secs + ((double) (tick - local_ticks) * (double) local_tempo * 1.0E-6 / (double) ppq);
99 static void tick2time(snd_seq_real_time_t * tm, int tick)
101 double secs = tick2time_dbl(tick);
102 tm->tv_sec = secs;
103 tm->tv_nsec = (secs - tm->tv_sec) * 1.0E9;
106 static void write_ev(snd_seq_event_t *ev)
108 int rc;
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);
116 return;
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);
129 /* read the byte */
130 static int mygetc(void)
132 return getc(F);
135 /* print out the text */
136 static void mytext(int type ATTRIBUTE_UNUSED, int leng, char *msg)
138 char *p;
139 char *ep = msg + leng;
141 if (verbose >= VERB_INFO) {
142 for (p = msg; p < ep; p++)
143 putchar(isprint(*p) ? *p : '?');
144 putchar('\n');
148 static void do_header(int format, int ntracks, int division)
150 snd_seq_queue_tempo_t *tempo;
152 if (verbose >= VERB_INFO)
153 printf("smf format %d, %d tracks, %d ppq\n", format, ntracks, division);
154 ppq = division;
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);
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);
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));
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;
202 /* fill the event time */
203 static void set_event_time(snd_seq_event_t *ev, unsigned int currtime)
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);
219 /* fill the normal event header */
220 static void set_event_header(snd_seq_event_t *ev)
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);
228 /* start the timer */
229 static void alsa_start_timer(void)
231 snd_seq_start_queue(seq_handle, dest_queue, NULL);
234 /* stop the timer */
235 static void alsa_stop_timer(void)
237 snd_seq_event_t ev;
238 set_event_header(&ev);
239 snd_seq_stop_queue(seq_handle, dest_queue, &ev);
242 /* change the tempo */
243 static void do_tempo(int us)
245 snd_seq_event_t ev;
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);
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;
258 set_event_header(&ev);
259 if (!slave)
260 snd_seq_change_queue_tempo(seq_handle, dest_queue, us, &ev);
263 static void do_noteon(int chan, int pitch, int vol)
265 snd_seq_event_t ev;
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);
275 static void do_noteoff(int chan, int pitch, int vol)
277 snd_seq_event_t ev;
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);
287 static void do_program(int chan, int program)
289 snd_seq_event_t ev;
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);
299 static void do_parameter(int chan, int control, int value)
301 snd_seq_event_t ev;
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);
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;
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);
322 static void do_pressure(int chan, int pitch, int pressure)
324 snd_seq_event_t ev;
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);
333 static void do_chanpressure(int chan, int pressure)
335 snd_seq_event_t ev;
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);
344 static void do_sysex(int len, char *msg)
346 snd_seq_event_t ev;
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');
356 if (c % 16 != 15)
357 putchar('\n');
360 set_event_header(&ev);
361 snd_seq_ev_set_sysex(&ev, len, msg);
362 write_ev(&ev);
365 static snd_seq_event_t *wait_for_event(void)
367 int left;
368 snd_seq_event_t *input_event;
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);
387 if (left < 0) {
388 printf("alsa_sync error!:%s\n", snd_strerror(left));
389 return NULL;
392 return input_event;
395 /* synchronize to the end of the event */
396 static void alsa_sync(void)
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.. */
410 /* wait for the start of the queue */
411 static void wait_start(void)
413 snd_seq_event_t *input_event;
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;
427 snd_seq_free_event(input_event);
430 if (verbose >= VERB_MUCH)
431 printf("start received\n");
435 /* print the usage */
436 static void usage(void)
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");
449 int main(int argc, char *argv[])
451 int tmp;
452 int c;
453 snd_seq_addr_t dest_addr;
454 const char *addr = "65:0";
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);
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);
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);
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");
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);
507 tmp = snd_seq_nonblock(seq_handle, !use_blocking_mode);
508 if (tmp < 0) {
509 perror("block_mode");
510 exit(1);
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");
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);
530 if (snd_seq_parse_address(seq_handle, &dest_addr, addr) < 0) {
531 perror("invalid destination address");
532 exit(1);
534 dest_client = dest_addr.client;
535 dest_port = dest_addr.port;
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);
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);
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);
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);
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);
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);
585 } else
586 F = stdin;
588 Mf_header = do_header;
589 Mf_tempo = do_tempo;
590 Mf_getc = mygetc;
591 Mf_text = mytext;
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;
602 /* go.. go.. go.. */
603 mfread();
605 alsa_sync();
606 if (! shared_queue)
607 alsa_stop_timer();
609 snd_seq_close(seq_handle);
611 if (verbose >= VERB_INFO) {
612 printf("Stopping at %f s, tick %f\n",
613 tick2time_dbl(Mf_currtime + 1), (double) (Mf_currtime + 1));
616 exit(0);