mirror of
https://github.com/alsa-project/alsa-lib.git
synced 2025-11-01 22:58:49 -04:00
seq: Add UMP support
This patch adds the basic support of UMP on ALSA sequencer API. An extended event type, snd_seq_ump_event_t, is defined. It's compatible with the existing type, snd_seq_event_t, but it has a larger payload of 16 bytes instead of 12 bytes, for holding the full 128bit UMP packet. The new snd_seq_ump_event_t must have the bit SND_SEQ_EVENT_UMP in the event flags. A few new API functions have been added such as snd_seq_ump_event_output() and snd_seq_ump_event_input() for reading/writing this new event object. The support of UMP in the sequencer client is switched by the function snd_seq_client_set_midi_version(). It can switch from the default legacy MIDI to UMP MIDI 1.0 or 2.0 on the fly. The automatic event conversion among UMP and legacy clients can be suppressed via snd_seq_client_set_ump_conversion(). The inquiry of the associated UMP Endpoints and UMP Blocks can be done via snd_seq_get_ump_endpoint_info() and snd_seq_get_ump_block_info(). Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
parent
c40dc19a57
commit
2aefb5c41c
9 changed files with 604 additions and 51 deletions
|
|
@ -196,7 +196,9 @@
|
||||||
#define snd_seq_real_time sndrv_seq_real_time
|
#define snd_seq_real_time sndrv_seq_real_time
|
||||||
#define snd_seq_timestamp sndrv_seq_timestamp
|
#define snd_seq_timestamp sndrv_seq_timestamp
|
||||||
#define snd_seq_event_type_t sndrv_seq_event_type_t
|
#define snd_seq_event_type_t sndrv_seq_event_type_t
|
||||||
|
#define snd_seq_event_data sndrv_seq_event_data
|
||||||
#define snd_seq_event sndrv_seq_event
|
#define snd_seq_event sndrv_seq_event
|
||||||
|
#define snd_seq_ump_event sndrv_seq_ump_event
|
||||||
#define snd_seq_connect sndrv_seq_connect
|
#define snd_seq_connect sndrv_seq_connect
|
||||||
#define snd_seq_ev_note sndrv_seq_ev_note
|
#define snd_seq_ev_note sndrv_seq_ev_note
|
||||||
#define snd_seq_ev_ctrl sndrv_seq_ev_ctrl
|
#define snd_seq_ev_ctrl sndrv_seq_ev_ctrl
|
||||||
|
|
|
||||||
|
|
@ -130,6 +130,13 @@ typedef enum snd_seq_client_type {
|
||||||
SND_SEQ_KERNEL_CLIENT = 2 /**< kernel client */
|
SND_SEQ_KERNEL_CLIENT = 2 /**< kernel client */
|
||||||
} snd_seq_client_type_t;
|
} snd_seq_client_type_t;
|
||||||
|
|
||||||
|
/** client MIDI version */
|
||||||
|
enum {
|
||||||
|
SND_SEQ_CLIENT_LEGACY_MIDI = 0, /**< Legacy client */
|
||||||
|
SND_SEQ_CLIENT_UMP_MIDI_1_0 = 1, /**< UMP MIDI 1.0 */
|
||||||
|
SND_SEQ_CLIENT_UMP_MIDI_2_0 = 2 /**< UMP MIDI 2.0 */
|
||||||
|
};
|
||||||
|
|
||||||
size_t snd_seq_client_info_sizeof(void);
|
size_t snd_seq_client_info_sizeof(void);
|
||||||
/** allocate a #snd_seq_client_info_t container on stack */
|
/** allocate a #snd_seq_client_info_t container on stack */
|
||||||
#define snd_seq_client_info_alloca(ptr) \
|
#define snd_seq_client_info_alloca(ptr) \
|
||||||
|
|
@ -149,11 +156,19 @@ const unsigned char *snd_seq_client_info_get_event_filter(const snd_seq_client_i
|
||||||
int snd_seq_client_info_get_num_ports(const snd_seq_client_info_t *info);
|
int snd_seq_client_info_get_num_ports(const snd_seq_client_info_t *info);
|
||||||
int snd_seq_client_info_get_event_lost(const snd_seq_client_info_t *info);
|
int snd_seq_client_info_get_event_lost(const snd_seq_client_info_t *info);
|
||||||
|
|
||||||
|
int snd_seq_client_info_get_midi_version(const snd_seq_client_info_t *info);
|
||||||
|
int snd_seq_client_info_get_ump_group_enabled(const snd_seq_client_info_t *info,
|
||||||
|
int group);
|
||||||
|
int snd_seq_client_info_get_ump_conversion(const snd_seq_client_info_t *info);
|
||||||
void snd_seq_client_info_set_client(snd_seq_client_info_t *info, int client);
|
void snd_seq_client_info_set_client(snd_seq_client_info_t *info, int client);
|
||||||
void snd_seq_client_info_set_name(snd_seq_client_info_t *info, const char *name);
|
void snd_seq_client_info_set_name(snd_seq_client_info_t *info, const char *name);
|
||||||
void snd_seq_client_info_set_broadcast_filter(snd_seq_client_info_t *info, int val);
|
void snd_seq_client_info_set_broadcast_filter(snd_seq_client_info_t *info, int val);
|
||||||
void snd_seq_client_info_set_error_bounce(snd_seq_client_info_t *info, int val);
|
void snd_seq_client_info_set_error_bounce(snd_seq_client_info_t *info, int val);
|
||||||
void snd_seq_client_info_set_event_filter(snd_seq_client_info_t *info, unsigned char *filter);
|
void snd_seq_client_info_set_event_filter(snd_seq_client_info_t *info, unsigned char *filter);
|
||||||
|
void snd_seq_client_info_set_midi_version(snd_seq_client_info_t *info, int midi_version);
|
||||||
|
void snd_seq_client_info_set_ump_group_enabled(snd_seq_client_info_t *info,
|
||||||
|
int group, int enable);
|
||||||
|
void snd_seq_client_info_set_ump_conversion(snd_seq_client_info_t *info, int enable);
|
||||||
|
|
||||||
void snd_seq_client_info_event_filter_clear(snd_seq_client_info_t *info);
|
void snd_seq_client_info_event_filter_clear(snd_seq_client_info_t *info);
|
||||||
void snd_seq_client_info_event_filter_add(snd_seq_client_info_t *info, int event_type);
|
void snd_seq_client_info_event_filter_add(snd_seq_client_info_t *info, int event_type);
|
||||||
|
|
@ -165,6 +180,11 @@ int snd_seq_get_any_client_info(snd_seq_t *handle, int client, snd_seq_client_in
|
||||||
int snd_seq_set_client_info(snd_seq_t *handle, snd_seq_client_info_t *info);
|
int snd_seq_set_client_info(snd_seq_t *handle, snd_seq_client_info_t *info);
|
||||||
int snd_seq_query_next_client(snd_seq_t *handle, snd_seq_client_info_t *info);
|
int snd_seq_query_next_client(snd_seq_t *handle, snd_seq_client_info_t *info);
|
||||||
|
|
||||||
|
int snd_seq_get_ump_endpoint_info(snd_seq_t *seq, int client, void *info);
|
||||||
|
int snd_seq_get_ump_block_info(snd_seq_t *seq, int client, int blk, void *info);
|
||||||
|
int snd_seq_set_ump_endpoint_info(snd_seq_t *seq, const void *info);
|
||||||
|
int snd_seq_set_ump_block_info(snd_seq_t *seq, int blk, const void *info);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
@ -222,6 +242,14 @@ typedef struct _snd_seq_port_info snd_seq_port_info_t;
|
||||||
#define SND_SEQ_PORT_CAP_SUBS_READ (1<<5) /**< allow read subscription */
|
#define SND_SEQ_PORT_CAP_SUBS_READ (1<<5) /**< allow read subscription */
|
||||||
#define SND_SEQ_PORT_CAP_SUBS_WRITE (1<<6) /**< allow write subscription */
|
#define SND_SEQ_PORT_CAP_SUBS_WRITE (1<<6) /**< allow write subscription */
|
||||||
#define SND_SEQ_PORT_CAP_NO_EXPORT (1<<7) /**< routing not allowed */
|
#define SND_SEQ_PORT_CAP_NO_EXPORT (1<<7) /**< routing not allowed */
|
||||||
|
#define SND_SEQ_PORT_CAP_INACTIVE (1<<8) /**< inactive port */
|
||||||
|
#define SND_SEQ_PORT_CAP_UMP_ENDPOINT (1<<9) /**< UMP Endpoint port */
|
||||||
|
|
||||||
|
/** port direction */
|
||||||
|
#define SND_SEQ_PORT_DIR_UNKNOWN 0 /**< Unknown */
|
||||||
|
#define SND_SEQ_PORT_DIR_INPUT 1 /**< Input only */
|
||||||
|
#define SND_SEQ_PORT_DIR_OUTPUT 2 /**< Output only */
|
||||||
|
#define SND_SEQ_PORT_DIR_BIDIRECTION 3 /**< Input/output bidirectional */
|
||||||
|
|
||||||
/* port type */
|
/* port type */
|
||||||
/** Messages sent from/to this port have device-specific semantics. */
|
/** Messages sent from/to this port have device-specific semantics. */
|
||||||
|
|
@ -238,6 +266,8 @@ typedef struct _snd_seq_port_info snd_seq_port_info_t;
|
||||||
#define SND_SEQ_PORT_TYPE_MIDI_MT32 (1<<5)
|
#define SND_SEQ_PORT_TYPE_MIDI_MT32 (1<<5)
|
||||||
/** This port is compatible with the General MIDI 2 specification. */
|
/** This port is compatible with the General MIDI 2 specification. */
|
||||||
#define SND_SEQ_PORT_TYPE_MIDI_GM2 (1<<6)
|
#define SND_SEQ_PORT_TYPE_MIDI_GM2 (1<<6)
|
||||||
|
/** This port is a UMP port. */
|
||||||
|
#define SND_SEQ_PORT_TYPE_MIDI_UMP (1<<7)
|
||||||
/** This port understands SND_SEQ_EVENT_SAMPLE_xxx messages
|
/** This port understands SND_SEQ_EVENT_SAMPLE_xxx messages
|
||||||
(these are not MIDI messages). */
|
(these are not MIDI messages). */
|
||||||
#define SND_SEQ_PORT_TYPE_SYNTH (1<<10)
|
#define SND_SEQ_PORT_TYPE_SYNTH (1<<10)
|
||||||
|
|
@ -283,6 +313,8 @@ int snd_seq_port_info_get_port_specified(const snd_seq_port_info_t *info);
|
||||||
int snd_seq_port_info_get_timestamping(const snd_seq_port_info_t *info);
|
int snd_seq_port_info_get_timestamping(const snd_seq_port_info_t *info);
|
||||||
int snd_seq_port_info_get_timestamp_real(const snd_seq_port_info_t *info);
|
int snd_seq_port_info_get_timestamp_real(const snd_seq_port_info_t *info);
|
||||||
int snd_seq_port_info_get_timestamp_queue(const snd_seq_port_info_t *info);
|
int snd_seq_port_info_get_timestamp_queue(const snd_seq_port_info_t *info);
|
||||||
|
int snd_seq_port_info_get_direction(const snd_seq_port_info_t *info);
|
||||||
|
int snd_seq_port_info_get_ump_group(const snd_seq_port_info_t *info);
|
||||||
|
|
||||||
void snd_seq_port_info_set_client(snd_seq_port_info_t *info, int client);
|
void snd_seq_port_info_set_client(snd_seq_port_info_t *info, int client);
|
||||||
void snd_seq_port_info_set_port(snd_seq_port_info_t *info, int port);
|
void snd_seq_port_info_set_port(snd_seq_port_info_t *info, int port);
|
||||||
|
|
@ -297,6 +329,8 @@ void snd_seq_port_info_set_port_specified(snd_seq_port_info_t *info, int val);
|
||||||
void snd_seq_port_info_set_timestamping(snd_seq_port_info_t *info, int enable);
|
void snd_seq_port_info_set_timestamping(snd_seq_port_info_t *info, int enable);
|
||||||
void snd_seq_port_info_set_timestamp_real(snd_seq_port_info_t *info, int realtime);
|
void snd_seq_port_info_set_timestamp_real(snd_seq_port_info_t *info, int realtime);
|
||||||
void snd_seq_port_info_set_timestamp_queue(snd_seq_port_info_t *info, int queue);
|
void snd_seq_port_info_set_timestamp_queue(snd_seq_port_info_t *info, int queue);
|
||||||
|
void snd_seq_port_info_set_direction(snd_seq_port_info_t *info, int direction);
|
||||||
|
void snd_seq_port_info_set_ump_gruop(snd_seq_port_info_t *info, int ump_group);
|
||||||
|
|
||||||
int snd_seq_create_port(snd_seq_t *handle, snd_seq_port_info_t *info);
|
int snd_seq_create_port(snd_seq_t *handle, snd_seq_port_info_t *info);
|
||||||
int snd_seq_delete_port(snd_seq_t *handle, int port);
|
int snd_seq_delete_port(snd_seq_t *handle, int port);
|
||||||
|
|
@ -572,6 +606,12 @@ void snd_seq_remove_events_set_tag(snd_seq_remove_events_t *info, int tag);
|
||||||
|
|
||||||
int snd_seq_remove_events(snd_seq_t *handle, snd_seq_remove_events_t *info);
|
int snd_seq_remove_events(snd_seq_t *handle, snd_seq_remove_events_t *info);
|
||||||
|
|
||||||
|
int snd_seq_ump_event_output(snd_seq_t *seq, snd_seq_ump_event_t *ev);
|
||||||
|
int snd_seq_ump_event_output_buffer(snd_seq_t *seq, snd_seq_ump_event_t *ev);
|
||||||
|
int snd_seq_ump_extract_output(snd_seq_t *seq, snd_seq_ump_event_t **ev_res);
|
||||||
|
int snd_seq_ump_event_output_direct(snd_seq_t *seq, snd_seq_ump_event_t *ev);
|
||||||
|
int snd_seq_ump_event_input(snd_seq_t *seq, snd_seq_ump_event_t **ev);
|
||||||
|
|
||||||
/** \} */
|
/** \} */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -729,6 +769,10 @@ extern const unsigned int snd_seq_event_types[];
|
||||||
#define snd_seq_ev_is_direct(ev) \
|
#define snd_seq_ev_is_direct(ev) \
|
||||||
((ev)->queue == SND_SEQ_QUEUE_DIRECT)
|
((ev)->queue == SND_SEQ_QUEUE_DIRECT)
|
||||||
|
|
||||||
|
/** UMP events */
|
||||||
|
#define snd_seq_ev_is_ump(ev) \
|
||||||
|
((ev)->flags & SND_SEQ_EVENT_UMP)
|
||||||
|
|
||||||
/** \} */
|
/** \} */
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|
|
||||||
|
|
@ -225,6 +225,7 @@ typedef union snd_seq_timestamp {
|
||||||
#define SND_SEQ_PRIORITY_HIGH (1<<4) /**< event should be processed before others */
|
#define SND_SEQ_PRIORITY_HIGH (1<<4) /**< event should be processed before others */
|
||||||
#define SND_SEQ_PRIORITY_MASK (1<<4) /**< mask for priority bits */
|
#define SND_SEQ_PRIORITY_MASK (1<<4) /**< mask for priority bits */
|
||||||
|
|
||||||
|
#define SND_SEQ_EVENT_UMP (1<<5) /**< UMP packet event */
|
||||||
|
|
||||||
/** Note event */
|
/** Note event */
|
||||||
typedef struct snd_seq_ev_note {
|
typedef struct snd_seq_ev_note {
|
||||||
|
|
@ -291,6 +292,19 @@ typedef struct snd_seq_ev_queue_control {
|
||||||
} param; /**< data value union */
|
} param; /**< data value union */
|
||||||
} snd_seq_ev_queue_control_t;
|
} snd_seq_ev_queue_control_t;
|
||||||
|
|
||||||
|
/** Sequencer event data */
|
||||||
|
typedef union snd_seq_event_data {
|
||||||
|
snd_seq_ev_note_t note; /**< note information */
|
||||||
|
snd_seq_ev_ctrl_t control; /**< MIDI control information */
|
||||||
|
snd_seq_ev_raw8_t raw8; /**< raw8 data */
|
||||||
|
snd_seq_ev_raw32_t raw32; /**< raw32 data */
|
||||||
|
snd_seq_ev_ext_t ext; /**< external data */
|
||||||
|
snd_seq_ev_queue_control_t queue; /**< queue control */
|
||||||
|
snd_seq_timestamp_t time; /**< timestamp */
|
||||||
|
snd_seq_addr_t addr; /**< address */
|
||||||
|
snd_seq_connect_t connect; /**< connect information */
|
||||||
|
snd_seq_result_t result; /**< operation result code */
|
||||||
|
} snd_seq_event_data_t;
|
||||||
|
|
||||||
/** Sequencer event */
|
/** Sequencer event */
|
||||||
typedef struct snd_seq_event {
|
typedef struct snd_seq_event {
|
||||||
|
|
@ -304,20 +318,24 @@ typedef struct snd_seq_event {
|
||||||
snd_seq_addr_t source; /**< source address */
|
snd_seq_addr_t source; /**< source address */
|
||||||
snd_seq_addr_t dest; /**< destination address */
|
snd_seq_addr_t dest; /**< destination address */
|
||||||
|
|
||||||
union {
|
snd_seq_event_data_t data; /**< event data... */
|
||||||
snd_seq_ev_note_t note; /**< note information */
|
|
||||||
snd_seq_ev_ctrl_t control; /**< MIDI control information */
|
|
||||||
snd_seq_ev_raw8_t raw8; /**< raw8 data */
|
|
||||||
snd_seq_ev_raw32_t raw32; /**< raw32 data */
|
|
||||||
snd_seq_ev_ext_t ext; /**< external data */
|
|
||||||
snd_seq_ev_queue_control_t queue; /**< queue control */
|
|
||||||
snd_seq_timestamp_t time; /**< timestamp */
|
|
||||||
snd_seq_addr_t addr; /**< address */
|
|
||||||
snd_seq_connect_t connect; /**< connect information */
|
|
||||||
snd_seq_result_t result; /**< operation result code */
|
|
||||||
} data; /**< event data... */
|
|
||||||
} snd_seq_event_t;
|
} snd_seq_event_t;
|
||||||
|
|
||||||
|
/** UMP sequencer event; compatible with legacy sequencer event */
|
||||||
|
typedef struct snd_seq_ump_event {
|
||||||
|
snd_seq_event_type_t type; /**< event type */
|
||||||
|
unsigned char flags; /**< event flags */
|
||||||
|
unsigned char tag; /**< tag */
|
||||||
|
unsigned char queue; /**< schedule queue */
|
||||||
|
snd_seq_timestamp_t time; /**< schedule time */
|
||||||
|
snd_seq_addr_t source; /**< source address */
|
||||||
|
snd_seq_addr_t dest; /**< destination address */
|
||||||
|
|
||||||
|
union {
|
||||||
|
snd_seq_event_data_t data; /**< (shared) legacy data */
|
||||||
|
unsigned int ump[4]; /**< UMP data bytes */
|
||||||
|
};
|
||||||
|
} snd_seq_ump_event_t;
|
||||||
|
|
||||||
/** \} */
|
/** \} */
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -284,6 +284,28 @@ extern "C" {
|
||||||
(ev)->data.queue.queue = (q),\
|
(ev)->data.queue.queue = (q),\
|
||||||
(ev)->data.queue.param.time.tick = (ttime))
|
(ev)->data.queue.param.time.tick = (ttime))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief set the event UMP flag
|
||||||
|
* \param ev event record
|
||||||
|
*/
|
||||||
|
static inline void snd_seq_ev_set_ump(snd_seq_ump_event_t *ev)
|
||||||
|
{
|
||||||
|
ev->flags |= SND_SEQ_EVENT_UMP;
|
||||||
|
ev->type = 0; /* unused for UMP */
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief set the event UMP flag and fill UMP raw bytes
|
||||||
|
* \param ev event record
|
||||||
|
* \param data UMP packet data
|
||||||
|
* \param bytes UMP packet size in bytes
|
||||||
|
*/
|
||||||
|
static inline void snd_seq_ev_set_ump_data(snd_seq_ump_event_t *ev, void *data, size_t bytes)
|
||||||
|
{
|
||||||
|
snd_seq_ev_set_ump(ev);
|
||||||
|
memcpy(ev->ump, data, bytes);
|
||||||
|
}
|
||||||
|
|
||||||
/* set and send a queue control event */
|
/* set and send a queue control event */
|
||||||
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);
|
||||||
|
|
||||||
|
|
@ -343,6 +365,8 @@ int snd_seq_disconnect_to(snd_seq_t *seq, int my_port, int dest_client, int dest
|
||||||
*/
|
*/
|
||||||
int snd_seq_set_client_name(snd_seq_t *seq, const char *name);
|
int snd_seq_set_client_name(snd_seq_t *seq, const char *name);
|
||||||
int snd_seq_set_client_event_filter(snd_seq_t *seq, int event_type);
|
int snd_seq_set_client_event_filter(snd_seq_t *seq, int event_type);
|
||||||
|
int snd_seq_set_client_midi_version(snd_seq_t *seq, int midi_version);
|
||||||
|
int snd_seq_set_client_ump_conversion(snd_seq_t *seq, int enable);
|
||||||
int snd_seq_set_client_pool_output(snd_seq_t *seq, size_t size);
|
int snd_seq_set_client_pool_output(snd_seq_t *seq, size_t size);
|
||||||
int snd_seq_set_client_pool_output_room(snd_seq_t *seq, size_t size);
|
int snd_seq_set_client_pool_output_room(snd_seq_t *seq, size_t size);
|
||||||
int snd_seq_set_client_pool_input(snd_seq_t *seq, size_t size);
|
int snd_seq_set_client_pool_input(snd_seq_t *seq, size_t size);
|
||||||
|
|
|
||||||
|
|
@ -156,4 +156,21 @@ ALSA_1.2.10 {
|
||||||
@SYMBOL_PREFIX@snd_ctl_ump_next_device;
|
@SYMBOL_PREFIX@snd_ctl_ump_next_device;
|
||||||
@SYMBOL_PREFIX@snd_ctl_ump_endpoint_info;
|
@SYMBOL_PREFIX@snd_ctl_ump_endpoint_info;
|
||||||
@SYMBOL_PREFIX@snd_ctl_ump_block_info;
|
@SYMBOL_PREFIX@snd_ctl_ump_block_info;
|
||||||
|
@SYMBOL_PREFIX@snd_seq_ump_*;
|
||||||
|
@SYMBOL_PREFIX@snd_seq_client_info_get_midi_version;
|
||||||
|
@SYMBOL_PREFIX@snd_seq_seq_client_info_get_ump_group_enabled;
|
||||||
|
@SYMBOL_PREFIX@snd_seq_seq_client_get_ump_conversion;
|
||||||
|
@SYMBOL_PREFIX@snd_seq_client_info_set_midi_version;
|
||||||
|
@SYMBOL_PREFIX@snd_seq_seq_client_info_set_ump_group_enabled;
|
||||||
|
@SYMBOL_PREFIX@snd_seq_seq_client_set_ump_conversion;
|
||||||
|
@SYMBOL_PREFIX@snd_seq_get_ump_endpoint_info;
|
||||||
|
@SYMBOL_PREFIX@snd_seq_get_ump_block_info;
|
||||||
|
@SYMBOL_PREFIX@snd_seq_set_ump_endpoint_info;
|
||||||
|
@SYMBOL_PREFIX@snd_seq_set_ump_block_info;
|
||||||
|
@SYMBOL_PREFIX@snd_seq_port_info_get_direction;
|
||||||
|
@SYMBOL_PREFIX@snd_seq_port_info_get_ump_group;
|
||||||
|
@SYMBOL_PREFIX@snd_seq_port_info_set_direction;
|
||||||
|
@SYMBOL_PREFIX@snd_seq_port_info_set_ump_group;
|
||||||
|
@SYMBOL_PREFIX@snd_seq_set_client_midi_version;
|
||||||
|
@SYMBOL_PREFIX@snd_seq_set_client_ump_conversion;
|
||||||
} ALSA_1.2.9;
|
} ALSA_1.2.9;
|
||||||
|
|
|
||||||
410
src/seq/seq.c
410
src/seq/seq.c
|
|
@ -1204,6 +1204,11 @@ size_t snd_seq_get_output_buffer_size(snd_seq_t *seq)
|
||||||
return seq->obufsize;
|
return seq->obufsize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline size_t get_packet_size(snd_seq_t *seq)
|
||||||
|
{
|
||||||
|
return seq->packet_size ? seq->packet_size : sizeof(snd_seq_event_t);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Return the size of input buffer
|
* \brief Return the size of input buffer
|
||||||
* \param seq sequencer handle
|
* \param seq sequencer handle
|
||||||
|
|
@ -1219,7 +1224,7 @@ size_t snd_seq_get_input_buffer_size(snd_seq_t *seq)
|
||||||
assert(seq);
|
assert(seq);
|
||||||
if (!seq->ibuf)
|
if (!seq->ibuf)
|
||||||
return 0;
|
return 0;
|
||||||
return seq->ibufsize * sizeof(snd_seq_event_t);
|
return seq->ibufsize * get_packet_size(seq);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -1261,13 +1266,17 @@ int snd_seq_set_output_buffer_size(snd_seq_t *seq, size_t size)
|
||||||
*/
|
*/
|
||||||
int snd_seq_set_input_buffer_size(snd_seq_t *seq, size_t size)
|
int snd_seq_set_input_buffer_size(snd_seq_t *seq, size_t size)
|
||||||
{
|
{
|
||||||
|
size_t packet_size;
|
||||||
|
|
||||||
assert(seq && seq->ibuf);
|
assert(seq && seq->ibuf);
|
||||||
assert(size >= sizeof(snd_seq_event_t));
|
assert(size >= packet_size);
|
||||||
snd_seq_drop_input(seq);
|
snd_seq_drop_input(seq);
|
||||||
size = (size + sizeof(snd_seq_event_t) - 1) / sizeof(snd_seq_event_t);
|
packet_size = get_packet_size(seq);
|
||||||
|
size = (size + packet_size - 1) / packet_size;
|
||||||
if (size != seq->ibufsize) {
|
if (size != seq->ibufsize) {
|
||||||
snd_seq_event_t *newbuf;
|
char *newbuf;
|
||||||
newbuf = calloc(sizeof(snd_seq_event_t), size);
|
/* use ump event size for avoiding reallocation at switching */
|
||||||
|
newbuf = calloc(sizeof(snd_seq_ump_event_t), size);
|
||||||
if (newbuf == NULL)
|
if (newbuf == NULL)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
free(seq->ibuf);
|
free(seq->ibuf);
|
||||||
|
|
@ -1726,6 +1735,47 @@ int snd_seq_client_info_get_event_lost(const snd_seq_client_info_t *info)
|
||||||
return info->event_lost;
|
return info->event_lost;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Get the MIDI protocol version number of a client_info container
|
||||||
|
* \param info client_info container
|
||||||
|
* \return MIDI protocol version
|
||||||
|
*
|
||||||
|
* \sa snd_seq_get_client_info()
|
||||||
|
*/
|
||||||
|
int snd_seq_client_info_get_midi_version(const snd_seq_client_info_t *info)
|
||||||
|
{
|
||||||
|
assert(info);
|
||||||
|
return info->midi_version;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Get the UMP group filter status
|
||||||
|
* \param info client_info container
|
||||||
|
* \param group 0-based group index
|
||||||
|
* \return 0 if the group is filtered / disabled, 1 if it's processed
|
||||||
|
*
|
||||||
|
* \sa snd_seq_get_client_info()
|
||||||
|
*/
|
||||||
|
int snd_seq_client_info_get_ump_group_enabled(const snd_seq_client_info_t *info,
|
||||||
|
int group)
|
||||||
|
{
|
||||||
|
assert(info);
|
||||||
|
return !(info->group_filter & (1U << group));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Get the automatic conversion mode for UMP
|
||||||
|
* \param info client_info container
|
||||||
|
* \return 1 if the conversion is enabled, 0 if not
|
||||||
|
*
|
||||||
|
* \sa snd_seq_get_client_info()
|
||||||
|
*/
|
||||||
|
int snd_seq_client_info_get_ump_conversion(const snd_seq_client_info_t *info)
|
||||||
|
{
|
||||||
|
assert(info);
|
||||||
|
return info->midi_version;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Set the client id of a client_info container
|
* \brief Set the client id of a client_info container
|
||||||
* \param info client_info container
|
* \param info client_info container
|
||||||
|
|
@ -1769,6 +1819,54 @@ void snd_seq_client_info_set_broadcast_filter(snd_seq_client_info_t *info, int v
|
||||||
info->filter &= ~SNDRV_SEQ_FILTER_BROADCAST;
|
info->filter &= ~SNDRV_SEQ_FILTER_BROADCAST;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Set the MIDI protocol version of a client_info container
|
||||||
|
* \param info client_info container
|
||||||
|
* \param midi_version MIDI protocol version to set
|
||||||
|
*
|
||||||
|
* \sa snd_seq_get_client_info(), snd_seq_client_info_get_midi_version()
|
||||||
|
*/
|
||||||
|
void snd_seq_client_info_set_midi_version(snd_seq_client_info_t *info, int midi_version)
|
||||||
|
{
|
||||||
|
assert(info);
|
||||||
|
info->midi_version = midi_version;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Set the UMP group filter status
|
||||||
|
* \param info client_info container
|
||||||
|
* \param group 0-based group index
|
||||||
|
* \param enable 0 to filter/disable the group, non-zero to enable
|
||||||
|
*
|
||||||
|
* \sa snd_seq_set_client_info(), snd_seq_client_info_get_ump_group_enabled()
|
||||||
|
*/
|
||||||
|
void snd_seq_client_info_set_ump_group_enabled(snd_seq_client_info_t *info,
|
||||||
|
int group, int enable)
|
||||||
|
{
|
||||||
|
assert(info);
|
||||||
|
if (enable)
|
||||||
|
info->group_filter &= ~(1U << group);
|
||||||
|
else
|
||||||
|
info->group_filter |= (1U << group);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Set the automatic conversion mode for UMP
|
||||||
|
* \param info client_info container
|
||||||
|
* \param enable 0 or 1 for disabling/enabling the conversion
|
||||||
|
*
|
||||||
|
* \sa snd_seq_set_client_info(), snd_seq_client_info_get_ump_conversion()
|
||||||
|
*/
|
||||||
|
void snd_seq_client_info_set_ump_conversion(snd_seq_client_info_t *info,
|
||||||
|
int enable)
|
||||||
|
{
|
||||||
|
assert(info);
|
||||||
|
if (enable)
|
||||||
|
info->filter &= ~SNDRV_SEQ_FILTER_NO_CONVERT;
|
||||||
|
else
|
||||||
|
info->filter |= SNDRV_SEQ_FILTER_NO_CONVERT;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Set the error-bounce usage of a client_info container
|
* \brief Set the error-bounce usage of a client_info container
|
||||||
* \param info client_info container
|
* \param info client_info container
|
||||||
|
|
@ -1887,6 +1985,65 @@ int snd_seq_query_next_client(snd_seq_t *seq, snd_seq_client_info_t *info)
|
||||||
return seq->ops->query_next_client(seq, info);
|
return seq->ops->query_next_client(seq, info);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Get UMP Endpoint information
|
||||||
|
* \param seq sequencer handle
|
||||||
|
* \param client client number to query
|
||||||
|
* \param info the pointer to store snd_ump_endpoint_info_t data
|
||||||
|
* \return 0 on success otherwise a negative error code
|
||||||
|
*/
|
||||||
|
int snd_seq_get_ump_endpoint_info(snd_seq_t *seq, int client, void *info)
|
||||||
|
{
|
||||||
|
assert(seq && info);
|
||||||
|
return seq->ops->get_ump_info(seq, client,
|
||||||
|
SNDRV_SEQ_CLIENT_UMP_INFO_ENDPOINT,
|
||||||
|
info);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Get UMP Block information
|
||||||
|
* \param seq sequencer handle
|
||||||
|
* \param client sequencer client number to query
|
||||||
|
* \param blk UMP block number (0-based) to query
|
||||||
|
* \param info the pointer to store snd_ump_block_info_t data
|
||||||
|
* \return 0 on success otherwise a negative error code
|
||||||
|
*/
|
||||||
|
int snd_seq_get_ump_block_info(snd_seq_t *seq, int client, int blk, void *info)
|
||||||
|
{
|
||||||
|
assert(seq && info);
|
||||||
|
return seq->ops->get_ump_info(seq, client,
|
||||||
|
SNDRV_SEQ_CLIENT_UMP_INFO_BLOCK + blk,
|
||||||
|
info);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Set UMP Endpoint information to the current client
|
||||||
|
* \param seq sequencer handle
|
||||||
|
* \param info the pointer to send snd_ump_endpoint_info_t data
|
||||||
|
* \return 0 on success otherwise a negative error code
|
||||||
|
*/
|
||||||
|
int snd_seq_set_ump_endpoint_info(snd_seq_t *seq, const void *info)
|
||||||
|
{
|
||||||
|
assert(seq && info);
|
||||||
|
return seq->ops->set_ump_info(seq,
|
||||||
|
SNDRV_SEQ_CLIENT_UMP_INFO_ENDPOINT,
|
||||||
|
info);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Set UMP Block information to the current client
|
||||||
|
* \param seq sequencer handle
|
||||||
|
* \param blk UMP block number (0-based) to send
|
||||||
|
* \param info the pointer to send snd_ump_block_info_t data
|
||||||
|
* \return 0 on success otherwise a negative error code
|
||||||
|
*/
|
||||||
|
int snd_seq_set_ump_block_info(snd_seq_t *seq, int blk, const void *info)
|
||||||
|
{
|
||||||
|
assert(seq && info);
|
||||||
|
return seq->ops->set_ump_info(seq,
|
||||||
|
SNDRV_SEQ_CLIENT_UMP_INFO_BLOCK + blk,
|
||||||
|
info);
|
||||||
|
}
|
||||||
|
|
||||||
/*----------------------------------------------------------------*/
|
/*----------------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
@ -2134,6 +2291,32 @@ int snd_seq_port_info_get_timestamp_queue(const snd_seq_port_info_t *info)
|
||||||
return info->time_queue;
|
return info->time_queue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Get the direction of the port
|
||||||
|
* \param info port_info container
|
||||||
|
* \return the direction of the port
|
||||||
|
*
|
||||||
|
* \sa snd_seq_get_port_info(), snd_seq_port_info_set_direction()
|
||||||
|
*/
|
||||||
|
int snd_seq_port_info_get_direction(const snd_seq_port_info_t *info)
|
||||||
|
{
|
||||||
|
assert(info);
|
||||||
|
return info->direction;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Get the UMP Group assigned to the port
|
||||||
|
* \param info port_info container
|
||||||
|
* \return 0 for no conversion, or the (1-based) UMP Group number assigned to the port
|
||||||
|
*
|
||||||
|
* \sa snd_seq_get_port_info(), snd_seq_port_info_set_ump_group()
|
||||||
|
*/
|
||||||
|
int snd_seq_port_info_get_ump_group(const snd_seq_port_info_t *info)
|
||||||
|
{
|
||||||
|
assert(info);
|
||||||
|
return info->ump_group;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Set the client id of a port_info container
|
* \brief Set the client id of a port_info container
|
||||||
* \param info port_info container
|
* \param info port_info container
|
||||||
|
|
@ -2312,6 +2495,31 @@ void snd_seq_port_info_set_timestamp_queue(snd_seq_port_info_t *info, int queue)
|
||||||
info->time_queue = queue;
|
info->time_queue = queue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Set the direction of the port
|
||||||
|
* \param info port_info container
|
||||||
|
* \param direction the port direction
|
||||||
|
*
|
||||||
|
* \sa snd_seq_get_port_info(), snd_seq_port_info_get_direction()
|
||||||
|
*/
|
||||||
|
void snd_seq_port_info_set_direction(snd_seq_port_info_t *info, int direction)
|
||||||
|
{
|
||||||
|
assert(info);
|
||||||
|
info->direction = direction;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Set the UMP Group assigned to the port
|
||||||
|
* \param info port_info container
|
||||||
|
* \param ump_group 0 for no conversion, or the (1-based) UMP Group number
|
||||||
|
*
|
||||||
|
* \sa snd_seq_get_port_info(), snd_seq_port_info_get_ump_gruop()
|
||||||
|
*/
|
||||||
|
void snd_seq_port_info_set_ump_group(snd_seq_port_info_t *info, int ump_group)
|
||||||
|
{
|
||||||
|
assert(info);
|
||||||
|
info->ump_group = ump_group;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief create a sequencer port on the current client
|
* \brief create a sequencer port on the current client
|
||||||
|
|
@ -3874,7 +4082,9 @@ ssize_t snd_seq_event_length(snd_seq_event_t *ev)
|
||||||
{
|
{
|
||||||
ssize_t len = sizeof(snd_seq_event_t);
|
ssize_t len = sizeof(snd_seq_event_t);
|
||||||
assert(ev);
|
assert(ev);
|
||||||
if (snd_seq_ev_is_variable(ev))
|
if (snd_seq_ev_is_ump(ev))
|
||||||
|
len = sizeof(snd_seq_ump_event_t);
|
||||||
|
else if (snd_seq_ev_is_variable(ev))
|
||||||
len += ev->data.ext.len;
|
len += ev->data.ext.len;
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
@ -3925,7 +4135,10 @@ int snd_seq_event_output(snd_seq_t *seq, snd_seq_event_t *ev)
|
||||||
*
|
*
|
||||||
* This function doesn't drain buffer unlike snd_seq_event_output().
|
* This function doesn't drain buffer unlike snd_seq_event_output().
|
||||||
*
|
*
|
||||||
* \sa snd_seq_event_output()
|
* \note
|
||||||
|
* For a UMP event, use snd_seq_ump_event_output_buffer() instead.
|
||||||
|
*
|
||||||
|
* \sa snd_seq_event_output(), snd_seq_ump_event_output_buffer()
|
||||||
*/
|
*/
|
||||||
int snd_seq_event_output_buffer(snd_seq_t *seq, snd_seq_event_t *ev)
|
int snd_seq_event_output_buffer(snd_seq_t *seq, snd_seq_event_t *ev)
|
||||||
{
|
{
|
||||||
|
|
@ -3938,12 +4151,15 @@ int snd_seq_event_output_buffer(snd_seq_t *seq, snd_seq_event_t *ev)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
if ((seq->obufsize - seq->obufused) < (size_t) len)
|
if ((seq->obufsize - seq->obufused) < (size_t) len)
|
||||||
return -EAGAIN;
|
return -EAGAIN;
|
||||||
memcpy(seq->obuf + seq->obufused, ev, sizeof(snd_seq_event_t));
|
if (snd_seq_ev_is_ump(ev)) {
|
||||||
seq->obufused += sizeof(snd_seq_event_t);
|
memcpy(seq->obuf + seq->obufused, ev, sizeof(snd_seq_ump_event_t));
|
||||||
if (snd_seq_ev_is_variable(ev)) {
|
} else {
|
||||||
memcpy(seq->obuf + seq->obufused, ev->data.ext.ptr, ev->data.ext.len);
|
memcpy(seq->obuf + seq->obufused, ev, sizeof(snd_seq_event_t));
|
||||||
seq->obufused += ev->data.ext.len;
|
if (snd_seq_ev_is_variable(ev))
|
||||||
|
memcpy(seq->obuf + seq->obufused + sizeof(snd_seq_event_t),
|
||||||
|
ev->data.ext.ptr, ev->data.ext.len);
|
||||||
}
|
}
|
||||||
|
seq->obufused += len;
|
||||||
return seq->obufused;
|
return seq->obufused;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3991,7 +4207,7 @@ int snd_seq_event_output_direct(snd_seq_t *seq, snd_seq_event_t *ev)
|
||||||
len = snd_seq_event_length(ev);
|
len = snd_seq_event_length(ev);
|
||||||
if (len < 0)
|
if (len < 0)
|
||||||
return len;
|
return len;
|
||||||
else if (len == sizeof(*ev)) {
|
if (snd_seq_ev_is_ump(ev) || !snd_seq_ev_is_variable(ev)) {
|
||||||
buf = ev;
|
buf = ev;
|
||||||
} else {
|
} else {
|
||||||
if (alloc_tmpbuf(seq, (size_t)len) < 0)
|
if (alloc_tmpbuf(seq, (size_t)len) < 0)
|
||||||
|
|
@ -4049,6 +4265,36 @@ int snd_seq_drain_output(snd_seq_t *seq)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int extract_output(snd_seq_t *seq, snd_seq_event_t **ev_res, int ump_allowed)
|
||||||
|
{
|
||||||
|
size_t len, olen;
|
||||||
|
assert(seq);
|
||||||
|
if (ev_res)
|
||||||
|
*ev_res = NULL;
|
||||||
|
repeat:
|
||||||
|
if ((olen = seq->obufused) < sizeof(snd_seq_event_t))
|
||||||
|
return -ENOENT;
|
||||||
|
len = snd_seq_event_length((snd_seq_event_t *)seq->obuf);
|
||||||
|
if (olen < len)
|
||||||
|
return -ENOENT;
|
||||||
|
/* skip invalid UMP events */
|
||||||
|
if (snd_seq_ev_is_ump((snd_seq_event_t *)seq->obuf) && !ump_allowed) {
|
||||||
|
seq->obufused -= len;
|
||||||
|
memmove(seq->obuf, seq->obuf + len, seq->obufused);
|
||||||
|
goto repeat;
|
||||||
|
}
|
||||||
|
if (ev_res) {
|
||||||
|
/* extract the event */
|
||||||
|
if (alloc_tmpbuf(seq, len) < 0)
|
||||||
|
return -ENOMEM;
|
||||||
|
memcpy(seq->tmpbuf, seq->obuf, len);
|
||||||
|
*ev_res = (snd_seq_event_t *)seq->tmpbuf;
|
||||||
|
}
|
||||||
|
seq->obufused = olen - len;
|
||||||
|
memmove(seq->obuf, seq->obuf + len, seq->obufused);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief extract the first event in output buffer
|
* \brief extract the first event in output buffer
|
||||||
* \param seq sequencer handle
|
* \param seq sequencer handle
|
||||||
|
|
@ -4062,25 +4308,7 @@ int snd_seq_drain_output(snd_seq_t *seq)
|
||||||
*/
|
*/
|
||||||
int snd_seq_extract_output(snd_seq_t *seq, snd_seq_event_t **ev_res)
|
int snd_seq_extract_output(snd_seq_t *seq, snd_seq_event_t **ev_res)
|
||||||
{
|
{
|
||||||
size_t len, olen;
|
return extract_output(seq, ev_res, 0);
|
||||||
snd_seq_event_t ev;
|
|
||||||
assert(seq);
|
|
||||||
if (ev_res)
|
|
||||||
*ev_res = NULL;
|
|
||||||
if ((olen = seq->obufused) < sizeof(snd_seq_event_t))
|
|
||||||
return -ENOENT;
|
|
||||||
memcpy(&ev, seq->obuf, sizeof(snd_seq_event_t));
|
|
||||||
len = snd_seq_event_length(&ev);
|
|
||||||
if (ev_res) {
|
|
||||||
/* extract the event */
|
|
||||||
if (alloc_tmpbuf(seq, len) < 0)
|
|
||||||
return -ENOMEM;
|
|
||||||
memcpy(seq->tmpbuf, seq->obuf, len);
|
|
||||||
*ev_res = seq->tmpbuf;
|
|
||||||
}
|
|
||||||
seq->obufused = olen - len;
|
|
||||||
memmove(seq->obuf, seq->obuf + len, seq->obufused);
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*----------------------------------------------------------------*/
|
/*----------------------------------------------------------------*/
|
||||||
|
|
@ -4094,32 +4322,35 @@ int snd_seq_extract_output(snd_seq_t *seq, snd_seq_event_t **ev_res)
|
||||||
*/
|
*/
|
||||||
static ssize_t snd_seq_event_read_buffer(snd_seq_t *seq)
|
static ssize_t snd_seq_event_read_buffer(snd_seq_t *seq)
|
||||||
{
|
{
|
||||||
|
size_t packet_size = get_packet_size(seq);
|
||||||
ssize_t len;
|
ssize_t len;
|
||||||
len = (seq->ops->read)(seq, seq->ibuf, seq->ibufsize * sizeof(snd_seq_event_t));
|
|
||||||
|
len = (seq->ops->read)(seq, seq->ibuf, seq->ibufsize * packet_size);
|
||||||
if (len < 0)
|
if (len < 0)
|
||||||
return len;
|
return len;
|
||||||
seq->ibuflen = len / sizeof(snd_seq_event_t);
|
seq->ibuflen = len / packet_size;
|
||||||
seq->ibufptr = 0;
|
seq->ibufptr = 0;
|
||||||
return seq->ibuflen;
|
return seq->ibuflen;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int snd_seq_event_retrieve_buffer(snd_seq_t *seq, snd_seq_event_t **retp)
|
static int snd_seq_event_retrieve_buffer(snd_seq_t *seq, snd_seq_event_t **retp)
|
||||||
{
|
{
|
||||||
|
size_t packet_size = get_packet_size(seq);
|
||||||
size_t ncells;
|
size_t ncells;
|
||||||
snd_seq_event_t *ev;
|
snd_seq_event_t *ev;
|
||||||
|
|
||||||
*retp = ev = &seq->ibuf[seq->ibufptr];
|
*retp = ev = (snd_seq_event_t *)(seq->ibuf + seq->ibufptr * packet_size);
|
||||||
seq->ibufptr++;
|
seq->ibufptr++;
|
||||||
seq->ibuflen--;
|
seq->ibuflen--;
|
||||||
if (! snd_seq_ev_is_variable(ev))
|
if (! snd_seq_ev_is_variable(ev))
|
||||||
return 1;
|
return 1;
|
||||||
ncells = (ev->data.ext.len + sizeof(snd_seq_event_t) - 1) / sizeof(snd_seq_event_t);
|
ncells = (ev->data.ext.len + packet_size - 1) / packet_size;
|
||||||
if (seq->ibuflen < ncells) {
|
if (seq->ibuflen < ncells) {
|
||||||
seq->ibuflen = 0; /* clear buffer */
|
seq->ibuflen = 0; /* clear buffer */
|
||||||
*retp = NULL;
|
*retp = NULL;
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
ev->data.ext.ptr = ev + 1;
|
ev->data.ext.ptr = (char *)ev + packet_size;
|
||||||
seq->ibuflen -= ncells;
|
seq->ibuflen -= ncells;
|
||||||
seq->ibufptr += ncells;
|
seq->ibufptr += ncells;
|
||||||
return 1;
|
return 1;
|
||||||
|
|
@ -4212,6 +4443,111 @@ int snd_seq_event_input_pending(snd_seq_t *seq, int fetch_sequencer)
|
||||||
|
|
||||||
/*----------------------------------------------------------------*/
|
/*----------------------------------------------------------------*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* I/O for UMP packets
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief output a UMP event
|
||||||
|
* \param seq sequencer handle
|
||||||
|
* \param ev UMP event to be output
|
||||||
|
* \return the number of remaining events or a negative error code
|
||||||
|
*
|
||||||
|
* Just like snd_seq_event_output(), it puts an event onto the buffer,
|
||||||
|
* draining the buffer automatically when needed, but the event is
|
||||||
|
* snd_seq_ump_event_t type instead snd_seq_event_t.
|
||||||
|
*
|
||||||
|
* Calling this function is allowed only when the client is set to
|
||||||
|
* \c SND_SEQ_CLIENT_UMP_MIDI_1_0 or \c SND_SEQ_CLIENT_UMP_MIDI_2_0.
|
||||||
|
*
|
||||||
|
* The flushing and clearing of the buffer is done via the same functions,
|
||||||
|
* snd_seq_event_drain_output() and snd_seq_drop_output().
|
||||||
|
*
|
||||||
|
* \sa snd_seq_event_output()
|
||||||
|
*/
|
||||||
|
int snd_seq_ump_event_output(snd_seq_t *seq, snd_seq_ump_event_t *ev)
|
||||||
|
{
|
||||||
|
if (!seq->midi_version)
|
||||||
|
return -EBADFD;
|
||||||
|
return snd_seq_event_output(seq, (snd_seq_event_t *)ev);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief output an event onto the lib buffer without draining buffer
|
||||||
|
* \param seq sequencer handle
|
||||||
|
* \param ev UMP event to be output
|
||||||
|
* \return the byte size of remaining events. \c -EAGAIN if the buffer becomes full.
|
||||||
|
*
|
||||||
|
* This is a UMP event version of snd_seq_event_output_buffer().
|
||||||
|
*
|
||||||
|
* \sa snd_seq_event_output_buffer(), snd_seq_ump_event_output()
|
||||||
|
*/
|
||||||
|
int snd_seq_ump_event_output_buffer(snd_seq_t *seq, snd_seq_ump_event_t *ev)
|
||||||
|
{
|
||||||
|
if (!seq->midi_version)
|
||||||
|
return -EBADFD;
|
||||||
|
return snd_seq_event_output_buffer(seq, (snd_seq_event_t *)ev);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief extract the first UMP event in output buffer
|
||||||
|
* \param seq sequencer handle
|
||||||
|
* \param ev_res UMP event pointer to be extracted
|
||||||
|
* \return 0 on success otherwise a negative error code
|
||||||
|
*
|
||||||
|
* This is a UMP event version of snd_seq_extract_output().
|
||||||
|
*
|
||||||
|
* \sa snd_seq_extract_output(), snd_seq_ump_event_output()
|
||||||
|
*/
|
||||||
|
int snd_seq_ump_extract_output(snd_seq_t *seq, snd_seq_ump_event_t **ev_res)
|
||||||
|
{
|
||||||
|
if (!seq->midi_version)
|
||||||
|
return -EBADFD;
|
||||||
|
return extract_output(seq, (snd_seq_event_t **)ev_res, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief output a UMP event directly to the sequencer NOT through output buffer
|
||||||
|
* \param seq sequencer handle
|
||||||
|
* \param ev UMP event to be output
|
||||||
|
* \return the byte size sent to sequencer or a negative error code
|
||||||
|
*
|
||||||
|
* This is a UMP event version of snd_seq_event_output_direct().
|
||||||
|
*
|
||||||
|
* \sa snd_seq_event_output_direct()
|
||||||
|
*/
|
||||||
|
int snd_seq_ump_event_output_direct(snd_seq_t *seq, snd_seq_ump_event_t *ev)
|
||||||
|
{
|
||||||
|
if (!seq->midi_version)
|
||||||
|
return -EBADFD;
|
||||||
|
return snd_seq_event_output_direct(seq, (snd_seq_event_t *)ev);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief retrieve a UMP event from sequencer
|
||||||
|
* \param seq sequencer handle
|
||||||
|
* \param ev UMP event pointer to be stored
|
||||||
|
*
|
||||||
|
* Like snd_seq_event_input(), this reads out the input event, but in
|
||||||
|
* snd_seq_ump_event_t type instead of snd_seq_event_t type.
|
||||||
|
*
|
||||||
|
* Calling this function is allowed only when the client is set to
|
||||||
|
* \c SND_SEQ_CLIENT_UMP_MIDI_1_0 or \c SND_SEQ_CLIENT_UMP_MIDI_2_0.
|
||||||
|
*
|
||||||
|
* For other input operations, the same function like
|
||||||
|
* snd_seq_event_input_pending() or snd_seq_drop_input() can be still used.
|
||||||
|
*
|
||||||
|
* \sa snd_seq_event_input()
|
||||||
|
*/
|
||||||
|
int snd_seq_ump_event_input(snd_seq_t *seq, snd_seq_ump_event_t **ev)
|
||||||
|
{
|
||||||
|
if (!seq->midi_version)
|
||||||
|
return -EBADFD;
|
||||||
|
return snd_seq_event_input(seq, (snd_seq_event_t **)ev);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*----------------------------------------------------------------*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* clear event buffers
|
* clear event buffers
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -94,6 +94,20 @@ static int snd_seq_hw_system_info(snd_seq_t *seq, snd_seq_system_info_t * info)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void update_midi_version(snd_seq_t *seq, snd_seq_client_info_t *info)
|
||||||
|
{
|
||||||
|
snd_seq_hw_t *hw = seq->private_data;
|
||||||
|
|
||||||
|
if (SNDRV_PROTOCOL_VERSION(1, 0, 3) <= hw->version &&
|
||||||
|
seq->midi_version != (int)info->midi_version) {
|
||||||
|
seq->midi_version = info->midi_version;
|
||||||
|
if (info->midi_version > 0)
|
||||||
|
seq->packet_size = sizeof(snd_seq_ump_event_t);
|
||||||
|
else
|
||||||
|
seq->packet_size = sizeof(snd_seq_event_t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int snd_seq_hw_get_client_info(snd_seq_t *seq, snd_seq_client_info_t * info)
|
static int snd_seq_hw_get_client_info(snd_seq_t *seq, snd_seq_client_info_t * info)
|
||||||
{
|
{
|
||||||
snd_seq_hw_t *hw = seq->private_data;
|
snd_seq_hw_t *hw = seq->private_data;
|
||||||
|
|
@ -105,16 +119,64 @@ static int snd_seq_hw_get_client_info(snd_seq_t *seq, snd_seq_client_info_t * in
|
||||||
info->card = -1;
|
info->card = -1;
|
||||||
info->pid = -1;
|
info->pid = -1;
|
||||||
}
|
}
|
||||||
|
update_midi_version(seq, info);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int snd_seq_hw_set_client_info(snd_seq_t *seq, snd_seq_client_info_t * info)
|
static int snd_seq_hw_set_client_info(snd_seq_t *seq, snd_seq_client_info_t * info)
|
||||||
{
|
{
|
||||||
snd_seq_hw_t *hw = seq->private_data;
|
snd_seq_hw_t *hw = seq->private_data;
|
||||||
|
|
||||||
if (ioctl(hw->fd, SNDRV_SEQ_IOCTL_SET_CLIENT_INFO, info) < 0) {
|
if (ioctl(hw->fd, SNDRV_SEQ_IOCTL_SET_CLIENT_INFO, info) < 0) {
|
||||||
/*SYSERR("SNDRV_SEQ_IOCTL_SET_CLIENT_INFO failed");*/
|
/*SYSERR("SNDRV_SEQ_IOCTL_SET_CLIENT_INFO failed");*/
|
||||||
return -errno;
|
return -errno;
|
||||||
}
|
}
|
||||||
|
update_midi_version(seq, info);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int snd_seq_hw_get_ump_info(snd_seq_t *seq, int client, int type, void *info)
|
||||||
|
{
|
||||||
|
snd_seq_hw_t *hw = seq->private_data;
|
||||||
|
struct snd_seq_client_ump_info buf;
|
||||||
|
size_t size;
|
||||||
|
|
||||||
|
if (type < 0 || type >= SNDRV_SEQ_CLIENT_UMP_INFO_BLOCK + 32)
|
||||||
|
return -EINVAL;
|
||||||
|
if (hw->version < SNDRV_PROTOCOL_VERSION(1, 0, 3))
|
||||||
|
return -ENOTTY;
|
||||||
|
if (type == SNDRV_SEQ_CLIENT_UMP_INFO_ENDPOINT)
|
||||||
|
size = sizeof(struct snd_ump_endpoint_info);
|
||||||
|
else
|
||||||
|
size = sizeof(struct snd_ump_block_info);
|
||||||
|
buf.client = client;
|
||||||
|
buf.type = type;
|
||||||
|
if (ioctl(hw->fd, SNDRV_SEQ_IOCTL_GET_CLIENT_UMP_INFO, &buf) < 0)
|
||||||
|
return -errno;
|
||||||
|
memcpy(info, buf.info, size);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int snd_seq_hw_set_ump_info(snd_seq_t *seq, int type, const void *info)
|
||||||
|
{
|
||||||
|
snd_seq_hw_t *hw = seq->private_data;
|
||||||
|
struct snd_seq_client_ump_info buf;
|
||||||
|
size_t size;
|
||||||
|
|
||||||
|
if (type < 0 || type >= SNDRV_SEQ_CLIENT_UMP_INFO_BLOCK + 32)
|
||||||
|
return -EINVAL;
|
||||||
|
if (hw->version < SNDRV_PROTOCOL_VERSION(1, 0, 3))
|
||||||
|
return -ENOTTY;
|
||||||
|
if (type == SNDRV_SEQ_CLIENT_UMP_INFO_ENDPOINT)
|
||||||
|
size = sizeof(struct snd_ump_endpoint_info);
|
||||||
|
else
|
||||||
|
size = sizeof(struct snd_ump_block_info);
|
||||||
|
buf.client = seq->client;
|
||||||
|
buf.type = type;
|
||||||
|
memcpy(buf.info, info, size);
|
||||||
|
*(int *)buf.info = -1; /* invalidate the card number */
|
||||||
|
if (ioctl(hw->fd, SNDRV_SEQ_IOCTL_SET_CLIENT_UMP_INFO, &buf) < 0)
|
||||||
|
return -errno;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -396,6 +458,8 @@ static const snd_seq_ops_t snd_seq_hw_ops = {
|
||||||
.system_info = snd_seq_hw_system_info,
|
.system_info = snd_seq_hw_system_info,
|
||||||
.get_client_info = snd_seq_hw_get_client_info,
|
.get_client_info = snd_seq_hw_get_client_info,
|
||||||
.set_client_info = snd_seq_hw_set_client_info,
|
.set_client_info = snd_seq_hw_set_client_info,
|
||||||
|
.get_ump_info = snd_seq_hw_get_ump_info,
|
||||||
|
.set_ump_info = snd_seq_hw_set_ump_info,
|
||||||
.create_port = snd_seq_hw_create_port,
|
.create_port = snd_seq_hw_create_port,
|
||||||
.delete_port = snd_seq_hw_delete_port,
|
.delete_port = snd_seq_hw_delete_port,
|
||||||
.get_port_info = snd_seq_hw_get_port_info,
|
.get_port_info = snd_seq_hw_get_port_info,
|
||||||
|
|
@ -476,6 +540,11 @@ int snd_seq_hw_open(snd_seq_t **handle, const char *name, int streams, int mode)
|
||||||
close(fd);
|
close(fd);
|
||||||
return -SND_ERROR_INCOMPATIBLE_VERSION;
|
return -SND_ERROR_INCOMPATIBLE_VERSION;
|
||||||
}
|
}
|
||||||
|
if (SNDRV_PROTOCOL_VERSION(1, 0, 3) <= ver) {
|
||||||
|
/* inform the protocol version we're supporting */
|
||||||
|
unsigned int user_ver = SNDRV_SEQ_VERSION;
|
||||||
|
ioctl(fd, SNDRV_SEQ_IOCTL_USER_PVERSION, &user_ver);
|
||||||
|
}
|
||||||
hw = calloc(1, sizeof(snd_seq_hw_t));
|
hw = calloc(1, sizeof(snd_seq_hw_t));
|
||||||
if (hw == NULL) {
|
if (hw == NULL) {
|
||||||
close(fd);
|
close(fd);
|
||||||
|
|
@ -500,7 +569,7 @@ int snd_seq_hw_open(snd_seq_t **handle, const char *name, int streams, int mode)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (streams & SND_SEQ_OPEN_INPUT) {
|
if (streams & SND_SEQ_OPEN_INPUT) {
|
||||||
seq->ibuf = (snd_seq_event_t *) calloc(sizeof(snd_seq_event_t), seq->ibufsize = SND_SEQ_IBUF_SIZE);
|
seq->ibuf = (char *) calloc(sizeof(snd_seq_ump_event_t), seq->ibufsize = SND_SEQ_IBUF_SIZE);
|
||||||
if (!seq->ibuf) {
|
if (!seq->ibuf) {
|
||||||
free(seq->obuf);
|
free(seq->obuf);
|
||||||
free(hw);
|
free(hw);
|
||||||
|
|
@ -519,6 +588,7 @@ int snd_seq_hw_open(snd_seq_t **handle, const char *name, int streams, int mode)
|
||||||
seq->poll_fd = fd;
|
seq->poll_fd = fd;
|
||||||
seq->ops = &snd_seq_hw_ops;
|
seq->ops = &snd_seq_hw_ops;
|
||||||
seq->private_data = hw;
|
seq->private_data = hw;
|
||||||
|
seq->packet_size = sizeof(snd_seq_event_t);
|
||||||
client = snd_seq_hw_client_id(seq);
|
client = snd_seq_hw_client_id(seq);
|
||||||
if (client < 0) {
|
if (client < 0) {
|
||||||
snd_seq_close(seq);
|
snd_seq_close(seq);
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,8 @@ typedef struct {
|
||||||
int (*system_info)(snd_seq_t *seq, snd_seq_system_info_t * info);
|
int (*system_info)(snd_seq_t *seq, snd_seq_system_info_t * info);
|
||||||
int (*get_client_info)(snd_seq_t *seq, snd_seq_client_info_t * info);
|
int (*get_client_info)(snd_seq_t *seq, snd_seq_client_info_t * info);
|
||||||
int (*set_client_info)(snd_seq_t *seq, snd_seq_client_info_t * info);
|
int (*set_client_info)(snd_seq_t *seq, snd_seq_client_info_t * info);
|
||||||
|
int (*get_ump_info)(snd_seq_t *seq, int client, int type, void *info);
|
||||||
|
int (*set_ump_info)(snd_seq_t *seq, int type, const void *info);
|
||||||
int (*create_port)(snd_seq_t *seq, snd_seq_port_info_t * port);
|
int (*create_port)(snd_seq_t *seq, snd_seq_port_info_t * port);
|
||||||
int (*delete_port)(snd_seq_t *seq, snd_seq_port_info_t * port);
|
int (*delete_port)(snd_seq_t *seq, snd_seq_port_info_t * port);
|
||||||
int (*get_port_info)(snd_seq_t *seq, snd_seq_port_info_t * info);
|
int (*get_port_info)(snd_seq_t *seq, snd_seq_port_info_t * info);
|
||||||
|
|
@ -84,12 +86,14 @@ struct _snd_seq {
|
||||||
char *obuf; /* output buffer */
|
char *obuf; /* output buffer */
|
||||||
size_t obufsize; /* output buffer size */
|
size_t obufsize; /* output buffer size */
|
||||||
size_t obufused; /* output buffer used size */
|
size_t obufused; /* output buffer used size */
|
||||||
snd_seq_event_t *ibuf; /* input buffer */
|
char *ibuf; /* input buffer */
|
||||||
size_t ibufptr; /* current pointer of input buffer */
|
size_t ibufptr; /* current pointer of input buffer */
|
||||||
size_t ibuflen; /* queued length */
|
size_t ibuflen; /* queued length */
|
||||||
size_t ibufsize; /* input buffer size */
|
size_t ibufsize; /* input buffer size */
|
||||||
snd_seq_event_t *tmpbuf; /* temporary event for extracted event */
|
snd_seq_event_t *tmpbuf; /* temporary event for extracted event */
|
||||||
size_t tmpbufsize; /* size of errbuf */
|
size_t tmpbufsize; /* size of errbuf */
|
||||||
|
size_t packet_size; /* input packet alignment size */
|
||||||
|
int midi_version; /* current protocol version */
|
||||||
};
|
};
|
||||||
|
|
||||||
int snd_seq_hw_open(snd_seq_t **handle, const char *name, int streams, int mode);
|
int snd_seq_hw_open(snd_seq_t **handle, const char *name, int streams, int mode);
|
||||||
|
|
|
||||||
|
|
@ -255,6 +255,44 @@ int snd_seq_set_client_event_filter(snd_seq_t *seq, int event_type)
|
||||||
return snd_seq_set_client_info(seq, &info);
|
return snd_seq_set_client_info(seq, &info);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief set client MIDI protocol version
|
||||||
|
* \param seq sequencer handle
|
||||||
|
* \param midi_version MIDI protocol version to set
|
||||||
|
* \return 0 on success or negative error code
|
||||||
|
*
|
||||||
|
* \sa snd_seq_set_client_info()
|
||||||
|
*/
|
||||||
|
int snd_seq_set_client_midi_version(snd_seq_t *seq, int midi_version)
|
||||||
|
{
|
||||||
|
snd_seq_client_info_t info;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
if ((err = snd_seq_get_client_info(seq, &info)) < 0)
|
||||||
|
return err;
|
||||||
|
snd_seq_client_info_set_midi_version(&info, midi_version);
|
||||||
|
return snd_seq_set_client_info(seq, &info);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief enable/disable client's automatic conversion of UMP/legacy events
|
||||||
|
* \param seq sequencer handle
|
||||||
|
* \param enable 0 or 1 to disable/enable the conversion
|
||||||
|
* \return 0 on success or negative error code
|
||||||
|
*
|
||||||
|
* \sa snd_seq_set_client_info()
|
||||||
|
*/
|
||||||
|
int snd_seq_set_client_ump_conversion(snd_seq_t *seq, int enable)
|
||||||
|
{
|
||||||
|
snd_seq_client_info_t info;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
if ((err = snd_seq_get_client_info(seq, &info)) < 0)
|
||||||
|
return err;
|
||||||
|
snd_seq_client_info_set_ump_conversion(&info, enable);
|
||||||
|
return snd_seq_set_client_info(seq, &info);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief change the output pool size of the given client
|
* \brief change the output pool size of the given client
|
||||||
* \param seq sequencer handle
|
* \param seq sequencer handle
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue