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., 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 */
52static int use_realtime = 0;
53
54/* control the event buffering by using a blocking mode */
55static 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
66static FILE *F;
67static snd_seq_t *seq_handle = NULL;
68static int ppq = 96;
69static int slave_ppq = 96;
70
71static double local_secs = 0;
72static int local_ticks = 0;
73static int local_tempo = 500000;
74
75static int dest_queue = -1;
76static int shared_queue = 0;
77static int tick_offset = 0;
78static int dest_client = DEST_CLIENT_NUMBER;
79static int dest_port = DEST_PORT_NUMBER;
80static int my_port = 0;
81
82static int verbose = 0;
83static int slave   = 0;		/* allow external sync */
84
85#define VERB_INFO	1
86#define VERB_MUCH	2
87#define VERB_EVENT	3
88
89static void alsa_start_timer(void);
90static void alsa_stop_timer(void);
91static void wait_start(void);
92
93
94static 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
99static 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
106static 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 */
130static int mygetc(void)
131{
132	return getc(F);
133}
134
135/* print out the text */
136static 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
148static 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 */
203static 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 */
220static 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 */
229static void alsa_start_timer(void)
230{
231	snd_seq_start_queue(seq_handle, dest_queue, NULL);
232}
233
234/* stop the timer */
235static 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 */
243static 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
263static 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
275static 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
287static 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
299static 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
311static 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
322static 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
333static 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
344static 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
365static 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 */
396static 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 */
411static 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 */
436static 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
449int 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