From 682deca3703b85dd85133918fdd3c932f2655624 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Fri, 17 Sep 1999 16:17:21 +0000 Subject: [PATCH] Takashi Iwai Fri, 17 Sep 1999 17:24:43 +0200 OK, the attached is the patch to alsa-driver and alsa-lib. It will really violate the source/binary compatibility as I wrote :-p It includes: - change of event data for accessing Timer Port - new middle-level functions for sequencer in alsa-lib - some comments / fixes The test programs in alsa-lib (playmidi1, aconnect, aseqnet) were rewritten to use the new functions above. I included also a patch to pmidi-1.2.2. --- include/Makefile.am | 2 +- include/seqmid.h | 192 ++++++++++++++++++++++++++ src/seq/Makefile.am | 4 +- src/seq/seq.c | 22 +-- src/seq/seq_priv.h | 45 +++++++ src/seq/seqmid.c | 319 ++++++++++++++++++++++++++++++++++++++++++++ test/aconnect.c | 1 + test/aseqnet.c | 103 +++++++------- test/playmidi1.c | 237 ++++++++++---------------------- 9 files changed, 686 insertions(+), 239 deletions(-) create mode 100644 include/seqmid.h create mode 100644 src/seq/seq_priv.h create mode 100644 src/seq/seqmid.c diff --git a/include/Makefile.am b/include/Makefile.am index 33b57f4e..fdb8036e 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -4,7 +4,7 @@ sysinclude_HEADERS = asoundlib.h # This is the order they will be concatenated into asoundlib.h! # header_files=header.h version.h error.h control.h mixer.h pcm.h rawmidi.h \ - timer.h seq.h conv.h instr.h footer.h + timer.h seq.h seqmid.h conv.h instr.h footer.h noinst_HEADERS=$(header_files) diff --git a/include/seqmid.h b/include/seqmid.h new file mode 100644 index 00000000..eb96dce5 --- /dev/null +++ b/include/seqmid.h @@ -0,0 +1,192 @@ +/**************************************************************************** + * * + * Sequencer Middle Level * + * * + ****************************************************************************/ + +#ifdef __cplusplus +extern "C" { +#endif + +/* initialize event record */ +void snd_seq_ev_clear(snd_seq_event_t *ev); + +/* set destination - following three macros are exclusive */ + /* explicit destination */ +void snd_seq_ev_set_dest(snd_seq_event_t *ev, int client, int port); + /* to subscribers */ +void snd_seq_ev_set_subs(snd_seq_event_t *ev); + /* broadcast to all clients/ports */ +void snd_seq_ev_set_broadcast(snd_seq_event_t *ev); + +/* set source port */ +void snd_seq_ev_set_source(snd_seq_event_t *ev, int port); + +/* set scheduling - following three macros are exclusive */ + /* direct event passing without enqueued */ +void snd_seq_ev_set_direct(snd_seq_event_t *ev); + /* scheduled on tick-queue */ +void snd_seq_ev_schedule_tick(snd_seq_event_t *ev, int q, int relative, + unsigned long tick); + /* scheduled on real-time-queue */ +void snd_seq_ev_schedule_real(snd_seq_event_t *ev, int q, int relative, + snd_seq_real_time_t *real); + +/* set event priority (optional) */ +void snd_seq_ev_set_priority(snd_seq_event_t *ev, int high_prior); + +/* set event data type - following two macros are exclusive */ + /* fixed size event */ +void snd_seq_ev_set_fixed(snd_seq_event_t *ev); + /* variable size event */ +void snd_seq_ev_set_variable(snd_seq_event_t *ev, int len, void *ptr); + +/* queue controls - + * to send at scheduled time, set the schedule in ev. + * 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() + * apropriately. + */ +int snd_seq_control_queue(snd_seq_t *seq, int q, int type, int value, snd_seq_event_t *ev); +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_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); + +/* create a port - simple version - return the port number */ +int snd_seq_create_simple_port(snd_seq_t *seq, char *name, + unsigned int caps, unsigned int type); +/* delete the port */ +int snd_seq_delete_simple_port(snd_seq_t *seq, int port); + +/* simple subscription between this port and another port + (w/o exclusive & time conversion) + */ +int snd_seq_connect_from(snd_seq_t *seq, int my_port, int src_client, int src_port); +int snd_seq_connect_to(snd_seq_t *seq, int my_port, int dest_client, int dest_port); +int snd_seq_disconnect_from(snd_seq_t *seq, int my_port, int src_client, int src_port); +int snd_seq_disconnect_to(snd_seq_t *seq, int my_port, int dest_client, int dest_port); + +/* + * set client information + */ +int snd_seq_set_client_name(snd_seq_t *seq, char *name); +int snd_seq_set_client_group(snd_seq_t *seq, char *name); +int snd_seq_set_client_filter(snd_seq_t *seq, unsigned int filter); +int snd_seq_set_client_event_filter(snd_seq_t *seq, int event_type); +int snd_seq_set_client_pool_output(snd_seq_t *seq, int size); +int snd_seq_set_client_pool_output_room(snd_seq_t *seq, int size); +int snd_seq_set_client_pool_input(snd_seq_t *seq, int size); + +/* + * reset client input/output pool + */ +int snd_seq_reset_pool_output(snd_seq_t *seq); +int snd_seq_reset_pool_input(snd_seq_t *seq); + +/* + * equivalent macros + */ +#define __snd_seq_ev_clear(ev) memset(ev, 0, sizeof(snd_seq_event_t)) +#define __snd_seq_ev_set_dest(ev,c,p) \ + ((ev)->dest.client = (c), (ev)->dest.port = (p)) +#define __snd_seq_ev_set_subs(ev) \ + ((ev)->dest.client = SND_SEQ_ADDRESS_SUBSCRIBERS,\ + (ev)->dest.port = SND_SEQ_ADDRESS_UNKNOWN) +#define __snd_seq_ev_set_broadcast(ev) \ + ((ev)->dest.client = 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_start_queue(seq,q,ev) \ + snd_seq_control_queue(seq, q, SND_SEQ_EVENT_START, 0, ev) +#define __snd_seq_stop_queue(seq,q,ev) \ + snd_seq_control_queue(seq, q, SND_SEQ_EVENT_STOP, 0, ev) +#define __snd_seq_continue_queue(seq,q,ev) \ + snd_seq_control_queue(seq, q, SND_SEQ_EVENT_CONTINUE, 0, ev) +#define __snd_seq_change_queue_tempo(seq,q,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 + */ +#define snd_seq_ev_set_note(ev,ch,key,vel,dur) \ + ((ev)->type = SND_SEQ_EVENT_NOTE,\ + snd_seq_ev_set_fixed(ev),\ + (ev)->dest.channel = (ch),\ + (ev)->data.note.note = (key),\ + (ev)->data.note.velocity = (vel),\ + (ev)->data.note.dulation = (dur)) +#define snd_seq_ev_set_noteon(ev,ch,key,vel) \ + ((ev)->type = SND_SEQ_EVENT_NOTEON,\ + snd_seq_ev_set_fixed(ev),\ + (ev)->dest.channel = (ch),\ + (ev)->data.note.note = (key),\ + (ev)->data.note.velocity = (vel)) +#define snd_seq_ev_set_noteoff(ev,ch,key,vel) \ + ((ev)->type = SND_SEQ_EVENT_NOTEOFF,\ + snd_seq_ev_set_fixed(ev),\ + (ev)->dest.channel = (ch),\ + (ev)->data.note.note = (key),\ + (ev)->data.note.velocity = (vel)) +#define snd_seq_ev_set_keypress(ev,ch,key,vel) \ + ((ev)->type = SND_SEQ_EVENT_KEYPRESS,\ + snd_seq_ev_set_fixed(ev),\ + (ev)->dest.channel = (ch),\ + (ev)->data.note.note = (key),\ + (ev)->data.note.velocity = (vel)) +#define snd_seq_ev_set_controller(ev,ch,cc,val) \ + ((ev)->type = SND_SEQ_EVENT_CONTROLLER,\ + snd_seq_ev_set_fixed(ev),\ + (ev)->dest.channel = (ch),\ + (ev)->data.control.param = (cc),\ + (ev)->data.control.value = (val)) +#define snd_seq_ev_set_pgmchange(ev,ch,val) \ + ((ev)->type = SND_SEQ_EVENT_PGMCHANGE,\ + snd_seq_ev_set_fixed(ev),\ + (ev)->dest.channel = (ch),\ + (ev)->data.control.value = (val)) +#define snd_seq_ev_set_pitchbend(ev,ch,val) \ + ((ev)->type = SND_SEQ_EVENT_PITCHBEND,\ + snd_seq_ev_set_fixed(ev),\ + (ev)->dest.channel = (ch),\ + (ev)->data.control.value = (val)) +#define snd_seq_ev_set_chanpress(ev,ch,val) \ + ((ev)->type = SND_SEQ_EVENT_CHANPRESS,\ + snd_seq_ev_set_fixed(ev),\ + (ev)->dest.channel = (ch),\ + (ev)->data.control.value = (val)) +#define snd_seq_ev_set_sysex(ev,datalen,dataptr) \ + ((ev)->type = SND_SEQ_EVENT_SYSEX,\ + snd_seq_ev_set_variable(ev, datalen, dataptr)) + +/* etc. etc... */ + + +#ifdef __cplusplus +} +#endif + diff --git a/src/seq/Makefile.am b/src/seq/Makefile.am index 778893d3..637dfec8 100644 --- a/src/seq/Makefile.am +++ b/src/seq/Makefile.am @@ -1,6 +1,8 @@ EXTRA_LTLIBRARIES=libseq.la -libseq_la_SOURCES = seq.c +libseq_la_SOURCES = seq.c seqmid.c +noinst_HEADERS = seq_priv.h + all: libseq.la diff --git a/src/seq/seq.c b/src/seq/seq.c index 33ba13d6..38ff3206 100644 --- a/src/seq/seq.c +++ b/src/seq/seq.c @@ -27,6 +27,7 @@ #include #include #include "asoundlib.h" +#include "seq_priv.h" #define SND_FILE_SEQ "/dev/snd/seq" #define SND_FILE_ALOADSEQ "/dev/aloadSEQ" @@ -34,26 +35,6 @@ #define SND_SEQ_OBUF_SIZE (16*1024) /* should be configurable */ #define SND_SEQ_IBUF_SIZE (4*1024) /* should be configurable */ -typedef struct snd_stru_seq_cell { - snd_seq_event_t ev; - struct snd_stru_seq_cell *next; -} snd_seq_cell_t; - -struct snd_seq { - int client; /* client number */ - int fd; - /* buffers */ - char *obuf; /* output buffer */ - int obufsize; /* output buffer size */ - int obufused; /* output buffer used size */ - char *ibuf; /* input buffer */ - int ibufsize; /* input buffer size */ - /* input queue */ - int cells; - snd_seq_cell_t *head; - snd_seq_cell_t *tail; -}; - int snd_seq_open(snd_seq_t **handle, int mode) { int fd, ver, client, flg; @@ -863,4 +844,3 @@ int snd_seq_get_bit(int nr, void *array) return ((((unsigned int *)array)[nr >> 5]) & (1UL << (nr & 31))) ? 1 : 0; } - diff --git a/src/seq/seq_priv.h b/src/seq/seq_priv.h new file mode 100644 index 00000000..1f35642e --- /dev/null +++ b/src/seq/seq_priv.h @@ -0,0 +1,45 @@ +/* + * Sequencer Interface - definition of sequencer event handler + * Copyright (c) 1998 by Jaroslav Kysela + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library 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 Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef __SEQ_PRIV_H +#define __SEQ_PRIV_H + +typedef struct snd_stru_seq_cell { + snd_seq_event_t ev; + struct snd_stru_seq_cell *next; +} snd_seq_cell_t; + +struct snd_seq { + int client; /* client number */ + int fd; + /* buffers */ + char *obuf; /* output buffer */ + int obufsize; /* output buffer size */ + int obufused; /* output buffer used size */ + char *ibuf; /* input buffer */ + int ibufsize; /* input buffer size */ + /* input queue */ + int cells; + snd_seq_cell_t *head; + snd_seq_cell_t *tail; +}; + +#endif diff --git a/src/seq/seqmid.c b/src/seq/seqmid.c new file mode 100644 index 00000000..f2999e0d --- /dev/null +++ b/src/seq/seqmid.c @@ -0,0 +1,319 @@ +/* + * Sequencer Interface - middle-level routines + * + * Copyright (c) 1999 by Takashi Iwai + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library 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 Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include "asoundlib.h" +#include "seq_priv.h" + +/* direct passing (without queued) */ +void snd_seq_ev_set_direct(snd_seq_event_t *ev) +{ + ev->flags &= ~SND_SEQ_DEST_MASK; + ev->flags |= SND_SEQ_DEST_DIRECT; + ev->dest.queue = SND_SEQ_ADDRESS_UNKNOWN; /* XXX */ +} + +/* queued on tick */ +void snd_seq_ev_schedule_tick(snd_seq_event_t *ev, int q, int relative, + unsigned long tick) +{ + ev->flags &= ~(SND_SEQ_DEST_MASK | SND_SEQ_TIME_STAMP_MASK | + SND_SEQ_TIME_MODE_MASK); + ev->flags |= SND_SEQ_DEST_QUEUE; + ev->flags |= SND_SEQ_TIME_STAMP_TICK; + ev->flags |= relative ? SND_SEQ_TIME_MODE_REL : SND_SEQ_TIME_MODE_ABS; + ev->time.tick = tick; +} + +/* queued on real-time */ +void snd_seq_ev_schedule_real(snd_seq_event_t *ev, int q, int relative, + snd_seq_real_time_t *real) +{ + ev->flags &= ~(SND_SEQ_DEST_MASK | SND_SEQ_TIME_STAMP_MASK | + SND_SEQ_TIME_MODE_MASK); + ev->flags |= SND_SEQ_DEST_QUEUE; + ev->flags |= SND_SEQ_TIME_STAMP_REAL; + ev->flags |= relative ? SND_SEQ_TIME_MODE_REL : SND_SEQ_TIME_MODE_ABS; + ev->time.real = *real; +} + +/* set event priority */ +void snd_seq_ev_set_priority(snd_seq_event_t *ev, int high_prior) +{ + ev->flags &= ~SND_SEQ_PRIORITY_MASK; + ev->flags |= high_prior ? SND_SEQ_PRIORITY_HIGH : SND_SEQ_PRIORITY_NORMAL; +} + +/* set fixed data */ +void snd_seq_ev_set_fixed(snd_seq_event_t *ev) +{ + ev->flags &= ~SND_SEQ_EVENT_LENGTH_MASK; + ev->flags |= SND_SEQ_EVENT_LENGTH_FIXED; +} + +/* set variable data */ +void snd_seq_ev_set_variable(snd_seq_event_t *ev, int len, void *ptr) +{ + ev->flags &= ~SND_SEQ_EVENT_LENGTH_MASK; + ev->flags |= SND_SEQ_EVENT_LENGTH_VARIABLE; + ev->data.ext.len = len; + ev->data.ext.ptr = ptr; +} + +/* queue controls - start/stop/continue */ +/* if ev is NULL, send events immediately. + 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) +{ + snd_seq_event_t tmpev; + if (ev == NULL) { + snd_seq_ev_clear(&tmpev); + ev = &tmpev; + snd_seq_ev_set_direct(ev); + } + + 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); +} + + +/* create a port - simple version + * return the port number + */ +int snd_seq_create_simple_port(snd_seq_t *seq, char *name, + unsigned int caps, unsigned int type) +{ + snd_seq_port_info_t pinfo; + int result; + + memset(&pinfo, 0, sizeof(pinfo)); + if (name) + strncpy(pinfo.name, name, sizeof(pinfo.name) - 1); + pinfo.capability = caps; + pinfo.cap_group = caps; + pinfo.type = type; + pinfo.midi_channels = 16; + pinfo.midi_voices = 64; /* XXX */ + pinfo.synth_voices = 0; /* XXX */ + pinfo.kernel = NULL; + + result = snd_seq_create_port(seq, &pinfo); + if (result < 0) + return result; + else + return pinfo.port; +} + +/* delete the port */ +int snd_seq_delete_simple_port(snd_seq_t *seq, int port) +{ + snd_seq_port_info_t pinfo; + + memset(&pinfo, 0, sizeof(pinfo)); + pinfo.port = port; + + return snd_seq_delete_port(seq, &pinfo); +} + +/* + * sipmle subscription (w/o exclusive & time conversion) + */ +int snd_seq_connect_from(snd_seq_t *seq, int myport, int src_client, int src_port) +{ + snd_seq_port_subscribe_t subs; + + memset(&subs, 0, sizeof(subs)); + subs.sender.client = src_client; + subs.sender.port = src_port; + /*subs.dest.client = seq->client;*/ + subs.dest.client = snd_seq_client_id(seq); + subs.dest.port = myport; + + return snd_seq_subscribe_port(seq, &subs); +} + +int snd_seq_connect_to(snd_seq_t *seq, int myport, int dest_client, int dest_port) +{ + snd_seq_port_subscribe_t subs; + + memset(&subs, 0, sizeof(subs)); + /*subs.sender.client = seq->client;*/ + subs.sender.client = snd_seq_client_id(seq); + subs.sender.port = myport; + subs.dest.client = dest_client; + subs.dest.port = dest_port; + + return snd_seq_subscribe_port(seq, &subs); +} + +int snd_seq_disconnect_from(snd_seq_t *seq, int myport, int src_client, int src_port) +{ + snd_seq_port_subscribe_t subs; + + memset(&subs, 0, sizeof(subs)); + subs.sender.client = src_client; + subs.sender.port = src_port; + /*subs.dest.client = seq->client;*/ + subs.dest.client = snd_seq_client_id(seq); + subs.dest.port = myport; + + return snd_seq_unsubscribe_port(seq, &subs); +} + +int snd_seq_disconnect_to(snd_seq_t *seq, int myport, int dest_client, int dest_port) +{ + snd_seq_port_subscribe_t subs; + + memset(&subs, 0, sizeof(subs)); + /*subs.sender.client = seq->client;*/ + subs.sender.client = snd_seq_client_id(seq); + subs.sender.port = myport; + subs.dest.client = dest_client; + subs.dest.port = dest_port; + + return snd_seq_unsubscribe_port(seq, &subs); +} + +/* + * set client information + */ +int snd_seq_set_client_name(snd_seq_t *seq, char *name) +{ + snd_seq_client_info_t info; + int err; + + if ((err = snd_seq_get_client_info(seq, &info)) < 0) + return err; + strncpy(info.name, name, sizeof(info.name) - 1); + return snd_seq_set_client_info(seq, &info); +} + +int snd_seq_set_client_group(snd_seq_t *seq, char *name) +{ + snd_seq_client_info_t info; + int err; + + if ((err = snd_seq_get_client_info(seq, &info)) < 0) + return err; + strncpy(info.group, name, sizeof(info.group) - 1); + return snd_seq_set_client_info(seq, &info); +} + +int snd_seq_set_client_filter(snd_seq_t *seq, unsigned int filter) +{ + snd_seq_client_info_t info; + int err; + + if ((err = snd_seq_get_client_info(seq, &info)) < 0) + return err; + info.filter = filter; + return snd_seq_set_client_info(seq, &info); +} + +int snd_seq_set_client_event_filter(snd_seq_t *seq, int event_type) +{ + snd_seq_client_info_t info; + int err; + + if ((err = snd_seq_get_client_info(seq, &info)) < 0) + return err; + info.filter |= SND_SEQ_FILTER_USE_EVENT; + snd_seq_set_bit(event_type, info.event_filter); + return snd_seq_set_client_info(seq, &info); +} + +int snd_seq_set_client_pool_output(snd_seq_t *seq, int size) +{ + snd_seq_client_pool_t info; + int err; + + if ((err = snd_seq_get_client_pool(seq, &info)) < 0) + return err; + info.output_pool = size; + return snd_seq_set_client_pool(seq, &info); +} + +int snd_seq_set_client_pool_output_room(snd_seq_t *seq, int size) +{ + snd_seq_client_pool_t info; + int err; + + if ((err = snd_seq_get_client_pool(seq, &info)) < 0) + return err; + info.output_room = size; + return snd_seq_set_client_pool(seq, &info); +} + +int snd_seq_set_client_pool_input(snd_seq_t *seq, int size) +{ + snd_seq_client_pool_t info; + int err; + + if ((err = snd_seq_get_client_pool(seq, &info)) < 0) + return err; + info.input_pool = size; + return snd_seq_set_client_pool(seq, &info); +} + +/* + * reset client input/output pool + * use REMOVE_EVENTS ioctl instead of RESET_POOL + */ +int snd_seq_reset_pool_output(snd_seq_t *seq) +{ + snd_seq_remove_events_t rmp; + + memset(&rmp, 0, sizeof(rmp)); + rmp.output = 1; + rmp.remove_mode = 0; /* remove all */ + return snd_seq_remove_events(seq, &rmp); +} + +int snd_seq_reset_pool_input(snd_seq_t *seq) +{ + snd_seq_remove_events_t rmp; + + memset(&rmp, 0, sizeof(rmp)); + rmp.input = 1; + rmp.remove_mode = 0; /* remove all */ + return snd_seq_remove_events(seq, &rmp); +} + diff --git a/test/aconnect.c b/test/aconnect.c index 888f2301..0adf8d6f 100644 --- a/test/aconnect.c +++ b/test/aconnect.c @@ -37,6 +37,7 @@ static void usage(void) fprintf(stderr, " list input ports\n"); fprintf(stderr, " aconnect -o [-g group] [-l]\n"); fprintf(stderr, " list output ports\n"); + fprintf(stderr, " -l = list current connections\n"); } /* diff --git a/test/aseqnet.c b/test/aseqnet.c index 101981a5..d2f993dd 100644 --- a/test/aseqnet.c +++ b/test/aseqnet.c @@ -23,14 +23,17 @@ #include #include #include +#include /* * prototypes */ static void usage(void); static void init_buf(void); +static void close_files(void); static void init_seq(char *source, char *dest); static int get_port(char *service); +static void sigterm_exit(int sig); static void init_server(int port); static void init_client(char *server, int port); static void do_loop(void); @@ -54,7 +57,7 @@ static int cur_wrlen, max_wrlen; #define MAX_CONNECTION 10 static snd_seq_t *handle; -static int seqfd, sockfd, netfd[MAX_CONNECTION] = {[1 ... MAX_CONNECTION] = -1}; +static int seqfd, sockfd, netfd[MAX_CONNECTION] = {[0 ... MAX_CONNECTION-1] = -1}; static int max_connection; static int cur_connected; static int seq_port; @@ -68,7 +71,7 @@ static int server_mode; int main(int argc, char **argv) { - int c, i; + int c; int port = DEFAULT_PORT; char *source = NULL, *dest = NULL; @@ -92,6 +95,9 @@ int main(int argc, char **argv) } } + signal(SIGINT, sigterm_exit); + signal(SIGTERM, sigterm_exit); + init_buf(); init_seq(source, dest); @@ -107,12 +113,7 @@ int main(int argc, char **argv) do_loop(); - for (i = 0; i < max_connection; i++) { - if (netfd[i] >= 0) - close(netfd[i]); - } - if (sockfd >= 0) - close(sockfd); + close_files(); return 0; } @@ -167,14 +168,29 @@ static void parse_addr(snd_seq_addr_t *addr, char *arg) addr->port = 0; } + +/* + * close all files + */ +static void close_files(void) +{ + int i; +fprintf(stderr, "closing files..\n"); + for (i = 0; i < max_connection; i++) { + if (netfd[i] >= 0) + close(netfd[i]); + } + if (sockfd >= 0) + close(sockfd); +} + + /* * initialize sequencer */ static void init_seq(char *source, char *dest) { - snd_seq_client_info_t cinfo; - snd_seq_port_info_t pinfo; - snd_seq_port_subscribe_t subs; + snd_seq_addr_t addr; if (snd_seq_open(&handle, SND_SEQ_OPEN) < 0) { perror("snd_seq_open"); @@ -184,49 +200,38 @@ static void init_seq(char *source, char *dest) snd_seq_block_mode(handle, 0); /* set client info */ - memset(&cinfo, 0, sizeof(cinfo)); if (server_mode) - strcpy(cinfo.name, "Net Server"); + snd_seq_set_client_name(handle, "Net Server"); else - strcpy(cinfo.name, "Net Client"); - if (snd_seq_set_client_info(handle, &cinfo) < 0) { - perror("set client info"); - exit(1); - } + snd_seq_set_client_name(handle, "Net Client"); /* create a port */ - memset(&pinfo, 0, sizeof(pinfo)); - pinfo.capability = SND_SEQ_PORT_CAP_READ|SND_SEQ_PORT_CAP_WRITE| - SND_SEQ_PORT_CAP_SUBS_READ|SND_SEQ_PORT_CAP_SUBS_WRITE; - strcpy(pinfo.name, "Network"); - pinfo.port = 0; - if (snd_seq_create_port(handle, &pinfo) < 0) { + seq_port = snd_seq_create_simple_port(handle, "Network", + SND_SEQ_PORT_CAP_READ | + SND_SEQ_PORT_CAP_WRITE | + SND_SEQ_PORT_CAP_SUBS_READ | + SND_SEQ_PORT_CAP_SUBS_WRITE, + SND_SEQ_PORT_TYPE_MIDI_GENERIC); + if (seq_port < 0) { perror("create seq port"); exit(1); } - seq_port = pinfo.port; - fprintf(stderr, "sequencer opened: %d:%d\n", pinfo.client, pinfo.port); + fprintf(stderr, "sequencer opened: %d:%d\n", + snd_seq_client_id(handle), seq_port); /* explicit subscriptions */ - memset(&subs, 0, sizeof(subs)); if (source) { /* read subscription */ - parse_addr(&subs.sender, source); - subs.dest.client = pinfo.client; - subs.dest.port = pinfo.port; - subs.sender.queue = subs.dest.queue = 0; - if (snd_seq_subscribe_port(handle, &subs)) { + parse_addr(&addr, source); + if (snd_seq_connect_from(handle, seq_port, addr.client, addr.port)) { perror("read subscription"); exit(1); } } if (dest) { /* write subscription */ - parse_addr(&subs.dest, dest); - subs.sender.client = pinfo.client; - subs.sender.port = pinfo.port; - subs.sender.queue = subs.dest.queue = 0; - if (snd_seq_subscribe_port(handle, &subs)) { + parse_addr(&addr, dest); + if (snd_seq_connect_to(handle, seq_port, addr.client, addr.port)) { perror("write subscription"); exit(1); } @@ -248,6 +253,16 @@ static int get_port(char *service) return sp->s_port; } +/* + * signal handler + */ +static void sigterm_exit(int sig) +{ + close_files(); + exit(1); +} + + /* * initialize network server */ @@ -395,11 +410,6 @@ static void do_loop(void) } -/* - * is variable length event? - */ -#define is_varlen(ev) (((ev)->flags & SND_SEQ_EVENT_LENGTH_MASK) == SND_SEQ_EVENT_LENGTH_VARIABLE) - /* * flush write buffer - send data to the socket */ @@ -442,7 +452,7 @@ static int copy_local_to_remote(void) snd_seq_free_event(ev); continue; } - if (is_varlen(ev)) { + if (snd_seq_ev_is_variable(ev)) { int len; len = sizeof(snd_seq_event_t) + ev->data.ext.len; buf = get_writebuf(len); @@ -483,7 +493,7 @@ static int copy_remote_to_local(int fd) memcpy(ev, buf, sizeof(snd_seq_event_t)); buf += sizeof(snd_seq_event_t); count -= sizeof(snd_seq_event_t); - if (is_varlen(ev) && ev->data.ext.len > 0) { + if (snd_seq_ev_is_variable(ev) && ev->data.ext.len > 0) { ev->data.ext.ptr = malloc(ev->data.ext.len); if (ev->data.ext.ptr == NULL) { fprintf(stderr, "can't malloc\n"); @@ -493,8 +503,9 @@ static int copy_remote_to_local(int fd) buf += ev->data.ext.len; count -= ev->data.ext.len; } - ev->source.port = seq_port; - ev->dest.queue = SND_SEQ_ADDRESS_SUBSCRIBERS; + snd_seq_ev_set_direct(ev); + snd_seq_ev_set_source(ev, seq_port); + snd_seq_ev_set_subs(ev); snd_seq_event_output(handle, ev); snd_seq_free_event(ev); } diff --git a/test/playmidi1.c b/test/playmidi1.c index 6c6151aa..37446b0e 100644 --- a/test/playmidi1.c +++ b/test/playmidi1.c @@ -15,6 +15,9 @@ * 19990827 Takashi Iwai * - use snd_seq_alloc_queue() * + * 19990916 Takashi Iwai + * - use middle-level sequencer routines and macros + * * 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 @@ -71,8 +74,7 @@ static int local_tempo = 500000; static int dest_queue = 0; static int dest_client = DEST_CLIENT_NUMBER; static int dest_port = DEST_PORT_NUMBER; -static int source_channel = 0; -static int source_port = 0; +static int my_port = 0; static int verbose = 0; static int slave = 0; /* allow external sync */ @@ -102,7 +104,7 @@ static void tick2time(snd_seq_real_time_t * tm, int tick) #ifdef USE_BLOCKING_MODE /* write event - using blocking mode */ -static void write_ev_im(snd_seq_event_t *ev) +static void write_ev(snd_seq_event_t *ev) { int written; @@ -114,7 +116,7 @@ static void write_ev_im(snd_seq_event_t *ev) } #else /* write event - using select syscall */ -static void write_ev_im(snd_seq_event_t *ev) +static void write_ev(snd_seq_event_t *ev) { int rc; @@ -132,24 +134,6 @@ static void write_ev_im(snd_seq_event_t *ev) } #endif -/* write event to ALSA sequencer */ -static void write_ev(snd_seq_event_t * ev) -{ - ev->flags &= ~SND_SEQ_EVENT_LENGTH_MASK; - ev->flags |= SND_SEQ_EVENT_LENGTH_FIXED; - write_ev_im(ev); -} - -/* write variable length event to ALSA sequencer */ -static void write_ev_var(snd_seq_event_t * ev, int len, void *ptr) -{ - ev->flags &= ~SND_SEQ_EVENT_LENGTH_MASK; - ev->flags |= SND_SEQ_EVENT_LENGTH_VARIABLE; - ev->data.ext.len = len; - ev->data.ext.ptr = ptr; - write_ev_im(ev); -} - /* read byte */ static int mygetc(void) { @@ -210,75 +194,39 @@ static void do_header(int format, int ntracks, int division) alsa_start_timer(); } -/* fill normal event header */ -static void set_event_header(snd_seq_event_t *ev, int type, int chan) +/* fill time */ +static void set_event_time(snd_seq_event_t *ev, unsigned int currtime) { - ev->source.port = source_port; - ev->source.channel = source_channel; - - ev->dest.queue = dest_queue; - ev->dest.client = dest_client; - ev->dest.port = dest_port; - ev->dest.channel = chan; - #ifdef USE_REALTIME - ev->flags = SND_SEQ_TIME_STAMP_REAL | SND_SEQ_TIME_MODE_ABS; - tick2time(&ev->time.real, Mf_currtime); + snd_seq_real_time_t rtime; + tick2time(&rtime, currtime); + snd_seq_ev_schedule_real(ev, dest_queue, 0, &rtime); #else - ev->flags = SND_SEQ_TIME_STAMP_TICK | SND_SEQ_TIME_MODE_ABS; - ev->time.tick = Mf_currtime; + snd_seq_ev_schedule_tick(ev, dest_queue, 0, currtime); #endif - - ev->type = type; } -/* fill timer event header */ -static void set_timer_event_header(snd_seq_event_t *ev, int type) +/* fill normal event header */ +static void set_event_header(snd_seq_event_t *ev) { - ev->source.port = source_port; - ev->source.channel = 0; - - ev->dest.queue = dest_queue; - ev->dest.client = SND_SEQ_CLIENT_SYSTEM; /* system */ - ev->dest.port = SND_SEQ_PORT_SYSTEM_TIMER; /* timer */ - ev->dest.channel = 0; /* don't care */ - -#ifdef USE_REALTIME - ev->flags = SND_SEQ_TIME_STAMP_REAL | SND_SEQ_TIME_MODE_ABS; - tick2time(&ev->time.real, Mf_currtime); -#else - ev->flags = SND_SEQ_TIME_STAMP_TICK | SND_SEQ_TIME_MODE_ABS; - ev->time.tick = Mf_currtime; -#endif - - ev->type = type; + 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); } /* start timer */ static void alsa_start_timer(void) { - snd_seq_event_t ev; - - set_timer_event_header(&ev, SND_SEQ_EVENT_START); -#ifdef USE_REALTIME - ev.flags = SND_SEQ_TIME_STAMP_REAL | SND_SEQ_TIME_MODE_REL; - ev.time.real.tv_sec = 0; - ev.time.real.tv_nsec = 0; -#else - ev.flags = SND_SEQ_TIME_STAMP_TICK | SND_SEQ_TIME_MODE_REL; - ev.time.tick = Mf_currtime; -#endif - - write_ev(&ev); + snd_seq_start_queue(seq_handle, dest_queue, NULL); } /* stop timer */ static void alsa_stop_timer(void) { snd_seq_event_t ev; - - set_timer_event_header(&ev, SND_SEQ_EVENT_STOP); - write_ev(&ev); + set_event_header(&ev); + snd_seq_stop_queue(seq_handle, dest_queue, &ev); } /* change tempo */ @@ -297,11 +245,9 @@ static void do_tempo(int us) local_ticks = Mf_currtime; local_tempo = us; - set_timer_event_header(&ev, SND_SEQ_EVENT_TEMPO); - ev.data.queue.addr.queue = dest_queue; - ev.data.queue.value = us; + set_event_header(&ev); if (!slave) - write_ev(&ev); + snd_seq_change_queue_tempo(seq_handle, dest_queue, us, &ev); } static void do_noteon(int chan, int pitch, int vol) @@ -310,10 +256,8 @@ static void do_noteon(int chan, int pitch, int vol) if (verbose >= VERB_EVENT) printf("NoteOn (%d) %d %d\n", chan, pitch, vol); - set_event_header(&ev, SND_SEQ_EVENT_NOTEON, chan); - ev.data.note.note = pitch; - ev.data.note.velocity = vol; - + set_event_header(&ev); + snd_seq_ev_set_noteon(&ev, chan, pitch, vol); write_ev(&ev); } @@ -324,10 +268,8 @@ static void do_noteoff(int chan, int pitch, int vol) if (verbose >= VERB_EVENT) printf("NoteOff (%d) %d %d\n", chan, pitch, vol); - set_event_header(&ev, SND_SEQ_EVENT_NOTEOFF, chan); - ev.data.note.note = pitch; - ev.data.note.velocity = vol; - + set_event_header(&ev); + snd_seq_ev_set_noteoff(&ev, chan, pitch, vol); write_ev(&ev); } @@ -338,9 +280,8 @@ static void do_program(int chan, int program) if (verbose >= VERB_EVENT) printf("Program (%d) %d\n", chan, program); - set_event_header(&ev, SND_SEQ_EVENT_PGMCHANGE, chan); - ev.data.control.value = program; - + set_event_header(&ev); + snd_seq_ev_set_pgmchange(&ev, chan, program); write_ev(&ev); } @@ -351,10 +292,8 @@ static void do_parameter(int chan, int control, int value) if (verbose >= VERB_EVENT) printf("Control (%d) %d %d\n", chan, control, value); - set_event_header(&ev, SND_SEQ_EVENT_CONTROLLER, chan); - ev.data.control.param = control; - ev.data.control.value = value; - + set_event_header(&ev); + snd_seq_ev_set_controller(&ev, chan, control, value); write_ev(&ev); } @@ -365,9 +304,8 @@ static void do_pitchbend(int chan, int lsb, int msb) if (verbose >= VERB_EVENT) printf("Pitchbend (%d) %d %d\n", chan, lsb, msb); - set_event_header(&ev, SND_SEQ_EVENT_PITCHBEND, chan); - ev.data.control.value = (lsb + (msb << 7)) - 8192; - + set_event_header(&ev); + snd_seq_ev_set_pitchbend(&ev, chan, (lsb + (msb << 7)) - 8192); write_ev(&ev); } @@ -377,10 +315,8 @@ static void do_pressure(int chan, int pitch, int pressure) if (verbose >= VERB_EVENT) printf("KeyPress (%d) %d %d\n", chan, pitch, pressure); - set_event_header(&ev, SND_SEQ_EVENT_KEYPRESS, chan); - ev.data.control.param = pitch; - ev.data.control.value = pressure; - + set_event_header(&ev); + snd_seq_ev_set_keypress(&ev, chan, pitch, pressure); write_ev(&ev); } @@ -390,9 +326,8 @@ static void do_chanpressure(int chan, int pressure) if (verbose >= VERB_EVENT) printf("ChanPress (%d) %d\n", chan, pressure); - set_event_header(&ev, SND_SEQ_EVENT_CHANPRESS, chan); - ev.data.control.value = pressure; - + set_event_header(&ev); + snd_seq_ev_set_chanpress(&ev, chan, pressure); write_ev(&ev); } @@ -412,8 +347,9 @@ static void do_sysex(int len, char *msg) putchar('\n'); } - set_event_header(&ev, SND_SEQ_EVENT_SYSEX, 0); - write_ev_var(&ev, len, msg); + set_event_header(&ev); + snd_seq_ev_set_sysex(&ev, len, msg); + write_ev(&ev); } static snd_seq_event_t *wait_for_event(void) @@ -458,19 +394,11 @@ static void alsa_sync(void) if (verbose >= VERB_MUCH) printf("alsa_sync syncing... send ECHO(%d) event to myself. time=%f\n", SND_SEQ_EVENT_ECHO, (double) Mf_currtime+1); - ev.source.port = source_port; - ev.dest.queue = dest_queue; - ev.dest.client = snd_seq_client_id(seq_handle); - ev.dest.port = source_port; - ev.dest.channel = 0; /* don't care */ - -#ifdef USE_REALTIME - ev.flags = SND_SEQ_TIME_STAMP_REAL | SND_SEQ_TIME_MODE_ABS; - tick2time(&ev.time.real, Mf_currtime+1); -#else - ev.flags = SND_SEQ_TIME_STAMP_TICK | SND_SEQ_TIME_MODE_ABS; - ev.time.tick = Mf_currtime+1; -#endif + snd_seq_ev_clear(&ev); + /* redirect to itself */ + snd_seq_ev_set_dest(&ev, snd_seq_client_id(seq_handle), my_port); + snd_seq_ev_set_source(&ev, my_port); + set_event_time(&ev, Mf_currtime+1); ev.type = SND_SEQ_EVENT_ECHO; write_ev(&ev); @@ -484,8 +412,11 @@ static void alsa_sync(void) if (verbose >= VERB_MUCH) printf("alsa_sync got event. type=%d, flags=%d\n", input_event->type, input_event->flags); - if (input_event->type == SND_SEQ_EVENT_ECHO) + if (input_event->type == SND_SEQ_EVENT_ECHO && + input_event->source.client == snd_seq_client_id(seq_handle)) { + snd_seq_free_event(input_event); break; + } snd_seq_free_event(input_event); } } @@ -507,8 +438,10 @@ static void wait_start(void) printf("wait_start got event. type=%d, flags=%d\n", input_event->type, input_event->flags); if (input_event->type == SND_SEQ_EVENT_START && - input_event->data.addr.queue == dest_queue) + input_event->data.addr.queue == dest_queue) { + snd_seq_free_event(input_event); break; + } snd_seq_free_event(input_event); } } @@ -540,10 +473,6 @@ void parse_address(char *arg, int *clientp, int *portp) int main(int argc, char *argv[]) { - snd_seq_client_info_t inf; - snd_seq_port_info_t src_port_info; - snd_seq_port_subscribe_t subscribe; - snd_seq_client_pool_t pool; int tmp; int c; @@ -594,31 +523,20 @@ int main(int argc, char *argv[]) /* set name */ /* set event filter to recieve only echo event */ /* if running in slave mode also listen for START event */ - memset(&inf, 0, sizeof(snd_seq_client_info_t)); - inf.filter |= SND_SEQ_FILTER_USE_EVENT; - memset(&inf.event_filter, 0, sizeof(inf.event_filter)); - snd_seq_set_bit(SND_SEQ_EVENT_ECHO, inf.event_filter); + snd_seq_set_client_event_filter(seq_handle, SND_SEQ_EVENT_ECHO); if (slave) - snd_seq_set_bit(SND_SEQ_EVENT_START, inf.event_filter); - strcpy(inf.name, "MIDI file player"); - if (snd_seq_set_client_info(seq_handle, &inf) < 0) { - perror("ioctl"); - exit(1); - } + snd_seq_set_client_event_filter(seq_handle, SND_SEQ_EVENT_ECHO); + snd_seq_set_client_name(seq_handle, "MIDI file player"); /* create port */ - memset(&src_port_info, 0, sizeof(snd_seq_port_info_t)); - src_port_info.capability = SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_READ; - src_port_info.type = SND_SEQ_PORT_TYPE_MIDI_GENERIC; - src_port_info.midi_channels = 16; - src_port_info.synth_voices = 0; - src_port_info.kernel = NULL; - tmp = snd_seq_create_port(seq_handle, &src_port_info); - if (tmp < 0) { + 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) { perror("creat port"); exit(1); } - source_port = src_port_info.port; /* setup queue */ dest_queue = snd_seq_alloc_queue(seq_handle); @@ -628,19 +546,7 @@ int main(int argc, char *argv[]) } /* setup subscriber */ - bzero(&subscribe,sizeof(subscribe)); - if (verbose >= VERB_INFO) - printf("debug subscribe src_port_info.client=%d\n", - src_port_info.client); - subscribe.sender.client = snd_seq_client_id(seq_handle); - subscribe.sender.queue = dest_queue; - subscribe.sender.port = src_port_info.port; - subscribe.dest.client = dest_client; - subscribe.dest.port = dest_port; - subscribe.dest.queue = dest_queue; - subscribe.realtime = 1; - subscribe.exclusive = 0; - tmp = snd_seq_subscribe_port(seq_handle, &subscribe); + tmp = snd_seq_connect_to(seq_handle, my_port, dest_client, dest_port); if (tmp < 0) { perror("subscribe"); exit(1); @@ -648,15 +554,9 @@ int main(int argc, char *argv[]) /* subscribe for timer START event */ if (slave) { - subscribe.sender.client = SND_SEQ_CLIENT_SYSTEM; - subscribe.sender.queue = dest_queue; - subscribe.sender.port = SND_SEQ_PORT_SYSTEM_TIMER; - subscribe.dest.client = snd_seq_client_id(seq_handle); - subscribe.dest.port = src_port_info.port; - subscribe.dest.queue = dest_queue; - subscribe.realtime = 0; - subscribe.exclusive = 0; - tmp = snd_seq_subscribe_port(seq_handle, &subscribe); + tmp = snd_seq_connect_from(seq_handle, my_port, + SND_SEQ_CLIENT_SYSTEM, + SND_SEQ_PORT_SYSTEM_TIMER); if (tmp < 0) { perror("subscribe"); exit(1); @@ -664,12 +564,9 @@ int main(int argc, char *argv[]) } /* change pool size */ - bzero(&pool,sizeof(pool)); - pool.output_pool = WRITE_POOL_SIZE; - pool.input_pool = READ_POOL_SIZE; - pool.output_room = WRITE_POOL_SPACE; - tmp = snd_seq_set_client_pool(seq_handle, &pool); - if (tmp < 0) { + 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) { perror("pool"); exit(1); } -- 2.47.1