| 
									
										
										
										
											1999-01-24 12:00:39 +00:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  *   MIDI file player for ALSA sequencer  | 
					
						
							|  |  |  |  *   (type 0 only!, the library that is used doesn't support merging of tracks) | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *   Copyright (c) 1998 by Frank van de Pol <F.K.W.van.de.Pol@inter.nl.net> | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											1999-02-03 10:18:00 +00:00
										 |  |  |  *   Modified so that this uses alsa-lib | 
					
						
							|  |  |  |  *   1999 Jan. by Isaku Yamahata <yamahata@kusm.kyoto-u.ac.jp> | 
					
						
							| 
									
										
										
										
											1999-01-24 12:00:39 +00:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											1999-06-15 22:26:21 +00:00
										 |  |  |  *   19990604	Takashi Iwai <iwai@ww.uni-erlangen.de> | 
					
						
							|  |  |  |  *	- use blocking mode | 
					
						
							|  |  |  |  *	- fix tempo event bug | 
					
						
							|  |  |  |  *	- add command line options | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											1999-09-01 22:19:11 +00:00
										 |  |  |  *   19990827	Takashi Iwai <iwai@ww.uni-erlangen.de> | 
					
						
							|  |  |  |  *	- use snd_seq_alloc_queue() | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											1999-09-17 16:17:21 +00:00
										 |  |  |  *   19990916	Takashi Iwai <iwai@ww.uni-erlangen.de> | 
					
						
							|  |  |  |  *	- use middle-level sequencer routines and macros | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											1999-01-24 12:00:39 +00:00
										 |  |  |  *   This program is free software; you can redistribute it and/or modify | 
					
						
							|  |  |  |  *   it under the terms of the GNU General Public License as published by | 
					
						
							|  |  |  |  *   the Free Software Foundation; either version 2 of the License, or | 
					
						
							|  |  |  |  *   (at your option) any later version. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *   This program is distributed in the hope that it will be useful, | 
					
						
							|  |  |  |  *   but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  |  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
					
						
							|  |  |  |  *   GNU General Public License for more details. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *   You should have received a copy of the GNU General Public License | 
					
						
							|  |  |  |  *   along with this program; if not, write to the Free Software | 
					
						
							| 
									
										
										
										
											2017-11-14 14:29:26 +01:00
										 |  |  |  *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA | 
					
						
							| 
									
										
										
										
											1999-01-24 12:00:39 +00:00
										 |  |  |  * | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-30 18:22:59 +02:00
										 |  |  | #include "config.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1999-01-24 12:00:39 +00:00
										 |  |  | #include <stdio.h>
 | 
					
						
							|  |  |  | #include <ctype.h>
 | 
					
						
							|  |  |  | #include <fcntl.h>
 | 
					
						
							|  |  |  | #include <stdlib.h>
 | 
					
						
							|  |  |  | #include <sys/ioctl.h>
 | 
					
						
							|  |  |  | #include <unistd.h>
 | 
					
						
							|  |  |  | #include <errno.h>
 | 
					
						
							| 
									
										
										
										
											1999-01-25 20:49:14 +00:00
										 |  |  | #include <string.h>
 | 
					
						
							| 
									
										
										
										
											1999-01-24 12:00:39 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | #include "midifile.h"		/* SMF library header */
 | 
					
						
							|  |  |  | #include "midifile.c"		/* SMF library code */
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1999-06-03 21:41:29 +00:00
										 |  |  | #include "../include/asoundlib.h"
 | 
					
						
							| 
									
										
										
										
											1999-01-24 12:00:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-03-12 20:14:33 +00:00
										 |  |  | /* send the real-time time stamps (instead of midi ticks) to the ALSA sequencer */ | 
					
						
							| 
									
										
										
										
											2000-09-05 17:15:11 +00:00
										 |  |  | static int use_realtime = 0; | 
					
						
							| 
									
										
										
										
											1999-06-15 22:26:21 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-03-12 20:14:33 +00:00
										 |  |  | /* control the event buffering by using a blocking mode */ | 
					
						
							| 
									
										
										
										
											2000-09-05 17:15:11 +00:00
										 |  |  | static int use_blocking_mode = 1; | 
					
						
							| 
									
										
										
										
											1999-06-15 22:26:21 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | /* default destination queue, client and port numbers */ | 
					
						
							|  |  |  | #define DEST_CLIENT_NUMBER	65
 | 
					
						
							|  |  |  | #define DEST_PORT_NUMBER	0
 | 
					
						
							| 
									
										
										
										
											1999-05-23 18:34:46 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1999-06-15 22:26:21 +00:00
										 |  |  | /* event pool size */ | 
					
						
							|  |  |  | #define WRITE_POOL_SIZE		200
 | 
					
						
							|  |  |  | #define WRITE_POOL_SPACE	10
 | 
					
						
							| 
									
										
										
										
											2002-03-12 20:14:33 +00:00
										 |  |  | #define READ_POOL_SIZE		10	/* we need to read the pool only for echoing */
 | 
					
						
							| 
									
										
										
										
											1999-01-24 12:00:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1999-06-15 22:26:21 +00:00
										 |  |  | static FILE *F; | 
					
						
							|  |  |  | static snd_seq_t *seq_handle = NULL; | 
					
						
							|  |  |  | static int ppq = 96; | 
					
						
							| 
									
										
										
										
											2000-09-05 17:15:11 +00:00
										 |  |  | static int slave_ppq = 96; | 
					
						
							| 
									
										
										
										
											1999-01-24 12:00:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1999-06-15 22:26:21 +00:00
										 |  |  | static double local_secs = 0; | 
					
						
							|  |  |  | static int local_ticks = 0; | 
					
						
							|  |  |  | static int local_tempo = 500000; | 
					
						
							| 
									
										
										
										
											1999-01-24 12:00:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-09-05 17:15:11 +00:00
										 |  |  | static int dest_queue = -1; | 
					
						
							| 
									
										
										
										
											2001-12-10 16:45:05 +00:00
										 |  |  | static int shared_queue = 0; | 
					
						
							|  |  |  | static int tick_offset = 0; | 
					
						
							| 
									
										
										
										
											1999-01-24 12:00:39 +00:00
										 |  |  | static int dest_client = DEST_CLIENT_NUMBER; | 
					
						
							| 
									
										
										
										
											1999-05-23 18:34:46 +00:00
										 |  |  | static int dest_port = DEST_PORT_NUMBER; | 
					
						
							| 
									
										
										
										
											1999-09-17 16:17:21 +00:00
										 |  |  | static int my_port = 0; | 
					
						
							| 
									
										
										
										
											1999-01-24 12:00:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1999-06-15 22:26:21 +00:00
										 |  |  | static int verbose = 0; | 
					
						
							| 
									
										
										
										
											1999-08-08 17:41:09 +00:00
										 |  |  | static int slave   = 0;		/* allow external sync */ | 
					
						
							| 
									
										
										
										
											1999-01-24 12:00:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1999-06-15 22:26:21 +00:00
										 |  |  | #define VERB_INFO	1
 | 
					
						
							|  |  |  | #define VERB_MUCH	2
 | 
					
						
							|  |  |  | #define VERB_EVENT	3
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void alsa_start_timer(void); | 
					
						
							|  |  |  | static void alsa_stop_timer(void); | 
					
						
							| 
									
										
										
										
											1999-08-08 17:41:09 +00:00
										 |  |  | static void wait_start(void); | 
					
						
							| 
									
										
										
										
											1999-01-24 12:00:39 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static inline double tick2time_dbl(int tick) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											1999-06-15 22:26:21 +00:00
										 |  |  | 	return local_secs + ((double) (tick - local_ticks) * (double) local_tempo * 1.0E-6 / (double) ppq); | 
					
						
							| 
									
										
										
										
											1999-01-24 12:00:39 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void tick2time(snd_seq_real_time_t * tm, int tick) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	double secs = tick2time_dbl(tick); | 
					
						
							|  |  |  | 	tm->tv_sec = secs; | 
					
						
							|  |  |  | 	tm->tv_nsec = (secs - tm->tv_sec) * 1.0E9; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1999-09-17 16:17:21 +00:00
										 |  |  | static void write_ev(snd_seq_event_t *ev) | 
					
						
							| 
									
										
										
										
											1999-06-15 22:26:21 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	int rc; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-09-05 17:15:11 +00:00
										 |  |  | 	if (use_blocking_mode) { | 
					
						
							|  |  |  | 		rc = snd_seq_event_output(seq_handle, ev); | 
					
						
							|  |  |  | 		if (rc < 0) { | 
					
						
							|  |  |  | 			printf("written = %i (%s)\n", rc, snd_strerror(rc)); | 
					
						
							|  |  |  | 			exit(1); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											1999-06-15 22:26:21 +00:00
										 |  |  | 	while ((rc = snd_seq_event_output(seq_handle, ev)) < 0) { | 
					
						
							| 
									
										
										
										
											2001-07-04 13:54:13 +00:00
										 |  |  | 		int npfds = snd_seq_poll_descriptors_count(seq_handle, POLLOUT); | 
					
						
							|  |  |  | 		struct pollfd *pfds = alloca(sizeof(*pfds) * npfds); | 
					
						
							|  |  |  | 		snd_seq_poll_descriptors(seq_handle, pfds, npfds, POLLOUT); | 
					
						
							|  |  |  | 		if ((rc = poll(pfds, npfds, -1)) < 0) { | 
					
						
							|  |  |  | 			printf("poll error = %i (%s)\n", rc, snd_strerror(errno)); | 
					
						
							| 
									
										
										
										
											1999-06-15 22:26:21 +00:00
										 |  |  | 			exit(1); | 
					
						
							| 
									
										
										
										
											1999-01-24 12:00:39 +00:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-03-12 20:14:33 +00:00
										 |  |  | /* read the byte */ | 
					
						
							| 
									
										
										
										
											1999-06-15 22:26:21 +00:00
										 |  |  | static int mygetc(void) | 
					
						
							| 
									
										
										
										
											1999-01-24 12:00:39 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											1999-06-15 22:26:21 +00:00
										 |  |  | 	return getc(F); | 
					
						
							| 
									
										
										
										
											1999-01-24 12:00:39 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-03-12 20:14:33 +00:00
										 |  |  | /* print out the text */ | 
					
						
							| 
									
										
										
										
											2001-09-03 10:41:18 +00:00
										 |  |  | static void mytext(int type ATTRIBUTE_UNUSED, int leng, char *msg) | 
					
						
							| 
									
										
										
										
											1999-01-24 12:00:39 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	char *p; | 
					
						
							|  |  |  | 	char *ep = msg + leng; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1999-06-15 22:26:21 +00:00
										 |  |  | 	if (verbose >= VERB_INFO) { | 
					
						
							|  |  |  | 		for (p = msg; p < ep; p++) | 
					
						
							|  |  |  | 			putchar(isprint(*p) ? *p : '?'); | 
					
						
							|  |  |  | 		putchar('\n'); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											1999-01-24 12:00:39 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1999-06-15 22:26:21 +00:00
										 |  |  | static void do_header(int format, int ntracks, int division) | 
					
						
							| 
									
										
										
										
											1999-01-24 12:00:39 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2001-07-04 13:54:13 +00:00
										 |  |  | 	snd_seq_queue_tempo_t *tempo; | 
					
						
							| 
									
										
										
										
											1999-06-15 22:26:21 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (verbose >= VERB_INFO) | 
					
						
							|  |  |  | 		printf("smf format %d, %d tracks, %d ppq\n", format, ntracks, division); | 
					
						
							| 
									
										
										
										
											1999-01-24 12:00:39 +00:00
										 |  |  | 	ppq = division; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1999-06-15 22:26:21 +00:00
										 |  |  | 	if (format != 0 || ntracks != 1) { | 
					
						
							| 
									
										
										
										
											1999-01-24 12:00:39 +00:00
										 |  |  | 		printf("This player does not support merging of tracks.\n"); | 
					
						
							| 
									
										
										
										
											2001-12-10 16:45:05 +00:00
										 |  |  | 		if (! shared_queue) | 
					
						
							|  |  |  | 			alsa_stop_timer(); | 
					
						
							| 
									
										
										
										
											1999-01-24 12:00:39 +00:00
										 |  |  | 		exit(1); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2002-03-12 20:14:33 +00:00
										 |  |  | 	/* set the ppq */ | 
					
						
							| 
									
										
										
										
											2001-07-04 13:54:13 +00:00
										 |  |  | 	snd_seq_queue_tempo_alloca(&tempo); | 
					
						
							| 
									
										
										
										
											2002-03-12 20:14:33 +00:00
										 |  |  | 	/* ppq must be set before starting the timer */ | 
					
						
							| 
									
										
										
										
											2001-07-04 13:54:13 +00:00
										 |  |  | 	if (snd_seq_get_queue_tempo(seq_handle, dest_queue, tempo) < 0) { | 
					
						
							| 
									
										
										
										
											1999-06-15 22:26:21 +00:00
										 |  |  |     		perror("get_queue_tempo"); | 
					
						
							|  |  |  |     		exit(1); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2001-12-10 16:45:05 +00:00
										 |  |  | 	if ((slave_ppq = snd_seq_queue_tempo_get_ppq(tempo)) != ppq) { | 
					
						
							| 
									
										
										
										
											2001-07-04 13:54:13 +00:00
										 |  |  | 		snd_seq_queue_tempo_set_ppq(tempo, ppq); | 
					
						
							|  |  |  | 		if (snd_seq_set_queue_tempo(seq_handle, dest_queue, tempo) < 0) { | 
					
						
							| 
									
										
										
										
											1999-06-15 22:26:21 +00:00
										 |  |  |     			perror("set_queue_tempo"); | 
					
						
							| 
									
										
										
										
											2001-12-10 16:45:05 +00:00
										 |  |  |     			if (!slave && !shared_queue) | 
					
						
							| 
									
										
										
										
											1999-08-06 19:31:15 +00:00
										 |  |  |     				exit(1); | 
					
						
							| 
									
										
										
										
											2000-09-05 17:15:11 +00:00
										 |  |  | 			else | 
					
						
							|  |  |  | 				printf("different PPQ %d in SMF from queue PPQ %d\n", ppq, slave_ppq); | 
					
						
							|  |  |  | 		} else | 
					
						
							|  |  |  | 			slave_ppq = ppq; | 
					
						
							| 
									
										
										
										
											1999-06-15 22:26:21 +00:00
										 |  |  | 		if (verbose >= VERB_INFO) | 
					
						
							| 
									
										
										
										
											2001-07-04 13:54:13 +00:00
										 |  |  | 			printf("ALSA Timer updated, PPQ = %d\n", snd_seq_queue_tempo_get_ppq(tempo)); | 
					
						
							| 
									
										
										
										
											1999-01-24 12:00:39 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* start playing... */ | 
					
						
							| 
									
										
										
										
											1999-08-08 17:41:09 +00:00
										 |  |  | 	if (slave) { | 
					
						
							|  |  |  | 		if (verbose >= VERB_INFO) | 
					
						
							|  |  |  | 			printf("Wait till timer starts...\n");	 | 
					
						
							|  |  |  | 		wait_start(); | 
					
						
							|  |  |  | 		if (verbose >= VERB_INFO) | 
					
						
							|  |  |  | 			printf("Go!\n");	 | 
					
						
							| 
									
										
										
										
											2001-12-10 16:45:05 +00:00
										 |  |  | 	} else if (shared_queue) { | 
					
						
							|  |  |  | 		snd_seq_queue_status_t *stat; | 
					
						
							|  |  |  | 		snd_seq_queue_status_alloca(&stat); | 
					
						
							|  |  |  | 		snd_seq_get_queue_status(seq_handle, dest_queue, stat); | 
					
						
							|  |  |  | 		tick_offset = snd_seq_queue_status_get_tick_time(stat); | 
					
						
							|  |  |  | 		fprintf(stderr, "tick offset = %d\n", tick_offset); | 
					
						
							|  |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											1999-08-06 19:31:15 +00:00
										 |  |  | 		alsa_start_timer(); | 
					
						
							| 
									
										
										
										
											2001-12-10 16:45:05 +00:00
										 |  |  | 		tick_offset = 0; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											1999-01-24 12:00:39 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-03-12 20:14:33 +00:00
										 |  |  | /* fill the event time */ | 
					
						
							| 
									
										
										
										
											1999-09-17 16:17:21 +00:00
										 |  |  | static void set_event_time(snd_seq_event_t *ev, unsigned int currtime) | 
					
						
							| 
									
										
										
										
											1999-01-24 12:00:39 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2000-09-05 17:15:11 +00:00
										 |  |  | 	if (use_realtime) { | 
					
						
							|  |  |  | 		snd_seq_real_time_t rtime; | 
					
						
							|  |  |  | 		if (ppq != slave_ppq) | 
					
						
							|  |  |  | 			currtime = (currtime * slave_ppq) / ppq; | 
					
						
							|  |  |  | 		tick2time(&rtime, currtime); | 
					
						
							|  |  |  | 		snd_seq_ev_schedule_real(ev, dest_queue, 0, &rtime); | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		if (ppq != slave_ppq) | 
					
						
							|  |  |  | 			currtime = (currtime * slave_ppq) / ppq; | 
					
						
							| 
									
										
										
										
											2001-12-10 16:45:05 +00:00
										 |  |  | 		currtime += tick_offset; | 
					
						
							| 
									
										
										
										
											2000-09-05 17:15:11 +00:00
										 |  |  | 		snd_seq_ev_schedule_tick(ev, dest_queue, 0, currtime); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											1999-06-15 22:26:21 +00:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											1999-01-24 12:00:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-03-12 20:14:33 +00:00
										 |  |  | /* fill the normal event header */ | 
					
						
							| 
									
										
										
										
											1999-09-17 16:17:21 +00:00
										 |  |  | static void set_event_header(snd_seq_event_t *ev) | 
					
						
							| 
									
										
										
										
											1999-06-15 22:26:21 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											1999-09-17 16:17:21 +00:00
										 |  |  | 	snd_seq_ev_clear(ev); | 
					
						
							|  |  |  | 	snd_seq_ev_set_dest(ev, dest_client, dest_port); | 
					
						
							|  |  |  | 	snd_seq_ev_set_source(ev, my_port); | 
					
						
							|  |  |  | 	set_event_time(ev, Mf_currtime); | 
					
						
							| 
									
										
										
										
											1999-01-24 12:00:39 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-03-12 20:14:33 +00:00
										 |  |  | /* start the timer */ | 
					
						
							| 
									
										
										
										
											1999-06-15 22:26:21 +00:00
										 |  |  | static void alsa_start_timer(void) | 
					
						
							| 
									
										
										
										
											1999-01-24 12:00:39 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											1999-09-17 16:17:21 +00:00
										 |  |  | 	snd_seq_start_queue(seq_handle, dest_queue, NULL); | 
					
						
							| 
									
										
										
										
											1999-01-24 12:00:39 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-03-12 20:14:33 +00:00
										 |  |  | /* stop the timer */ | 
					
						
							| 
									
										
										
										
											1999-06-15 22:26:21 +00:00
										 |  |  | static void alsa_stop_timer(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	snd_seq_event_t ev; | 
					
						
							| 
									
										
										
										
											1999-09-17 16:17:21 +00:00
										 |  |  | 	set_event_header(&ev); | 
					
						
							|  |  |  | 	snd_seq_stop_queue(seq_handle, dest_queue, &ev); | 
					
						
							| 
									
										
										
										
											1999-06-15 22:26:21 +00:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											1999-01-24 12:00:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-03-12 20:14:33 +00:00
										 |  |  | /* change the tempo */ | 
					
						
							| 
									
										
										
										
											1999-06-15 22:26:21 +00:00
										 |  |  | static void do_tempo(int us) | 
					
						
							| 
									
										
										
										
											1999-01-24 12:00:39 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	snd_seq_event_t ev; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1999-06-15 22:26:21 +00:00
										 |  |  | 	if (verbose >= VERB_MUCH) { | 
					
						
							|  |  |  | 		double bpm; | 
					
						
							|  |  |  | 		bpm = 60.0E6 / (double) us; | 
					
						
							|  |  |  | 		printf("Tempo %d us/beat, %.2f bpm\n", us, bpm); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											1999-01-24 12:00:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-03-12 20:14:33 +00:00
										 |  |  | 	/* store the new tempo and timestamp of the tempo change */ | 
					
						
							| 
									
										
										
										
											1999-06-15 22:26:21 +00:00
										 |  |  | 	local_secs = tick2time_dbl(Mf_currtime); | 
					
						
							|  |  |  | 	local_ticks = Mf_currtime; | 
					
						
							|  |  |  | 	local_tempo = us; | 
					
						
							| 
									
										
										
										
											1999-01-24 12:00:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1999-09-17 16:17:21 +00:00
										 |  |  | 	set_event_header(&ev); | 
					
						
							| 
									
										
										
										
											1999-08-08 17:41:09 +00:00
										 |  |  | 	if (!slave) | 
					
						
							| 
									
										
										
										
											1999-09-17 16:17:21 +00:00
										 |  |  | 		snd_seq_change_queue_tempo(seq_handle, dest_queue, us, &ev); | 
					
						
							| 
									
										
										
										
											1999-06-15 22:26:21 +00:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											1999-01-24 12:00:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1999-06-15 22:26:21 +00:00
										 |  |  | static void do_noteon(int chan, int pitch, int vol) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	snd_seq_event_t ev; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (verbose >= VERB_EVENT) | 
					
						
							| 
									
										
										
										
											2019-02-17 05:00:53 -08:00
										 |  |  | 		printf("%lu: NoteOn (%d) %d %d\n", Mf_currtime, chan, pitch, vol); | 
					
						
							| 
									
										
										
										
											1999-09-17 16:17:21 +00:00
										 |  |  | 	set_event_header(&ev); | 
					
						
							|  |  |  | 	snd_seq_ev_set_noteon(&ev, chan, pitch, vol); | 
					
						
							| 
									
										
										
										
											1999-01-24 12:00:39 +00:00
										 |  |  | 	write_ev(&ev); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1999-06-15 22:26:21 +00:00
										 |  |  | static void do_noteoff(int chan, int pitch, int vol) | 
					
						
							| 
									
										
										
										
											1999-01-24 12:00:39 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	snd_seq_event_t ev; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1999-06-15 22:26:21 +00:00
										 |  |  | 	if (verbose >= VERB_EVENT) | 
					
						
							| 
									
										
										
										
											2019-02-17 05:00:53 -08:00
										 |  |  | 		printf("%lu: NoteOff (%d) %d %d\n", Mf_currtime, chan, pitch, vol); | 
					
						
							| 
									
										
										
										
											1999-09-17 16:17:21 +00:00
										 |  |  | 	set_event_header(&ev); | 
					
						
							|  |  |  | 	snd_seq_ev_set_noteoff(&ev, chan, pitch, vol); | 
					
						
							| 
									
										
										
										
											1999-06-15 22:26:21 +00:00
										 |  |  | 	write_ev(&ev); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											1999-01-24 12:00:39 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1999-06-15 22:26:21 +00:00
										 |  |  | static void do_program(int chan, int program) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	snd_seq_event_t ev; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (verbose >= VERB_EVENT) | 
					
						
							| 
									
										
										
										
											2019-02-17 05:00:53 -08:00
										 |  |  | 		printf("%lu: Program (%d) %d\n", Mf_currtime, chan, program); | 
					
						
							| 
									
										
										
										
											1999-09-17 16:17:21 +00:00
										 |  |  | 	set_event_header(&ev); | 
					
						
							|  |  |  | 	snd_seq_ev_set_pgmchange(&ev, chan, program); | 
					
						
							| 
									
										
										
										
											1999-06-15 22:26:21 +00:00
										 |  |  | 	write_ev(&ev); | 
					
						
							| 
									
										
										
										
											1999-01-24 12:00:39 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1999-06-15 22:26:21 +00:00
										 |  |  | static void do_parameter(int chan, int control, int value) | 
					
						
							| 
									
										
										
										
											1999-01-24 12:00:39 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	snd_seq_event_t ev; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1999-06-15 22:26:21 +00:00
										 |  |  | 	if (verbose >= VERB_EVENT) | 
					
						
							| 
									
										
										
										
											2019-02-17 05:00:53 -08:00
										 |  |  | 		printf("%lu: Control (%d) %d %d\n", Mf_currtime, chan, control, value); | 
					
						
							| 
									
										
										
										
											1999-09-17 16:17:21 +00:00
										 |  |  | 	set_event_header(&ev); | 
					
						
							|  |  |  | 	snd_seq_ev_set_controller(&ev, chan, control, value); | 
					
						
							| 
									
										
										
										
											1999-01-24 12:00:39 +00:00
										 |  |  | 	write_ev(&ev); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1999-06-15 22:26:21 +00:00
										 |  |  | static void do_pitchbend(int chan, int lsb, int msb) | 
					
						
							| 
									
										
										
										
											2002-03-12 20:14:33 +00:00
										 |  |  | {	/* !@#$% lsb & msb are in the wrong order in docs */ | 
					
						
							| 
									
										
										
										
											1999-01-24 12:00:39 +00:00
										 |  |  | 	snd_seq_event_t ev; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1999-06-15 22:26:21 +00:00
										 |  |  | 	if (verbose >= VERB_EVENT) | 
					
						
							| 
									
										
										
										
											2019-02-17 05:00:53 -08:00
										 |  |  | 		printf("%lu: Pitchbend (%d) %d %d\n", Mf_currtime, chan, lsb, msb); | 
					
						
							| 
									
										
										
										
											1999-09-17 16:17:21 +00:00
										 |  |  | 	set_event_header(&ev); | 
					
						
							|  |  |  | 	snd_seq_ev_set_pitchbend(&ev, chan, (lsb + (msb << 7)) - 8192); | 
					
						
							| 
									
										
										
										
											1999-01-24 12:00:39 +00:00
										 |  |  | 	write_ev(&ev); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1999-06-15 22:26:21 +00:00
										 |  |  | static void do_pressure(int chan, int pitch, int pressure) | 
					
						
							| 
									
										
										
										
											1999-01-24 12:00:39 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	snd_seq_event_t ev; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1999-06-15 22:26:21 +00:00
										 |  |  | 	if (verbose >= VERB_EVENT) | 
					
						
							| 
									
										
										
										
											2019-02-17 05:00:53 -08:00
										 |  |  | 		printf("%lu: KeyPress (%d) %d %d\n", Mf_currtime, chan, pitch, pressure); | 
					
						
							| 
									
										
										
										
											1999-09-17 16:17:21 +00:00
										 |  |  | 	set_event_header(&ev); | 
					
						
							|  |  |  | 	snd_seq_ev_set_keypress(&ev, chan, pitch, pressure); | 
					
						
							| 
									
										
										
										
											1999-01-24 12:00:39 +00:00
										 |  |  | 	write_ev(&ev); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1999-06-15 22:26:21 +00:00
										 |  |  | static void do_chanpressure(int chan, int pressure) | 
					
						
							| 
									
										
										
										
											1999-01-24 12:00:39 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	snd_seq_event_t ev; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1999-06-15 22:26:21 +00:00
										 |  |  | 	if (verbose >= VERB_EVENT) | 
					
						
							| 
									
										
										
										
											2019-02-17 05:00:53 -08:00
										 |  |  | 		printf("%lu: ChanPress (%d) %d\n", Mf_currtime, chan, pressure); | 
					
						
							| 
									
										
										
										
											1999-09-17 16:17:21 +00:00
										 |  |  | 	set_event_header(&ev); | 
					
						
							|  |  |  | 	snd_seq_ev_set_chanpress(&ev, chan, pressure); | 
					
						
							| 
									
										
										
										
											1999-01-24 12:00:39 +00:00
										 |  |  | 	write_ev(&ev); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1999-06-15 22:26:21 +00:00
										 |  |  | static void do_sysex(int len, char *msg) | 
					
						
							| 
									
										
										
										
											1999-01-24 12:00:39 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	snd_seq_event_t ev; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1999-06-15 22:26:21 +00:00
										 |  |  | 	if (verbose >= VERB_MUCH) { | 
					
						
							|  |  |  | 		int c; | 
					
						
							| 
									
										
										
										
											2019-02-17 05:00:53 -08:00
										 |  |  | 		printf("%lu: Sysex, len=%d\n", Mf_currtime, len); | 
					
						
							| 
									
										
										
										
											1999-06-15 22:26:21 +00:00
										 |  |  | 		for (c = 0; c < len; c++) { | 
					
						
							|  |  |  | 			printf(" %02x", (unsigned char)msg[c]); | 
					
						
							|  |  |  | 			if (c % 16 == 15) | 
					
						
							|  |  |  | 				putchar('\n'); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if (c % 16 != 15) | 
					
						
							|  |  |  | 			putchar('\n'); | 
					
						
							| 
									
										
										
										
											1999-01-24 12:00:39 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1999-09-17 16:17:21 +00:00
										 |  |  | 	set_event_header(&ev); | 
					
						
							|  |  |  | 	snd_seq_ev_set_sysex(&ev, len, msg); | 
					
						
							|  |  |  | 	write_ev(&ev); | 
					
						
							| 
									
										
										
										
											1999-06-15 22:26:21 +00:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											1999-01-24 12:00:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1999-09-01 22:19:11 +00:00
										 |  |  | static snd_seq_event_t *wait_for_event(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int left; | 
					
						
							|  |  |  | 	snd_seq_event_t *input_event; | 
					
						
							|  |  |  |    | 
					
						
							| 
									
										
										
										
											2000-09-05 17:15:11 +00:00
										 |  |  | 	if (use_blocking_mode) { | 
					
						
							| 
									
										
										
										
											2002-03-12 20:14:33 +00:00
										 |  |  | 		/* read the event - blocked until any event is read */ | 
					
						
							| 
									
										
										
										
											2000-09-05 17:15:11 +00:00
										 |  |  | 		left = snd_seq_event_input(seq_handle, &input_event); | 
					
						
							|  |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2002-03-12 20:14:33 +00:00
										 |  |  | 		/* read the event - using select syscall */ | 
					
						
							| 
									
										
										
										
											2000-09-05 17:15:11 +00:00
										 |  |  | 		while ((left = snd_seq_event_input(seq_handle, &input_event)) >= 0 && | 
					
						
							|  |  |  | 		       input_event == NULL) { | 
					
						
							| 
									
										
										
										
											2001-07-04 13:54:13 +00:00
										 |  |  | 			int npfds = snd_seq_poll_descriptors_count(seq_handle, POLLIN); | 
					
						
							|  |  |  | 			struct pollfd *pfds = alloca(sizeof(*pfds) * npfds); | 
					
						
							|  |  |  | 			snd_seq_poll_descriptors(seq_handle, pfds, npfds, POLLIN); | 
					
						
							|  |  |  | 			if ((left = poll(pfds, npfds, -1)) < 0) { | 
					
						
							|  |  |  | 				printf("poll error = %i (%s)\n", errno, snd_strerror(errno)); | 
					
						
							| 
									
										
										
										
											2000-09-05 17:15:11 +00:00
										 |  |  | 				exit(1); | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											1999-09-01 22:19:11 +00:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2000-09-05 17:15:11 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1999-09-01 22:19:11 +00:00
										 |  |  | 	if (left < 0) { | 
					
						
							|  |  |  | 		printf("alsa_sync error!:%s\n", snd_strerror(left)); | 
					
						
							|  |  |  | 		return NULL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return input_event; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-03-12 20:14:33 +00:00
										 |  |  | /* synchronize to the end of the event */ | 
					
						
							| 
									
										
										
										
											1999-06-15 22:26:21 +00:00
										 |  |  | static void alsa_sync(void) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2002-03-12 20:14:33 +00:00
										 |  |  | 	/* send the echo event to the self client. */ | 
					
						
							| 
									
										
										
										
											1999-06-15 22:26:21 +00:00
										 |  |  | 	if (verbose >= VERB_MUCH) | 
					
						
							| 
									
										
										
										
											2001-09-03 10:41:18 +00:00
										 |  |  | 		printf("alsa_sync syncing...\n"); | 
					
						
							| 
									
										
										
										
											2002-03-12 20:14:33 +00:00
										 |  |  | 	/* dump the buffer */ | 
					
						
							| 
									
										
										
										
											2001-09-03 10:41:18 +00:00
										 |  |  | 	snd_seq_drain_output(seq_handle); | 
					
						
							|  |  |  | 	snd_seq_sync_output_queue(seq_handle); | 
					
						
							| 
									
										
										
										
											1999-06-15 22:26:21 +00:00
										 |  |  | 	if (verbose >= VERB_MUCH) | 
					
						
							|  |  |  | 		printf("alsa_sync synced\n"); | 
					
						
							| 
									
										
										
										
											2001-09-03 10:41:18 +00:00
										 |  |  | 	sleep(1); /* give a time for note releasing.. */ | 
					
						
							| 
									
										
										
										
											1999-01-24 12:00:39 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-03-12 20:14:33 +00:00
										 |  |  | /* wait for the start of the queue */ | 
					
						
							| 
									
										
										
										
											1999-08-08 17:41:09 +00:00
										 |  |  | static void wait_start(void) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											1999-09-01 22:19:11 +00:00
										 |  |  | 	snd_seq_event_t *input_event; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-03-12 20:14:33 +00:00
										 |  |  | 	/* wait for the start event from the system timer */ | 
					
						
							| 
									
										
										
										
											1999-09-01 22:19:11 +00:00
										 |  |  | 	for (;;) { | 
					
						
							|  |  |  | 		input_event = wait_for_event(); | 
					
						
							|  |  |  | 		if (input_event) { | 
					
						
							|  |  |  | 			if (verbose >= VERB_MUCH) | 
					
						
							|  |  |  | 				printf("wait_start got event. type=%d, flags=%d\n", | 
					
						
							|  |  |  | 				       input_event->type, input_event->flags); | 
					
						
							|  |  |  | 			if (input_event->type == SND_SEQ_EVENT_START && | 
					
						
							| 
									
										
										
										
											1999-12-15 18:34:12 +00:00
										 |  |  | 			    input_event->data.queue.queue == dest_queue) { | 
					
						
							| 
									
										
										
										
											1999-09-17 16:17:21 +00:00
										 |  |  | 				snd_seq_free_event(input_event); | 
					
						
							| 
									
										
										
										
											1999-09-01 22:19:11 +00:00
										 |  |  | 				break; | 
					
						
							| 
									
										
										
										
											1999-09-17 16:17:21 +00:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											1999-09-01 22:19:11 +00:00
										 |  |  | 			snd_seq_free_event(input_event); | 
					
						
							| 
									
										
										
										
											1999-08-08 17:41:09 +00:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											1999-09-01 22:19:11 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											1999-08-08 17:41:09 +00:00
										 |  |  | 	if (verbose >= VERB_MUCH) | 
					
						
							|  |  |  | 		printf("start received\n"); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-03-12 20:14:33 +00:00
										 |  |  | /* print the usage */ | 
					
						
							| 
									
										
										
										
											1999-06-15 22:26:21 +00:00
										 |  |  | static void usage(void) | 
					
						
							| 
									
										
										
										
											1999-01-24 12:00:39 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											1999-06-15 22:26:21 +00:00
										 |  |  | 	fprintf(stderr, "usage: playmidi1 [options] [file]\n"); | 
					
						
							|  |  |  | 	fprintf(stderr, "  options:\n"); | 
					
						
							|  |  |  | 	fprintf(stderr, "  -v: verbose mode\n"); | 
					
						
							| 
									
										
										
										
											1999-09-01 22:19:11 +00:00
										 |  |  | 	fprintf(stderr, "  -a client:port : set destination address (default=%d:%d)\n", | 
					
						
							|  |  |  | 		DEST_CLIENT_NUMBER, DEST_PORT_NUMBER); | 
					
						
							| 
									
										
										
										
											2000-09-05 17:15:11 +00:00
										 |  |  | 	fprintf(stderr, "  -q queue: use the specified queue\n"); | 
					
						
							| 
									
										
										
										
											2002-03-12 20:14:33 +00:00
										 |  |  | 	fprintf(stderr, "  -s queue: slave mode (allow external clock synchronization)\n"); | 
					
						
							| 
									
										
										
										
											2000-09-05 17:15:11 +00:00
										 |  |  | 	fprintf(stderr, "  -r : play on real-time mode\n"); | 
					
						
							|  |  |  | 	fprintf(stderr, "  -b : play on non-blocking mode\n"); | 
					
						
							| 
									
										
										
										
											1999-01-24 12:00:39 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int main(int argc, char *argv[]) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int tmp; | 
					
						
							| 
									
										
										
										
											1999-06-15 22:26:21 +00:00
										 |  |  | 	int c; | 
					
						
							| 
									
										
										
										
											2001-09-03 10:41:18 +00:00
										 |  |  | 	snd_seq_addr_t dest_addr; | 
					
						
							| 
									
										
										
										
											2001-12-10 16:45:05 +00:00
										 |  |  | 	const char *addr = "65:0"; | 
					
						
							| 
									
										
										
										
											1999-06-15 22:26:21 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-09-03 10:41:18 +00:00
										 |  |  | 	while ((c = getopt(argc, argv, "s:a:p:q:vrb")) != -1) { | 
					
						
							| 
									
										
										
										
											1999-06-15 22:26:21 +00:00
										 |  |  | 		switch (c) { | 
					
						
							|  |  |  | 		case 'v': | 
					
						
							|  |  |  | 			verbose++; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case 'a': | 
					
						
							| 
									
										
										
										
											2001-09-03 10:41:18 +00:00
										 |  |  | 		case 'p': | 
					
						
							|  |  |  | 			addr = optarg; | 
					
						
							| 
									
										
										
										
											1999-06-15 22:26:21 +00:00
										 |  |  | 			break; | 
					
						
							| 
									
										
										
										
											2000-09-05 17:15:11 +00:00
										 |  |  | 		case 'q': | 
					
						
							|  |  |  | 			dest_queue = atoi(optarg); | 
					
						
							|  |  |  | 			if (dest_queue < 0) { | 
					
						
							|  |  |  | 				fprintf(stderr, "invalid queue number %d\n", dest_queue); | 
					
						
							|  |  |  | 				exit(1); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			break; | 
					
						
							| 
									
										
										
										
											1999-08-06 19:31:15 +00:00
										 |  |  | 		case 's': | 
					
						
							|  |  |  | 			slave = 1; | 
					
						
							| 
									
										
										
										
											1999-12-15 18:34:12 +00:00
										 |  |  | 			dest_queue = atoi(optarg); | 
					
						
							|  |  |  | 			if (dest_queue < 0) { | 
					
						
							|  |  |  | 				fprintf(stderr, "invalid queue number %d\n", dest_queue); | 
					
						
							|  |  |  | 				exit(1); | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											1999-08-06 19:31:15 +00:00
										 |  |  | 			break; | 
					
						
							| 
									
										
										
										
											2000-09-05 17:15:11 +00:00
										 |  |  | 		case 'r': | 
					
						
							|  |  |  | 			use_realtime = 1; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case 'b': | 
					
						
							|  |  |  | 			use_blocking_mode = 0; | 
					
						
							|  |  |  | 			break; | 
					
						
							| 
									
										
										
										
											1999-06-15 22:26:21 +00:00
										 |  |  | 		default: | 
					
						
							|  |  |  | 			usage(); | 
					
						
							|  |  |  | 			exit(1); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											1999-01-24 12:00:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1999-06-15 22:26:21 +00:00
										 |  |  | 	if (verbose >= VERB_INFO) { | 
					
						
							| 
									
										
										
										
											2000-09-05 17:15:11 +00:00
										 |  |  | 		if (use_realtime) | 
					
						
							|  |  |  | 			printf("ALSA MIDI Player, feeding events to real-time queue\n"); | 
					
						
							|  |  |  | 		else | 
					
						
							|  |  |  | 			printf("ALSA MIDI Player, feeding events to song queue\n"); | 
					
						
							| 
									
										
										
										
											1999-06-15 22:26:21 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											1999-01-24 12:00:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-03-12 20:14:33 +00:00
										 |  |  | 	/* open the sequencer device */ | 
					
						
							|  |  |  | 	/* Here we open the device in read/write for slave mode. */ | 
					
						
							| 
									
										
										
										
											2001-09-03 10:41:18 +00:00
										 |  |  | 	tmp = snd_seq_open(&seq_handle, "hw", slave ? SND_SEQ_OPEN_DUPLEX : SND_SEQ_OPEN_OUTPUT, 0); | 
					
						
							| 
									
										
										
										
											1999-01-24 12:00:39 +00:00
										 |  |  | 	if (tmp < 0) { | 
					
						
							|  |  |  | 		perror("open /dev/snd/seq"); | 
					
						
							|  |  |  | 		exit(1); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	 | 
					
						
							| 
									
										
										
										
											2001-07-04 13:54:13 +00:00
										 |  |  | 	tmp = snd_seq_nonblock(seq_handle, !use_blocking_mode); | 
					
						
							| 
									
										
										
										
											1999-06-15 22:26:21 +00:00
										 |  |  | 	if (tmp < 0) { | 
					
						
							|  |  |  | 		perror("block_mode"); | 
					
						
							|  |  |  | 		exit(1); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											1999-08-08 17:41:09 +00:00
										 |  |  | 			 | 
					
						
							| 
									
										
										
										
											2002-03-12 20:14:33 +00:00
										 |  |  | 	/* set the name */ | 
					
						
							|  |  |  | 	/* set the event filter to receive only the echo event */ | 
					
						
							|  |  |  | 	/* if running in slave mode, also listen for a START event */ | 
					
						
							| 
									
										
										
										
											1999-08-08 17:41:09 +00:00
										 |  |  | 	if (slave) | 
					
						
							| 
									
										
										
										
											1999-12-15 18:34:12 +00:00
										 |  |  | 		snd_seq_set_client_event_filter(seq_handle, SND_SEQ_EVENT_START); | 
					
						
							| 
									
										
										
										
											1999-09-17 16:17:21 +00:00
										 |  |  | 	snd_seq_set_client_name(seq_handle, "MIDI file player"); | 
					
						
							| 
									
										
										
										
											1999-01-24 12:00:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-03-12 20:14:33 +00:00
										 |  |  | 	/* create the port */ | 
					
						
							| 
									
										
										
										
											1999-09-17 16:17:21 +00:00
										 |  |  | 	my_port = snd_seq_create_simple_port(seq_handle, "Port 0", | 
					
						
							|  |  |  | 					     SND_SEQ_PORT_CAP_WRITE | | 
					
						
							|  |  |  | 					     SND_SEQ_PORT_CAP_READ, | 
					
						
							|  |  |  | 					     SND_SEQ_PORT_TYPE_MIDI_GENERIC); | 
					
						
							|  |  |  | 	if (my_port < 0) { | 
					
						
							| 
									
										
										
										
											2002-03-12 20:14:33 +00:00
										 |  |  | 		perror("create port"); | 
					
						
							| 
									
										
										
										
											1999-06-15 22:26:21 +00:00
										 |  |  | 		exit(1); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											1999-01-24 12:00:39 +00:00
										 |  |  | 	 | 
					
						
							| 
									
										
										
										
											2001-09-03 10:41:18 +00:00
										 |  |  | 	if (snd_seq_parse_address(seq_handle, &dest_addr, addr) < 0) { | 
					
						
							|  |  |  | 		perror("invalid destination address"); | 
					
						
							|  |  |  | 		exit(1); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	dest_client = dest_addr.client; | 
					
						
							|  |  |  | 	dest_port = dest_addr.port; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-03-12 20:14:33 +00:00
										 |  |  | 	/* set the queue */ | 
					
						
							| 
									
										
										
										
											2000-09-05 17:15:11 +00:00
										 |  |  | 	if (dest_queue >= 0) { | 
					
						
							| 
									
										
										
										
											2001-12-10 16:45:05 +00:00
										 |  |  | 		shared_queue = 1; | 
					
						
							| 
									
										
										
										
											2001-07-04 13:54:13 +00:00
										 |  |  | 		if (snd_seq_set_queue_usage(seq_handle, dest_queue, 1) < 0) { | 
					
						
							| 
									
										
										
										
											2000-09-05 17:15:11 +00:00
										 |  |  | 			perror("use queue"); | 
					
						
							|  |  |  | 			exit(1); | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											1999-12-15 18:34:12 +00:00
										 |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2001-12-10 16:45:05 +00:00
										 |  |  | 		shared_queue = 0; | 
					
						
							| 
									
										
										
										
											1999-12-15 18:34:12 +00:00
										 |  |  | 		dest_queue = snd_seq_alloc_queue(seq_handle); | 
					
						
							|  |  |  | 		if (dest_queue < 0) { | 
					
						
							|  |  |  | 			perror("alloc queue"); | 
					
						
							|  |  |  | 			exit(1); | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											1999-06-15 22:26:21 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-03-12 20:14:33 +00:00
										 |  |  | 	/* set the subscriber */ | 
					
						
							| 
									
										
										
										
											1999-09-17 16:17:21 +00:00
										 |  |  | 	tmp = snd_seq_connect_to(seq_handle, my_port, dest_client, dest_port); | 
					
						
							| 
									
										
										
										
											1999-06-15 22:26:21 +00:00
										 |  |  | 	if (tmp < 0) { | 
					
						
							|  |  |  | 		perror("subscribe"); | 
					
						
							|  |  |  | 		exit(1); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											1999-08-08 17:41:09 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-03-12 20:14:33 +00:00
										 |  |  | 	/* subscribe for the timer START event */	 | 
					
						
							| 
									
										
										
										
											1999-08-08 17:41:09 +00:00
										 |  |  | 	if (slave) {	 | 
					
						
							| 
									
										
										
										
											1999-09-17 16:17:21 +00:00
										 |  |  | 		tmp = snd_seq_connect_from(seq_handle, my_port, | 
					
						
							|  |  |  | 					   SND_SEQ_CLIENT_SYSTEM, | 
					
						
							| 
									
										
										
										
											2001-07-04 13:54:13 +00:00
										 |  |  | 					   dest_queue + 16 /*snd_seq_queue_sync_port(dest_queue)*/); | 
					
						
							| 
									
										
										
										
											1999-08-08 17:41:09 +00:00
										 |  |  | 		if (tmp < 0) { | 
					
						
							|  |  |  | 			perror("subscribe"); | 
					
						
							|  |  |  | 			exit(1); | 
					
						
							|  |  |  | 		}	 | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											1999-01-24 12:00:39 +00:00
										 |  |  | 	 | 
					
						
							| 
									
										
										
										
											2002-03-12 20:14:33 +00:00
										 |  |  | 	/* change the pool size */ | 
					
						
							| 
									
										
										
										
											1999-09-17 16:17:21 +00:00
										 |  |  | 	if (snd_seq_set_client_pool_output(seq_handle, WRITE_POOL_SIZE) < 0 || | 
					
						
							|  |  |  | 	    snd_seq_set_client_pool_input(seq_handle, READ_POOL_SIZE) < 0 || | 
					
						
							|  |  |  | 	    snd_seq_set_client_pool_output_room(seq_handle, WRITE_POOL_SPACE) < 0) { | 
					
						
							| 
									
										
										
										
											1999-06-15 22:26:21 +00:00
										 |  |  | 		perror("pool"); | 
					
						
							|  |  |  | 		exit(1); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	if (optind < argc) { | 
					
						
							|  |  |  | 		F = fopen(argv[optind], "r"); | 
					
						
							|  |  |  | 		if (F == NULL) { | 
					
						
							|  |  |  | 			fprintf(stderr, "playmidi1: can't open file %s\n", argv[optind]); | 
					
						
							|  |  |  | 			exit(1); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} else | 
					
						
							| 
									
										
										
										
											1999-01-24 12:00:39 +00:00
										 |  |  | 		F = stdin; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	Mf_header = do_header; | 
					
						
							|  |  |  | 	Mf_tempo = do_tempo; | 
					
						
							|  |  |  | 	Mf_getc = mygetc; | 
					
						
							|  |  |  | 	Mf_text = mytext; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	Mf_noteon = do_noteon; | 
					
						
							|  |  |  | 	Mf_noteoff = do_noteoff; | 
					
						
							|  |  |  | 	Mf_program = do_program; | 
					
						
							|  |  |  | 	Mf_parameter = do_parameter; | 
					
						
							|  |  |  | 	Mf_pitchbend = do_pitchbend; | 
					
						
							|  |  |  | 	Mf_pressure = do_pressure; | 
					
						
							|  |  |  | 	Mf_chanpressure = do_chanpressure; | 
					
						
							|  |  |  | 	Mf_sysex = do_sysex; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* go.. go.. go.. */ | 
					
						
							|  |  |  | 	mfread(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1999-06-15 22:26:21 +00:00
										 |  |  | 	alsa_sync(); | 
					
						
							| 
									
										
										
										
											2001-12-10 16:45:05 +00:00
										 |  |  | 	if (! shared_queue) | 
					
						
							|  |  |  | 		alsa_stop_timer(); | 
					
						
							| 
									
										
										
										
											1999-01-24 12:00:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1999-06-15 22:26:21 +00:00
										 |  |  | 	snd_seq_close(seq_handle); | 
					
						
							| 
									
										
										
										
											1999-01-25 20:49:14 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1999-06-15 22:26:21 +00:00
										 |  |  | 	if (verbose >= VERB_INFO) { | 
					
						
							|  |  |  | 		printf("Stopping at %f s,  tick %f\n", | 
					
						
							|  |  |  | 		       tick2time_dbl(Mf_currtime + 1), (double) (Mf_currtime + 1)); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											1999-01-24 12:00:39 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	exit(0); | 
					
						
							|  |  |  | } |