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