mirror of
https://github.com/alsa-project/alsa-lib.git
synced 2025-10-29 05:40:25 -04:00
Takashi Iwai <iwai@ww.uni-erlangen.de>
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.
This commit is contained in:
parent
2fad3ef64b
commit
682deca370
9 changed files with 686 additions and 239 deletions
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
192
include/seqmid.h
Normal file
192
include/seqmid.h
Normal file
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#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;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
45
src/seq/seq_priv.h
Normal file
45
src/seq/seq_priv.h
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* Sequencer Interface - definition of sequencer event handler
|
||||
* Copyright (c) 1998 by Jaroslav Kysela <perex@suse.cz>
|
||||
*
|
||||
*
|
||||
* 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
|
||||
319
src/seq/seqmid.c
Normal file
319
src/seq/seqmid.c
Normal file
|
|
@ -0,0 +1,319 @@
|
|||
/*
|
||||
* Sequencer Interface - middle-level routines
|
||||
*
|
||||
* Copyright (c) 1999 by Takashi Iwai <iwai@ww.uni-erlangen.de>
|
||||
*
|
||||
*
|
||||
* 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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#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);
|
||||
}
|
||||
|
||||
|
|
@ -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");
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
103
test/aseqnet.c
103
test/aseqnet.c
|
|
@ -23,14 +23,17 @@
|
|||
#include <netdb.h>
|
||||
#include <sys/asoundlib.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
|
|
|
|||
237
test/playmidi1.c
237
test/playmidi1.c
|
|
@ -15,6 +15,9 @@
|
|||
* 19990827 Takashi Iwai <iwai@ww.uni-erlangen.de>
|
||||
* - use snd_seq_alloc_queue()
|
||||
*
|
||||
* 19990916 Takashi Iwai <iwai@ww.uni-erlangen.de>
|
||||
* - 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);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue