summaryrefslogtreecommitdiff
path: root/drivers/alsa_midi/alsa_midi.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/alsa_midi/alsa_midi.c')
-rw-r--r--drivers/alsa_midi/alsa_midi.c1032
1 files changed, 515 insertions, 517 deletions
diff --git a/drivers/alsa_midi/alsa_midi.c b/drivers/alsa_midi/alsa_midi.c
index a4542b4..28a00cd 100644
--- a/drivers/alsa_midi/alsa_midi.c
+++ b/drivers/alsa_midi/alsa_midi.c
@@ -42,6 +42,7 @@ void
_a2j_debug (const char* fmt, ...)
{
va_list ap;
+
va_start (ap, fmt);
vfprintf (stderr, fmt, ap);
fputc ('\n', stderr);
@@ -52,25 +53,26 @@ void
a2j_error (const char* fmt, ...)
{
va_list ap;
+
va_start (ap, fmt);
vfprintf (stdout, fmt, ap);
fputc ('\n', stdout);
}
static bool
-a2j_stream_init(alsa_midi_driver_t* driver, int which)
+a2j_stream_init (alsa_midi_driver_t* driver, int which)
{
- struct a2j_stream *str = &driver->stream[which];
-
- str->new_ports = jack_ringbuffer_create (MAX_PORTS * sizeof(struct a2j_port *));
- if (str->new_ports == NULL) {
- return false;
- }
-
- snd_midi_event_new (MAX_EVENT_SIZE, &str->codec);
- INIT_LIST_HEAD (&str->list);
-
- return true;
+ struct a2j_stream *str = &driver->stream[which];
+
+ str->new_ports = jack_ringbuffer_create (MAX_PORTS * sizeof(struct a2j_port *));
+ if (str->new_ports == NULL) {
+ return false;
+ }
+
+ snd_midi_event_new (MAX_EVENT_SIZE, &str->codec);
+ INIT_LIST_HEAD (&str->list);
+
+ return true;
}
static void
@@ -78,10 +80,10 @@ a2j_stream_detach (struct a2j_stream * stream_ptr)
{
struct a2j_port * port_ptr;
struct list_head * node_ptr;
-
- if (!stream_ptr) {
- return;
- }
+
+ if (!stream_ptr) {
+ return;
+ }
while (!list_empty (&stream_ptr->list)) {
node_ptr = stream_ptr->list.next;
@@ -98,34 +100,36 @@ a2j_stream_close (alsa_midi_driver_t* driver, int which)
{
struct a2j_stream *str = &driver->stream[which];
- if (!str) {
- return;
- }
+ if (!str) {
+ return;
+ }
- if (str->codec)
+ if (str->codec) {
snd_midi_event_free (str->codec);
- if (str->new_ports)
+ }
+ if (str->new_ports) {
jack_ringbuffer_free (str->new_ports);
+ }
}
static void
stop_threads (alsa_midi_driver_t* driver)
{
- if (driver->running) {
- void* thread_status;
-
- driver->running = false; /* tell alsa io thread to stop, whenever they wake up */
- /* do something that we need to do anyway and will wake the io thread, then join */
- snd_seq_disconnect_from (driver->seq, driver->port_id, SND_SEQ_CLIENT_SYSTEM, SND_SEQ_PORT_SYSTEM_ANNOUNCE);
- a2j_debug ("wait for ALSA input thread\n");
- pthread_join (driver->alsa_input_thread, &thread_status);
- a2j_debug ("input thread done\n");
-
- /* wake output thread and join */
- sem_post (&driver->output_semaphore);
- pthread_join (driver->alsa_output_thread, &thread_status);
- a2j_debug ("output thread done\n");
- }
+ if (driver->running) {
+ void* thread_status;
+
+ driver->running = false; /* tell alsa io thread to stop, whenever they wake up */
+ /* do something that we need to do anyway and will wake the io thread, then join */
+ snd_seq_disconnect_from (driver->seq, driver->port_id, SND_SEQ_CLIENT_SYSTEM, SND_SEQ_PORT_SYSTEM_ANNOUNCE);
+ a2j_debug ("wait for ALSA input thread\n");
+ pthread_join (driver->alsa_input_thread, &thread_status);
+ a2j_debug ("input thread done\n");
+
+ /* wake output thread and join */
+ sem_post (&driver->output_semaphore);
+ pthread_join (driver->alsa_output_thread, &thread_status);
+ a2j_debug ("output thread done\n");
+ }
}
/*
@@ -135,8 +139,9 @@ stop_threads (alsa_midi_driver_t* driver)
void a2j_add_ports (struct a2j_stream * str)
{
struct a2j_port * port_ptr;
- while (jack_ringbuffer_read (str->new_ports, (char *)&port_ptr, sizeof(port_ptr))) {
- a2j_debug("jack: inserted port %s", port_ptr->name);
+
+ while (jack_ringbuffer_read (str->new_ports, (char*)&port_ptr, sizeof(port_ptr))) {
+ a2j_debug ("jack: inserted port %s", port_ptr->name);
a2j_port_insert (str->port_hash, port_ptr);
}
}
@@ -147,19 +152,20 @@ a2j_port_event (alsa_midi_driver_t* driver, snd_seq_event_t * ev)
{
const snd_seq_addr_t addr = ev->data.addr;
- if (addr.client == driver->client_id)
+ if (addr.client == driver->client_id) {
return;
+ }
if (ev->type == SND_SEQ_EVENT_PORT_START) {
- a2j_debug("port_event: add %d:%d", addr.client, addr.port);
+ a2j_debug ("port_event: add %d:%d", addr.client, addr.port);
a2j_new_ports (driver, addr);
} else if (ev->type == SND_SEQ_EVENT_PORT_CHANGE) {
- a2j_debug("port_event: change %d:%d", addr.client, addr.port);
+ a2j_debug ("port_event: change %d:%d", addr.client, addr.port);
a2j_update_ports (driver, addr);
} else if (ev->type == SND_SEQ_EVENT_PORT_EXIT) {
- a2j_debug("port_event: del %d:%d", addr.client, addr.port);
- a2j_port_setdead(driver->stream[A2J_PORT_CAPTURE].port_hash, addr);
- a2j_port_setdead(driver->stream[A2J_PORT_PLAYBACK].port_hash, addr);
+ a2j_debug ("port_event: del %d:%d", addr.client, addr.port);
+ a2j_port_setdead (driver->stream[A2J_PORT_CAPTURE].port_hash, addr);
+ a2j_port_setdead (driver->stream[A2J_PORT_PLAYBACK].port_hash, addr);
}
}
@@ -175,8 +181,8 @@ a2j_input_event (alsa_midi_driver_t* driver, snd_seq_event_t * alsa_event)
jack_nframes_t now;
now = jack_frame_time (driver->jack_client);
-
- if ((port = a2j_port_get(str->port_hash, alsa_event->source)) == NULL) {
+
+ if ((port = a2j_port_get (str->port_hash, alsa_event->source)) == NULL) {
return;
}
@@ -184,8 +190,8 @@ a2j_input_event (alsa_midi_driver_t* driver, snd_seq_event_t * alsa_event)
* RPNs, NRPNs, Bank Change, etc. need special handling
* but seems, ALSA does it for us already.
*/
- snd_midi_event_reset_decode(str->codec);
- if ((size = snd_midi_event_decode(str->codec, data, sizeof(data), alsa_event))<0) {
+ snd_midi_event_reset_decode (str->codec);
+ if ((size = snd_midi_event_decode (str->codec, data, sizeof(data), alsa_event)) < 0) {
return;
}
@@ -195,47 +201,47 @@ a2j_input_event (alsa_midi_driver_t* driver, snd_seq_event_t * alsa_event)
data[2] = 0x40;
}
- a2j_debug("input: %d bytes at event_frame=%u", (int)size, now);
+ a2j_debug ("input: %d bytes at event_frame=%u", (int)size, now);
- if (jack_ringbuffer_write_space(port->inbound_events) >= (sizeof(struct a2j_alsa_midi_event) + size)) {
+ if (jack_ringbuffer_write_space (port->inbound_events) >= (sizeof(struct a2j_alsa_midi_event) + size)) {
struct a2j_alsa_midi_event ev;
- char *ev_charp = (char*) &ev;
+ char *ev_charp = (char*)&ev;
size_t limit;
size_t to_write = sizeof(ev);
jack_ringbuffer_data_t vec[2];
- jack_ringbuffer_get_write_vector( port->inbound_events, vec );
+ jack_ringbuffer_get_write_vector ( port->inbound_events, vec );
ev.time = now;
ev.size = size;
-
+
limit = (to_write > vec[0].len ? vec[0].len : to_write);
if (limit) {
- memcpy( vec[0].buf, ev_charp, limit );
- to_write -= limit;
- ev_charp += limit;
- vec[0].buf += limit;
- vec[0].len -= limit;
+ memcpy ( vec[0].buf, ev_charp, limit );
+ to_write -= limit;
+ ev_charp += limit;
+ vec[0].buf += limit;
+ vec[0].len -= limit;
}
if (to_write) {
- memcpy( vec[1].buf, ev_charp, to_write );
- vec[1].buf += to_write;
- vec[1].len -= to_write;
+ memcpy ( vec[1].buf, ev_charp, to_write );
+ vec[1].buf += to_write;
+ vec[1].len -= to_write;
}
to_write = size;
- ev_charp = (char *)data;
+ ev_charp = (char*)data;
limit = (to_write > vec[0].len ? vec[0].len : to_write);
if (limit) {
memcpy (vec[0].buf, ev_charp, limit);
- }
+ }
to_write -= limit;
ev_charp += limit;
if (to_write) {
memcpy (vec[1].buf, ev_charp, to_write);
- }
+ }
- jack_ringbuffer_write_advance( port->inbound_events, sizeof(ev) + size );
+ jack_ringbuffer_write_advance ( port->inbound_events, sizeof(ev) + size );
} else {
a2j_error ("MIDI data lost (incoming event buffer full): %ld bytes lost", size);
}
@@ -245,74 +251,74 @@ a2j_input_event (alsa_midi_driver_t* driver, snd_seq_event_t * alsa_event)
static int
a2j_process_incoming (alsa_midi_driver_t* driver, struct a2j_port* port, jack_nframes_t nframes)
{
- jack_nframes_t one_period;
- struct a2j_alsa_midi_event ev;
- char *ev_buf;
-
- /* grab data queued by the ALSA input thread and write it into the JACK
- port buffer. it will delivered during the JACK period that this
- function is called from.
- */
-
- /* first clear the JACK port buffer in preparation for new data
- */
-
- a2j_debug ("PORT: %s process input", jack_port_name (port->jack_port));
-
- jack_midi_clear_buffer (port->jack_buf);
-
- one_period = jack_get_buffer_size (driver->jack_client);
-
- while (jack_ringbuffer_peek (port->inbound_events, (char*)&ev, sizeof(ev) ) == sizeof(ev) ) {
-
- jack_midi_data_t* buf;
- jack_nframes_t offset;
-
- a2j_debug ("Seen inbound event from read callback\n");
-
- if (ev.time >= driver->cycle_start) {
- a2j_debug ("event is too late\n");
- break;
- }
-
- //jack_ringbuffer_read_advance (port->inbound_events, sizeof (ev));
- ev_buf = (char *) alloca( sizeof(ev) + ev.size );
-
- if (jack_ringbuffer_peek (port->inbound_events, ev_buf, sizeof(ev) + ev.size ) != sizeof(ev) + ev.size) {
- break;
- }
-
- offset = driver->cycle_start - ev.time;
- if (offset > one_period) {
- /* from a previous cycle, somehow. cram it in at the front */
- offset = 0;
- } else {
- /* offset from start of the current cycle */
- offset = one_period - offset;
- }
-
- a2j_debug ("event at %d offset %d", ev.time, offset);
-
- /* make sure there is space for it */
-
- buf = jack_midi_event_reserve (port->jack_buf, offset, ev.size);
-
- if (buf) {
- /* grab the event */
- memcpy( buf, ev_buf + sizeof(ev), ev.size );
- } else {
- /* throw it away (no space) */
- a2j_error ("threw away MIDI event - not reserved at time %d", ev.time);
- }
- jack_ringbuffer_read_advance (port->inbound_events, sizeof(ev) + ev.size);
-
- a2j_debug("input on %s: sucked %d bytes from inbound at %d", jack_port_name (port->jack_port), ev.size, ev.time);
- }
-
- return 0;
+ jack_nframes_t one_period;
+ struct a2j_alsa_midi_event ev;
+ char *ev_buf;
+
+ /* grab data queued by the ALSA input thread and write it into the JACK
+ port buffer. it will delivered during the JACK period that this
+ function is called from.
+ */
+
+ /* first clear the JACK port buffer in preparation for new data
+ */
+
+ a2j_debug ("PORT: %s process input", jack_port_name (port->jack_port));
+
+ jack_midi_clear_buffer (port->jack_buf);
+
+ one_period = jack_get_buffer_size (driver->jack_client);
+
+ while (jack_ringbuffer_peek (port->inbound_events, (char*)&ev, sizeof(ev) ) == sizeof(ev) ) {
+
+ jack_midi_data_t* buf;
+ jack_nframes_t offset;
+
+ a2j_debug ("Seen inbound event from read callback\n");
+
+ if (ev.time >= driver->cycle_start) {
+ a2j_debug ("event is too late\n");
+ break;
+ }
+
+ //jack_ringbuffer_read_advance (port->inbound_events, sizeof (ev));
+ ev_buf = (char*)alloca ( sizeof(ev) + ev.size );
+
+ if (jack_ringbuffer_peek (port->inbound_events, ev_buf, sizeof(ev) + ev.size ) != sizeof(ev) + ev.size) {
+ break;
+ }
+
+ offset = driver->cycle_start - ev.time;
+ if (offset > one_period) {
+ /* from a previous cycle, somehow. cram it in at the front */
+ offset = 0;
+ } else {
+ /* offset from start of the current cycle */
+ offset = one_period - offset;
+ }
+
+ a2j_debug ("event at %d offset %d", ev.time, offset);
+
+ /* make sure there is space for it */
+
+ buf = jack_midi_event_reserve (port->jack_buf, offset, ev.size);
+
+ if (buf) {
+ /* grab the event */
+ memcpy ( buf, ev_buf + sizeof(ev), ev.size );
+ } else {
+ /* throw it away (no space) */
+ a2j_error ("threw away MIDI event - not reserved at time %d", ev.time);
+ }
+ jack_ringbuffer_read_advance (port->inbound_events, sizeof(ev) + ev.size);
+
+ a2j_debug ("input on %s: sucked %d bytes from inbound at %d", jack_port_name (port->jack_port), ev.size, ev.time);
+ }
+
+ return 0;
}
-void*
+void*
alsa_input_thread (void* arg)
{
alsa_midi_driver_t* driver = arg;
@@ -324,25 +330,25 @@ alsa_input_thread (void* arg)
snd_seq_event_t * event;
int ret;
- npfd = snd_seq_poll_descriptors_count(driver->seq, POLLIN);
- pfd = (struct pollfd *)alloca(npfd * sizeof(struct pollfd));
- snd_seq_poll_descriptors(driver->seq, pfd, npfd, POLLIN);
+ npfd = snd_seq_poll_descriptors_count (driver->seq, POLLIN);
+ pfd = (struct pollfd*)alloca (npfd * sizeof(struct pollfd));
+ snd_seq_poll_descriptors (driver->seq, pfd, npfd, POLLIN);
initial = true;
while (driver->running) {
- if ((ret = poll(pfd, npfd, 1000)) > 0) {
+ if ((ret = poll (pfd, npfd, 1000)) > 0) {
while (snd_seq_event_input (driver->seq, &event) > 0) {
if (initial) {
- snd_seq_client_info_alloca(&client_info);
- snd_seq_client_info_set_client(client_info, -1);
- while (snd_seq_query_next_client(driver->seq, client_info) >= 0) {
- addr.client = snd_seq_client_info_get_client(client_info);
+ snd_seq_client_info_alloca (&client_info);
+ snd_seq_client_info_set_client (client_info, -1);
+ while (snd_seq_query_next_client (driver->seq, client_info) >= 0) {
+ addr.client = snd_seq_client_info_get_client (client_info);
if (addr.client == SND_SEQ_CLIENT_SYSTEM || addr.client == driver->client_id) {
continue;
}
-
+
a2j_new_ports (driver, addr);
}
@@ -350,9 +356,9 @@ alsa_input_thread (void* arg)
}
if (event->source.client == SND_SEQ_CLIENT_SYSTEM) {
- a2j_port_event(driver, event);
+ a2j_port_event (driver, event);
} else {
- a2j_input_event(driver, event);
+ a2j_input_event (driver, event);
}
snd_seq_free_event (event);
@@ -360,214 +366,207 @@ alsa_input_thread (void* arg)
}
}
- return (void*) 0;
+ return (void*)0;
}
/* --- OUTBOUND FROM JACK TO ALSA ---- */
int
a2j_process_outgoing (
- alsa_midi_driver_t* driver,
- struct a2j_port * port)
+ alsa_midi_driver_t* driver,
+ struct a2j_port * port)
{
- /* collect data from JACK port buffer and queue it for delivery by ALSA output thread */
-
- int nevents;
- jack_ringbuffer_data_t vec[2];
- int i;
- int written = 0;
- size_t limit;
- struct a2j_delivery_event* dev;
- size_t gap = 0;
-
- jack_ringbuffer_get_write_vector (driver->outbound_events, vec);
-
- dev = (struct a2j_delivery_event*) vec[0].buf;
- limit = vec[0].len / sizeof (struct a2j_delivery_event);
- nevents = jack_midi_get_event_count (port->jack_buf);
-
- a2j_debug ("alsa_out: port has %d events for delivery\n", nevents);
-
- for (i = 0; (i < nevents) && (written < limit); ++i) {
-
- jack_midi_event_get (&dev->jack_event, port->jack_buf, i);
- if (dev->jack_event.size <= MAX_JACKMIDI_EV_SIZE)
- {
- dev->time = dev->jack_event.time;
- dev->port = port;
- memcpy( dev->midistring, dev->jack_event.buffer, dev->jack_event.size );
- written++;
- ++dev;
- }
- }
-
- /* anything left? use the second part of the vector, as much as possible */
-
- if (i < nevents)
- {
- if (vec[0].len)
- {
- gap = vec[0].len - written * sizeof(struct a2j_delivery_event);
- }
-
- dev = (struct a2j_delivery_event*) vec[1].buf;
-
- limit += (vec[1].len / sizeof (struct a2j_delivery_event));
-
- while ((i < nevents) && (written < limit))
- {
- jack_midi_event_get(&dev->jack_event, port->jack_buf, i);
- if (dev->jack_event.size <= MAX_JACKMIDI_EV_SIZE)
- {
- dev->time = dev->jack_event.time;
- dev->port = port;
- memcpy(dev->midistring, dev->jack_event.buffer, dev->jack_event.size);
- written++;
- ++dev;
- }
- ++i;
- }
- }
-
- a2j_debug( "done pushing events: %d ... gap: %d ", (int)written, (int)gap );
- /* clear JACK port buffer; advance ring buffer ptr */
-
- jack_ringbuffer_write_advance (driver->outbound_events, written * sizeof (struct a2j_delivery_event) + gap);
-
- return nevents;
+ /* collect data from JACK port buffer and queue it for delivery by ALSA output thread */
+
+ int nevents;
+ jack_ringbuffer_data_t vec[2];
+ int i;
+ int written = 0;
+ size_t limit;
+ struct a2j_delivery_event* dev;
+ size_t gap = 0;
+
+ jack_ringbuffer_get_write_vector (driver->outbound_events, vec);
+
+ dev = (struct a2j_delivery_event*)vec[0].buf;
+ limit = vec[0].len / sizeof(struct a2j_delivery_event);
+ nevents = jack_midi_get_event_count (port->jack_buf);
+
+ a2j_debug ("alsa_out: port has %d events for delivery\n", nevents);
+
+ for (i = 0; (i < nevents) && (written < limit); ++i) {
+
+ jack_midi_event_get (&dev->jack_event, port->jack_buf, i);
+ if (dev->jack_event.size <= MAX_JACKMIDI_EV_SIZE) {
+ dev->time = dev->jack_event.time;
+ dev->port = port;
+ memcpy ( dev->midistring, dev->jack_event.buffer, dev->jack_event.size );
+ written++;
+ ++dev;
+ }
+ }
+
+ /* anything left? use the second part of the vector, as much as possible */
+
+ if (i < nevents) {
+ if (vec[0].len) {
+ gap = vec[0].len - written * sizeof(struct a2j_delivery_event);
+ }
+
+ dev = (struct a2j_delivery_event*)vec[1].buf;
+
+ limit += (vec[1].len / sizeof(struct a2j_delivery_event));
+
+ while ((i < nevents) && (written < limit)) {
+ jack_midi_event_get (&dev->jack_event, port->jack_buf, i);
+ if (dev->jack_event.size <= MAX_JACKMIDI_EV_SIZE) {
+ dev->time = dev->jack_event.time;
+ dev->port = port;
+ memcpy (dev->midistring, dev->jack_event.buffer, dev->jack_event.size);
+ written++;
+ ++dev;
+ }
+ ++i;
+ }
+ }
+
+ a2j_debug ( "done pushing events: %d ... gap: %d ", (int)written, (int)gap );
+ /* clear JACK port buffer; advance ring buffer ptr */
+
+ jack_ringbuffer_write_advance (driver->outbound_events, written * sizeof(struct a2j_delivery_event) + gap);
+
+ return nevents;
}
static int
time_sorter (struct a2j_delivery_event * a, struct a2j_delivery_event * b)
{
- if (a->time < b->time) {
- return -1;
- } else if (a->time > b->time) {
- return 1;
- }
- return 0;
+ if (a->time < b->time) {
+ return -1;
+ } else if (a->time > b->time) {
+ return 1;
+ }
+ return 0;
}
-static void*
-alsa_output_thread(void * arg)
+static void*
+alsa_output_thread (void * arg)
{
- alsa_midi_driver_t * driver = (alsa_midi_driver_t*) arg;
- struct a2j_stream *str = &driver->stream[A2J_PORT_PLAYBACK];
- int i;
- struct list_head evlist;
- struct list_head * node_ptr;
- jack_ringbuffer_data_t vec[2];
- snd_seq_event_t alsa_event;
- struct a2j_delivery_event* ev;
- float sr;
- jack_nframes_t now;
- int limit;
-
- while (driver->running) {
- /* pre-first, handle port deletion requests */
-
- a2j_free_ports(driver);
-
- /* first, make a list of all events in the outbound_events FIFO */
-
- INIT_LIST_HEAD(&evlist);
-
- jack_ringbuffer_get_read_vector (driver->outbound_events, vec);
-
- a2j_debug ("alsa_out: output thread: got %d+%d events",
- (vec[0].len / sizeof (struct a2j_delivery_event)),
- (vec[1].len / sizeof (struct a2j_delivery_event)));
-
- ev = (struct a2j_delivery_event*) vec[0].buf;
- limit = vec[0].len / sizeof (struct a2j_delivery_event);
- for (i = 0; i < limit; ++i) {
- list_add_tail(&ev->siblings, &evlist);
- ev++;
- }
-
- ev = (struct a2j_delivery_event*) vec[1].buf;
- limit = vec[1].len / sizeof (struct a2j_delivery_event);
- for (i = 0; i < limit; ++i) {
- list_add_tail(&ev->siblings, &evlist);
- ev++;
- }
-
- if (vec[0].len < sizeof(struct a2j_delivery_event) && (vec[1].len == 0)) {
- /* no events: wait for some */
- a2j_debug ("alsa_out: output thread: wait for events");
- sem_wait (&driver->output_semaphore);
- a2j_debug ("alsa_out: output thread: AWAKE ... loop back for events");
- continue;
- }
-
- /* now sort this list by time */
-
- list_sort(&evlist, struct a2j_delivery_event, siblings, time_sorter);
-
- /* now deliver */
-
- sr = jack_get_sample_rate (driver->jack_client);
-
- list_for_each(node_ptr, &evlist)
- {
- ev = list_entry(node_ptr, struct a2j_delivery_event, siblings);
-
- snd_seq_ev_clear(&alsa_event);
- snd_midi_event_reset_encode(str->codec);
- if (!snd_midi_event_encode(str->codec, (const unsigned char *)ev->midistring, ev->jack_event.size, &alsa_event))
- {
- a2j_debug ("alsa_out: invalid event of size %d, ignored\n", ev->jack_event.size);
- continue; // invalid event
- }
-
- snd_seq_ev_set_source(&alsa_event, driver->port_id);
- snd_seq_ev_set_dest(&alsa_event, ev->port->remote.client, ev->port->remote.port);
- snd_seq_ev_set_direct (&alsa_event);
-
- now = jack_frame_time (driver->jack_client);
-
- ev->time += driver->cycle_start;
-
- a2j_debug ("alsa_out:@ %d, next event @ %d", now, ev->time);
-
- /* do we need to wait a while before delivering? */
-
- if (ev->time > now) {
- struct timespec nanoseconds;
- jack_nframes_t sleep_frames = ev->time - now;
- float seconds = sleep_frames / sr;
-
- /* if the gap is long enough, sleep */
-
- if (seconds > 0.001) {
- nanoseconds.tv_sec = (time_t) seconds;
- nanoseconds.tv_nsec = (long) NSEC_PER_SEC * (seconds - nanoseconds.tv_sec);
-
- a2j_debug ("alsa_out: output thread sleeps for %.2f msec", ((double) nanoseconds.tv_nsec / NSEC_PER_SEC) * 1000.0);
-
- if (nanosleep (&nanoseconds, NULL) < 0) {
- fprintf (stderr, "BAD SLEEP\n");
- /* do something ? */
- }
- }
- }
-
- /* its time to deliver */
- snd_seq_event_output(driver->seq, &alsa_event);
- snd_seq_drain_output (driver->seq);
- now = jack_frame_time (driver->jack_client);
- a2j_debug("alsa_out: written %d bytes to %s at %d, DELTA = %d", ev->jack_event.size, ev->port->name, now,
- (int32_t) (now - ev->time));
- }
-
- /* free up space in the FIFO */
-
- jack_ringbuffer_read_advance (driver->outbound_events, vec[0].len + vec[1].len);
-
- /* and head back for more */
- }
-
- return (void*) 0;
+ alsa_midi_driver_t * driver = (alsa_midi_driver_t*)arg;
+ struct a2j_stream *str = &driver->stream[A2J_PORT_PLAYBACK];
+ int i;
+ struct list_head evlist;
+ struct list_head * node_ptr;
+ jack_ringbuffer_data_t vec[2];
+ snd_seq_event_t alsa_event;
+ struct a2j_delivery_event* ev;
+ float sr;
+ jack_nframes_t now;
+ int limit;
+
+ while (driver->running) {
+ /* pre-first, handle port deletion requests */
+
+ a2j_free_ports (driver);
+
+ /* first, make a list of all events in the outbound_events FIFO */
+
+ INIT_LIST_HEAD (&evlist);
+
+ jack_ringbuffer_get_read_vector (driver->outbound_events, vec);
+
+ a2j_debug ("alsa_out: output thread: got %d+%d events",
+ (vec[0].len / sizeof(struct a2j_delivery_event)),
+ (vec[1].len / sizeof(struct a2j_delivery_event)));
+
+ ev = (struct a2j_delivery_event*)vec[0].buf;
+ limit = vec[0].len / sizeof(struct a2j_delivery_event);
+ for (i = 0; i < limit; ++i) {
+ list_add_tail (&ev->siblings, &evlist);
+ ev++;
+ }
+
+ ev = (struct a2j_delivery_event*)vec[1].buf;
+ limit = vec[1].len / sizeof(struct a2j_delivery_event);
+ for (i = 0; i < limit; ++i) {
+ list_add_tail (&ev->siblings, &evlist);
+ ev++;
+ }
+
+ if (vec[0].len < sizeof(struct a2j_delivery_event) && (vec[1].len == 0)) {
+ /* no events: wait for some */
+ a2j_debug ("alsa_out: output thread: wait for events");
+ sem_wait (&driver->output_semaphore);
+ a2j_debug ("alsa_out: output thread: AWAKE ... loop back for events");
+ continue;
+ }
+
+ /* now sort this list by time */
+
+ list_sort (&evlist, struct a2j_delivery_event, siblings, time_sorter);
+
+ /* now deliver */
+
+ sr = jack_get_sample_rate (driver->jack_client);
+
+ list_for_each (node_ptr, &evlist){
+ ev = list_entry (node_ptr, struct a2j_delivery_event, siblings);
+
+ snd_seq_ev_clear (&alsa_event);
+ snd_midi_event_reset_encode (str->codec);
+ if (!snd_midi_event_encode (str->codec, (const unsigned char*)ev->midistring, ev->jack_event.size, &alsa_event)) {
+ a2j_debug ("alsa_out: invalid event of size %d, ignored\n", ev->jack_event.size);
+ continue; // invalid event
+ }
+
+ snd_seq_ev_set_source (&alsa_event, driver->port_id);
+ snd_seq_ev_set_dest (&alsa_event, ev->port->remote.client, ev->port->remote.port);
+ snd_seq_ev_set_direct (&alsa_event);
+
+ now = jack_frame_time (driver->jack_client);
+
+ ev->time += driver->cycle_start;
+
+ a2j_debug ("alsa_out:@ %d, next event @ %d", now, ev->time);
+
+ /* do we need to wait a while before delivering? */
+
+ if (ev->time > now) {
+ struct timespec nanoseconds;
+ jack_nframes_t sleep_frames = ev->time - now;
+ float seconds = sleep_frames / sr;
+
+ /* if the gap is long enough, sleep */
+
+ if (seconds > 0.001) {
+ nanoseconds.tv_sec = (time_t)seconds;
+ nanoseconds.tv_nsec = (long)NSEC_PER_SEC * (seconds - nanoseconds.tv_sec);
+
+ a2j_debug ("alsa_out: output thread sleeps for %.2f msec", ((double)nanoseconds.tv_nsec / NSEC_PER_SEC) * 1000.0);
+
+ if (nanosleep (&nanoseconds, NULL) < 0) {
+ fprintf (stderr, "BAD SLEEP\n");
+ /* do something ? */
+ }
+ }
+ }
+
+ /* its time to deliver */
+ snd_seq_event_output (driver->seq, &alsa_event);
+ snd_seq_drain_output (driver->seq);
+ now = jack_frame_time (driver->jack_client);
+ a2j_debug ("alsa_out: written %d bytes to %s at %d, DELTA = %d", ev->jack_event.size, ev->port->name, now,
+ (int32_t)(now - ev->time));
+ }
+
+ /* free up space in the FIFO */
+
+ jack_ringbuffer_read_advance (driver->outbound_events, vec[0].len + vec[1].len);
+
+ /* and head back for more */
+ }
+
+ return (void*)0;
}
/** CORE JACK PROCESSING */
@@ -578,56 +577,54 @@ alsa_output_thread(void * arg)
static void
a2j_jack_process_internal (alsa_midi_driver_t* driver, int dir, jack_nframes_t nframes)
{
- struct a2j_stream * stream_ptr;
- int i;
- struct a2j_port ** port_ptr_ptr;
- struct a2j_port * port_ptr;
- int nevents = 0;
-
- stream_ptr = &driver->stream[dir];
- a2j_add_ports(stream_ptr);
-
- // process ports
- for (i = 0 ; i < PORT_HASH_SIZE ; i++)
- {
- port_ptr_ptr = &stream_ptr->port_hash[i];
- while (*port_ptr_ptr != NULL)
- {
- port_ptr = *port_ptr_ptr;
-
- if (!port_ptr->is_dead) {
- port_ptr->jack_buf = jack_port_get_buffer(port_ptr->jack_port, nframes);
-
- if (dir == A2J_PORT_CAPTURE) {
- a2j_process_incoming (driver, port_ptr, nframes);
- } else {
- nevents += a2j_process_outgoing (driver, port_ptr);
- }
-
- } else if (jack_ringbuffer_write_space (driver->port_del) >= sizeof(port_ptr)) {
-
- a2j_debug("jack: removed port %s", port_ptr->name);
- *port_ptr_ptr = port_ptr->next;
- jack_ringbuffer_write(driver->port_del, (char*)&port_ptr, sizeof(port_ptr));
- nevents += 1; /* wake up output thread, see: a2j_free_ports */
- continue;
-
- }
-
- port_ptr_ptr = &port_ptr->next;
- }
- }
-
- if (dir == A2J_PORT_PLAYBACK && nevents > 0) {
- int sv;
-
- /* if we queued up anything for output, tell the output thread in
- case its waiting for us.
- */
-
- sem_getvalue (&driver->output_semaphore, &sv);
- sem_post (&driver->output_semaphore);
- }
+ struct a2j_stream * stream_ptr;
+ int i;
+ struct a2j_port ** port_ptr_ptr;
+ struct a2j_port * port_ptr;
+ int nevents = 0;
+
+ stream_ptr = &driver->stream[dir];
+ a2j_add_ports (stream_ptr);
+
+ // process ports
+ for (i = 0; i < PORT_HASH_SIZE; i++) {
+ port_ptr_ptr = &stream_ptr->port_hash[i];
+ while (*port_ptr_ptr != NULL) {
+ port_ptr = *port_ptr_ptr;
+
+ if (!port_ptr->is_dead) {
+ port_ptr->jack_buf = jack_port_get_buffer (port_ptr->jack_port, nframes);
+
+ if (dir == A2J_PORT_CAPTURE) {
+ a2j_process_incoming (driver, port_ptr, nframes);
+ } else {
+ nevents += a2j_process_outgoing (driver, port_ptr);
+ }
+
+ } else if (jack_ringbuffer_write_space (driver->port_del) >= sizeof(port_ptr)) {
+
+ a2j_debug ("jack: removed port %s", port_ptr->name);
+ *port_ptr_ptr = port_ptr->next;
+ jack_ringbuffer_write (driver->port_del, (char*)&port_ptr, sizeof(port_ptr));
+ nevents += 1; /* wake up output thread, see: a2j_free_ports */
+ continue;
+
+ }
+
+ port_ptr_ptr = &port_ptr->next;
+ }
+ }
+
+ if (dir == A2J_PORT_PLAYBACK && nevents > 0) {
+ int sv;
+
+ /* if we queued up anything for output, tell the output thread in
+ case its waiting for us.
+ */
+
+ sem_getvalue (&driver->output_semaphore, &sv);
+ sem_post (&driver->output_semaphore);
+ }
}
/* JACK DRIVER FUNCTIONS */
@@ -635,178 +632,178 @@ a2j_jack_process_internal (alsa_midi_driver_t* driver, int dir, jack_nframes_t n
static int
alsa_midi_read (alsa_midi_driver_t* driver, jack_nframes_t nframes)
{
- driver->cycle_start = jack_last_frame_time (driver->jack_client);
- a2j_jack_process_internal (driver, A2J_PORT_CAPTURE, nframes);
- return 0;
+ driver->cycle_start = jack_last_frame_time (driver->jack_client);
+ a2j_jack_process_internal (driver, A2J_PORT_CAPTURE, nframes);
+ return 0;
}
static int
alsa_midi_write (alsa_midi_driver_t* driver, jack_nframes_t nframes)
{
- driver->cycle_start = jack_last_frame_time (driver->jack_client);
- a2j_jack_process_internal (driver, A2J_PORT_PLAYBACK, nframes);
- return 0;
+ driver->cycle_start = jack_last_frame_time (driver->jack_client);
+ a2j_jack_process_internal (driver, A2J_PORT_PLAYBACK, nframes);
+ return 0;
}
-static int
+static int
alsa_midi_start (alsa_midi_driver_t* driver)
{
- int error;
-
- snd_seq_start_queue (driver->seq, driver->queue, 0);
- snd_seq_drop_input (driver->seq);
-
- a2j_add_ports(&driver->stream[A2J_PORT_CAPTURE]);
- a2j_add_ports(&driver->stream[A2J_PORT_PLAYBACK]);
-
- driver->running = true;
-
- if (pthread_create(&driver->alsa_input_thread, NULL, alsa_input_thread, driver) < 0) {
- a2j_error("cannot start ALSA input thread");
- return -1;
- }
-
- /* wake the poll loop in the alsa input thread so initial ports are fetched */
- if ((error = snd_seq_connect_from (driver->seq, driver->port_id, SND_SEQ_CLIENT_SYSTEM, SND_SEQ_PORT_SYSTEM_ANNOUNCE)) < 0) {
- a2j_error("snd_seq_connect_from() failed");
- return -1;
- }
-
- if (pthread_create(&driver->alsa_output_thread, NULL, alsa_output_thread, driver) < 0) {
- a2j_error("cannot start ALSA output thread");
- return -1;
- }
-
- return 0;
+ int error;
+
+ snd_seq_start_queue (driver->seq, driver->queue, 0);
+ snd_seq_drop_input (driver->seq);
+
+ a2j_add_ports (&driver->stream[A2J_PORT_CAPTURE]);
+ a2j_add_ports (&driver->stream[A2J_PORT_PLAYBACK]);
+
+ driver->running = true;
+
+ if (pthread_create (&driver->alsa_input_thread, NULL, alsa_input_thread, driver) < 0) {
+ a2j_error ("cannot start ALSA input thread");
+ return -1;
+ }
+
+ /* wake the poll loop in the alsa input thread so initial ports are fetched */
+ if ((error = snd_seq_connect_from (driver->seq, driver->port_id, SND_SEQ_CLIENT_SYSTEM, SND_SEQ_PORT_SYSTEM_ANNOUNCE)) < 0) {
+ a2j_error ("snd_seq_connect_from() failed");
+ return -1;
+ }
+
+ if (pthread_create (&driver->alsa_output_thread, NULL, alsa_output_thread, driver) < 0) {
+ a2j_error ("cannot start ALSA output thread");
+ return -1;
+ }
+
+ return 0;
}
static int
alsa_midi_stop (alsa_midi_driver_t* driver)
{
- stop_threads (driver);
+ stop_threads (driver);
- (void) snd_seq_stop_queue (driver->seq, driver->queue, 0);
- return 0;
+ (void)snd_seq_stop_queue (driver->seq, driver->queue, 0);
+ return 0;
}
static int
alsa_midi_attach (alsa_midi_driver_t* driver, jack_engine_t* engine)
{
- int error;
-
- driver->port_del = jack_ringbuffer_create(2 * MAX_PORTS * sizeof(struct a2j_port *));
- if (driver->port_del == NULL) {
- return -1;
- }
-
- driver->outbound_events = jack_ringbuffer_create (MAX_EVENT_SIZE * 16 * sizeof(struct a2j_delivery_event));
- if (driver->outbound_events == NULL) {
- return -1;
- }
-
- if (!a2j_stream_init (driver, A2J_PORT_CAPTURE)) {
- return -1;
- }
-
- if (!a2j_stream_init (driver, A2J_PORT_PLAYBACK)) {
- return -1;
- }
-
- if ((error = snd_seq_open(&driver->seq, "hw", SND_SEQ_OPEN_DUPLEX, 0)) < 0) {
- a2j_error("failed to open alsa seq");
- return -1;
- }
-
- if ((error = snd_seq_set_client_name(driver->seq, "jackmidi")) < 0) {
- a2j_error("snd_seq_set_client_name() failed");
- return -1;
- }
-
- if ((driver->port_id = snd_seq_create_simple_port(
- driver->seq,
- "port",
- SND_SEQ_PORT_CAP_READ|SND_SEQ_PORT_CAP_WRITE
+ int error;
+
+ driver->port_del = jack_ringbuffer_create (2 * MAX_PORTS * sizeof(struct a2j_port *));
+ if (driver->port_del == NULL) {
+ return -1;
+ }
+
+ driver->outbound_events = jack_ringbuffer_create (MAX_EVENT_SIZE * 16 * sizeof(struct a2j_delivery_event));
+ if (driver->outbound_events == NULL) {
+ return -1;
+ }
+
+ if (!a2j_stream_init (driver, A2J_PORT_CAPTURE)) {
+ return -1;
+ }
+
+ if (!a2j_stream_init (driver, A2J_PORT_PLAYBACK)) {
+ return -1;
+ }
+
+ if ((error = snd_seq_open (&driver->seq, "hw", SND_SEQ_OPEN_DUPLEX, 0)) < 0) {
+ a2j_error ("failed to open alsa seq");
+ return -1;
+ }
+
+ if ((error = snd_seq_set_client_name (driver->seq, "jackmidi")) < 0) {
+ a2j_error ("snd_seq_set_client_name() failed");
+ return -1;
+ }
+
+ if ((driver->port_id = snd_seq_create_simple_port (
+ driver->seq,
+ "port",
+ SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_WRITE
#ifndef DEBUG
- |SND_SEQ_PORT_CAP_NO_EXPORT
+ | SND_SEQ_PORT_CAP_NO_EXPORT
#endif
- ,SND_SEQ_PORT_TYPE_APPLICATION)) < 0) {
-
- a2j_error("snd_seq_create_simple_port() failed");
- return -1;
- }
-
- if ((driver->client_id = snd_seq_client_id(driver->seq)) < 0) {
- a2j_error("snd_seq_client_id() failed");
- return -1;
- }
-
- if ((driver->queue = snd_seq_alloc_queue(driver->seq)) < 0) {
- a2j_error("snd_seq_alloc_queue() failed");
- return -1;
- }
-
- if ((error = snd_seq_nonblock(driver->seq, 1)) < 0) {
- a2j_error("snd_seq_nonblock() failed");
- return -1;
- }
-
- return jack_activate (driver->jack_client);
+ , SND_SEQ_PORT_TYPE_APPLICATION)) < 0) {
+
+ a2j_error ("snd_seq_create_simple_port() failed");
+ return -1;
+ }
+
+ if ((driver->client_id = snd_seq_client_id (driver->seq)) < 0) {
+ a2j_error ("snd_seq_client_id() failed");
+ return -1;
+ }
+
+ if ((driver->queue = snd_seq_alloc_queue (driver->seq)) < 0) {
+ a2j_error ("snd_seq_alloc_queue() failed");
+ return -1;
+ }
+
+ if ((error = snd_seq_nonblock (driver->seq, 1)) < 0) {
+ a2j_error ("snd_seq_nonblock() failed");
+ return -1;
+ }
+
+ return jack_activate (driver->jack_client);
}
static int
alsa_midi_detach (alsa_midi_driver_t* driver, jack_engine_t* engine)
{
- driver->finishing = true;
-
- snd_seq_close (driver->seq);
- driver->seq = NULL;
- return 0;
+ driver->finishing = true;
+
+ snd_seq_close (driver->seq);
+ driver->seq = NULL;
+ return 0;
}
static jack_driver_t *
alsa_midi_driver_new (jack_client_t *client, const char *name)
{
- alsa_midi_driver_t* driver = calloc(1, sizeof(alsa_midi_driver_t));
+ alsa_midi_driver_t* driver = calloc (1, sizeof(alsa_midi_driver_t));
- jack_info ("creating alsa_midi driver ...");
+ jack_info ("creating alsa_midi driver ...");
if (!driver) {
return NULL;
}
- jack_driver_init ((jack_driver_t *) driver);
+ jack_driver_init ((jack_driver_t*)driver);
- driver->attach = (JackDriverAttachFunction) alsa_midi_attach;
- driver->detach = (JackDriverDetachFunction) alsa_midi_detach;
- driver->read = (JackDriverReadFunction) alsa_midi_read;
- driver->write = (JackDriverWriteFunction) alsa_midi_write;
- driver->start = (JackDriverStartFunction) alsa_midi_start;
- driver->stop = (JackDriverStartFunction) alsa_midi_stop;
+ driver->attach = (JackDriverAttachFunction)alsa_midi_attach;
+ driver->detach = (JackDriverDetachFunction)alsa_midi_detach;
+ driver->read = (JackDriverReadFunction)alsa_midi_read;
+ driver->write = (JackDriverWriteFunction)alsa_midi_write;
+ driver->start = (JackDriverStartFunction)alsa_midi_start;
+ driver->stop = (JackDriverStartFunction)alsa_midi_stop;
driver->jack_client = client;
- if (sem_init(&driver->output_semaphore, 0, 0) < 0) {
- a2j_error ("can't create IO semaphore");
- free (driver);
- return NULL;
- }
+ if (sem_init (&driver->output_semaphore, 0, 0) < 0) {
+ a2j_error ("can't create IO semaphore");
+ free (driver);
+ return NULL;
+ }
- return (jack_driver_t *) driver;
+ return (jack_driver_t*)driver;
}
static void
alsa_midi_driver_delete (alsa_midi_driver_t* driver)
{
- a2j_stream_detach (&driver->stream[A2J_PORT_CAPTURE]);
- a2j_stream_detach (&driver->stream[A2J_PORT_PLAYBACK]);
- a2j_stream_close (driver, A2J_PORT_CAPTURE);
- a2j_stream_close (driver, A2J_PORT_PLAYBACK);
-
- sem_destroy (&driver->output_semaphore);
-
- jack_ringbuffer_free (driver->outbound_events);
- jack_ringbuffer_free (driver->port_del);
+ a2j_stream_detach (&driver->stream[A2J_PORT_CAPTURE]);
+ a2j_stream_detach (&driver->stream[A2J_PORT_PLAYBACK]);
+ a2j_stream_close (driver, A2J_PORT_CAPTURE);
+ a2j_stream_close (driver, A2J_PORT_PLAYBACK);
+
+ sem_destroy (&driver->output_semaphore);
+
+ jack_ringbuffer_free (driver->outbound_events);
+ jack_ringbuffer_free (driver->port_del);
}
/* DRIVER "PLUGIN" INTERFACE */
@@ -818,14 +815,15 @@ driver_get_descriptor ()
{
jack_driver_desc_t * desc;
jack_driver_param_desc_t * params;
+
//unsigned int i;
- desc = calloc (1, sizeof (jack_driver_desc_t));
+ desc = calloc (1, sizeof(jack_driver_desc_t));
- strcpy (desc->name,"alsa_midi");
+ strcpy (desc->name, "alsa_midi");
desc->nparams = 0;
-
- params = calloc (desc->nparams, sizeof (jack_driver_param_desc_t));
+
+ params = calloc (desc->nparams, sizeof(jack_driver_param_desc_t));
desc->params = params;
@@ -839,19 +837,19 @@ driver_initialize (jack_client_t *client, const JSList * params)
const jack_driver_param_t * param;
for (node = params; node; node = jack_slist_next (node)) {
- param = (const jack_driver_param_t *) node->data;
+ param = (const jack_driver_param_t*)node->data;
switch (param->character) {
- default:
- break;
+ default:
+ break;
}
}
-
+
return alsa_midi_driver_new (client, NULL);
}
void
driver_finish (jack_driver_t *driver)
{
- alsa_midi_driver_delete ((alsa_midi_driver_t *) driver);
+ alsa_midi_driver_delete ((alsa_midi_driver_t*)driver);
}