Takashi Iwai <iwai@ww.uni-erlangen.de>

Frank van de Pol <frank@vande-pol.demon.nl>
Major sequencer changes and cleanups for 1.0.0.
This commit is contained in:
Jaroslav Kysela 1999-12-15 18:34:12 +00:00
parent 7b0898c17d
commit a3aaf0582a
8 changed files with 176 additions and 121 deletions

View file

@ -27,7 +27,7 @@ void snd_seq_ev_set_source(snd_seq_event_t *ev, int port);
void snd_seq_ev_set_direct(snd_seq_event_t *ev); void snd_seq_ev_set_direct(snd_seq_event_t *ev);
/* scheduled on tick-queue */ /* scheduled on tick-queue */
void snd_seq_ev_schedule_tick(snd_seq_event_t *ev, int q, int relative, void snd_seq_ev_schedule_tick(snd_seq_event_t *ev, int q, int relative,
unsigned long tick); snd_seq_tick_time_t tick);
/* scheduled on real-time-queue */ /* scheduled on real-time-queue */
void snd_seq_ev_schedule_real(snd_seq_event_t *ev, int q, int relative, void snd_seq_ev_schedule_real(snd_seq_event_t *ev, int q, int relative,
snd_seq_real_time_t *real); snd_seq_real_time_t *real);
@ -41,7 +41,22 @@ void snd_seq_ev_set_fixed(snd_seq_event_t *ev);
/* variable size event */ /* variable size event */
void snd_seq_ev_set_variable(snd_seq_event_t *ev, int len, void *ptr); void snd_seq_ev_set_variable(snd_seq_event_t *ev, int len, void *ptr);
/* queue controls - /* set queue control event data */
/* destination is overwritten to Timer port (0:0) */
int snd_seq_ev_set_queue_start(snd_seq_event_t *ev, int q);
int snd_seq_ev_set_queue_stop(snd_seq_event_t *ev, int q);
int snd_seq_ev_set_queue_continue(snd_seq_event_t *ev, int q);
int snd_seq_ev_set_queue_tempo(snd_seq_event_t *ev, int q, int tempo);
int snd_seq_ev_set_queue_control(snd_seq_event_t *ev, int type, int q, int value);
int snd_seq_ev_set_queue_pos_real(snd_seq_event_t *ev, int q, snd_seq_real_time_t *rtime);
int snd_seq_ev_set_queue_pos_tick(snd_seq_event_t *ev, int q, snd_seq_tick_time_t tick);
/*
* use/unuse a queue
*/
int snd_seq_use_queue(snd_seq_t *seq, int q, int use);
/* set and send a queue control event:
* to send at scheduled time, set the schedule in ev. * to send at scheduled time, set the schedule in ev.
* if ev is NULL, event is sent immediately (to output queue). * if ev is NULL, event is sent immediately (to output queue).
* Note: to send actually to driver, you need to call snd_seq_flush_event() * Note: to send actually to driver, you need to call snd_seq_flush_event()
@ -52,6 +67,7 @@ int snd_seq_start_queue(snd_seq_t *seq, int q, snd_seq_event_t *ev);
int snd_seq_stop_queue(snd_seq_t *seq, int q, snd_seq_event_t *ev); int snd_seq_stop_queue(snd_seq_t *seq, int q, snd_seq_event_t *ev);
int snd_seq_continue_queue(snd_seq_t *seq, int q, snd_seq_event_t *ev); int snd_seq_continue_queue(snd_seq_t *seq, int q, snd_seq_event_t *ev);
int snd_seq_change_queue_tempo(snd_seq_t *seq, int q, int tempo, snd_seq_event_t *ev); int snd_seq_change_queue_tempo(snd_seq_t *seq, int q, int tempo, snd_seq_event_t *ev);
int snd_seq_setpos_queue(snd_seq_t *seq, int q, snd_seq_timestamp_t *rtime, snd_seq_event_t *ev);
/* create a port - simple version - return the port number */ /* create a port - simple version - return the port number */
int snd_seq_create_simple_port(snd_seq_t *seq, char *name, int snd_seq_create_simple_port(snd_seq_t *seq, char *name,
@ -87,97 +103,101 @@ int snd_seq_reset_pool_input(snd_seq_t *seq);
/* /*
* equivalent macros * equivalent macros
*/ */
#define __snd_seq_ev_clear(ev) memset(ev, 0, sizeof(snd_seq_event_t)) #define snd_seq_ev_clear(ev) memset(ev, 0, sizeof(snd_seq_event_t))
#define __snd_seq_ev_set_dest(ev,c,p) \ #define snd_seq_ev_set_dest(ev,c,p) \
((ev)->dest.client = (c), (ev)->dest.port = (p)) ((ev)->dest.client = (c), (ev)->dest.port = (p))
#define __snd_seq_ev_set_subs(ev) \ #define snd_seq_ev_set_subs(ev) \
((ev)->dest.client = SND_SEQ_ADDRESS_SUBSCRIBERS,\ ((ev)->dest.client = SND_SEQ_ADDRESS_SUBSCRIBERS,\
(ev)->dest.port = SND_SEQ_ADDRESS_UNKNOWN) (ev)->dest.port = SND_SEQ_ADDRESS_UNKNOWN)
#define __snd_seq_ev_set_broadcast(ev) \ #define snd_seq_ev_set_broadcast(ev) \
((ev)->dest.client = SND_SEQ_ADDRESS_BROADCAST,\ ((ev)->dest.client = SND_SEQ_ADDRESS_BROADCAST,\
(ev)->dest.port = SND_SEQ_ADDRESS_BROADCAST) (ev)->dest.port = SND_SEQ_ADDRESS_BROADCAST)
#define __snd_seq_ev_set_source(ev,p) ((ev)->source.port = (p)) #define snd_seq_ev_set_source(ev,p) ((ev)->source.port = (p))
#define __snd_seq_start_queue(seq,q,ev) \ /*
* queue controls
*/
#define snd_seq_ev_set_queue_control(ev,t,q,val) \
((ev)->type = (t),\
snd_seq_ev_set_dest(ev, SND_SEQ_CLIENT_SYSTEM, SND_SEQ_PORT_SYSTEM_TIMER),\
(ev)->data.queue.queue = (q),\
(ev)->data.queue.param.value = (val))
#define snd_seq_ev_set_queue_start(ev,q) \
snd_seq_ev_set_queue_control(ev,SND_SEQ_EVENT_START,q,0)
#define snd_seq_ev_set_queue_stop(ev,q) \
snd_seq_ev_set_queue_control(ev,SND_SEQ_EVENT_STOP,q,0)
#define snd_seq_ev_set_queue_continue(ev,q) \
snd_seq_ev_set_queue_control(ev,SND_SEQ_EVENT_CONTINUE,q,0)
#define snd_seq_ev_set_queue_tempo(ev,q,val) \
snd_seq_ev_set_queue_control(ev,SND_SEQ_EVENT_TEMPO,q,val)
#define snd_seq_ev_set_queue_pos_real(ev,q,rtime) \
((ev)->type = SND_SEQ_EVENT_SETPOS_TIME,\
snd_seq_ev_set_dest(ev, SND_SEQ_CLIENT_SYSTEM, SND_SEQ_PORT_SYSTEM_TIMER),\
(ev)->data.queue.queue = (q),\
(ev)->data.queue.param.time.real = *(rtime))
#define snd_seq_ev_set_queue_pos_tick(ev,q,ttime) \
((ev)->type = SND_SEQ_EVENT_SETPOS_TICK,\
snd_seq_ev_set_dest(ev, SND_SEQ_CLIENT_SYSTEM, SND_SEQ_PORT_SYSTEM_TIMER),\
(ev)->data.queue.queue = (q),\
(ev)->data.queue.param.time.tick = (ttime))
#define snd_seq_start_queue(seq,q,ev) \
snd_seq_control_queue(seq, q, SND_SEQ_EVENT_START, 0, ev) snd_seq_control_queue(seq, q, SND_SEQ_EVENT_START, 0, ev)
#define __snd_seq_stop_queue(seq,q,ev) \ #define snd_seq_stop_queue(seq,q,ev) \
snd_seq_control_queue(seq, q, SND_SEQ_EVENT_STOP, 0, ev) snd_seq_control_queue(seq, q, SND_SEQ_EVENT_STOP, 0, ev)
#define __snd_seq_continue_queue(seq,q,ev) \ #define snd_seq_continue_queue(seq,q,ev) \
snd_seq_control_queue(seq, q, SND_SEQ_EVENT_CONTINUE, 0, ev) snd_seq_control_queue(seq, q, SND_SEQ_EVENT_CONTINUE, 0, ev)
#define __snd_seq_change_queue_tempo(seq,q,tempo,ev) \ #define snd_seq_change_queue_tempo(seq,q,tempo,ev) \
snd_seq_control_queue(seq, q, SND_SEQ_EVENT_TEMPO, tempo, ev) snd_seq_control_queue(seq, q, SND_SEQ_EVENT_TEMPO, tempo, ev)
/*
* redefintion
*/
#define snd_seq_ev_clear(ev) __snd_seq_ev_clear(ev)
#define snd_seq_ev_set_dest(ev,c,p) __snd_seq_ev_set_dest(ev,c,p)
#define snd_seq_ev_set_subs(ev) __snd_seq_ev_set_subs(ev)
#define snd_seq_ev_set_broadcast(ev) __snd_seq_ev_set_broadcast(ev)
#define snd_seq_ev_set_source(ev,p) __snd_seq_ev_set_source(ev,p)
#define snd_seq_start_queue(seq,q,ev) __snd_seq_start_queue(seq,q,ev)
#define snd_seq_stop_queue(seq,q,ev) __snd_seq_stop_queue(seq,q,ev)
#define snd_seq_continue_queue(seq,q,ev) __snd_seq_continue_queue(seq,q,ev)
#define snd_seq_change_queue_tempo(seq,q,tempo,ev) __snd_seq_change_queue_tempo(seq,q,tempo,ev)
/*
* check event flags
*/
#define snd_seq_ev_is_direct(ev) ((ev)->flags & SND_SEQ_DEST_MASK)
#define snd_seq_ev_is_prior(ev) ((ev)->flags & SND_SEQ_PRIORITY_MASK)
#define snd_seq_ev_is_variable(ev) (((ev)->flags & SND_SEQ_EVENT_LENGTH_MASK) == SND_SEQ_EVENT_LENGTH_VARIABLE)
#define snd_seq_ev_is_realtime(ev) ((ev)->flags & SND_SEQ_TIME_STAMP_MASK)
#define snd_seq_ev_is_relative(ev) ((ev)->flags & SND_SEQ_TIME_MODE_MASK)
/* ... etc. */
/* /*
* macros to set standard event data * macros to set standard event data
*/ */
#define snd_seq_ev_set_note(ev,ch,key,vel,dur) \ #define snd_seq_ev_set_note(ev,ch,key,vel,dur) \
((ev)->type = SND_SEQ_EVENT_NOTE,\ ((ev)->type = SND_SEQ_EVENT_NOTE,\
snd_seq_ev_set_fixed(ev),\ snd_seq_ev_set_fixed(ev),\
(ev)->dest.channel = (ch),\ (ev)->data.note.channel = (ch),\
(ev)->data.note.note = (key),\ (ev)->data.note.note = (key),\
(ev)->data.note.velocity = (vel),\ (ev)->data.note.velocity = (vel),\
(ev)->data.note.dulation = (dur)) (ev)->data.note.dulation = (dur))
#define snd_seq_ev_set_noteon(ev,ch,key,vel) \ #define snd_seq_ev_set_noteon(ev,ch,key,vel) \
((ev)->type = SND_SEQ_EVENT_NOTEON,\ ((ev)->type = SND_SEQ_EVENT_NOTEON,\
snd_seq_ev_set_fixed(ev),\ snd_seq_ev_set_fixed(ev),\
(ev)->dest.channel = (ch),\ (ev)->data.note.channel = (ch),\
(ev)->data.note.note = (key),\ (ev)->data.note.note = (key),\
(ev)->data.note.velocity = (vel)) (ev)->data.note.velocity = (vel))
#define snd_seq_ev_set_noteoff(ev,ch,key,vel) \ #define snd_seq_ev_set_noteoff(ev,ch,key,vel) \
((ev)->type = SND_SEQ_EVENT_NOTEOFF,\ ((ev)->type = SND_SEQ_EVENT_NOTEOFF,\
snd_seq_ev_set_fixed(ev),\ snd_seq_ev_set_fixed(ev),\
(ev)->dest.channel = (ch),\ (ev)->data.note.channel = (ch),\
(ev)->data.note.note = (key),\ (ev)->data.note.note = (key),\
(ev)->data.note.velocity = (vel)) (ev)->data.note.velocity = (vel))
#define snd_seq_ev_set_keypress(ev,ch,key,vel) \ #define snd_seq_ev_set_keypress(ev,ch,key,vel) \
((ev)->type = SND_SEQ_EVENT_KEYPRESS,\ ((ev)->type = SND_SEQ_EVENT_KEYPRESS,\
snd_seq_ev_set_fixed(ev),\ snd_seq_ev_set_fixed(ev),\
(ev)->dest.channel = (ch),\ (ev)->data.note.channel = (ch),\
(ev)->data.note.note = (key),\ (ev)->data.note.note = (key),\
(ev)->data.note.velocity = (vel)) (ev)->data.note.velocity = (vel))
#define snd_seq_ev_set_controller(ev,ch,cc,val) \ #define snd_seq_ev_set_controller(ev,ch,cc,val) \
((ev)->type = SND_SEQ_EVENT_CONTROLLER,\ ((ev)->type = SND_SEQ_EVENT_CONTROLLER,\
snd_seq_ev_set_fixed(ev),\ snd_seq_ev_set_fixed(ev),\
(ev)->dest.channel = (ch),\ (ev)->data.control.channel = (ch),\
(ev)->data.control.param = (cc),\ (ev)->data.control.param = (cc),\
(ev)->data.control.value = (val)) (ev)->data.control.value = (val))
#define snd_seq_ev_set_pgmchange(ev,ch,val) \ #define snd_seq_ev_set_pgmchange(ev,ch,val) \
((ev)->type = SND_SEQ_EVENT_PGMCHANGE,\ ((ev)->type = SND_SEQ_EVENT_PGMCHANGE,\
snd_seq_ev_set_fixed(ev),\ snd_seq_ev_set_fixed(ev),\
(ev)->dest.channel = (ch),\ (ev)->data.control.channel = (ch),\
(ev)->data.control.value = (val)) (ev)->data.control.value = (val))
#define snd_seq_ev_set_pitchbend(ev,ch,val) \ #define snd_seq_ev_set_pitchbend(ev,ch,val) \
((ev)->type = SND_SEQ_EVENT_PITCHBEND,\ ((ev)->type = SND_SEQ_EVENT_PITCHBEND,\
snd_seq_ev_set_fixed(ev),\ snd_seq_ev_set_fixed(ev),\
(ev)->dest.channel = (ch),\ (ev)->data.control.channel = (ch),\
(ev)->data.control.value = (val)) (ev)->data.control.value = (val))
#define snd_seq_ev_set_chanpress(ev,ch,val) \ #define snd_seq_ev_set_chanpress(ev,ch,val) \
((ev)->type = SND_SEQ_EVENT_CHANPRESS,\ ((ev)->type = SND_SEQ_EVENT_CHANPRESS,\
snd_seq_ev_set_fixed(ev),\ snd_seq_ev_set_fixed(ev),\
(ev)->dest.channel = (ch),\ (ev)->data.control.channel = (ch),\
(ev)->data.control.value = (val)) (ev)->data.control.value = (val))
#define snd_seq_ev_set_sysex(ev,datalen,dataptr) \ #define snd_seq_ev_set_sysex(ev,datalen,dataptr) \
((ev)->type = SND_SEQ_EVENT_SYSEX,\ ((ev)->type = SND_SEQ_EVENT_SYSEX,\

View file

@ -31,7 +31,7 @@
#define SND_FILE_SEQ "/dev/snd/seq" #define SND_FILE_SEQ "/dev/snd/seq"
#define SND_FILE_ALOADSEQ "/dev/aloadSEQ" #define SND_FILE_ALOADSEQ "/dev/aloadSEQ"
#define SND_SEQ_VERSION_MAX SND_PROTOCOL_VERSION( 0, 0, 1 ) #define SND_SEQ_VERSION_MAX SND_PROTOCOL_VERSION( 1, 0, 0 )
#define SND_SEQ_OBUF_SIZE (16*1024) /* should be configurable */ #define SND_SEQ_OBUF_SIZE (16*1024) /* should be configurable */
#define SND_SEQ_IBUF_SIZE (4*1024) /* should be configurable */ #define SND_SEQ_IBUF_SIZE (4*1024) /* should be configurable */
@ -721,7 +721,10 @@ static int remove_match(snd_seq_remove_events_t *info,
return 0; return 0;
} }
if (info->remove_mode & SND_SEQ_REMOVE_DEST_CHANNEL) { if (info->remove_mode & SND_SEQ_REMOVE_DEST_CHANNEL) {
if (ev->dest.channel != info->dest.channel) if (! snd_seq_ev_is_channel_type(ev))
return 0;
/* data.note.channel and data.control.channel are identical */
if (ev->data.note.channel != info->channel)
return 0; return 0;
} }
if (info->remove_mode & SND_SEQ_REMOVE_TIME_AFTER) { if (info->remove_mode & SND_SEQ_REMOVE_TIME_AFTER) {

View file

@ -35,12 +35,12 @@ void snd_seq_ev_set_direct(snd_seq_event_t *ev)
{ {
ev->flags &= ~SND_SEQ_DEST_MASK; ev->flags &= ~SND_SEQ_DEST_MASK;
ev->flags |= SND_SEQ_DEST_DIRECT; ev->flags |= SND_SEQ_DEST_DIRECT;
ev->dest.queue = SND_SEQ_ADDRESS_UNKNOWN; /* XXX */ ev->queue = SND_SEQ_ADDRESS_UNKNOWN; /* XXX */
} }
/* queued on tick */ /* queued on tick */
void snd_seq_ev_schedule_tick(snd_seq_event_t *ev, int q, int relative, void snd_seq_ev_schedule_tick(snd_seq_event_t *ev, int q, int relative,
unsigned long tick) snd_seq_tick_time_t tick)
{ {
ev->flags &= ~(SND_SEQ_DEST_MASK | SND_SEQ_TIME_STAMP_MASK | ev->flags &= ~(SND_SEQ_DEST_MASK | SND_SEQ_TIME_STAMP_MASK |
SND_SEQ_TIME_MODE_MASK); SND_SEQ_TIME_MODE_MASK);
@ -85,11 +85,21 @@ void snd_seq_ev_set_variable(snd_seq_event_t *ev, int len, void *ptr)
ev->data.ext.ptr = ptr; ev->data.ext.ptr = ptr;
} }
/* use or unuse a queue */
int snd_seq_use_queue(snd_seq_t *seq, int q, int use)
{
snd_seq_queue_client_t info;
memset(&info, 0, sizeof(info));
info.used = use;
return snd_seq_set_queue_client(seq, q, &info);
}
/* queue controls - start/stop/continue */ /* queue controls - start/stop/continue */
/* if ev is NULL, send events immediately. /* if ev is NULL, send events immediately.
otherwise, duplicate the given event data. otherwise, duplicate the given event data. */
destination is overwritten to Timer port (0:0)
*/
int snd_seq_control_queue(snd_seq_t *seq, int q, int type, int value, snd_seq_event_t *ev) int snd_seq_control_queue(snd_seq_t *seq, int q, int type, int value, snd_seq_event_t *ev)
{ {
snd_seq_event_t tmpev; snd_seq_event_t tmpev;
@ -98,22 +108,35 @@ int snd_seq_control_queue(snd_seq_t *seq, int q, int type, int value, snd_seq_ev
ev = &tmpev; ev = &tmpev;
snd_seq_ev_set_direct(ev); snd_seq_ev_set_direct(ev);
} }
snd_seq_ev_set_queue_control(ev, type, q, value);
ev->type = type;
snd_seq_ev_set_dest(ev, SND_SEQ_CLIENT_SYSTEM, SND_SEQ_PORT_SYSTEM_TIMER);
#if 1
/* new type */
ev->data.queue.addr.queue = q;
ev->data.queue.value = value;
#else
/* old type */
ev->dest.queue = q;
ev->data.control.value = value;
#endif
return snd_seq_event_output(seq, ev); return snd_seq_event_output(seq, ev);
} }
/* reset queue position:
* new values of both real-time and tick values must be given.
*/
int snd_seq_setpos_queue(snd_seq_t *seq, int q, snd_seq_timestamp_t *rtime, snd_seq_event_t *ev)
{
snd_seq_event_t tmpev;
int result;
if (ev == NULL) {
snd_seq_ev_clear(&tmpev);
ev = &tmpev;
snd_seq_ev_set_direct(ev);
}
/* stop the timer */
result = snd_seq_stop_queue(seq, q, ev);
/* reset queue position */
snd_seq_ev_set_queue_pos_real(ev, q, &rtime->real);
result = snd_seq_event_output(seq, ev);
snd_seq_ev_set_queue_pos_tick(ev, q, rtime->tick);
result = snd_seq_event_output(seq, ev);
/* continue the timer */
result = snd_seq_continue_queue(seq, q, ev);
return result;
}
/* create a port - simple version /* create a port - simple version
* return the port number * return the port number
@ -295,7 +318,7 @@ int snd_seq_set_client_pool_input(snd_seq_t *seq, int size)
/* /*
* reset client input/output pool * reset client input/output pool
* use REMOVE_EVENTS ioctl instead of RESET_POOL * use REMOVE_EVENTS ioctl
*/ */
int snd_seq_reset_pool_output(snd_seq_t *seq) int snd_seq_reset_pool_output(snd_seq_t *seq)
{ {

View file

@ -78,10 +78,16 @@ static void list_each_subs(snd_seq_t *seq, snd_seq_query_subs_t *subs, int type,
subs->index = 0; subs->index = 0;
while (snd_seq_query_port_subscribers(seq, subs) >= 0) { while (snd_seq_query_port_subscribers(seq, subs) >= 0) {
if (subs->index == 0) if (subs->index == 0)
printf("\t%s: %d:%d:%d", msg, printf("\t%s: ", msg);
subs->addr.queue, subs->addr.client, subs->addr.port);
else else
printf(", %d:%d:%d", subs->addr.queue, subs->addr.client, subs->addr.port); printf(", ");
printf("%d:%d", subs->addr.client, subs->addr.port);
if (subs->exclusive)
printf("[ex]");
if (subs->convert_time)
printf("[%s:%d]",
(subs->realtime ? "real" : "tick"),
subs->queue);
subs->index++; subs->index++;
} }
if (subs->index) if (subs->index)
@ -228,7 +234,7 @@ int main(int argc, char **argv)
memset(&subs, 0, sizeof(subs)); memset(&subs, 0, sizeof(subs));
parse_address(&subs.sender, argv[optind]); parse_address(&subs.sender, argv[optind]);
parse_address(&subs.dest, argv[optind + 1]); parse_address(&subs.dest, argv[optind + 1]);
subs.sender.queue = subs.dest.queue = queue; subs.queue = queue;
subs.exclusive = 0; subs.exclusive = 0;
subs.convert_time = 0; subs.convert_time = 0;
subs.realtime = 0; subs.realtime = 0;

View file

@ -438,7 +438,7 @@ static void wait_start(void)
printf("wait_start got event. type=%d, flags=%d\n", printf("wait_start got event. type=%d, flags=%d\n",
input_event->type, input_event->flags); input_event->type, input_event->flags);
if (input_event->type == SND_SEQ_EVENT_START && if (input_event->type == SND_SEQ_EVENT_START &&
input_event->data.addr.queue == dest_queue) { input_event->data.queue.queue == dest_queue) {
snd_seq_free_event(input_event); snd_seq_free_event(input_event);
break; break;
} }
@ -458,7 +458,7 @@ static void usage(void)
fprintf(stderr, " -v: verbose mode\n"); fprintf(stderr, " -v: verbose mode\n");
fprintf(stderr, " -a client:port : set destination address (default=%d:%d)\n", fprintf(stderr, " -a client:port : set destination address (default=%d:%d)\n",
DEST_CLIENT_NUMBER, DEST_PORT_NUMBER); DEST_CLIENT_NUMBER, DEST_PORT_NUMBER);
fprintf(stderr, " -s: slave mode (allow external clock synchronisation)\n"); fprintf(stderr, " -s queue: slave mode (allow external clock synchronisation)\n");
} }
/* parse destination address (-a option) */ /* parse destination address (-a option) */
@ -476,7 +476,7 @@ int main(int argc, char *argv[])
int tmp; int tmp;
int c; int c;
while ((c = getopt(argc, argv, "sa:v")) != -1) { while ((c = getopt(argc, argv, "s:a:v")) != -1) {
switch (c) { switch (c) {
case 'v': case 'v':
verbose++; verbose++;
@ -486,6 +486,11 @@ int main(int argc, char *argv[])
break; break;
case 's': case 's':
slave = 1; slave = 1;
dest_queue = atoi(optarg);
if (dest_queue < 0) {
fprintf(stderr, "invalid queue number %d\n", dest_queue);
exit(1);
}
break; break;
default: default:
usage(); usage();
@ -525,7 +530,7 @@ int main(int argc, char *argv[])
/* if running in slave mode also listen for START event */ /* if running in slave mode also listen for START event */
snd_seq_set_client_event_filter(seq_handle, SND_SEQ_EVENT_ECHO); snd_seq_set_client_event_filter(seq_handle, SND_SEQ_EVENT_ECHO);
if (slave) if (slave)
snd_seq_set_client_event_filter(seq_handle, SND_SEQ_EVENT_ECHO); snd_seq_set_client_event_filter(seq_handle, SND_SEQ_EVENT_START);
snd_seq_set_client_name(seq_handle, "MIDI file player"); snd_seq_set_client_name(seq_handle, "MIDI file player");
/* create port */ /* create port */
@ -539,10 +544,14 @@ int main(int argc, char *argv[])
} }
/* setup queue */ /* setup queue */
dest_queue = snd_seq_alloc_queue(seq_handle); if (slave) {
if (dest_queue < 0) { snd_seq_use_queue(seq_handle, dest_queue, 1);
perror("alloc queue"); } else {
exit(1); dest_queue = snd_seq_alloc_queue(seq_handle);
if (dest_queue < 0) {
perror("alloc queue");
exit(1);
}
} }
/* setup subscriber */ /* setup subscriber */

View file

@ -287,22 +287,20 @@ int decode_event(snd_seq_event_t * ev)
(int)ev->time.real.tv_nsec); (int)ev->time.real.tv_nsec);
break; break;
} }
printf("\n%sSource = %d.%d.%d.%d, dest = %d.%d.%d.%d\n", printf("\n%sSource = %d.%d, dest = %d.%d, queue = %d\n",
space, space,
ev->source.queue,
ev->source.client, ev->source.client,
ev->source.port, ev->source.port,
ev->source.channel,
ev->dest.queue,
ev->dest.client, ev->dest.client,
ev->dest.port, ev->dest.port,
ev->dest.channel); ev->queue);
printf("%sEvent = %s", space, event_names[ev->type]); printf("%sEvent = %s", space, event_names[ev->type]);
/* decode actual event data... */ /* decode actual event data... */
switch (ev->type) { switch (ev->type) {
case SND_SEQ_EVENT_NOTE: case SND_SEQ_EVENT_NOTE:
printf("; note=%d, velocity=%d, duration=%d\n", printf("; ch=%d, note=%d, velocity=%d, duration=%d\n",
ev->data.note.channel,
ev->data.note.note, ev->data.note.note,
ev->data.note.velocity, ev->data.note.velocity,
ev->data.note.duration); ev->data.note.duration);
@ -310,25 +308,31 @@ int decode_event(snd_seq_event_t * ev)
case SND_SEQ_EVENT_NOTEON: case SND_SEQ_EVENT_NOTEON:
case SND_SEQ_EVENT_NOTEOFF: case SND_SEQ_EVENT_NOTEOFF:
printf("; note=%d, velocity=%d\n", case SND_SEQ_EVENT_KEYPRESS:
printf("; ch=%d, note=%d, velocity=%d\n",
ev->data.note.channel,
ev->data.note.note, ev->data.note.note,
ev->data.note.velocity); ev->data.note.velocity);
break; break;
case SND_SEQ_EVENT_KEYPRESS:
case SND_SEQ_EVENT_CONTROLLER: case SND_SEQ_EVENT_CONTROLLER:
printf("; param=%i, value=%i\n", printf("; ch=%d, param=%i, value=%i\n",
ev->data.control.param, ev->data.control.channel,
ev->data.control.value); ev->data.control.param,
ev->data.control.value);
break; break;
case SND_SEQ_EVENT_PGMCHANGE: case SND_SEQ_EVENT_PGMCHANGE:
printf("; program=%i\n", ev->data.control.value); printf("; ch=%d, program=%i\n",
ev->data.control.channel,
ev->data.control.value);
break; break;
case SND_SEQ_EVENT_CHANPRESS: case SND_SEQ_EVENT_CHANPRESS:
case SND_SEQ_EVENT_PITCHBEND: case SND_SEQ_EVENT_PITCHBEND:
printf("; value=%i\n", ev->data.control.value); printf("; ch=%d, value=%i\n",
ev->data.control.channel,
ev->data.control.value);
break; break;
case SND_SEQ_EVENT_SYSEX: case SND_SEQ_EVENT_SYSEX:
@ -353,10 +357,10 @@ int decode_event(snd_seq_event_t * ev)
case SND_SEQ_EVENT_START: case SND_SEQ_EVENT_START:
case SND_SEQ_EVENT_CONTINUE: case SND_SEQ_EVENT_CONTINUE:
case SND_SEQ_EVENT_STOP: case SND_SEQ_EVENT_STOP:
printf("; queue = %i, client = %i\n", ev->data.addr.queue, ev->data.addr.client); printf("; queue = %i\n", ev->data.queue.queue);
break; break;
case SND_SEQ_EVENT_HEARTBEAT: case SND_SEQ_EVENT_SENSING:
printf("\n"); printf("\n");
break; break;
@ -402,18 +406,8 @@ int decode_event(snd_seq_event_t * ev)
void event_decoder_start_timer(snd_seq_t *handle, int queue, int client, int port) void event_decoder_start_timer(snd_seq_t *handle, int queue, int client, int port)
{ {
int err; int err;
snd_seq_event_t ev;
if ((err = snd_seq_start_queue(handle, queue, NULL))<0)
bzero(&ev, sizeof(ev));
ev.source.queue = queue;
ev.source.client = client;
ev.source.port = 0;
ev.dest.queue = queue;
ev.dest.client = SND_SEQ_CLIENT_SYSTEM;
ev.dest.port = SND_SEQ_PORT_SYSTEM_TIMER;
ev.flags = SND_SEQ_TIME_STAMP_REAL | SND_SEQ_TIME_MODE_REL;
ev.type = SND_SEQ_EVENT_START;
if ((err = snd_seq_event_output(handle, &ev))<0)
fprintf(stderr, "Timer event output error: %s\n", snd_strerror(err)); fprintf(stderr, "Timer event output error: %s\n", snd_strerror(err));
while (snd_seq_flush_output(handle)>0) while (snd_seq_flush_output(handle)>0)
sleep(1); sleep(1);
@ -442,7 +436,7 @@ void event_decoder(snd_seq_t *handle, int argc, char *argv[])
fprintf(stderr, "Cannot set nonblock mode: %s\n", snd_strerror(err)); fprintf(stderr, "Cannot set nonblock mode: %s\n", snd_strerror(err));
bzero(&port, sizeof(port)); bzero(&port, sizeof(port));
strcpy(port.name, "Input"); strcpy(port.name, "Input");
port.capability = SND_SEQ_PORT_CAP_WRITE; port.capability = SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_READ;
if ((err = snd_seq_create_port(handle, &port)) < 0) { if ((err = snd_seq_create_port(handle, &port)) < 0) {
fprintf(stderr, "Cannot create input port: %s\n", snd_strerror(err)); fprintf(stderr, "Cannot create input port: %s\n", snd_strerror(err));
return; return;
@ -450,10 +444,8 @@ void event_decoder(snd_seq_t *handle, int argc, char *argv[])
event_decoder_start_timer(handle, queue, client, port.port); event_decoder_start_timer(handle, queue, client, port.port);
bzero(&sub, sizeof(sub)); bzero(&sub, sizeof(sub));
sub.sender.queue = queue;
sub.sender.client = SND_SEQ_CLIENT_SYSTEM; sub.sender.client = SND_SEQ_CLIENT_SYSTEM;
sub.sender.port = SND_SEQ_PORT_SYSTEM_ANNOUNCE; sub.sender.port = SND_SEQ_PORT_SYSTEM_ANNOUNCE;
sub.dest.queue = queue;
sub.dest.client = client; sub.dest.client = client;
sub.dest.port = port.port; sub.dest.port = port.port;
sub.exclusive = 0; sub.exclusive = 0;

View file

@ -1,3 +1,5 @@
#ifdef USE_PCM
/* /*
* PCM timer layer * PCM timer layer
*/ */
@ -50,7 +52,7 @@ void show_playback_status(snd_pcm_t *phandle)
printf(" Fragments : %i\n", pstatus.fragments); printf(" Fragments : %i\n", pstatus.fragments);
printf(" Fragment size : %i\n", pstatus.fragment_size); printf(" Fragment size : %i\n", pstatus.fragment_size);
} }
#endif
/* /*
* Simple event sender * Simple event sender
*/ */
@ -58,8 +60,8 @@ void show_playback_status(snd_pcm_t *phandle)
void event_sender_start_timer(snd_seq_t *handle, int client, int queue, snd_pcm_t *phandle) void event_sender_start_timer(snd_seq_t *handle, int client, int queue, snd_pcm_t *phandle)
{ {
int err; int err;
snd_seq_event_t ev;
#ifdef USE_PCM
if (phandle) { if (phandle) {
snd_pcm_playback_info_t pinfo; snd_pcm_playback_info_t pinfo;
snd_seq_queue_timer_t qtimer; snd_seq_queue_timer_t qtimer;
@ -78,16 +80,8 @@ void event_sender_start_timer(snd_seq_t *handle, int client, int queue, snd_pcm_
exit(0); exit(0);
} }
} }
bzero(&ev, sizeof(ev)); #endif
ev.source.queue = queue; if ((err = snd_seq_start_queue(handle, queue, NULL))<0)
ev.source.client = client;
ev.source.port = 0;
ev.dest.queue = queue;
ev.dest.client = SND_SEQ_CLIENT_SYSTEM;
ev.dest.port = SND_SEQ_PORT_SYSTEM_TIMER;
ev.flags = SND_SEQ_TIME_STAMP_REAL | SND_SEQ_TIME_MODE_REL;
ev.type = SND_SEQ_EVENT_START;
if ((err = snd_seq_event_output(handle, &ev))<0)
fprintf(stderr, "Timer event output error: %s\n", snd_strerror(err)); fprintf(stderr, "Timer event output error: %s\n", snd_strerror(err));
/* ugly, but working */ /* ugly, but working */
while (snd_seq_flush_output(handle)>0) while (snd_seq_flush_output(handle)>0)
@ -119,7 +113,7 @@ void send_event(snd_seq_t *handle, int queue, int client, int port,
snd_seq_event_t ev; snd_seq_event_t ev;
bzero(&ev, sizeof(ev)); bzero(&ev, sizeof(ev));
ev.source.queue = ev.dest.queue = queue; ev.queue = queue;
ev.source.client = ev.dest.client = client; ev.source.client = ev.dest.client = client;
ev.source.port = ev.dest.port = port; ev.source.port = ev.dest.port = port;
ev.flags = SND_SEQ_TIME_STAMP_REAL | SND_SEQ_TIME_MODE_ABS; ev.flags = SND_SEQ_TIME_STAMP_REAL | SND_SEQ_TIME_MODE_ABS;
@ -129,10 +123,11 @@ void send_event(snd_seq_t *handle, int queue, int client, int port,
fprintf(stderr, "Event output error: %s\n", snd_strerror(err)); fprintf(stderr, "Event output error: %s\n", snd_strerror(err));
ev.dest.client = sub->dest.client; ev.dest.client = sub->dest.client;
ev.dest.port = sub->dest.port; ev.dest.port = sub->dest.port;
ev.dest.channel = 0;
ev.type = SND_SEQ_EVENT_NOTE; ev.type = SND_SEQ_EVENT_NOTE;
ev.data.note.channel = 0;
ev.data.note.note = 64 + (queue*2); ev.data.note.note = 64 + (queue*2);
ev.data.note.velocity = 127; ev.data.note.velocity = 127;
ev.data.note.off_velocity = 127;
ev.data.note.duration = 500; /* 0.5sec */ ev.data.note.duration = 500; /* 0.5sec */
if ((err = snd_seq_event_output(handle, &ev))<0) if ((err = snd_seq_event_output(handle, &ev))<0)
fprintf(stderr, "Event output error: %s\n", snd_strerror(err)); fprintf(stderr, "Event output error: %s\n", snd_strerror(err));
@ -178,10 +173,8 @@ void event_sender(snd_seq_t *handle, int argc, char *argv[])
} }
bzero(&sub, sizeof(sub)); bzero(&sub, sizeof(sub));
sub.sender.queue = queue;
sub.sender.client = client; sub.sender.client = client;
sub.sender.port = port.port; sub.sender.port = port.port;
sub.dest.queue = queue;
sub.exclusive = 0; sub.exclusive = 0;
for (max = 0; max < argc; max++) { for (max = 0; max < argc; max++) {
@ -206,6 +199,7 @@ void event_sender(snd_seq_t *handle, int argc, char *argv[])
printf("Destonation client = %i, port = %i\n", sub.dest.client, sub.dest.port); printf("Destonation client = %i, port = %i\n", sub.dest.client, sub.dest.port);
#ifdef USE_PCM
if (pcm_flag) { if (pcm_flag) {
if ((err = snd_pcm_open(&phandle, pcard, pdevice, SND_PCM_OPEN_PLAYBACK)) < 0) { if ((err = snd_pcm_open(&phandle, pcard, pdevice, SND_PCM_OPEN_PLAYBACK)) < 0) {
fprintf(stderr, "Playback open error: %s\n", snd_strerror(err)); fprintf(stderr, "Playback open error: %s\n", snd_strerror(err));
@ -220,6 +214,7 @@ void event_sender(snd_seq_t *handle, int argc, char *argv[])
exit(0); exit(0);
} }
} }
#endif
event_sender_start_timer(handle, client, queue, phandle); event_sender_start_timer(handle, client, queue, phandle);
first = 1; first = 1;
@ -229,19 +224,23 @@ void event_sender(snd_seq_t *handle, int argc, char *argv[])
max = snd_seq_file_descriptor(handle); max = snd_seq_file_descriptor(handle);
FD_SET(snd_seq_file_descriptor(handle), &out); FD_SET(snd_seq_file_descriptor(handle), &out);
FD_SET(snd_seq_file_descriptor(handle), &in); FD_SET(snd_seq_file_descriptor(handle), &in);
#ifdef USE_PCM
if (phandle) { if (phandle) {
if (snd_pcm_file_descriptor(phandle) > max) if (snd_pcm_file_descriptor(phandle) > max)
max = snd_pcm_file_descriptor(phandle); max = snd_pcm_file_descriptor(phandle);
FD_SET(snd_pcm_file_descriptor(phandle), &out); FD_SET(snd_pcm_file_descriptor(phandle), &out);
} }
#endif
if (select(max + 1, &in, &out, NULL, NULL) < 0) if (select(max + 1, &in, &out, NULL, NULL) < 0)
break; break;
#ifdef USE_PCM
if (phandle && FD_ISSET(snd_pcm_file_descriptor(phandle), &out)) { if (phandle && FD_ISSET(snd_pcm_file_descriptor(phandle), &out)) {
if (snd_pcm_write(phandle, pbuf, pfragment_size) != pfragment_size) { if (snd_pcm_write(phandle, pbuf, pfragment_size) != pfragment_size) {
fprintf(stderr, "Playback write error!!\n"); fprintf(stderr, "Playback write error!!\n");
exit(0); exit(0);
} }
} }
#endif
if (FD_ISSET(snd_seq_file_descriptor(handle), &out)) { if (FD_ISSET(snd_seq_file_descriptor(handle), &out)) {
if (first) { if (first) {
send_event(handle, queue, client, port.port, &sub, &time); send_event(handle, queue, client, port.port, &sub, &time);

View file

@ -151,6 +151,8 @@ int main(int argc, char *argv[])
{"version", 0, NULL, HELPID_VERSION}, {"version", 0, NULL, HELPID_VERSION},
{NULL, 0, NULL, 0}, {NULL, 0, NULL, 0},
}; };
morehelp = 0;
while (1) { while (1) {
int c; int c;
@ -193,6 +195,7 @@ int main(int argc, char *argv[])
} }
set_name(handle); set_name(handle);
system_info(handle); system_info(handle);
if (!strcmp(argv[optind], "system")) { if (!strcmp(argv[optind], "system")) {
show_system_info(handle); show_system_info(handle);
} else if (!strcmp(argv[optind], "queue")) { } else if (!strcmp(argv[optind], "queue")) {