[Demudi-commits] r1518 - in timidity/trunk: debian interface

andete-guest at alioth.debian.org andete-guest at alioth.debian.org
Thu Jul 26 18:41:10 UTC 2007


Author: andete-guest
Date: 2007-07-26 18:41:10 +0000 (Thu, 26 Jul 2007)
New Revision: 1518

Added:
   timidity/trunk/interface/alsaseq_c.c
Modified:
   timidity/trunk/debian/README.Debian
   timidity/trunk/debian/changelog
   timidity/trunk/debian/rules
Log:


Modified: timidity/trunk/debian/README.Debian
===================================================================
--- timidity/trunk/debian/README.Debian	2007-07-25 15:52:22 UTC (rev 1517)
+++ timidity/trunk/debian/README.Debian	2007-07-26 18:41:10 UTC (rev 1518)
@@ -1,5 +1,4 @@
 TiMidity++ for Debian
-$Id: README.Debian,v 1.3 2004/08/07 14:33:59 hmh Exp $
 -----------------------------------------------------------
 
 Installing Patchsets/soundfonts 
@@ -61,3 +60,40 @@
 to load in config files distributed along with patchsets.
 
  -- Henrique de Moraes Holschuh <hmh at debian.org>
+
+ Pulseaudio
+ ----------
+
+If you use a systemwide pulseaudio daemon, and you also want to run the timidity
+sequencer systemwide, make sure the root user uses the correct alsa pulseaudio
+configuration.  This can be done by creating a file /etc/asound.conf with the
+following content:
+
+#-- begin --
+pcm.pulse {
+            type pulse
+}
+
+ctl.pulse {
+             type pulse
+}
+
+pcm.!default {
+    type pulse
+}
+ctl.!default {
+    type pulse
+}
+#-- end --
+
+And also add the root user to the pulse-access group:
+
+# adduser root pulse-access
+
+This will cause timidity to use pulseaudio. This is only an example; more
+advanced setups might require more or different configuration. Please
+consult the pulseaudio documentation.
+
+Alternatively you could run timidity in daemon mode as user.
+
+ -- Joost Yervante Damad <andete at debian.org>

Modified: timidity/trunk/debian/changelog
===================================================================
--- timidity/trunk/debian/changelog	2007-07-25 15:52:22 UTC (rev 1517)
+++ timidity/trunk/debian/changelog	2007-07-26 18:41:10 UTC (rev 1518)
@@ -1,3 +1,14 @@
+timidity (2.13.2-14) unstable; urgency=low
+
+  * Add note to README.Debian about how to get a systemwide timidity
+    sequencer to work together with the pulseaudio system (Closes: #428353)
+  * lintian fixes: first run configure before doing make clean in the
+    debian/rules clean target
+  * use neat exponentional backup select in interface/alsaseq_c.c
+    with thanks to  "C. " <chunkeey at web.de> (Closes: #433643)
+
+ -- Joost Yervante Damad <andete at debian.org>  Thu, 26 Jul 2007 20:40:14 +0200
+
 timidity (2.13.2-13) unstable; urgency=low
 
   * Make work with flac 1.1.4 API (Closes: #426669, #427593)

Modified: timidity/trunk/debian/rules
===================================================================
--- timidity/trunk/debian/rules	2007-07-25 15:52:22 UTC (rev 1517)
+++ timidity/trunk/debian/rules	2007-07-26 18:41:10 UTC (rev 1518)
@@ -51,9 +51,15 @@
 ##  The rules
 ##
 
-build: build-stamp
+build: doconfigure build-stamp
 build-stamp:
 	dh_testdir
+	$(MAKE)
+	touch build-stamp
+
+doconfigure: doconfigure-stamp
+doconfigure-stamp:
+	dh_testdir
 	rm -f autoconf/config.sub autoconf/config.guess
 	ln -s /usr/share/misc/config.sub autoconf/config.sub
 	ln -s /usr/share/misc/config.guess autoconf/config.guess
@@ -71,25 +77,23 @@
 	 --enable-interface=$(interface) \
 	 --enable-dynamic=slang,tcltk,vt100,xskin,gtk \
 	 --enable-server --enable-network --enable-spectrogram --enable-wrd
-	$(MAKE)
+	touch doconfigure-stamp
 
-	touch build-stamp
-
-clean:	configure
+clean:	configure doconfigure
 	dh_testdir
 	dh_testroot
 	-find -type f -perm +111 ! -name 'rules' -exec chmod 644 {} \;
 	-xargs -t -r chmod +x < debian/executable.files
 	rm -f build-stamp
-	-$(MAKE) clean
-	-$(MAKE) distclean
+	$(MAKE) clean
+	$(MAKE) distclean
 	rm -f common.makefile TiMidity-uj.ad TiMidity.ad
 	rm -f interface/tclIndex
 	rm -f doc/timidity.1 doc/timidity.cfg.5
 	rm -f autoconf/config.sub autoconf/config.guess
 	rm -rf autom4te.cache
 	rm -f config.log Makefile
-	-xargs -t -r rm -f < debian/deletable.files
+	rm -f doconfigure-stamp
 	dh_clean
 
 configure:

Added: timidity/trunk/interface/alsaseq_c.c
===================================================================
--- timidity/trunk/interface/alsaseq_c.c	                        (rev 0)
+++ timidity/trunk/interface/alsaseq_c.c	2007-07-26 18:41:10 UTC (rev 1518)
@@ -0,0 +1,817 @@
+/*
+    TiMidity++ -- MIDI to WAVE converter and player
+    Copyright (C) 1999-2004 Masanao Izumo <iz at onicos.co.jp>
+    Copyright (C) 1995 Tuukka Toivonen <tt at cgs.fi>
+
+    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
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+    alsaseq_c.c - ALSA sequencer server interface
+        Copyright (c) 2000  Takashi Iwai <tiwai at suse.de>
+
+    This interface provides an ALSA sequencer client which receives
+    events and plays it in real-time.  On this mode, TiMidity works
+    as a software (quasi-)real-time MIDI synth engine.
+
+    See doc/C/README.alsaseq for more details.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <sched.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#ifndef NO_STRING_H
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+#include <math.h>
+#include <signal.h>
+
+#if HAVE_ALSA_ASOUNDLIB_H
+#include <alsa/asoundlib.h>
+#else
+#include <sys/asoundlib.h>
+#endif
+
+#include "timidity.h"
+#include "common.h"
+#include "controls.h"
+#include "instrum.h"
+#include "playmidi.h"
+#include "readmidi.h"
+#include "recache.h"
+#include "output.h"
+#include "aq.h"
+#include "timer.h"
+
+
+void readmidi_read_init(void);
+
+#define MAX_PORTS	16
+
+#define TICKTIME_HZ	100
+
+struct seq_context {
+	snd_seq_t *handle;	/* The snd_seq handle to /dev/snd/seq */
+	int client;		/* The client associated with this context */
+	int num_ports;		/* number of ports */
+	int port[MAX_PORTS];	/* created sequencer ports */
+	int fd;			/* The file descriptor */
+	int used;		/* number of current connection */
+	int active;		/* */
+	int queue;
+	snd_seq_queue_status_t *q_status;
+};
+
+static struct seq_context alsactx;
+
+#if SND_LIB_MAJOR > 0 || SND_LIB_MINOR >= 6
+/* !! this is a dirty hack.  not sure to work in future !! */
+static int snd_seq_file_descriptor(snd_seq_t *handle)
+{
+	int pfds = snd_seq_poll_descriptors_count(handle, POLLIN);
+	if (pfds > 0) {
+		struct pollfd pfd;
+		if (snd_seq_poll_descriptors(handle, &pfd, 1, POLLIN) >= 0)
+			return pfd.fd;
+	}
+	return -ENXIO;
+}
+
+static int alsa_seq_open(snd_seq_t **seqp)
+{
+	return snd_seq_open(seqp, "hw", SND_SEQ_OPEN_DUPLEX, 0);
+}
+
+static int alsa_create_port(snd_seq_t *seq, int index)
+{
+	char name[32];
+	int port;
+
+	sprintf(name, "TiMidity port %d", index);
+	port = snd_seq_create_simple_port(seq, name,
+					  SND_SEQ_PORT_CAP_WRITE|SND_SEQ_PORT_CAP_SUBS_WRITE,
+					  SND_SEQ_PORT_TYPE_MIDI_GENERIC);
+	if (port < 0) {
+		fprintf(stderr, "error in snd_seq_create_simple_port\n");
+		return -1;
+	}
+
+	return port;
+}
+
+#else
+static int alsa_seq_open(snd_seq_t **seqp)
+{
+	return snd_seq_open(seqp, SND_SEQ_OPEN_IN);
+}
+
+static int alsa_create_port(snd_seq_t *seq, int index)
+{
+	snd_seq_port_info_t pinfo;
+
+	memset(&pinfo, 0, sizeof(pinfo));
+	sprintf(pinfo.name, "TiMidity port %d", index);
+	pinfo.capability = SND_SEQ_PORT_CAP_WRITE|SND_SEQ_PORT_CAP_SUBS_WRITE;
+	pinfo.type = SND_SEQ_PORT_TYPE_MIDI_GENERIC;
+	strcpy(pinfo.group, SND_SEQ_GROUP_DEVICE);
+	if (snd_seq_create_port(alsactx.handle, &pinfo) < 0) {
+		fprintf(stderr, "error in snd_seq_create_simple_port\n");
+		return -1;
+	}
+	return pinfo.port;
+}
+
+#endif
+
+static void alsa_set_timestamping(struct seq_context *ctxp, int port)
+{
+#if HAVE_SND_SEQ_PORT_INFO_SET_TIMESTAMPING
+	int q = 0;
+	snd_seq_port_info_t *pinfo;
+
+	if (ctxp->queue < 0) {
+		q = snd_seq_alloc_queue(ctxp->handle);
+		ctxp->queue = q;
+		if (q < 0)
+			return;
+		if (snd_seq_queue_status_malloc(&ctxp->q_status) < 0) {
+			fprintf(stderr, "no memory!\n");
+			exit(1);
+		}
+	}
+
+	snd_seq_port_info_alloca(&pinfo);
+	if (snd_seq_get_port_info(ctxp->handle, port, pinfo) < 0)
+		return;
+	snd_seq_port_info_set_timestamping(pinfo, 1);
+	snd_seq_port_info_set_timestamp_real(pinfo, 1);
+	snd_seq_port_info_set_timestamp_queue(pinfo, q);
+	if (snd_seq_set_port_info(ctxp->handle, port, pinfo) < 0)
+		return;
+#endif
+}
+
+
+static int ctl_open(int using_stdin, int using_stdout);
+static void ctl_close(void);
+static int ctl_read(int32 *valp);
+static int cmsg(int type, int verbosity_level, char *fmt, ...);
+static void ctl_event(CtlEvent *e);
+static void ctl_pass_playing_list(int n, char *args[]);
+
+/**********************************/
+/* export the interface functions */
+
+#define ctl alsaseq_control_mode
+
+ControlMode ctl=
+{
+    "ALSA sequencer interface", 'A',
+    1,0,0,
+    0,
+    ctl_open,
+    ctl_close,
+    ctl_pass_playing_list,
+    ctl_read,
+    cmsg,
+    ctl_event
+};
+
+/* options */
+int opt_realtime_priority = 0;
+int opt_sequencer_ports = 4;
+
+static int buffer_time_advance;
+static long buffer_time_offset;
+static long start_time_base;
+static long cur_time_offset;
+static long last_queue_offset;
+static double rate_frac, rate_frac_nsec;
+static FILE *outfp;
+
+/*ARGSUSED*/
+static int ctl_open(int using_stdin, int using_stdout)
+{
+	ctl.opened = 1;
+	ctl.flags &= ~(CTLF_LIST_RANDOM|CTLF_LIST_SORT);
+	if (using_stdout)
+		outfp = stderr;
+	else
+		outfp = stdout;
+	return 0;
+}
+
+static void ctl_close(void)
+{
+	if (!ctl.opened)
+		return;
+}
+
+static int ctl_read(int32 *valp)
+{
+    return RC_NONE;
+}
+
+static int cmsg(int type, int verbosity_level, char *fmt, ...)
+{
+    va_list ap;
+
+    if((type==CMSG_TEXT || type==CMSG_INFO || type==CMSG_WARNING) &&
+       ctl.verbosity < verbosity_level)
+	return 0;
+
+    if(outfp == NULL)
+	outfp = stderr;
+
+    va_start(ap, fmt);
+    vfprintf(outfp, fmt, ap);
+    fputs(NLS, outfp);
+    fflush(outfp);
+    va_end(ap);
+
+    return 0;
+}
+
+static void ctl_event(CtlEvent *e)
+{
+}
+
+static RETSIGTYPE sig_timeout(int sig)
+{
+    signal(SIGALRM, sig_timeout); /* For SysV base */
+    /* Expect EINTR */
+}
+
+static void doit(struct seq_context *ctxp);
+static int do_sequencer(struct seq_context *ctxp);
+static int start_sequencer(struct seq_context *ctxp);
+static void stop_sequencer(struct seq_context *ctxp);
+static void server_reset(void);
+
+/* reset all when SIGHUP is received */
+static RETSIGTYPE sig_reset(int sig)
+{
+	if (alsactx.active) {
+		stop_sequencer(&alsactx);
+		server_reset();
+	}
+	signal(SIGHUP, sig_reset);
+}
+
+/*
+ * set the process to realtime privs
+ */
+static int set_realtime_priority(void)
+{
+	struct sched_param schp;
+	int max_prio;
+
+	if (opt_realtime_priority <= 0)
+		return 0;
+
+        memset(&schp, 0, sizeof(schp));
+	max_prio = sched_get_priority_max(SCHED_FIFO);
+	if (max_prio < opt_realtime_priority)
+		opt_realtime_priority = max_prio;
+
+	schp.sched_priority = opt_realtime_priority;
+        if (sched_setscheduler(0, SCHED_FIFO, &schp) != 0) {
+		printf("can't set sched_setscheduler - using normal priority\n");
+                return -1;
+        }
+	/* drop root priv. */
+	if (! geteuid() && getuid() != geteuid()) {
+		if (setuid(getuid()))
+			perror("dropping root priv");
+	}
+	printf("set SCHED_FIFO(%d)\n", opt_realtime_priority);
+        return 0;
+}
+
+static void ctl_pass_playing_list(int n, char *args[])
+{
+	double btime;
+	int i, j;
+
+#ifdef SIGPIPE
+	signal(SIGPIPE, SIG_IGN);    /* Handle broken pipe */
+#endif /* SIGPIPE */
+
+	printf("TiMidity starting in ALSA server mode\n");
+
+	set_realtime_priority();
+
+	if (alsa_seq_open(&alsactx.handle) < 0) {
+		fprintf(stderr, "error in snd_seq_open\n");
+		return;
+	}
+	alsactx.queue = -1;
+	alsactx.client = snd_seq_client_id(alsactx.handle);
+	alsactx.fd = snd_seq_file_descriptor(alsactx.handle);
+	snd_seq_set_client_name(alsactx.handle, "TiMidity");
+	snd_seq_set_client_pool_input(alsactx.handle, 1000); /* enough? */
+	if (opt_sequencer_ports < 1)
+		alsactx.num_ports = 1;
+	else if (opt_sequencer_ports > MAX_PORTS)
+		alsactx.num_ports = MAX_PORTS;
+	else
+		alsactx.num_ports = opt_sequencer_ports;
+
+	printf("Opening sequencer port:");
+	for (i = 0; i < alsactx.num_ports; i++) {
+		int port;
+		port = alsa_create_port(alsactx.handle, i);
+		if (port < 0)
+			return;
+		alsactx.port[i] = port;
+		alsa_set_timestamping(&alsactx, port);
+		printf(" %d:%d", alsactx.client, alsactx.port[i]);
+	}
+	printf("\n");
+
+	alsactx.used = 0;
+	alsactx.active = 0;
+
+	opt_realtime_playing = 1; /* Enable loading patch while playing */
+	allocate_cache_size = 0; /* Don't use pre-calclated samples */
+	current_keysig = (opt_init_keysig == 8) ? 0 : opt_init_keysig;
+	note_key_offset = key_adjust;
+
+	if (IS_STREAM_TRACE) {
+		/* set the audio queue size as minimum as possible, since
+		 * we don't have to use audio queue..
+		 */
+		play_mode->acntl(PM_REQ_GETFRAGSIZ, &buffer_time_advance);
+		if (!(play_mode->encoding & PE_MONO))
+			buffer_time_advance >>= 1;
+		if (play_mode->encoding & PE_16BIT)
+			buffer_time_advance >>= 1;
+
+		btime = (double)buffer_time_advance / play_mode->rate;
+		btime *= 1.01; /* to be sure */
+		aq_set_soft_queue(btime, 0.0);
+	} else {
+		buffer_time_advance = 0;
+	}
+	rate_frac = (double)play_mode->rate / 1000000.0;
+	rate_frac_nsec = (double)play_mode->rate / 1000000000.0;
+
+	alarm(0);
+	signal(SIGALRM, sig_timeout);
+	signal(SIGINT, safe_exit);
+	signal(SIGTERM, safe_exit);
+	signal(SIGHUP, sig_reset);
+
+	i = current_keysig + ((current_keysig < 8) ? 7 : -9), j = 0;
+	while (i != 7)
+		i += (i < 7) ? 5 : -7, j++;
+	j += note_key_offset, j -= floor(j / 12.0) * 12;
+	current_freq_table = j;
+
+	play_mode->close_output();
+
+	if (ctl.flags & CTLF_DAEMONIZE)
+	{
+		int pid = fork();
+		FILE *pidf;
+		switch (pid)
+		{
+			case 0:			// child is the daemon
+				break;
+			case -1:		// error status return
+				exit(7);
+			default:		// no error, doing well
+				if ((pidf = fopen( "/var/run/timidity.pid", "w" )) != NULL )
+					fprintf( pidf, "%d\n", pid );
+				exit(0);
+		}
+	}
+
+	for (;;) {
+		server_reset();
+		doit(&alsactx);
+	}
+}
+
+/*
+ * get the current time in usec from gettimeofday()
+ */
+static long get_current_time(void)
+{
+	struct timeval tv;
+	long t;
+
+	gettimeofday(&tv, NULL);
+	t = tv.tv_sec * 1000000L + tv.tv_usec;
+	return t - start_time_base;
+}
+	
+/*
+ * convert from snd_seq_real_time_t to sample count
+ */
+inline static long queue_time_to_position(const snd_seq_real_time_t *t)
+{
+	return (long)t->tv_sec * play_mode->rate + (long)(t->tv_nsec * rate_frac_nsec);
+}
+
+/*
+ * get the current queue position in sample count
+ */
+static long get_current_queue_position(struct seq_context *ctxp)
+{
+#if HAVE_SND_SEQ_PORT_INFO_SET_TIMESTAMPING
+	snd_seq_get_queue_status(ctxp->handle, ctxp->queue, ctxp->q_status);
+	return queue_time_to_position(snd_seq_queue_status_get_real_time(ctxp->q_status));
+#else
+	return 0;
+#endif
+}
+
+/*
+ * update the current position from the event timestamp
+ */
+static void update_timestamp_from_event(snd_seq_event_t *ev)
+{
+	long t = queue_time_to_position(&ev->time.time) - last_queue_offset;
+	if (t < 0) {
+		// fprintf(stderr, "timestamp underflow! (delta=%d)\n", (int)t);
+		t = 0;
+	} else if (buffer_time_advance > 0 && t >= buffer_time_advance) {
+		// fprintf(stderr, "timestamp overflow! (delta=%d)\n", (int)t);
+		t = buffer_time_advance - 1;
+	}
+	t += buffer_time_offset;
+	if (t >= cur_time_offset)
+		cur_time_offset = t;
+}
+
+/*
+ * update the current position from system time
+ */
+static void update_timestamp(void)
+{
+	cur_time_offset = (long)(get_current_time() * rate_frac);
+}
+
+static void seq_play_event(MidiEvent *ev)
+{
+	//JAVE  make channel -Q channels quiet, modified some code from readmidi.c
+	int gch;
+	gch = GLOBAL_CHANNEL_EVENT_TYPE(ev->type);
+
+	if (gch || !IS_SET_CHANNELMASK(quietchannels, ev->channel)){
+		//if its a global event or not a masked event
+		ev->time = cur_time_offset;
+		play_event(ev);
+	}
+}
+
+static void stop_playing(void)
+{
+	if(upper_voices) {
+		MidiEvent ev;
+		ev.type = ME_EOT;
+		ev.a = 0;
+		ev.b = 0;
+		seq_play_event(&ev);
+		aq_flush(0);
+	}
+}
+
+static void doit(struct seq_context *ctxp)
+{
+	int err, timeout_val = 10;
+	for (;;) {
+		while (snd_seq_event_input_pending(ctxp->handle, 1)) {
+			if (do_sequencer(ctxp))
+				goto __done;
+		}
+		if (ctxp->active) {
+			MidiEvent ev;
+
+			if (IS_STREAM_TRACE) {
+				/* remember the last update position */
+				if (ctxp->queue >= 0)
+					last_queue_offset = get_current_queue_position(ctxp);
+				/* advance the buffer position */
+				buffer_time_offset += buffer_time_advance;
+				ev.time = buffer_time_offset;
+			} else {
+				/* update the current position */
+				if (ctxp->queue >= 0)
+					cur_time_offset = get_current_queue_position(ctxp);
+				else
+					update_timestamp();
+				ev.time = cur_time_offset;
+			}
+			ev.type = ME_NONE;
+			play_event(&ev);
+			aq_fill_nonblocking();
+		}
+		if (! ctxp->active || ! IS_STREAM_TRACE) {
+			fd_set rfds;
+			struct timeval timeout; 
+			FD_ZERO(&rfds);
+			FD_SET(ctxp->fd, &rfds);
+			timeout.tv_sec = (timeout_val / 1000);
+			timeout.tv_usec = (timeout_val % 1000) * 1000;
+			err = select(ctxp->fd + 1, &rfds, NULL, NULL, timeout_val < 0 ? NULL : &timeout);
+			if (err < 0) {
+				goto __done;
+			} else if (err == 0) {
+				if (timeout_val < 1024) {
+					timeout_val+=timeout_val;
+				} else {
+					timeout_val = -1;
+				}
+			} else {
+				timeout_val = 10;
+			}
+		}
+	}
+
+__done:
+	if (ctxp->active) {
+		stop_sequencer(ctxp);
+	}
+}
+
+static void server_reset(void)
+{
+	readmidi_read_init();
+	playmidi_stream_init();
+	if (free_instruments_afterwards)
+		free_instruments(0);
+	reduce_voice_threshold = 0; /* Disable auto reduction voice */
+	buffer_time_offset = 0;
+}
+
+static int start_sequencer(struct seq_context *ctxp)
+{
+	if (play_mode->open_output() < 0) {
+		ctl.cmsg(CMSG_FATAL, VERB_NORMAL,
+			 "Couldn't open %s (`%c')",
+			 play_mode->id_name, play_mode->id_character);
+		return 0;
+	}
+	ctxp->active = 1;
+
+	buffer_time_offset = 0;
+	last_queue_offset = 0;
+	cur_time_offset = 0;
+	if (ctxp->queue >= 0) {
+		if (snd_seq_start_queue(ctxp->handle, ctxp->queue, NULL) < 0)
+			ctxp->queue = -1;
+		else
+			snd_seq_drain_output(ctxp->handle);
+	}
+	if (ctxp->queue < 0) {
+		start_time_base = 0;
+		start_time_base = get_current_time();
+	}
+
+	return 1;
+}
+
+static void stop_sequencer(struct seq_context *ctxp)
+{
+	stop_playing();
+	if (ctxp->queue >= 0) {
+		snd_seq_stop_queue(ctxp->handle, ctxp->queue, NULL);
+		snd_seq_drain_output(ctxp->handle);
+	}
+	play_mode->close_output();
+	free_instruments(0);
+	free_global_mblock();
+	ctxp->used = 0;
+	ctxp->active = 0;
+}
+
+#define NOTE_CHAN(ev)	((ev)->dest.port * 16 + (ev)->data.note.channel)
+#define CTRL_CHAN(ev)	((ev)->dest.port * 16 + (ev)->data.control.channel)
+
+static int do_sequencer(struct seq_context *ctxp)
+{
+	int n, ne, i;
+	MidiEvent ev, evm[260];
+	snd_seq_event_t *aevp;
+
+	n = snd_seq_event_input(ctxp->handle, &aevp);
+	if (n < 0 || aevp == NULL)
+		return 0;
+
+	if (ctxp->active && ctxp->queue >= 0)
+		update_timestamp_from_event(aevp);
+	else if (IS_STREAM_TRACE)
+		cur_time_offset = buffer_time_offset;
+	else
+		update_timestamp();
+
+	switch(aevp->type) {
+	case SND_SEQ_EVENT_NOTEON:
+		ev.channel = NOTE_CHAN(aevp);
+		ev.a       = aevp->data.note.note;
+		ev.b       = aevp->data.note.velocity;
+		if (ev.b == 0)
+			ev.type = ME_NOTEOFF;
+		else
+			ev.type = ME_NOTEON;
+		seq_play_event(&ev);
+		break;
+
+	case SND_SEQ_EVENT_NOTEOFF:
+		ev.channel = NOTE_CHAN(aevp);
+		ev.a       = aevp->data.note.note;
+		ev.b       = aevp->data.note.velocity;
+		ev.type = ME_NOTEOFF;
+		seq_play_event(&ev);
+		break;
+
+	case SND_SEQ_EVENT_KEYPRESS:
+		ev.channel = NOTE_CHAN(aevp);
+		ev.a       = aevp->data.note.note;
+		ev.b       = aevp->data.note.velocity;
+		ev.type = ME_KEYPRESSURE;
+		seq_play_event(&ev);
+		break;
+
+	case SND_SEQ_EVENT_PGMCHANGE:
+		ev.channel = CTRL_CHAN(aevp);
+		ev.a = aevp->data.control.value;
+		ev.type = ME_PROGRAM;
+		seq_play_event(&ev);
+		break;
+
+	case SND_SEQ_EVENT_CONTROLLER:
+		if(convert_midi_control_change(CTRL_CHAN(aevp),
+					       aevp->data.control.param,
+					       aevp->data.control.value,
+					       &ev))
+			seq_play_event(&ev);
+		break;
+
+	case SND_SEQ_EVENT_CONTROL14:
+		if (aevp->data.control.param < 0 || aevp->data.control.param >= 32)
+			break;
+		if (! convert_midi_control_change(CTRL_CHAN(aevp),
+						  aevp->data.control.param,
+						  (aevp->data.control.value >> 7) & 0x7f,
+						  &ev))
+			break;
+		seq_play_event(&ev);
+		if (! convert_midi_control_change(CTRL_CHAN(aevp),
+						  aevp->data.control.param + 32,
+						  aevp->data.control.value & 0x7f,
+						  &ev))
+			break;
+		seq_play_event(&ev);
+		break;
+		    
+	case SND_SEQ_EVENT_PITCHBEND:
+		ev.type    = ME_PITCHWHEEL;
+		ev.channel = CTRL_CHAN(aevp);
+		aevp->data.control.value += 0x2000;
+		ev.a       = (aevp->data.control.value) & 0x7f;
+		ev.b       = (aevp->data.control.value>>7) & 0x7f;
+		seq_play_event(&ev);
+		break;
+
+	case SND_SEQ_EVENT_CHANPRESS:
+		ev.type    = ME_CHANNEL_PRESSURE;
+		ev.channel = CTRL_CHAN(aevp);
+		ev.a       = aevp->data.control.value;
+		seq_play_event(&ev);
+		break;
+		
+	case SND_SEQ_EVENT_NONREGPARAM:
+		/* Break it back into its controler values */
+		ev.type = ME_NRPN_MSB;
+		ev.channel = CTRL_CHAN(aevp);
+		ev.a = (aevp->data.control.param >> 7) & 0x7f;
+		seq_play_event(&ev);
+		ev.type = ME_NRPN_LSB;
+		ev.channel = CTRL_CHAN(aevp);
+		ev.a = aevp->data.control.param & 0x7f;
+		seq_play_event(&ev);
+		ev.type = ME_DATA_ENTRY_MSB;
+		ev.channel = CTRL_CHAN(aevp);
+		ev.a = (aevp->data.control.value >> 7) & 0x7f;
+		seq_play_event(&ev);
+		ev.type = ME_DATA_ENTRY_LSB;
+		ev.channel = CTRL_CHAN(aevp);
+		ev.a = aevp->data.control.value & 0x7f;
+		seq_play_event(&ev);
+		break;
+
+	case SND_SEQ_EVENT_REGPARAM:
+		/* Break it back into its controler values */
+		ev.type = ME_RPN_MSB;
+		ev.channel = CTRL_CHAN(aevp);
+		ev.a = (aevp->data.control.param >> 7) & 0x7f;
+		seq_play_event(&ev);
+		ev.type = ME_RPN_LSB;
+		ev.channel = CTRL_CHAN(aevp);
+		ev.a = aevp->data.control.param & 0x7f;
+		seq_play_event(&ev);
+		ev.type = ME_DATA_ENTRY_MSB;
+		ev.channel = CTRL_CHAN(aevp);
+		ev.a = (aevp->data.control.value >> 7) & 0x7f;
+		seq_play_event(&ev);
+		ev.type = ME_DATA_ENTRY_LSB;
+		ev.channel = CTRL_CHAN(aevp);
+		ev.a = aevp->data.control.value & 0x7f;
+		seq_play_event(&ev);
+		break;
+
+	case SND_SEQ_EVENT_SYSEX:
+		if (parse_sysex_event(aevp->data.ext.ptr + 1,
+				 aevp->data.ext.len - 1, &ev))
+			seq_play_event(&ev);
+		if ((ne = parse_sysex_event_multi(aevp->data.ext.ptr + 1,
+						  aevp->data.ext.len - 1, evm)) > 0)
+			for (i = 0; i < ne; i++)
+				seq_play_event(&evm[i]);
+		break;
+
+#if SND_LIB_MAJOR > 0 || SND_LIB_MINOR >= 6
+#define snd_seq_addr_equal(a,b)	((a)->client == (b)->client && (a)->port == (b)->port)
+	case SND_SEQ_EVENT_PORT_SUBSCRIBED:
+		if (snd_seq_addr_equal(&aevp->data.connect.dest, &aevp->dest)) {
+			if (! ctxp->active) {
+				if (! start_sequencer(ctxp)) {
+					snd_seq_free_event(aevp);
+					return 0;
+				}
+			}
+			ctxp->used++;
+		}
+		break;
+
+	case SND_SEQ_EVENT_PORT_UNSUBSCRIBED:
+		if (snd_seq_addr_equal(&aevp->data.connect.dest, &aevp->dest)) {
+			if (ctxp->active) {
+				ctxp->used--;
+				if (ctxp->used <= 0) {
+					snd_seq_free_event(aevp);
+					return 1; /* quit now */
+				}
+			}
+		}
+		break;
+#else
+	case SND_SEQ_EVENT_PORT_USED:
+		if (! ctxp->active) {
+			if (! start_sequencer(ctxp)) {
+				snd_seq_free_event(aevp);
+				return 0;
+			}
+		}
+		ctxp->used++;
+		break;
+
+	case SND_SEQ_EVENT_PORT_UNUSED:
+		if (ctxp->active) {
+			ctxp->used--;
+			if (ctxp->used <= 0) {
+				snd_seq_free_event(aevp);
+				return 1; /* quit now */
+			}
+		}
+		break;
+#endif
+		
+	default:
+		/*printf("Unsupported event %d\n", aevp->type);*/
+		break;
+	}
+	snd_seq_free_event(aevp);
+	return 0;
+}
+
+/*
+ * interface_<id>_loader();
+ */
+ControlMode *interface_A_loader(void)
+{
+    return &ctl;
+}




More information about the Demudi-commits mailing list