|
- /* -*- 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_debug("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);
- }
- }
- }
|