/** @file
* Wrappers for creating an ALSA MIDI sequencer client with i/o ports.
*/
#include "alsa.h"
/** Create a new ALSA sequencer client. */
static snd_seq_t* open_client(const char* name) {
snd_seq_t* handle;
if (snd_seq_open(&handle, "default", SND_SEQ_OPEN_DUPLEX, 0) < 0) {
return NULL;
}
if (snd_seq_set_client_name(handle, name) < 0) {
(void)snd_seq_close(handle);
return NULL;
}
return handle;
}
/** Create input and output ports. */
static int open_ports(snd_seq_t* handle, int* in_port, int* out_port) {
*in_port = snd_seq_create_simple_port(handle, "in", SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE,
SND_SEQ_PORT_TYPE_APPLICATION);
if (*in_port < 0) {
return -1;
}
*out_port = snd_seq_create_simple_port(handle, "out", SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_SUBS_READ,
SND_SEQ_PORT_TYPE_APPLICATION);
if (*out_port < 0) {
(void)snd_seq_delete_simple_port(handle, *in_port);
return -1;
}
int client_id = snd_seq_client_id(handle);
if (client_id < 0) {
(void)snd_seq_delete_simple_port(handle, *out_port);
(void)snd_seq_delete_simple_port(handle, *in_port);
return -1;
}
return client_id;
}
int client_open(alsa_seq_client_t* client, const char* name) {
client->handle = open_client(name);
if (client->handle == NULL) {
return -1;
}
client->client_id = open_ports(client->handle, &client->in_port, &client->out_port);
if (client->client_id < 0) {
snd_seq_close(client->handle);
return -1;
}
return 0;
}
void client_close(alsa_seq_client_t* client) {
(void)snd_seq_delete_simple_port(client->handle, client->in_port);
(void)snd_seq_delete_simple_port(client->handle, client->out_port);
(void)snd_seq_close(client->handle);
}
void client_input_loop(alsa_seq_client_t* client, client_loop_cb_t cb, void* cb_ctx) {
do {
snd_seq_event_t* ev;
if (snd_seq_event_input(client->handle, &ev) < 0 || ev == NULL) {
break;
}
ev = cb(ev, cb_ctx);
snd_seq_ev_set_source(ev, (unsigned char)client->out_port);
snd_seq_ev_set_subs(ev);
snd_seq_ev_set_direct(ev);
snd_seq_event_output_direct(client->handle, ev);
snd_seq_free_event(ev);
} while (snd_seq_event_input_pending(client->handle, 0) > 0);
}