summaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
m---------tools0
-rw-r--r--tools/alsa_midi/Makefile.am16
-rw-r--r--tools/alsa_midi/a2j.h126
-rw-r--r--tools/alsa_midi/alsa_midi.c878
-rw-r--r--tools/alsa_midi/list.c147
-rw-r--r--tools/alsa_midi/list.h903
-rw-r--r--tools/alsa_midi/port.c217
-rw-r--r--tools/alsa_midi/port.h29
-rw-r--r--tools/alsa_midi/port_hash.c63
-rw-r--r--tools/alsa_midi/port_hash.h35
-rw-r--r--tools/alsa_midi/port_thread.c235
-rw-r--r--tools/alsa_midi/port_thread.h49
12 files changed, 2698 insertions, 0 deletions
diff --git a/tools b/tools
deleted file mode 160000
-Subproject 3cbecc704f70f48ead70c92200e8aef20917bb5
diff --git a/tools/alsa_midi/Makefile.am b/tools/alsa_midi/Makefile.am
new file mode 100644
index 0000000..096e3ee
--- /dev/null
+++ b/tools/alsa_midi/Makefile.am
@@ -0,0 +1,16 @@
+MAINTAINERCLEANFILES = Makefile.in
+
+#
+# in-process ALSA/JACK MIDI bridge clients (1 for input, 1 for output)
+#
+
+a2j_clientdir = $(ADDON_DIR)
+
+a2j_client_LTLIBRARIES = a2j_in.la
+
+a2j_common_sources = port.c port_hash.c port_thread.c list.c
+
+a2j_in_la_LDFLAGS = -module -avoid-version @OS_LDFLAGS@
+a2j_in_la_SOURCES = input_client.c $(a2j_common_sources)
+
+noinst_HEADERS = a2j.h list.h port.h port_hash.h port_thread.h
diff --git a/tools/alsa_midi/a2j.h b/tools/alsa_midi/a2j.h
new file mode 100644
index 0000000..87453ae
--- /dev/null
+++ b/tools/alsa_midi/a2j.h
@@ -0,0 +1,126 @@
+/* -*- Mode: C ; c-basic-offset: 2 -*- */
+/*
+ * ALSA SEQ < - > JACK MIDI bridge
+ *
+ * Copyright (c) 2006,2007 Dmitry S. Baikov <c0ff@konstruktiv.org>
+ * Copyright (c) 2007,2008,2009 Nedko Arnaudov <nedko@arnaudov.name>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef STRUCTS_H__FD2CC895_411F_4ADE_9200_50FE395EDB72__INCLUDED
+#define STRUCTS_H__FD2CC895_411F_4ADE_9200_50FE395EDB72__INCLUDED
+
+#include <stdbool.h>
+#include <semaphore.h>
+#include <jack/midiport.h>
+
+#define JACK_INVALID_PORT NULL
+
+#define MAX_PORTS 2048
+#define MAX_EVENT_SIZE 1024
+
+#define PORT_HASH_BITS 4
+#define PORT_HASH_SIZE (1 << PORT_HASH_BITS)
+
+/* Beside enum use, these are indeces for (struct a2j).stream array */
+#define A2J_PORT_CAPTURE 0 // ALSA playback port -> JACK capture port
+#define A2J_PORT_PLAYBACK 1 // JACK playback port -> ALSA capture port
+
+typedef struct a2j_port * a2j_port_hash_t[PORT_HASH_SIZE];
+
+struct a2j;
+
+struct a2j_port
+{
+ struct a2j_port * next; /* hash - jack */
+ struct list_head siblings; /* list - main loop */
+ struct a2j * a2j_ptr;
+ bool is_dead;
+ char name[64];
+ snd_seq_addr_t remote;
+ jack_port_t * jack_port;
+
+ jack_ringbuffer_t * inbound_events; // alsa_midi_event_t + data
+ int64_t last_out_time;
+
+ void * jack_buf;
+};
+
+struct a2j_stream
+{
+ snd_midi_event_t *codec;
+
+ jack_ringbuffer_t *new_ports;
+
+ a2j_port_hash_t port_hash;
+ struct list_head list;
+};
+
+struct a2j
+{
+ jack_client_t * jack_client;
+
+ snd_seq_t *seq;
+ pthread_t alsa_input_thread;
+ pthread_t alsa_output_thread;
+ int client_id;
+ int port_id;
+ int queue;
+ bool freewheeling;
+ bool running;
+ bool finishing;
+
+ jack_ringbuffer_t* port_add; // snd_seq_addr_t
+ jack_ringbuffer_t* port_del; // struct a2j_port*
+ jack_ringbuffer_t* outbound_events; // struct a2j_delivery_event
+ jack_nframes_t cycle_start;
+
+ sem_t output_semaphore;
+
+ struct a2j_stream stream[2];
+};
+
+#define NSEC_PER_SEC ((int64_t)1000*1000*1000)
+
+struct a2j_alsa_midi_event
+{
+ int64_t time;
+ int size;
+};
+
+#define MAX_JACKMIDI_EV_SIZE 16
+
+struct a2j_delivery_event
+{
+ struct list_head siblings;
+
+ /* a jack MIDI event, plus the port its destined for: everything
+ the ALSA output thread needs to deliver the event. time is
+ part of the jack_event.
+ */
+ jack_midi_event_t jack_event;
+ jack_nframes_t time; /* realtime, not offset time */
+ struct a2j_port* port;
+ char midistring[MAX_JACKMIDI_EV_SIZE];
+};
+
+void a2j_info (const char* fmt, ...);
+void a2j_error (const char* fmt, ...);
+void a2j_debug (const char* fmt, ...);
+void a2j_warning (const char* fmt, ...);
+
+
+
+#endif /* #ifndef STRUCTS_H__FD2CC895_411F_4ADE_9200_50FE395EDB72__INCLUDED */
diff --git a/tools/alsa_midi/alsa_midi.c b/tools/alsa_midi/alsa_midi.c
new file mode 100644
index 0000000..ad06b1a
--- /dev/null
+++ b/tools/alsa_midi/alsa_midi.c
@@ -0,0 +1,878 @@
+/* -*- Mode: C ; c-basic-offset: 2 -*- */
+/*
+ * ALSA SEQ < - > JACK MIDI bridge
+ *
+ * Copyright (c) 2006,2007 Dmitry S. Baikov <c0ff@konstruktiv.org>
+ * Copyright (c) 2007,2008,2009 Nedko Arnaudov <nedko@arnaudov.name>
+ * Copyright (c) 2009,2010 Paul Davis <paul@linuxaudiosystems.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdbool.h>
+#include <stdarg.h>
+#include <string.h>
+#include <time.h>
+#include <alsa/asoundlib.h>
+#include <jack/jack.h>
+#include <jack/midiport.h>
+#include <jack/ringbuffer.h>
+
+#include "list.h"
+#include "a2j.h"
+#include "port_hash.h"
+#include "port.h"
+#include "port_thread.h"
+
+bool g_stop_request = false;
+
+void
+a2j_info (const char* fmt, ...)
+{
+ va_list ap;
+ va_start (ap, fmt);
+ vfprintf (stdout, fmt, ap);
+ fputc ('\n', stdout);
+}
+
+void
+a2j_error (const char* fmt, ...)
+{
+ va_list ap;
+ va_start (ap, fmt);
+ vfprintf (stdout, fmt, ap);
+ fputc ('\n', stdout);
+}
+
+
+void
+a2j_debug (const char* fmt, ...)
+{
+ va_list ap;
+ va_start (ap, fmt);
+ vfprintf (stderr, fmt, ap);
+ fputc ('\n', stdout);
+}
+
+void
+a2j_warning (const char* fmt, ...)
+{
+ va_list ap;
+ va_start (ap, fmt);
+ vfprintf (stdout, fmt, ap);
+ fputc ('\n', stdout);
+}
+
+static bool
+a2j_stream_init(struct a2j * self, int which)
+{
+ struct a2j_stream *str = &self->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
+a2j_stream_detach (struct a2j_stream * stream_ptr)
+{
+ struct a2j_port * port_ptr;
+ struct list_head * node_ptr;
+
+ while (!list_empty (&stream_ptr->list)) {
+ node_ptr = stream_ptr->list.next;
+ list_del (node_ptr);
+ port_ptr = list_entry (node_ptr, struct a2j_port, siblings);
+ a2j_info ("port deleted: %s", port_ptr->name);
+ a2j_port_free (port_ptr);
+ }
+}
+
+static
+void
+a2j_stream_close (struct a2j * self, int which)
+{
+ struct a2j_stream *str = &self->stream[which];
+
+ if (str->codec)
+ snd_midi_event_free (str->codec);
+ if (str->new_ports)
+ jack_ringbuffer_free (str->new_ports);
+}
+
+static void
+stop_threads (struct a2j* self)
+{
+ if (self->running) {
+ void* thread_status;
+
+ self->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 (self->seq, self->port_id, SND_SEQ_CLIENT_SYSTEM, SND_SEQ_PORT_SYSTEM_ANNOUNCE);
+ a2j_debug ("wait for ALSA input thread\n");
+ pthread_join (self->alsa_input_thread, &thread_status);
+ a2j_debug ("input thread done\n");
+
+ /* wake output thread and join */
+ sem_post(&self->output_semaphore);
+ pthread_join(self->alsa_output_thread, &thread_status);
+ a2j_debug ("output thread done\n");
+ }
+}
+
+/*
+ * =================== Input/output port handling =========================
+ */
+
+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);
+ a2j_port_insert (str->port_hash, port_ptr);
+ }
+}
+
+static
+void
+a2j_port_event (struct a2j * self, snd_seq_event_t * ev)
+{
+ const snd_seq_addr_t addr = ev->data.addr;
+
+ if (addr.client == self->client_id)
+ return;
+
+ if (ev->type == SND_SEQ_EVENT_PORT_START || ev->type == SND_SEQ_EVENT_PORT_CHANGE) {
+ if (jack_ringbuffer_write_space(self->port_add) >= sizeof(addr)) {
+ a2j_debug("port_event: add/change %d:%d", addr.client, addr.port);
+ jack_ringbuffer_write(self->port_add, (char*)&addr, sizeof(addr));
+ } else {
+ a2j_error("dropping port_event: add/change %d:%d", addr.client, addr.port);
+ }
+ } else if (ev->type == SND_SEQ_EVENT_PORT_EXIT) {
+ a2j_debug("port_event: del %d:%d", addr.client, addr.port);
+ a2j_port_setdead(self->stream[A2J_PORT_CAPTURE].port_hash, addr);
+ a2j_port_setdead(self->stream[A2J_PORT_PLAYBACK].port_hash, addr);
+ }
+}
+
+/* --- INBOUND FROM ALSA TO JACK ---- */
+
+static void
+a2j_input_event (struct a2j * self, snd_seq_event_t * alsa_event)
+{
+ jack_midi_data_t data[MAX_EVENT_SIZE];
+ struct a2j_stream *str = &self->stream[A2J_PORT_CAPTURE];
+ long size;
+ struct a2j_port *port;
+ jack_nframes_t now;
+
+ now = jack_frame_time (self->jack_client);
+
+ if ((port = a2j_port_get(str->port_hash, alsa_event->source)) == NULL) {
+ return;
+ }
+
+ /*
+ * 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) {
+ return;
+ }
+
+ // fixup NoteOn with vel 0
+ if ((data[0] & 0xF0) == 0x90 && data[2] == 0x00) {
+ data[0] = 0x80 + (data[0] & 0x0F);
+ data[2] = 0x40;
+ }
+
+ 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)) {
+ struct a2j_alsa_midi_event 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 );
+ 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;
+ }
+ if (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;
+ 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 );
+ } else {
+ a2j_error ("MIDI data lost (incoming event buffer full): %ld bytes lost", size);
+ }
+
+}
+
+static int
+a2j_process_incoming (struct a2j* self, 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 (self->jack_client);
+
+ while (jack_ringbuffer_peek (port->inbound_events, (char*)&ev, sizeof(ev) ) == sizeof(ev) ) {
+
+ jack_midi_data_t* buf;
+ jack_nframes_t offset;
+
+ if (ev.time >= self->cycle_start) {
+ 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 = self->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*
+alsa_input_thread (void* arg)
+{
+ struct a2j * self = arg;
+ int npfd;
+ struct pollfd * pfd;
+ snd_seq_addr_t addr;
+ snd_seq_client_info_t * client_info;
+ snd_seq_port_info_t * port_info;
+ bool initial;
+ snd_seq_event_t * event;
+ int ret;
+
+ npfd = snd_seq_poll_descriptors_count(self->seq, POLLIN);
+ pfd = (struct pollfd *)alloca(npfd * sizeof(struct pollfd));
+ snd_seq_poll_descriptors(self->seq, pfd, npfd, POLLIN);
+
+ initial = true;
+
+ while (self->running) {
+ if ((ret = poll(pfd, npfd, 1000)) > 0) {
+
+ while (snd_seq_event_input (self->seq, &event) > 0) {
+ if (initial) {
+ snd_seq_client_info_alloca(&client_info);
+ snd_seq_port_info_alloca(&port_info);
+ snd_seq_client_info_set_client(client_info, -1);
+ while (snd_seq_query_next_client(self->seq, client_info) >= 0) {
+ addr.client = snd_seq_client_info_get_client(client_info);
+ if (addr.client == SND_SEQ_CLIENT_SYSTEM || addr.client == self->client_id) {
+ continue;
+ }
+ snd_seq_port_info_set_client(port_info, addr.client);
+ snd_seq_port_info_set_port(port_info, -1);
+ while (snd_seq_query_next_port(self->seq, port_info) >= 0) {
+ addr.port = snd_seq_port_info_get_port(port_info);
+ a2j_update_port(self, addr, port_info);
+ }
+ }
+
+ initial = false;
+ }
+
+ if (event->source.client == SND_SEQ_CLIENT_SYSTEM) {
+ a2j_port_event(self, event);
+ } else {
+ a2j_input_event(self, event);
+ }
+
+ snd_seq_free_event (event);
+ }
+ }
+ }
+
+ return (void*) 0;
+}
+
+/* --- OUTBOUND FROM JACK TO ALSA ---- */
+
+int
+a2j_process_outgoing (
+ struct a2j * self,
+ 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 (self->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);
+
+ 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 (self->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;
+}
+
+static void*
+alsa_output_thread(void * arg)
+{
+ struct a2j * self = (struct a2j*) arg;
+ struct a2j_stream *str = &self->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 err;
+ int limit;
+
+ while (self->running) {
+ /* first, make a list of all events in the outbound_events FIFO */
+
+ INIT_LIST_HEAD(&evlist);
+
+ jack_ringbuffer_get_read_vector (self->outbound_events, vec);
+
+ a2j_debug ("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 ("output thread: wait for events");
+ sem_wait (&self->output_semaphore);
+ a2j_debug ("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 (self->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))
+ {
+ continue; // invalid event
+ }
+
+ snd_seq_ev_set_source(&alsa_event, self->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 (self->jack_client);
+
+ ev->time += self->cycle_start;
+
+ a2j_debug ("@ %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 ("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 */
+ err = snd_seq_event_output(self->seq, &alsa_event);
+ snd_seq_drain_output (self->seq);
+ now = jack_frame_time (self->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 (self->outbound_events, vec[0].len + vec[1].len);
+
+ /* and head back for more */
+ }
+
+ return (void*) 0;
+}
+
+/** CORE JACK PROCESSING */
+
+
+/* ALSA */
+
+static void
+a2j_jack_process_internal (struct a2j * self, 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 = &self->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 (self, port_ptr, nframes);
+ } else {
+ nevents += a2j_process_outgoing (self, port_ptr);
+ }
+
+ } else if (jack_ringbuffer_write_space (self->port_del) >= sizeof(port_ptr)) {
+
+ a2j_debug("jack: removed port %s", port_ptr->name);
+ *port_ptr_ptr = port_ptr->next;
+ jack_ringbuffer_write(self->port_del, (char*)&port_ptr, sizeof(port_ptr));
+ 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 (&self->output_semaphore, &sv);
+ sem_post (&self->output_semaphore);
+ }
+}
+
+static int
+a2j_process(jack_nframes_t nframes, void * arg)
+{
+ struct a2j* self = (struct a2j *) arg;
+
+ if (self->freewheeling) {
+ return 0;
+ }
+
+ self->cycle_start = jack_last_frame_time (self->jack_client);
+
+ a2j_jack_process_internal (self, A2J_PORT_CAPTURE, nframes);
+ a2j_jack_process_internal (self, A2J_PORT_PLAYBACK, nframes);
+
+ return 0;
+}
+
+/* --- */
+
+static
+void
+a2j_freewheel(int starting, void * arg)
+{
+ struct a2j* self = (struct a2j*) arg;
+ self->freewheeling = starting;
+}
+
+static
+void
+a2j_shutdown (void * arg)
+{
+ struct a2j* self = (struct a2j*) self;
+ a2j_warning ("JACK server shutdown notification received.");
+ stop_threads (self);
+}
+
+int
+connect_to_alsa (struct a2j* self)
+{
+ int error;
+ void* thread_status;
+
+ self->port_add = jack_ringbuffer_create (2 * MAX_PORTS * sizeof(snd_seq_addr_t));
+
+ if (self->port_add == NULL) {
+ goto free_self;
+ }
+
+ self->port_del = jack_ringbuffer_create(2 * MAX_PORTS * sizeof(struct a2j_port *));
+ if (self->port_del == NULL) {
+ goto free_ringbuffer_add;
+ }
+
+ self->outbound_events = jack_ringbuffer_create (MAX_EVENT_SIZE * 16 * sizeof(struct a2j_delivery_event));
+ if (self->outbound_events == NULL) {
+ goto free_ringbuffer_del;
+ }
+
+ if (!a2j_stream_init (self, A2J_PORT_CAPTURE)) {
+ goto free_ringbuffer_outbound;
+ }
+
+ if (!a2j_stream_init (self, A2J_PORT_PLAYBACK)) {
+ goto close_capture_stream;
+ }
+
+ if ((error = snd_seq_open(&self->seq, "hw", SND_SEQ_OPEN_DUPLEX, 0)) < 0) {
+ a2j_error("failed to open alsa seq");
+ goto close_playback_stream;
+ }
+
+ if ((error = snd_seq_set_client_name(self->seq, "jackmidi")) < 0) {
+ a2j_error("snd_seq_set_client_name() failed");
+ goto close_seq_client;
+ }
+
+ if ((self->port_id = snd_seq_create_simple_port(
+ self->seq,
+ "port",
+ SND_SEQ_PORT_CAP_READ|SND_SEQ_PORT_CAP_WRITE
+#ifndef DEBUG
+ |SND_SEQ_PORT_CAP_NO_EXPORT
+#endif
+ ,SND_SEQ_PORT_TYPE_APPLICATION)) < 0) {
+
+ a2j_error("snd_seq_create_simple_port() failed");
+ goto close_seq_client;
+ }
+
+ if ((self->client_id = snd_seq_client_id(self->seq)) < 0) {
+ a2j_error("snd_seq_client_id() failed");
+ goto close_seq_client;
+ }
+
+ if ((self->queue = snd_seq_alloc_queue(self->seq)) < 0) {
+ a2j_error("snd_seq_alloc_queue() failed");
+ goto close_seq_client;
+ }
+
+ snd_seq_start_queue (self->seq, self->queue, 0);
+
+ if ((error = snd_seq_nonblock(self->seq, 1)) < 0) {
+ a2j_error("snd_seq_nonblock() failed");
+ goto close_seq_client;
+ }
+
+ snd_seq_drop_input (self->seq);
+
+ a2j_add_ports(&self->stream[A2J_PORT_CAPTURE]);
+ a2j_add_ports(&self->stream[A2J_PORT_PLAYBACK]);
+
+ if (sem_init(&self->output_semaphore, 0, 0) < 0) {
+ a2j_error("can't create IO semaphore");
+ goto close_jack_client;
+ }
+
+ self->running = true;
+
+ if (pthread_create(&self->alsa_input_thread, NULL, alsa_input_thread, self) < 0) {
+ a2j_error("cannot start ALSA input thread");
+ goto sem_destroy;
+ }
+
+ /* wake the poll loop in the alsa input thread so initial ports are fetched */
+ if ((error = snd_seq_connect_from (self->seq, self->port_id, SND_SEQ_CLIENT_SYSTEM, SND_SEQ_PORT_SYSTEM_ANNOUNCE)) < 0) {
+ a2j_error("snd_seq_connect_from() failed");
+ goto join_input_thread;
+ }
+
+ if (pthread_create(&self->alsa_output_thread, NULL, alsa_output_thread, self) < 0) {
+ a2j_error("cannot start ALSA input thread");
+ goto sem_destroy;
+ }
+
+ return 0;
+
+ /* error handling */
+
+ self->running = false; /* tell alsa threads to stop */
+ self->finishing = false;
+
+ snd_seq_disconnect_from(self->seq, self->port_id, SND_SEQ_CLIENT_SYSTEM, SND_SEQ_PORT_SYSTEM_ANNOUNCE);
+ join_input_thread:
+ pthread_join (self->alsa_input_thread, &thread_status);
+ sem_destroy:
+ sem_destroy (&self->output_semaphore);
+ close_jack_client:
+ if ((error = jack_client_close(self->jack_client)) < 0) {
+ a2j_error("Cannot close jack client");
+ }
+ close_seq_client:
+ snd_seq_close(self->seq);
+ close_playback_stream:
+ a2j_stream_close(self, A2J_PORT_PLAYBACK);
+ close_capture_stream:
+ a2j_stream_close(self, A2J_PORT_CAPTURE);
+ free_ringbuffer_outbound:
+ jack_ringbuffer_free(self->outbound_events);
+ free_ringbuffer_del:
+ jack_ringbuffer_free(self->port_del);
+ free_ringbuffer_add:
+ jack_ringbuffer_free(self->port_add);
+ free_self:
+ free(self);
+ return -1;
+}
+
+/* JACK internal client API: 2 entry points
+ */
+
+int
+jack_initialize (jack_client_t *client, const char* load_init)
+{
+ struct a2j* self = calloc(1, sizeof(struct a2j));
+
+ if (!self) {
+ return -1;
+ }
+
+ self->jack_client = client;
+
+ if (load_init) {
+ char* args = strdup (load_init);
+ char* token;
+ char* ptr = args;
+ char* savep;
+
+ while (1) {
+ if ((token = strtok_r (ptr, ", ", &savep)) == NULL) {
+ break;
+ }
+#if 0
+ /* example of how to use tokens */
+
+ if (strncasecmp (token, "in", 2) == 0) {
+ self->input = 1;
+ }
+#endif
+
+ ptr = NULL;
+ }
+
+ free (args);
+ }
+
+ if (connect_to_alsa (self)) {
+ free (self);
+ return -1;
+ }
+
+ jack_set_process_callback (client, a2j_process, self);
+ jack_set_freewheel_callback (client, a2j_freewheel, self);
+ jack_on_shutdown (client, a2j_shutdown, self);
+
+ jack_activate (client);
+
+ return 0;
+}
+
+void
+jack_finish (void *arg)
+{
+ struct a2j* self = (struct a2j*) arg;
+
+ self->finishing = true;
+
+ stop_threads (self);
+ sem_destroy(&self->output_semaphore);
+ jack_ringbuffer_reset (self->port_add);
+ a2j_stream_detach (&self->stream[A2J_PORT_CAPTURE]);
+ a2j_stream_detach (&self->stream[A2J_PORT_PLAYBACK]);
+ snd_seq_close(self->seq);
+ self->seq = NULL;
+ a2j_stream_close (self, A2J_PORT_CAPTURE);
+ a2j_stream_close (self, A2J_PORT_PLAYBACK);
+ jack_ringbuffer_free(self->outbound_events);
+ jack_ringbuffer_free(self->port_add);
+ jack_ringbuffer_free(self->port_del);
+
+ free (self);
+}
diff --git a/tools/alsa_midi/list.c b/tools/alsa_midi/list.c
new file mode 100644
index 0000000..438066c
--- /dev/null
+++ b/tools/alsa_midi/list.c
@@ -0,0 +1,147 @@
+/* -*- Mode: C ; c-basic-offset: 2 -*- */
+/*****************************************************************************
+ *
+ * list_sort() adapted from linux kernel.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *****************************************************************************/
+
+#include <assert.h>
+
+#include "list.h"
+
+/* list sort from Mark J Roberts (mjr@znex.org) */
+void
+__list_sort(
+ struct list_head *head,
+ int member_offset,
+ int (*cmp)(void * a, void * b))
+{
+ struct list_head *p, *q, *e, *list, *tail, *oldhead;
+ int insize, nmerges, psize, qsize, i;
+
+ list = head->next;
+ list_del(head);
+ insize = 1;
+ for (;;) {
+ p = oldhead = list;
+ list = tail = NULL;
+ nmerges = 0;
+
+ while (p) {
+ nmerges++;
+ q = p;
+ psize = 0;
+ for (i = 0; i < insize; i++) {
+ psize++;
+ q = q->next == oldhead ? NULL : q->next;
+ if (!q)
+ break;
+ }
+
+ qsize = insize;
+ while (psize > 0 || (qsize > 0 && q)) {
+ if (!psize) {
+ e = q;
+ q = q->next;
+ qsize--;
+ if (q == oldhead)
+ q = NULL;
+ } else if (!qsize || !q) {
+ e = p;
+ p = p->next;
+ psize--;
+ if (p == oldhead)
+ p = NULL;
+ } else if (cmp((void *)p - member_offset, (void *)q - member_offset) <= 0) {
+ e = p;
+ p = p->next;
+ psize--;
+ if (p == oldhead)
+ p = NULL;
+ } else {
+ e = q;
+ q = q->next;
+ qsize--;
+ if (q == oldhead)
+ q = NULL;
+ }
+ if (tail)
+ tail->next = e;
+ else
+ list = e;
+ e->prev = tail;
+ tail = e;
+ }
+ p = q;
+ }
+
+ tail->next = list;
+ list->prev = tail;
+
+ if (nmerges <= 1)
+ break;
+
+ insize *= 2;
+ }
+
+ head->next = list;
+ head->prev = list->prev;
+ list->prev->next = head;
+ list->prev = head;
+}
+
+struct test_list_el {
+ int value;
+ struct list_head test_list_node;
+};
+
+int test_list_sort_comparator(struct test_list_el * e1, struct test_list_el * e2)
+{
+ return e1->value - e2->value;
+}
+
+void test_list_sort(void)
+{
+ struct list_head test_list;
+ struct test_list_el *el, *next;
+ struct test_list_el te1 = {.value = 1};
+ struct test_list_el te2 = {.value = 2};
+ struct test_list_el te3 = {.value = 3};
+ struct test_list_el te4 = {.value = 4};
+ struct test_list_el te5 = {.value = 5};
+ struct test_list_el te6 = {.value = 6};
+ struct test_list_el te7 = {.value = 7};
+
+ const int expected[] = {1, 2, 3, 4, 5, 6, 7};
+ int i;
+
+ INIT_LIST_HEAD(&test_list);
+ list_add_tail(&te2.test_list_node, &test_list);
+ list_add_tail(&te6.test_list_node, &test_list);
+ list_add_tail(&te4.test_list_node, &test_list);
+ list_add_tail(&te5.test_list_node, &test_list);
+ list_add_tail(&te7.test_list_node, &test_list);
+ list_add_tail(&te1.test_list_node, &test_list);
+ list_add_tail(&te3.test_list_node, &test_list);
+
+ list_sort(&test_list, struct test_list_el, test_list_node, test_list_sort_comparator);
+
+ i = 0;
+ list_for_each_entry_safe(el, next, &test_list, test_list_node) {
+ assert(el->value == expected[i]);
+ i++;
+ }
+}
diff --git a/tools/alsa_midi/list.h b/tools/alsa_midi/list.h
new file mode 100644
index 0000000..5b7f4d4
--- /dev/null
+++ b/tools/alsa_midi/list.h
@@ -0,0 +1,903 @@
+/* -*- Mode: C ; c-basic-offset: 2 -*- */
+/*****************************************************************************
+ *
+ * Linux kernel header adapted for user-mode
+ * The 2.6.17-rt1 version was used.
+ *
+ * Original copyright holders of this code are unknown, they were not
+ * mentioned in the original file.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *****************************************************************************/
+
+#ifndef _LINUX_LIST_H
+#define _LINUX_LIST_H
+
+#include <stddef.h>
+
+#if !defined(offsetof)
+#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
+#endif
+
+/**
+ * container_of - cast a member of a structure out to the containing structure
+ * @ptr: the pointer to the member.
+ * @type: the type of the container struct this is embedded in.
+ * @member: the name of the member within the struct.
+ *
+ */
+#define container_of(ptr, type, member) ({ \
+ const typeof( ((type *)0)->member ) *__mptr = (ptr); \
+ (type *)( (char *)__mptr - offsetof(type,member) );})
+
+#define prefetch(x) (x = x)
+
+/*
+ * These are non-NULL pointers that will result in page faults
+ * under normal circumstances, used to verify that nobody uses
+ * non-initialized list entries.
+ */
+#define LIST_POISON1 ((void *) 0x00100100)
+#define LIST_POISON2 ((void *) 0x00200200)
+
+/*
+ * Simple doubly linked list implementation.
+ *
+ * Some of the internal functions ("__xxx") are useful when
+ * manipulating whole lists rather than single entries, as
+ * sometimes we already know the next/prev entries and we can
+ * generate better code by using them directly rather than
+ * using the generic single-entry routines.
+ */
+
+struct list_head {
+ struct list_head *next, *prev;
+};
+
+#define LIST_HEAD_INIT(name) { &(name), &(name) }
+
+#define LIST_HEAD(name) \
+ struct list_head name = LIST_HEAD_INIT(name)
+
+static inline void INIT_LIST_HEAD(struct list_head *list)
+{
+ list->next = list;
+ list->prev = list;
+}
+
+/*
+ * Insert a new entry between two known consecutive entries.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void __list_add(struct list_head *new,
+ struct list_head *prev,
+ struct list_head *next)
+{
+ next->prev = new;
+ new->next = next;
+ new->prev = prev;
+ prev->next = new;
+}
+
+/**
+ * list_add - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it after
+ *
+ * Insert a new entry after the specified head.
+ * This is good for implementing stacks.
+ */
+static inline void list_add(struct list_head *new, struct list_head *head)
+{
+ __list_add(new, head, head->next);
+}
+
+/**
+ * list_add_tail - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it before
+ *
+ * Insert a new entry before the specified head.
+ * This is useful for implementing queues.
+ */
+static inline void list_add_tail(struct list_head *new, struct list_head *head)
+{
+ __list_add(new, head->prev, head);
+}
+
+/*
+ * Insert a new entry between two known consecutive entries.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void __list_add_rcu(struct list_head * new,
+ struct list_head * prev, struct list_head * next)
+{
+ new->next = next;
+ new->prev = prev;
+// smp_wmb();
+ next->prev = new;
+ prev->next = new;
+}
+
+/**
+ * list_add_rcu - add a new entry to rcu-protected list
+ * @new: new entry to be added
+ * @head: list head to add it after
+ *
+ * Insert a new entry after the specified head.
+ * This is good for implementing stacks.
+ *
+ * The caller must take whatever precautions are necessary
+ * (such as holding appropriate locks) to avoid racing
+ * with another list-mutation primitive, such as list_add_rcu()
+ * or list_del_rcu(), running on this same list.
+ * However, it is perfectly legal to run concurrently with
+ * the _rcu list-traversal primitives, such as
+ * list_for_each_entry_rcu().
+ */
+static inline void list_add_rcu(struct list_head *new, struct list_head *head)
+{
+ __list_add_rcu(new, head, head->next);
+}
+
+/**
+ * list_add_tail_rcu - add a new entry to rcu-protected list
+ * @new: new entry to be added
+ * @head: list head to add it before
+ *
+ * Insert a new entry before the specified head.
+ * This is useful for implementing queues.
+ *
+ * The caller must take whatever precautions are necessary
+ * (such as holding appropriate locks) to avoid racing
+ * with another list-mutation primitive, such as list_add_tail_rcu()
+ * or list_del_rcu(), running on this same list.
+ * However, it is perfectly legal to run concurrently with
+ * the _rcu list-traversal primitives, such as
+ * list_for_each_entry_rcu().
+ */
+static inline void list_add_tail_rcu(struct list_head *new,
+ struct list_head *head)
+{
+ __list_add_rcu(new, head->prev, head);
+}
+
+/*
+ * Delete a list entry by making the prev/next entries
+ * point to each other.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void __list_del(struct list_head * prev, struct list_head * next)
+{
+ next->prev = prev;
+ prev->next = next;
+}
+
+/**
+ * list_del - deletes entry from list.
+ * @entry: the element to delete from the list.
+ * Note: list_empty on entry does not return true after this, the entry is
+ * in an undefined state.
+ */
+static inline void list_del(struct list_head *entry)
+{
+ __list_del(entry->prev, entry->next);
+ entry->next = LIST_POISON1;
+ entry->prev = LIST_POISON2;
+}
+
+/**
+ * list_del_rcu - deletes entry from list without re-initialization
+ * @entry: the element to delete from the list.
+ *
+ * Note: list_empty on entry does not return true after this,
+ * the entry is in an undefined state. It is useful for RCU based
+ * lockfree traversal.
+ *
+ * In particular, it means that we can not poison the forward
+ * pointers that may still be used for walking the list.
+ *
+ * The caller must take whatever precautions are necessary
+ * (such as holding appropriate locks) to avoid racing
+ * with another list-mutation primitive, such as list_del_rcu()
+ * or list_add_rcu(), running on this same list.
+ * However, it is perfectly legal to run concurrently with
+ * the _rcu list-traversal primitives, such as
+ * list_for_each_entry_rcu().
+ *
+ * Note that the caller is not permitted to immediately free
+ * the newly deleted entry. Instead, either synchronize_rcu()
+ * or call_rcu() must be used to defer freeing until an RCU
+ * grace period has elapsed.
+ */
+static inline void list_del_rcu(struct list_head *entry)
+{
+ __list_del(entry->prev, entry->next);
+ entry->prev = LIST_POISON2;
+}
+
+/*
+ * list_replace_rcu - replace old entry by new one
+ * @old : the element to be replaced
+ * @new : the new element to insert
+ *
+ * The old entry will be replaced with the new entry atomically.
+ */
+static inline void list_replace_rcu(struct list_head *old,
+ struct list_head *new)
+{
+ new->next = old->next;
+ new->prev = old->prev;
+// smp_wmb();
+ new->next->prev = new;
+ new->prev->next = new;
+ old->prev = LIST_POISON2;
+}
+
+/**
+ * list_del_init - deletes entry from list and reinitialize it.
+ * @entry: the element to delete from the list.
+ */
+static inline void list_del_init(struct list_head *entry)
+{
+ __list_del(entry->prev, entry->next);
+ INIT_LIST_HEAD(entry);
+}
+
+/**
+ * list_move - delete from one list and add as another's head
+ * @list: the entry to move
+ * @head: the head that will precede our entry
+ */
+static inline void list_move(struct list_head *list, struct list_head *head)
+{
+ __list_del(list->prev, list->next);
+ list_add(list, head);
+}
+
+/**
+ * list_move_tail - delete from one list and add as another's tail
+ * @list: the entry to move
+ * @head: the head that will follow our entry
+ */
+static inline void list_move_tail(struct list_head *list,
+ struct list_head *head)
+{
+ __list_del(list->prev, list->next);
+ list_add_tail(list, head);
+}
+
+/**
+ * list_empty - tests whether a list is empty
+ * @head: the list to test.
+ */
+static inline int list_empty(const struct list_head *head)
+{
+ return head->next == head;
+}
+
+/**
+ * list_empty_careful - tests whether a list is
+ * empty _and_ checks that no other CPU might be
+ * in the process of still modifying either member
+ *
+ * NOTE: using list_empty_careful() without synchronization
+ * can only be safe if the only activity that can happen
+ * to the list entry is list_del_init(). Eg. it cannot be used
+ * if another CPU could re-list_add() it.
+ *
+ * @head: the list to test.
+ */
+static inline int list_empty_careful(const struct list_head *head)
+{
+ struct list_head *next = head->next;
+ return (next == head) && (next == head->prev);
+}
+
+static inline void __list_splice(struct list_head *list,
+ struct list_head *head)
+{
+ struct list_head *first = list->next;
+ struct list_head *last = list->prev;
+ struct list_head *at = head->next;
+
+ first->prev = head;
+ head->next = first;
+
+ last->next = at;
+ at->prev = last;
+}
+
+/**
+ * list_splice - join two lists
+ * @list: the new list to add.
+ * @head: the place to add it in the first list.
+ */
+static inline void list_splice(struct list_head *list, struct list_head *head)
+{
+ if (!list_empty(list))
+ __list_splice(list, head);
+}
+
+/**
+ * list_splice_init - join two lists and reinitialise the emptied list.
+ * @list: the new list to add.
+ * @head: the place to add it in the first list.
+ *
+ * The list at @list is reinitialised
+ */
+static inline void list_splice_init(struct list_head *list,
+ struct list_head *head)
+{
+ if (!list_empty(list)) {
+ __list_splice(list, head);
+ INIT_LIST_HEAD(list);
+ }
+}
+
+/**
+ * list_entry - get the struct for this entry
+ * @ptr: the &struct list_head pointer.
+ * @type: the type of the struct this is embedded in.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_entry(ptr, type, member) \
+ container_of(ptr, type, member)
+
+/**
+ * list_for_each - iterate over a list
+ * @pos: the &struct list_head to use as a loop counter.
+ * @head: the head for your list.
+ */
+#define list_for_each(pos, head) \
+ for (pos = (head)->next; prefetch(pos->next), pos != (head); \
+ pos = pos->next)
+
+/**
+ * __list_for_each - iterate over a list
+ * @pos: the &struct list_head to use as a loop counter.
+ * @head: the head for your list.
+ *
+ * This variant differs from list_for_each() in that it's the
+ * simplest possible list iteration code, no prefetching is done.
+ * Use this for code that knows the list to be very short (empty
+ * or 1 entry) most of the time.
+ */
+#define __list_for_each(pos, head) \
+ for (pos = (head)->next; pos != (head); pos = pos->next)
+
+/**
+ * list_for_each_prev - iterate over a list backwards
+ * @pos: the &struct list_head to use as a loop counter.
+ * @head: the head for your list.
+ */
+#define list_for_each_prev(pos, head) \
+ for (pos = (head)->prev; prefetch(pos->prev), pos != (head); \
+ pos = pos->prev)
+
+/**
+ * list_for_each_safe - iterate over a list safe against removal of list entry
+ * @pos: the &struct list_head to use as a loop counter.
+ * @n: another &struct list_head to use as temporary storage
+ * @head: the head for your list.
+ */
+#define list_for_each_safe(pos, n, head) \
+ for (pos = (head)->next, n = pos->next; pos != (head); \
+ pos = n, n = pos->next)
+
+/**
+ * list_for_each_entry - iterate over list of given type
+ * @pos: the type * to use as a loop counter.
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_for_each_entry(pos, head, member) \
+ for (pos = list_entry((head)->next, typeof(*pos), member); \
+ prefetch(pos->member.next), &pos->member != (head); \
+ pos = list_entry(pos->member.next, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_reverse - iterate backwards over list of given type.
+ * @pos: the type * to use as a loop counter.
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_reverse(pos, head, member) \
+ for (pos = list_entry((head)->prev, typeof(*pos), member); \
+ prefetch(pos->member.prev), &pos->member != (head); \
+ pos = list_entry(pos->member.prev, typeof(*pos), member))
+
+/**
+ * list_prepare_entry - prepare a pos entry for use as a start point in
+ * list_for_each_entry_continue
+ * @pos: the type * to use as a start point
+ * @head: the head of the list
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_prepare_entry(pos, head, member) \
+ ((pos) ? : list_entry(head, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_continue - iterate over list of given type
+ * continuing after existing point
+ * @pos: the type * to use as a loop counter.
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_continue(pos, head, member) \
+ for (pos = list_entry(pos->member.next, typeof(*pos), member); \
+ prefetch(pos->member.next), &pos->member != (head); \
+ pos = list_entry(pos->member.next, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_from - iterate over list of given type
+ * continuing from existing point
+ * @pos: the type * to use as a loop counter.
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_from(pos, head, member) \
+ for (; prefetch(pos->member.next), &pos->member != (head); \
+ pos = list_entry(pos->member.next, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
+ * @pos: the type * to use as a loop counter.
+ * @n: another type * to use as temporary storage
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_safe(pos, n, head, member) \
+ for (pos = list_entry((head)->next, typeof(*pos), member), \
+ n = list_entry(pos->member.next, typeof(*pos), member); \
+ &pos->member != (head); \
+ pos = n, n = list_entry(n->member.next, typeof(*n), member))
+
+/**
+ * list_for_each_entry_safe_continue - iterate over list of given type
+ * continuing after existing point safe against removal of list entry
+ * @pos: the type * to use as a loop counter.
+ * @n: another type * to use as temporary storage
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_safe_continue(pos, n, head, member) \
+ for (pos = list_entry(pos->member.next, typeof(*pos), member), \
+ n = list_entry(pos->member.next, typeof(*pos), member); \
+ &pos->member != (head); \
+ pos = n, n = list_entry(n->member.next, typeof(*n), member))
+
+/**
+ * list_for_each_entry_safe_from - iterate over list of given type
+ * from existing point safe against removal of list entry
+ * @pos: the type * to use as a loop counter.
+ * @n: another type * to use as temporary storage
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_safe_from(pos, n, head, member) \
+ for (n = list_entry(pos->member.next, typeof(*pos), member); \
+ &pos->member != (head); \
+ pos = n, n = list_entry(n->member.next, typeof(*n), member))
+
+/**
+ * list_for_each_entry_safe_reverse - iterate backwards over list of given type safe against
+ * removal of list entry
+ * @pos: the type * to use as a loop counter.
+ * @n: another type * to use as temporary storage
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_safe_reverse(pos, n, head, member) \
+ for (pos = list_entry((head)->prev, typeof(*pos), member), \
+ n = list_entry(pos->member.prev, typeof(*pos), member); \
+ &pos->member != (head); \
+ pos = n, n = list_entry(n->member.prev, typeof(*n), member))
+
+/**
+ * list_for_each_rcu - iterate over an rcu-protected list
+ * @pos: the &struct list_head to use as a loop counter.
+ * @head: the head for your list.
+ *
+ * This list-traversal primitive may safely run concurrently with
+ * the _rcu list-mutation primitives such as list_add_rcu()
+ * as long as the traversal is guarded by rcu_read_lock().
+ */
+#define list_for_each_rcu(pos, head) \
+ for (pos = (head)->next; \
+ prefetch(rcu_dereference(pos)->next), pos != (head); \
+ pos = pos->next)
+
+#define __list_for_each_rcu(pos, head) \
+ for (pos = (head)->next; \
+ rcu_dereference(pos) != (head); \
+ pos = pos->next)
+
+/**
+ * list_for_each_safe_rcu - iterate over an rcu-protected list safe
+ * against removal of list entry
+ * @pos: the &struct list_head to use as a loop counter.
+ * @n: another &struct list_head to use as temporary storage
+ * @head: the head for your list.
+ *
+ * This list-traversal primitive may safely run concurrently with
+ * the _rcu list-mutation primitives such as list_add_rcu()
+ * as long as the traversal is guarded by rcu_read_lock().
+ */
+#define list_for_each_safe_rcu(pos, n, head) \
+ for (pos = (head)->next; \
+ n = rcu_dereference(pos)->next, pos != (head); \
+ pos = n)
+
+/**
+ * list_for_each_entry_rcu - iterate over rcu list of given type
+ * @pos: the type * to use as a loop counter.
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ *
+ * This list-traversal primitive may safely run concurrently with
+ * the _rcu list-mutation primitives such as list_add_rcu()
+ * as long as the traversal is guarded by rcu_read_lock().
+ */
+#define list_for_each_entry_rcu(pos, head, member) \
+ for (pos = list_entry((head)->next, typeof(*pos), member); \
+ prefetch(rcu_dereference(pos)->member.next), \
+ &pos->member != (head); \
+ pos = list_entry(pos->member.next, typeof(*pos), member))
+
+
+/**
+ * list_for_each_continue_rcu - iterate over an rcu-protected list
+ * continuing after existing point.
+ * @pos: the &struct list_head to use as a loop counter.
+ * @head: the head for your list.
+ *
+ * This list-traversal primitive may safely run concurrently with
+ * the _rcu list-mutation primitives such as list_add_rcu()
+ * as long as the traversal is guarded by rcu_read_lock().
+ */
+#define list_for_each_continue_rcu(pos, head) \
+ for ((pos) = (pos)->next; \
+ prefetch(rcu_dereference((pos))->next), (pos) != (head); \
+ (pos) = (pos)->next)
+
+/*
+ * Double linked lists with a single pointer list head.
+ * Mostly useful for hash tables where the two pointer list head is
+ * too wasteful.
+ * You lose the ability to access the tail in O(1).
+ */
+
+struct hlist_head {
+ struct hlist_node *first;
+};
+
+struct hlist_node {
+ struct hlist_node *next, **pprev;
+};
+
+#define HLIST_HEAD_INIT { .first = NULL }
+#define HLIST_HEAD(name) struct hlist_head name = { .first = NULL }
+#define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL)
+static inline void INIT_HLIST_NODE(struct hlist_node *h)
+{
+ h->next = NULL;
+ h->pprev = NULL;
+}
+
+static inline int hlist_unhashed(const struct hlist_node *h)
+{
+ return !h->pprev;
+}
+
+static inline int hlist_empty(const struct hlist_head *h)
+{
+ return !h->first;
+}
+
+static inline void __hlist_del(struct hlist_node *n)
+{
+ struct hlist_node *next = n->next;
+ struct hlist_node **pprev = n->pprev;
+ *pprev = next;
+ if (next)
+ next->pprev = pprev;
+}
+
+static inline void hlist_del(struct hlist_node *n)
+{
+ __hlist_del(n);
+ n->next = LIST_POISON1;
+ n->pprev = LIST_POISON2;
+}
+
+/**
+ * hlist_del_rcu - deletes entry from hash list without re-initialization
+ * @n: the element to delete from the hash list.
+ *
+ * Note: list_unhashed() on entry does not return true after this,
+ * the entry is in an undefined state. It is useful for RCU based
+ * lockfree traversal.
+ *
+ * In particular, it means that we can not poison the forward
+ * pointers that may still be used for walking the hash list.
+ *
+ * The caller must take whatever precautions are necessary
+ * (such as holding appropriate locks) to avoid racing
+ * with another list-mutation primitive, such as hlist_add_head_rcu()
+ * or hlist_del_rcu(), running on this same list.
+ * However, it is perfectly legal to run concurrently with
+ * the _rcu list-traversal primitives, such as
+ * hlist_for_each_entry().
+ */
+static inline void hlist_del_rcu(struct hlist_node *n)
+{
+ __hlist_del(n);
+ n->pprev = LIST_POISON2;
+}
+
+static inline void hlist_del_init(struct hlist_node *n)
+{
+ if (!hlist_unhashed(n)) {
+ __hlist_del(n);
+ INIT_HLIST_NODE(n);
+ }
+}
+
+/*
+ * hlist_replace_rcu - replace old entry by new one
+ * @old : the element to be replaced
+ * @new : the new element to insert
+ *
+ * The old entry will be replaced with the new entry atomically.
+ */
+static inline void hlist_replace_rcu(struct hlist_node *old,
+ struct hlist_node *new)
+{
+ struct hlist_node *next = old->next;
+
+ new->next = next;
+ new->pprev = old->pprev;
+// smp_wmb();
+ if (next)
+ new->next->pprev = &new->next;
+ *new->pprev = new;
+ old->pprev = LIST_POISON2;
+}
+
+static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h)
+{
+ struct hlist_node *first = h->first;
+ n->next = first;
+ if (first)
+ first->pprev = &n->next;
+ h->first = n;
+ n->pprev = &h->first;
+}
+
+
+/**
+ * hlist_add_head_rcu - adds the specified element to the specified hlist,
+ * while permitting racing traversals.
+ * @n: the element to add to the hash list.
+ * @h: the list to add to.
+ *
+ * The caller must take whatever precautions are necessary
+ * (such as holding appropriate locks) to avoid racing
+ * with another list-mutation primitive, such as hlist_add_head_rcu()
+ * or hlist_del_rcu(), running on this same list.
+ * However, it is perfectly legal to run concurrently with
+ * the _rcu list-traversal primitives, such as
+ * hlist_for_each_entry_rcu(), used to prevent memory-consistency
+ * problems on Alpha CPUs. Regardless of the type of CPU, the
+ * list-traversal primitive must be guarded by rcu_read_lock().
+ */
+static inline void hlist_add_head_rcu(struct hlist_node *n,
+ struct hlist_head *h)
+{
+ struct hlist_node *first = h->first;
+ n->next = first;
+ n->pprev = &h->first;
+// smp_wmb();
+ if (first)
+ first->pprev = &n->next;
+ h->first = n;
+}
+
+/* next must be != NULL */
+static inline void hlist_add_before(struct hlist_node *n,
+ struct hlist_node *next)
+{
+ n->pprev = next->pprev;
+ n->next = next;
+ next->pprev = &n->next;
+ *(n->pprev) = n;
+}
+
+static inline void hlist_add_after(struct hlist_node *n,
+ struct hlist_node *next)
+{
+ next->next = n->next;
+ n->next = next;
+ next->pprev = &n->next;
+
+ if(next->next)
+ next->next->pprev = &next->next;
+}
+
+/**
+ * hlist_add_before_rcu - adds the specified element to the specified hlist
+ * before the specified node while permitting racing traversals.
+ * @n: the new element to add to the hash list.
+ * @next: the existing element to add the new element before.
+ *
+ * The caller must take whatever precautions are necessary
+ * (such as holding appropriate locks) to avoid racing
+ * with another list-mutation primitive, such as hlist_add_head_rcu()
+ * or hlist_del_rcu(), running on this same list.
+ * However, it is perfectly legal to run concurrently with
+ * the _rcu list-traversal primitives, such as
+ * hlist_for_each_entry_rcu(), used to prevent memory-consistency
+ * problems on Alpha CPUs.
+ */
+static inline void hlist_add_before_rcu(struct hlist_node *n,
+ struct hlist_node *next)
+{
+ n->pprev = next->pprev;
+ n->next = next;
+// smp_wmb();
+ next->pprev = &n->next;
+ *(n->pprev) = n;
+}
+
+/**
+ * hlist_add_after_rcu - adds the specified element to the specified hlist
+ * after the specified node while permitting racing traversals.
+ * @prev: the existing element to add the new element after.
+ * @n: the new element to add to the hash list.
+ *
+ * The caller must take whatever precautions are necessary
+ * (such as holding appropriate locks) to avoid racing
+ * with another list-mutation primitive, such as hlist_add_head_rcu()
+ * or hlist_del_rcu(), running on this same list.
+ * However, it is perfectly legal to run concurrently with
+ * the _rcu list-traversal primitives, such as
+ * hlist_for_each_entry_rcu(), used to prevent memory-consistency
+ * problems on Alpha CPUs.
+ */
+static inline void hlist_add_after_rcu(struct hlist_node *prev,
+ struct hlist_node *n)
+{
+ n->next = prev->next;
+ n->pprev = &prev->next;
+// smp_wmb();
+ prev->next = n;
+ if (n->next)
+ n->next->pprev = &n->next;
+}
+
+#define hlist_entry(ptr, type, member) container_of(ptr,type,member)
+
+#define hlist_for_each(pos, head) \
+ for (pos = (head)->first; pos && ({ prefetch(pos->next); 1; }); \
+ pos = pos->next)
+
+#define hlist_for_each_safe(pos, n, head) \
+ for (pos = (head)->first; pos && ({ n = pos->next; 1; }); \
+ pos = n)
+
+/**
+ * hlist_for_each_entry - iterate over list of given type
+ * @tpos: the type * to use as a loop counter.
+ * @pos: the &struct hlist_node to use as a loop counter.
+ * @head: the head for your list.
+ * @member: the name of the hlist_node within the struct.
+ */
+#define hlist_for_each_entry(tpos, pos, head, member) \
+ for (pos = (head)->first; \
+ pos && ({ prefetch(pos->next); 1;}) && \
+ ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
+ pos = pos->next)
+
+/**
+ * hlist_for_each_entry_continue - iterate over a hlist continuing after existing point
+ * @tpos: the type * to use as a loop counter.
+ * @pos: the &struct hlist_node to use as a loop counter.
+ * @member: the name of the hlist_node within the struct.
+ */
+#define hlist_for_each_entry_continue(tpos, pos, member) \
+ for (pos = (pos)->next; \
+ pos && ({ prefetch(pos->next); 1;}) && \
+ ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
+ pos = pos->next)
+
+/**
+ * hlist_for_each_entry_from - iterate over a hlist continuing from existing point
+ * @tpos: the type * to use as a loop counter.
+ * @pos: the &struct hlist_node to use as a loop counter.
+ * @member: the name of the hlist_node within the struct.
+ */
+#define hlist_for_each_entry_from(tpos, pos, member) \
+ for (; pos && ({ prefetch(pos->next); 1;}) && \
+ ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
+ pos = pos->next)
+
+/**
+ * hlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry
+ * @tpos: the type * to use as a loop counter.
+ * @pos: the &struct hlist_node to use as a loop counter.
+ * @n: another &struct hlist_node to use as temporary storage
+ * @head: the head for your list.
+ * @member: the name of the hlist_node within the struct.
+ */
+#define hlist_for_each_entry_safe(tpos, pos, n, head, member) \
+ for (pos = (head)->first; \
+ pos && ({ n = pos->next; 1; }) && \
+ ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
+ pos = n)
+
+/**
+ * hlist_for_each_entry_rcu - iterate over rcu list of given type
+ * @tpos: the type * to use as a loop counter.
+ * @pos: the &struct hlist_node to use as a loop counter.
+ * @head: the head for your list.
+ * @member: the name of the hlist_node within the struct.
+ *
+ * This list-traversal primitive may safely run concurrently with
+ * the _rcu list-mutation primitives such as hlist_add_head_rcu()
+ * as long as the traversal is guarded by rcu_read_lock().
+ */
+#define hlist_for_each_entry_rcu(tpos, pos, head, member) \
+ for (pos = (head)->first; \
+ rcu_dereference(pos) && ({ prefetch(pos->next); 1;}) && \
+ ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
+ pos = pos->next)
+
+#endif
+
+/**
+ * __list_sort - sort the list using given comparator with merge-sort algorithm
+ * @head: is a head of the list to be sorted
+ * @member_offset: is machine offset inside the list entry structure to the
+ * field of type struct list_head which links that entry with
+ * the list.
+ */
+extern void __list_sort(struct list_head * head,
+ int member_offset,
+ int (*comparator)(void*,void*));
+
+/**
+ * list_sort - wrapper for __list_sort
+ * @head: is a head of the list to be sorted
+ * @type: is the type of list entry
+ * @member: is the name of the field inside entry that links that entry with
+ * other entries in the list.
+ * @comaprator: function comparing two entries, should return value lesser
+ * than 0 when the first argument is lesser than the second one.
+ */
+#define list_sort(head,type,member,comparator) \
+ ({ \
+ __list_sort(head, \
+ offsetof(type, member), \
+ (int (*)(void*, void*)) comparator); \
+ })
+
+void test_list_sort(void);
diff --git a/tools/alsa_midi/port.c b/tools/alsa_midi/port.c
new file mode 100644
index 0000000..fd35864
--- /dev/null
+++ b/tools/alsa_midi/port.c
@@ -0,0 +1,217 @@
+/*
+ * ALSA SEQ < - > JACK MIDI bridge
+ *
+ * Copyright (c) 2006,2007 Dmitry S. Baikov <c0ff@konstruktiv.org>
+ * Copyright (c) 2007,2008,2009 Nedko Arnaudov <nedko@arnaudov.name>
+ * Copyright (c) 2009,2010 Paul Davis <paul@linuxaudiosystems.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdbool.h>
+#include <ctype.h>
+#include <semaphore.h>
+#include <alsa/asoundlib.h>
+#include <jack/jack.h>
+#include <jack/ringbuffer.h>
+
+#include "list.h"
+#include "a2j.h"
+#include "port_hash.h"
+#include "port.h"
+
+/* This should be part of JACK API */
+#define JACK_IS_VALID_PORT_NAME_CHAR(c) \
+ (isalnum(c) || \
+ (c) == '/' || \
+ (c) == '_' || \
+ (c) == '(' || \
+ (c) == ')' || \
+ (c) == '-' || \
+ (c) == '[' || \
+ (c) == ']')
+
+static
+int
+a2j_alsa_connect_from (struct a2j * self, int client, int port)
+{
+ snd_seq_port_subscribe_t* sub;
+ snd_seq_addr_t seq_addr;
+ int err;
+
+ snd_seq_port_subscribe_alloca (&sub);
+ seq_addr.client = client;
+ seq_addr.port = port;
+ snd_seq_port_subscribe_set_sender (sub, &seq_addr);
+ seq_addr.client = self->client_id;
+ seq_addr.port = self->port_id;
+ snd_seq_port_subscribe_set_dest (sub, &seq_addr);
+
+ snd_seq_port_subscribe_set_time_update (sub, 1);
+ snd_seq_port_subscribe_set_queue (sub, self->queue);
+ snd_seq_port_subscribe_set_time_real (sub, 1);
+
+ if ((err = snd_seq_subscribe_port (self->seq, sub))) {
+ a2j_error ("can't subscribe to %d:%d - %s", client, port, snd_strerror(err));
+ }
+
+ return err;
+}
+
+void
+a2j_port_setdead (a2j_port_hash_t hash, snd_seq_addr_t addr)
+{
+ struct a2j_port *port = a2j_port_get(hash, addr);
+
+ if (port) {
+ port->is_dead = true; // see jack_process_internal
+ } else {
+ a2j_debug("port_setdead: not found (%d:%d)", addr.client, addr.port);
+ }
+}
+
+void
+a2j_port_free (struct a2j_port * port)
+{
+ // snd_seq_disconnect_from (self->seq, self->port_id, port->remote.client, port->remote.port);
+ // snd_seq_disconnect_to (self->seq, self->port_id, port->remote.client, port->remote.port);
+
+ if (port->inbound_events) {
+ jack_ringbuffer_free (port->inbound_events);
+ }
+
+ if (port->jack_port != JACK_INVALID_PORT && !port->a2j_ptr->finishing) {
+ jack_port_unregister (port->a2j_ptr->jack_client, port->jack_port);
+ }
+
+ free (port);
+}
+
+void
+a2j_port_fill_name (struct a2j_port * port_ptr, int dir, snd_seq_client_info_t * client_info_ptr,
+ const snd_seq_port_info_t * port_info_ptr, bool make_unique)
+{
+ char *c;
+
+ if (make_unique) {
+ snprintf (port_ptr->name,
+ sizeof(port_ptr->name),
+ "%s [%d] %s %s",
+ snd_seq_client_info_get_name(client_info_ptr),
+ snd_seq_client_info_get_client(client_info_ptr),
+ snd_seq_port_info_get_name(port_info_ptr),
+ (dir == A2J_PORT_CAPTURE ? "in" : "out"));
+ } else {
+ snprintf (port_ptr->name,
+ sizeof(port_ptr->name),
+ "%s %s %s",
+ snd_seq_client_info_get_name(client_info_ptr),
+ snd_seq_port_info_get_name(port_info_ptr),
+ (dir == A2J_PORT_CAPTURE ? "in" : "out"));
+ }
+
+ // replace all offending characters with ' '
+ for (c = port_ptr->name; *c; ++c) {
+ if (!JACK_IS_VALID_PORT_NAME_CHAR(*c)) {
+ *c = ' ';
+ }
+ }
+}
+
+struct a2j_port *
+a2j_port_create (struct a2j * self, int dir, snd_seq_addr_t addr, const snd_seq_port_info_t * info)
+{
+ struct a2j_port *port;
+ int err;
+ int client;
+ snd_seq_client_info_t * client_info_ptr;
+ int jack_caps;
+ struct a2j_stream * stream_ptr;
+
+ stream_ptr = &self->stream[dir];
+
+ if ((err = snd_seq_client_info_malloc (&client_info_ptr)) != 0) {
+ a2j_error("Failed to allocate client info");
+ goto fail;
+ }
+
+ client = snd_seq_port_info_get_client (info);
+
+ err = snd_seq_get_any_client_info (self->seq, client, client_info_ptr);
+ if (err != 0) {
+ a2j_error("Failed to get client info");
+ goto fail_free_client_info;
+ }
+
+ a2j_debug ("client name: '%s'", snd_seq_client_info_get_name(client_info_ptr));
+ a2j_debug ("port name: '%s'", snd_seq_port_info_get_name(info));
+
+ port = calloc (1, sizeof(struct a2j_port));
+ if (!port) {
+ goto fail_free_client_info;
+ }
+
+ port->a2j_ptr = self;
+ port->jack_port = JACK_INVALID_PORT;
+ port->remote = addr;
+
+ a2j_port_fill_name (port, dir, client_info_ptr, info, false);
+
+ /* Add port to list early, before registering to JACK, so map functionality is guaranteed to work during port registration */
+ list_add_tail (&port->siblings, &stream_ptr->list);
+
+ if (dir == A2J_PORT_CAPTURE) {
+ jack_caps = JackPortIsOutput;
+ } else {
+ jack_caps = JackPortIsInput;
+ }
+
+ /* mark anything that looks like a hardware port as physical&terminal */
+ if (snd_seq_port_info_get_type (info) & (SND_SEQ_PORT_TYPE_HARDWARE|SND_SEQ_PORT_TYPE_PORT|SND_SEQ_PORT_TYPE_SPECIFIC)) {
+ jack_caps |= JackPortIsPhysical|JackPortIsTerminal;
+ }
+
+ port->jack_port = jack_port_register (self->jack_client, port->name, JACK_DEFAULT_MIDI_TYPE, jack_caps, 0);
+ if (port->jack_port == JACK_INVALID_PORT) {
+ a2j_error("jack_port_register() failed for '%s'", port->name);
+ goto fail_free_port;
+ }
+
+ if (dir == A2J_PORT_CAPTURE) {
+ err = a2j_alsa_connect_from (self, port->remote.client, port->remote.port);
+ } else {
+ err = snd_seq_connect_to (self->seq, self->port_id, port->remote.client, port->remote.port);
+ }
+
+ if (err) {
+ a2j_info("port skipped: %s", port->name);
+ goto fail_free_port;
+ }
+
+ port->inbound_events = jack_ringbuffer_create(MAX_EVENT_SIZE*16);
+
+ a2j_info("port created: %s", port->name);
+ return port;
+
+ fail_free_port:
+ list_del (&port->siblings);
+
+ a2j_port_free (port);
+
+ fail_free_client_info:
+ snd_seq_client_info_free (client_info_ptr);
+
+ fail:
+ return NULL;
+}
diff --git a/tools/alsa_midi/port.h b/tools/alsa_midi/port.h
new file mode 100644
index 0000000..07169a3
--- /dev/null
+++ b/tools/alsa_midi/port.h
@@ -0,0 +1,29 @@
+/* -*- Mode: C ; c-basic-offset: 2 -*- */
+/*
+ * ALSA SEQ < - > JACK MIDI bridge
+ *
+ * Copyright (c) 2006,2007 Dmitry S. Baikov <c0ff@konstruktiv.org>
+ * Copyright (c) 2007,2008,2009 Nedko Arnaudov <nedko@arnaudov.name>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PORT_H__757ADD0F_5E53_41F7_8B7F_8119C5E8A9F1__INCLUDED
+#define PORT_H__757ADD0F_5E53_41F7_8B7F_8119C5E8A9F1__INCLUDED
+
+struct a2j_port* a2j_port_create (struct a2j * self, int dir, snd_seq_addr_t addr, const snd_seq_port_info_t * info);
+void a2j_port_setdead (a2j_port_hash_t hash, snd_seq_addr_t addr);
+void a2j_port_free (struct a2j_port * port);
+
+#endif /* #ifndef PORT_H__757ADD0F_5E53_41F7_8B7F_8119C5E8A9F1__INCLUDED */
diff --git a/tools/alsa_midi/port_hash.c b/tools/alsa_midi/port_hash.c
new file mode 100644
index 0000000..cc9c5c6
--- /dev/null
+++ b/tools/alsa_midi/port_hash.c
@@ -0,0 +1,63 @@
+/* -*- Mode: C ; c-basic-offset: 2 -*- */
+/*
+ * ALSA SEQ < - > JACK MIDI bridge
+ *
+ * Copyright (c) 2006,2007 Dmitry S. Baikov <c0ff@konstruktiv.org>
+ * Copyright (c) 2007,2008,2009 Nedko Arnaudov <nedko@arnaudov.name>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdbool.h>
+#include <semaphore.h>
+#include <alsa/asoundlib.h>
+#include <jack/jack.h>
+#include <jack/ringbuffer.h>
+
+#include "list.h"
+#include "a2j.h"
+#include "port_hash.h"
+
+static inline
+int
+a2j_port_hash(
+ snd_seq_addr_t addr)
+{
+ return (addr.client + addr.port) % PORT_HASH_SIZE;
+}
+
+struct a2j_port *
+a2j_port_get(
+ a2j_port_hash_t hash,
+ snd_seq_addr_t addr)
+{
+ struct a2j_port **pport = &hash[a2j_port_hash(addr)];
+ while (*pport) {
+ struct a2j_port *port = *pport;
+ if (port->remote.client == addr.client && port->remote.port == addr.port)
+ return port;
+ pport = &port->next;
+ }
+ return NULL;
+}
+
+void
+a2j_port_insert(
+ a2j_port_hash_t hash,
+ struct a2j_port * port)
+{
+ struct a2j_port **pport = &hash[a2j_port_hash(port->remote)];
+ port->next = *pport;
+ *pport = port;
+}
diff --git a/tools/alsa_midi/port_hash.h b/tools/alsa_midi/port_hash.h
new file mode 100644
index 0000000..ec21f11
--- /dev/null
+++ b/tools/alsa_midi/port_hash.h
@@ -0,0 +1,35 @@
+/* -*- Mode: C ; c-basic-offset: 2 -*- */
+/*
+ * ALSA SEQ < - > JACK MIDI bridge
+ *
+ * Copyright (c) 2006,2007 Dmitry S. Baikov <c0ff@konstruktiv.org>
+ * Copyright (c) 2007,2008,2009 Nedko Arnaudov <nedko@arnaudov.name>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PORT_HASH_H__A44CBCD6_E075_49CB_8F73_DF9772511D55__INCLUDED
+#define PORT_HASH_H__A44CBCD6_E075_49CB_8F73_DF9772511D55__INCLUDED
+
+void
+a2j_port_insert(
+ a2j_port_hash_t hash,
+ struct a2j_port * port);
+
+struct a2j_port *
+a2j_port_get(
+ a2j_port_hash_t hash,
+ snd_seq_addr_t addr);
+
+#endif /* #ifndef PORT_HASH_H__A44CBCD6_E075_49CB_8F73_DF9772511D55__INCLUDED */
diff --git a/tools/alsa_midi/port_thread.c b/tools/alsa_midi/port_thread.c
new file mode 100644
index 0000000..98df0e2
--- /dev/null
+++ b/tools/alsa_midi/port_thread.c
@@ -0,0 +1,235 @@
+/* -*- Mode: C ; c-basic-offset: 2 -*- */
+/*
+ * ALSA SEQ < - > JACK MIDI bridge
+ *
+ * Copyright (c) 2006,2007 Dmitry S. Baikov <c0ff@konstruktiv.org>
+ * Copyright (c) 2007,2008,2009 Nedko Arnaudov <nedko@arnaudov.name>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdbool.h>
+#include <semaphore.h>
+#include <alsa/asoundlib.h>
+#include <jack/jack.h>
+#include <jack/ringbuffer.h>
+
+#include "list.h"
+#include "a2j.h"
+#include "port.h"
+#include "port_hash.h"
+#include "port_thread.h"
+
+struct a2j_port *
+a2j_find_port_by_addr(
+ struct a2j_stream * stream_ptr,
+ snd_seq_addr_t addr)
+{
+ struct list_head * node_ptr;
+ struct a2j_port * port_ptr;
+
+ list_for_each(node_ptr, &stream_ptr->list)
+ {
+ port_ptr = list_entry(node_ptr, struct a2j_port, siblings);
+ if (port_ptr->remote.client == addr.client && port_ptr->remote.port == addr.port)
+ {
+ return port_ptr;
+ }
+ }
+
+ return NULL;
+}
+
+struct a2j_port *
+a2j_find_port_by_jack_port_name(
+ struct a2j_stream * stream_ptr,
+ const char * jack_port)
+{
+ struct list_head * node_ptr;
+ struct a2j_port * port_ptr;
+
+ list_for_each(node_ptr, &stream_ptr->list)
+ {
+ port_ptr = list_entry(node_ptr, struct a2j_port, siblings);
+ if (strcmp(port_ptr->name, jack_port) == 0)
+ {
+ return port_ptr;
+ }
+ }
+
+ return NULL;
+}
+
+/*
+ * ==================== Port add/del handling thread ==============================
+ */
+
+static
+void
+a2j_update_port_type (struct a2j * self, int dir, snd_seq_addr_t addr, int caps, const snd_seq_port_info_t * info)
+{
+ struct a2j_stream * stream_ptr;
+ int alsa_mask;
+ struct a2j_port * port_ptr;
+
+ a2j_debug("update_port_type(%d:%d)", addr.client, addr.port);
+
+ stream_ptr = &self->stream[dir];
+ port_ptr = a2j_find_port_by_addr(stream_ptr, addr);
+
+ if (dir == A2J_PORT_CAPTURE) {
+ alsa_mask = SND_SEQ_PORT_CAP_SUBS_READ;
+ } else {
+ alsa_mask = SND_SEQ_PORT_CAP_SUBS_WRITE;
+ }
+
+ if (port_ptr != NULL && (caps & alsa_mask) != alsa_mask) {
+ a2j_debug("setdead: %s", port_ptr->name);
+ port_ptr->is_dead = true;
+ }
+
+ if (port_ptr == NULL && (caps & alsa_mask) == alsa_mask) {
+ if(jack_ringbuffer_write_space(stream_ptr->new_ports) >= sizeof(port_ptr)) {
+ port_ptr = a2j_port_create (self, dir, addr, info);
+ if (port_ptr != NULL) {
+ jack_ringbuffer_write(stream_ptr->new_ports, (char *)&port_ptr, sizeof(port_ptr));
+ }
+ } else {
+ a2j_error( "dropping new port event... increase MAX_PORTS" );
+ }
+ }
+}
+
+void
+a2j_update_port (struct a2j * self, snd_seq_addr_t addr, const snd_seq_port_info_t * info)
+{
+ unsigned int port_caps = snd_seq_port_info_get_capability(info);
+ unsigned int port_type = snd_seq_port_info_get_type(info);
+
+ a2j_debug("port %u:%u", addr.client, addr.port);
+ a2j_debug("port type: 0x%08X", port_type);
+ a2j_debug("port caps: 0x%08X", port_caps);
+
+ if (port_type & SND_SEQ_PORT_TYPE_SPECIFIC) {
+ a2j_debug("SPECIFIC");
+ }
+
+ if (port_type & SND_SEQ_PORT_TYPE_MIDI_GENERIC) {
+ a2j_debug("MIDI_GENERIC");
+ }
+
+ if (port_type & SND_SEQ_PORT_TYPE_MIDI_GM) {
+ a2j_debug("MIDI_GM");
+ }
+
+ if (port_type & SND_SEQ_PORT_TYPE_MIDI_GS) {
+ a2j_debug("MIDI_GS");
+ }
+
+ if (port_type & SND_SEQ_PORT_TYPE_MIDI_XG) {
+ a2j_debug("MIDI_XG");
+ }
+
+ if (port_type & SND_SEQ_PORT_TYPE_MIDI_MT32) {
+ a2j_debug("MIDI_MT32");
+ }
+
+ if (port_type & SND_SEQ_PORT_TYPE_MIDI_GM2) {
+ a2j_debug("MIDI_GM2");
+ }
+
+ if (port_type & SND_SEQ_PORT_TYPE_SYNTH) {
+ a2j_debug("SYNTH");
+ }
+
+ if (port_type & SND_SEQ_PORT_TYPE_DIRECT_SAMPLE) {
+ a2j_debug("DIRECT_SAMPLE");
+ }
+
+ if (port_type & SND_SEQ_PORT_TYPE_SAMPLE) {
+ a2j_debug("SAMPLE");
+ }
+
+ if (port_type & SND_SEQ_PORT_TYPE_HARDWARE) {
+ a2j_debug("HARDWARE");
+ }
+
+ if (port_type & SND_SEQ_PORT_TYPE_SOFTWARE) {
+ a2j_debug("SOFTWARE");
+ }
+
+ if (port_type & SND_SEQ_PORT_TYPE_SYNTHESIZER) {
+ a2j_debug("SYNTHESIZER");
+ }
+
+ if (port_type & SND_SEQ_PORT_TYPE_PORT) {
+ a2j_debug("PORT");
+ }
+
+ if (port_type & SND_SEQ_PORT_TYPE_APPLICATION) {
+ a2j_debug("APPLICATION");
+ }
+
+ if (port_type == 0) {
+ a2j_debug("Ignoring port of type 0");
+ return;
+ }
+
+ if (port_caps & SND_SEQ_PORT_CAP_NO_EXPORT) {
+ a2j_debug("Ignoring no-export port");
+ return;
+ }
+
+ a2j_update_port_type (self, A2J_PORT_CAPTURE, addr, port_caps, info);
+ a2j_update_port_type (self, A2J_PORT_PLAYBACK, addr, port_caps, info);
+}
+
+void
+a2j_free_ports (jack_ringbuffer_t * ports)
+{
+ struct a2j_port *port;
+ int sz;
+
+ while ((sz = jack_ringbuffer_read (ports, (char*)&port, sizeof(port)))) {
+ assert (sz == sizeof(port));
+ a2j_info("port deleted: %s", port->name);
+ list_del (&port->siblings);
+ a2j_port_free(port);
+ }
+}
+
+void
+a2j_update_ports (struct a2j * self)
+{
+ snd_seq_addr_t addr;
+ int size;
+
+ while ((size = jack_ringbuffer_read(self->port_add, (char *)&addr, sizeof(addr))) != 0) {
+
+ snd_seq_port_info_t * info;
+ int err;
+
+ snd_seq_port_info_alloca(&info);
+
+ assert (size == sizeof(addr));
+ assert (addr.client != self->client_id);
+
+ if ((err = snd_seq_get_any_port_info(self->seq, addr.client, addr.port, info)) >= 0) {
+ a2j_update_port(self, addr, info);
+ } else {
+ a2j_port_setdead(self->stream[A2J_PORT_CAPTURE].port_hash, addr);
+ a2j_port_setdead(self->stream[A2J_PORT_PLAYBACK].port_hash, addr);
+ }
+ }
+}
diff --git a/tools/alsa_midi/port_thread.h b/tools/alsa_midi/port_thread.h
new file mode 100644
index 0000000..e69af7f
--- /dev/null
+++ b/tools/alsa_midi/port_thread.h
@@ -0,0 +1,49 @@
+/* -*- Mode: C ; c-basic-offset: 2 -*- */
+/*
+ * ALSA SEQ < - > JACK MIDI bridge
+ *
+ * Copyright (c) 2006,2007 Dmitry S. Baikov <c0ff@konstruktiv.org>
+ * Copyright (c) 2007,2008,2009 Nedko Arnaudov <nedko@arnaudov.name>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PORT_THREAD_H__1C6B5065_5556_4AC6_AA9F_44C32A9648C6__INCLUDED
+#define PORT_THREAD_H__1C6B5065_5556_4AC6_AA9F_44C32A9648C6__INCLUDED
+
+void
+a2j_update_port(
+ struct a2j * self,
+ snd_seq_addr_t addr,
+ const snd_seq_port_info_t * info);
+
+void
+a2j_update_ports(
+ struct a2j * self);
+
+void
+a2j_free_ports(
+ jack_ringbuffer_t * ports);
+
+struct a2j_port *
+a2j_find_port_by_addr(
+ struct a2j_stream * stream_ptr,
+ snd_seq_addr_t addr);
+
+struct a2j_port *
+a2j_find_port_by_jack_port_name(
+ struct a2j_stream * stream_ptr,
+ const char * jack_port);
+
+#endif /* #ifndef PORT_THREAD_H__1C6B5065_5556_4AC6_AA9F_44C32A9648C6__INCLUDED */