2 * ALSA SEQ < - > JACK MIDI bridge
4 * Copyright (c) 2006,2007 Dmitry S. Baikov <c0ff@konstruktiv.org>
5 * Copyright (c) 2007,2008,2009,2011 Nedko Arnaudov <nedko@arnaudov.name>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; version 2 of the License.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 #include <semaphore.h>
29 #include <alsa/asoundlib.h>
31 #include <jack/jack.h>
32 #include <jack/midiport.h>
33 #include <jack/ringbuffer.h>
36 # include <dbus/dbus.h>
44 #include "port_thread.h"
45 #include "port_hash.h"
54 #include "siginfo/siginfo.h"
56 #include "gitversion.h"
58 #include "dbus_iface_control.h"
60 #define MAIN_LOOP_SLEEP_INTERVAL 50 // in milliseconds
62 bool g_keep_walking
= true;
63 bool g_keep_alsa_walking
= false;
64 bool g_stop_request
= false;
65 static bool g_started
= false;
66 struct a2j
* g_a2j
= NULL
;
67 size_t g_max_jack_port_name_size
;
68 bool g_disable_port_uniqueness
= false;
69 bool g_filter_note_on
= true;
71 bool g_a2j_export_hw_ports
= false;
72 char * g_a2j_jack_server_name
= "default";
79 ((void)(i
)); /* unreferenced parameter */
80 g_keep_walking
= false;
89 struct a2j_stream
*str
= &self
->stream
[dir
];
91 str
->new_ports
= jack_ringbuffer_create(MAX_PORTS
* sizeof(struct a2j_port
*));
92 if (str
->new_ports
== NULL
)
97 snd_midi_event_new(MAX_EVENT_SIZE
, &str
->codec
);
98 INIT_LIST_HEAD(&str
->list
);
106 struct a2j_stream
* stream_ptr
)
108 ((void)(stream_ptr
)); /* unreferenced parameter */
114 struct a2j_stream
* stream_ptr
)
116 struct a2j_port
* port_ptr
;
117 struct list_head
* node_ptr
;
119 while (!list_empty(&stream_ptr
->list
))
121 node_ptr
= stream_ptr
->list
.next
;
123 port_ptr
= list_entry(node_ptr
, struct a2j_port
, siblings
);
124 a2j_info("port deleted: %s", port_ptr
->name
);
125 a2j_port_free(port_ptr
);
135 struct a2j_stream
*str
= &self
->stream
[dir
];
138 snd_midi_event_free(str
->codec
);
140 jack_ringbuffer_free(str
->new_ports
);
143 struct a2j
* a2j_new(void)
146 void * thread_status
;
148 struct a2j
*self
= calloc(1, sizeof(struct a2j
));
149 a2j_debug("midi: new");
152 a2j_error("calloc() failed to allocate a2j struct");
156 self
->port_add
= jack_ringbuffer_create(2 * MAX_PORTS
* sizeof(snd_seq_addr_t
));
157 if (self
->port_add
== NULL
)
162 self
->port_del
= jack_ringbuffer_create(2 * MAX_PORTS
* sizeof(struct a2j_port
*));
163 if (self
->port_del
== NULL
)
165 goto free_ringbuffer_add
;
168 self
->outbound_events
= jack_ringbuffer_create(MAX_EVENT_SIZE
* 16 * sizeof(struct a2j_delivery_event
));
169 if (self
->outbound_events
== NULL
)
171 goto free_ringbuffer_del
;
174 if (!a2j_stream_init(self
, A2J_PORT_CAPTURE
))
176 goto free_ringbuffer_outbound
;
179 if (!a2j_stream_init(self
, A2J_PORT_PLAYBACK
))
181 goto close_capture_stream
;
184 error
= snd_seq_open(&self
->seq
, "hw", SND_SEQ_OPEN_DUPLEX
, 0);
187 a2j_error("failed to open alsa seq");
188 goto close_playback_stream
;
191 error
= snd_seq_set_client_name(self
->seq
, "a2jmidid");
194 a2j_error("snd_seq_set_client_name() failed");
195 goto close_seq_client
;
198 self
->port_id
= snd_seq_create_simple_port(
201 SND_SEQ_PORT_CAP_READ
|SND_SEQ_PORT_CAP_WRITE
203 |SND_SEQ_PORT_CAP_NO_EXPORT
205 ,SND_SEQ_PORT_TYPE_APPLICATION
);
206 if (self
->port_id
< 0)
208 a2j_error("snd_seq_create_simple_port() failed");
209 goto close_seq_client
;
212 self
->client_id
= snd_seq_client_id(self
->seq
);
213 if (self
->client_id
< 0)
215 a2j_error("snd_seq_client_id() failed");
216 goto close_seq_client
;
219 self
->queue
= snd_seq_alloc_queue(self
->seq
);
222 a2j_error("snd_seq_alloc_queue() failed");
223 goto close_seq_client
;
226 snd_seq_start_queue(self
->seq
, self
->queue
, 0);
228 a2j_stream_attach(self
->stream
+ A2J_PORT_CAPTURE
);
229 a2j_stream_attach(self
->stream
+ A2J_PORT_PLAYBACK
);
231 error
= snd_seq_nonblock(self
->seq
, 1);
234 a2j_error("snd_seq_nonblock() failed");
235 goto close_seq_client
;
238 snd_seq_drop_input(self
->seq
);
240 a2j_add_ports(&self
->stream
[A2J_PORT_CAPTURE
]);
241 a2j_add_ports(&self
->stream
[A2J_PORT_PLAYBACK
]);
243 self
->jack_client
= a2j_jack_client_create(self
, A2J_JACK_CLIENT_NAME
, g_a2j_jack_server_name
);
244 if (self
->jack_client
== NULL
)
249 if (sem_init(&self
->io_semaphore
, 0, 0) < 0)
251 a2j_error("can't create IO semaphore");
252 goto close_jack_client
;
255 if (jack_activate(self
->jack_client
))
257 a2j_error("can't activate jack client");
261 g_keep_alsa_walking
= true;
263 if (pthread_create(&self
->alsa_input_thread
, NULL
, a2j_alsa_input_thread
, self
) < 0)
265 a2j_error("cannot start ALSA input thread");
269 /* wake the poll loop in the alsa input thread so initial ports are fetched */
270 error
= snd_seq_connect_from(self
->seq
, self
->port_id
, SND_SEQ_CLIENT_SYSTEM
, SND_SEQ_PORT_SYSTEM_ANNOUNCE
);
273 a2j_error("snd_seq_connect_from() failed");
274 goto join_input_thread
;
277 if (pthread_create(&self
->alsa_output_thread
, NULL
, a2j_alsa_output_thread
, self
) < 0)
279 a2j_error("cannot start ALSA output thread");
286 g_keep_alsa_walking
= false; /* tell alsa threads to stop */
287 snd_seq_disconnect_from(self
->seq
, self
->port_id
, SND_SEQ_CLIENT_SYSTEM
, SND_SEQ_PORT_SYSTEM_ANNOUNCE
);
289 pthread_join(self
->alsa_input_thread
, &thread_status
);
291 sem_destroy(&self
->io_semaphore
);
293 error
= jack_client_close(self
->jack_client
);
296 a2j_error("Cannot close jack client");
299 snd_seq_close(self
->seq
);
300 close_playback_stream
:
301 a2j_stream_close(self
, A2J_PORT_PLAYBACK
);
302 close_capture_stream
:
303 a2j_stream_close(self
, A2J_PORT_CAPTURE
);
304 free_ringbuffer_outbound
:
305 jack_ringbuffer_free(self
->outbound_events
);
307 jack_ringbuffer_free(self
->port_del
);
309 jack_ringbuffer_free(self
->port_add
);
316 static void a2j_destroy(struct a2j
* self
)
319 void * thread_status
;
321 a2j_debug("midi: delete");
323 g_keep_alsa_walking
= false; /* tell alsa threads to stop */
325 /* do something that we need to do anyway and will wake the input thread, then join */
326 snd_seq_disconnect_from(self
->seq
, self
->port_id
, SND_SEQ_CLIENT_SYSTEM
, SND_SEQ_PORT_SYSTEM_ANNOUNCE
);
327 pthread_join(self
->alsa_input_thread
, &thread_status
);
329 /* wake output thread and join, then destroy the semaphore */
330 sem_post(&self
->io_semaphore
);
331 pthread_join(self
->alsa_output_thread
, &thread_status
);
332 sem_destroy(&self
->io_semaphore
);
334 jack_ringbuffer_reset(self
->port_add
);
336 jack_deactivate(self
->jack_client
);
338 a2j_stream_detach(self
->stream
+ A2J_PORT_CAPTURE
);
339 a2j_stream_detach(self
->stream
+ A2J_PORT_PLAYBACK
);
341 error
= jack_client_close(self
->jack_client
);
344 a2j_error("Cannot close jack client (%d)", error
);
347 snd_seq_close(self
->seq
);
350 a2j_stream_close(self
, A2J_PORT_PLAYBACK
);
351 a2j_stream_close(self
, A2J_PORT_CAPTURE
);
353 jack_ringbuffer_free(self
->outbound_events
);
354 jack_ringbuffer_free(self
->port_add
);
355 jack_ringbuffer_free(self
->port_del
);
364 a2j_error("Bridge already started");
368 a2j_info("Bridge starting...");
370 a2j_info("Using JACK server '%s'", g_a2j_jack_server_name
);
372 a2j_info("Hardware ports %s be exported.", g_a2j_export_hw_ports
? "will": "will not");
377 a2j_error("a2j_new() failed.");
381 a2j_info("Bridge started");
384 if (a2j_dbus_is_available())
386 a2j_dbus_signal_emit_bridge_started();
399 a2j_error("Bridge already stopped");
403 a2j_info("Bridge stopping...");
408 a2j_info("Bridge stopped");
413 if (a2j_dbus_is_available())
415 a2j_dbus_signal_emit_bridge_stopped();
433 a2j_info("Usage: %s [-j jack-server] [-e | --export-hw] [-u] [-n]", self
);
434 a2j_info("Defaults:");
435 a2j_info("-j default");
445 char timestamp_str
[26];
451 ctime_r(&st
.st_mtime
, timestamp_str
);
452 timestamp_str
[24] = 0;
454 g_max_jack_port_name_size
= jack_port_name_size();
456 if (!a2j_paths_init())
462 dbus
= argc
== 2 && strcmp(argv
[1], "dbus") == 0;
467 if (!a2j_log_init(dbus
))
469 goto fail_paths_uninit
;
474 struct option long_opts
[] = { { "export-hw", 0, 0, 'e' }, { 0, 0, 0, 0 } };
476 int option_index
= 0;
478 while ((c
= getopt_long(argc
, argv
, "j:eu", long_opts
, &option_index
)) != -1)
483 g_a2j_jack_server_name
= strdup(optarg
);
486 g_a2j_export_hw_ports
= true;
489 g_disable_port_uniqueness
= true;
492 g_filter_note_on
= false;
507 a2j_info("----------------------------");
510 a2j_info("JACK MIDI <-> ALSA sequencer MIDI bridge, version " A2J_VERSION
511 #if (HAVE_GITVERSION_H)
514 " built on %s", timestamp_str
);
515 a2j_info("Copyright 2006,2007 Dmitry S. Baikov");
516 a2j_info("Copyright 2007,2008,2009,2011,2012 Nedko Arnaudov");
520 a2j_info("----------------------------");
521 a2j_info("Activated.");
528 /* setup our SIGSEGV magic that prints nice stack in our logfile */
534 signal(SIGINT
, &a2j_sigint_handler
);
535 signal(SIGTERM
, &a2j_sigint_handler
);
540 if (!a2j_dbus_init())
542 a2j_error("a2j_dbus_init() failed.");
543 goto fail_uninit_log
;
551 goto fail_uninit_log
;
554 a2j_info("Press ctrl-c to stop the bridge");
557 while (g_keep_walking
)
562 if (!a2j_dbus_run(MAIN_LOOP_SLEEP_INTERVAL
))
564 a2j_warning("Disconnect message was received from D-Bus.");
571 usleep(MAIN_LOOP_SLEEP_INTERVAL
* 1000);
576 g_stop_request
= false;
588 a2j_free_ports(g_a2j
->port_del
);
589 a2j_update_ports(g_a2j
);
603 a2j_info("Deactivated.");
604 a2j_info("----------------------------");