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;
70 bool g_a2j_export_hw_ports
= false;
71 char * g_a2j_jack_server_name
= "default";
78 g_keep_walking
= false;
87 struct a2j_stream
*str
= &self
->stream
[dir
];
89 str
->new_ports
= jack_ringbuffer_create(MAX_PORTS
* sizeof(struct a2j_port
*));
90 if (str
->new_ports
== NULL
)
95 snd_midi_event_new(MAX_EVENT_SIZE
, &str
->codec
);
96 INIT_LIST_HEAD(&str
->list
);
104 struct a2j_stream
* stream_ptr
)
111 struct a2j_stream
* stream_ptr
)
113 struct a2j_port
* port_ptr
;
114 struct list_head
* node_ptr
;
116 while (!list_empty(&stream_ptr
->list
))
118 node_ptr
= stream_ptr
->list
.next
;
120 port_ptr
= list_entry(node_ptr
, struct a2j_port
, siblings
);
121 a2j_info("port deleted: %s", port_ptr
->name
);
122 a2j_port_free(port_ptr
);
132 struct a2j_stream
*str
= &self
->stream
[dir
];
135 snd_midi_event_free(str
->codec
);
137 jack_ringbuffer_free(str
->new_ports
);
140 struct a2j
* a2j_new(void)
143 void * thread_status
;
145 struct a2j
*self
= calloc(1, sizeof(struct a2j
));
146 a2j_debug("midi: new");
149 a2j_error("calloc() failed to allocate a2j struct");
153 self
->port_add
= jack_ringbuffer_create(2 * MAX_PORTS
* sizeof(snd_seq_addr_t
));
154 if (self
->port_add
== NULL
)
159 self
->port_del
= jack_ringbuffer_create(2 * MAX_PORTS
* sizeof(struct a2j_port
*));
160 if (self
->port_del
== NULL
)
162 goto free_ringbuffer_add
;
165 self
->outbound_events
= jack_ringbuffer_create(MAX_EVENT_SIZE
* 16 * sizeof(struct a2j_delivery_event
));
166 if (self
->outbound_events
== NULL
)
168 goto free_ringbuffer_del
;
171 if (!a2j_stream_init(self
, A2J_PORT_CAPTURE
))
173 goto free_ringbuffer_outbound
;
176 if (!a2j_stream_init(self
, A2J_PORT_PLAYBACK
))
178 goto close_capture_stream
;
181 error
= snd_seq_open(&self
->seq
, "hw", SND_SEQ_OPEN_DUPLEX
, 0);
184 a2j_error("failed to open alsa seq");
185 goto close_playback_stream
;
188 error
= snd_seq_set_client_name(self
->seq
, "a2jmidid");
191 a2j_error("snd_seq_set_client_name() failed");
192 goto close_seq_client
;
195 self
->port_id
= snd_seq_create_simple_port(
198 SND_SEQ_PORT_CAP_READ
|SND_SEQ_PORT_CAP_WRITE
200 |SND_SEQ_PORT_CAP_NO_EXPORT
202 ,SND_SEQ_PORT_TYPE_APPLICATION
);
203 if (self
->port_id
< 0)
205 a2j_error("snd_seq_create_simple_port() failed");
206 goto close_seq_client
;
209 self
->client_id
= snd_seq_client_id(self
->seq
);
210 if (self
->client_id
< 0)
212 a2j_error("snd_seq_client_id() failed");
213 goto close_seq_client
;
216 self
->queue
= snd_seq_alloc_queue(self
->seq
);
219 a2j_error("snd_seq_alloc_queue() failed");
220 goto close_seq_client
;
223 snd_seq_start_queue(self
->seq
, self
->queue
, 0);
225 a2j_stream_attach(self
->stream
+ A2J_PORT_CAPTURE
);
226 a2j_stream_attach(self
->stream
+ A2J_PORT_PLAYBACK
);
228 error
= snd_seq_nonblock(self
->seq
, 1);
231 a2j_error("snd_seq_nonblock() failed");
232 goto close_seq_client
;
235 snd_seq_drop_input(self
->seq
);
237 a2j_add_ports(&self
->stream
[A2J_PORT_CAPTURE
]);
238 a2j_add_ports(&self
->stream
[A2J_PORT_PLAYBACK
]);
240 self
->jack_client
= a2j_jack_client_create(self
, A2J_JACK_CLIENT_NAME
, g_a2j_jack_server_name
);
241 if (self
->jack_client
== NULL
)
246 if (sem_init(&self
->io_semaphore
, 0, 0) < 0)
248 a2j_error("can't create IO semaphore");
249 goto close_jack_client
;
252 if (jack_activate(self
->jack_client
))
254 a2j_error("can't activate jack client");
258 g_keep_alsa_walking
= true;
260 if (pthread_create(&self
->alsa_input_thread
, NULL
, a2j_alsa_input_thread
, self
) < 0)
262 a2j_error("cannot start ALSA input thread");
266 /* wake the poll loop in the alsa input thread so initial ports are fetched */
267 error
= snd_seq_connect_from(self
->seq
, self
->port_id
, SND_SEQ_CLIENT_SYSTEM
, SND_SEQ_PORT_SYSTEM_ANNOUNCE
);
270 a2j_error("snd_seq_connect_from() failed");
271 goto join_input_thread
;
274 if (pthread_create(&self
->alsa_output_thread
, NULL
, a2j_alsa_output_thread
, self
) < 0)
276 a2j_error("cannot start ALSA output thread");
283 g_keep_alsa_walking
= false; /* tell alsa threads to stop */
284 snd_seq_disconnect_from(self
->seq
, self
->port_id
, SND_SEQ_CLIENT_SYSTEM
, SND_SEQ_PORT_SYSTEM_ANNOUNCE
);
286 pthread_join(self
->alsa_input_thread
, &thread_status
);
288 sem_destroy(&self
->io_semaphore
);
290 error
= jack_client_close(self
->jack_client
);
293 a2j_error("Cannot close jack client");
296 snd_seq_close(self
->seq
);
297 close_playback_stream
:
298 a2j_stream_close(self
, A2J_PORT_PLAYBACK
);
299 close_capture_stream
:
300 a2j_stream_close(self
, A2J_PORT_CAPTURE
);
301 free_ringbuffer_outbound
:
302 jack_ringbuffer_free(self
->outbound_events
);
304 jack_ringbuffer_free(self
->port_del
);
306 jack_ringbuffer_free(self
->port_add
);
313 static void a2j_destroy(struct a2j
* self
)
316 void * thread_status
;
318 a2j_debug("midi: delete");
320 g_keep_alsa_walking
= false; /* tell alsa threads to stop */
322 /* do something that we need to do anyway and will wake the input thread, then join */
323 snd_seq_disconnect_from(self
->seq
, self
->port_id
, SND_SEQ_CLIENT_SYSTEM
, SND_SEQ_PORT_SYSTEM_ANNOUNCE
);
324 pthread_join(self
->alsa_input_thread
, &thread_status
);
326 /* wake output thread and join, then destroy the semaphore */
327 sem_post(&self
->io_semaphore
);
328 pthread_join(self
->alsa_output_thread
, &thread_status
);
329 sem_destroy(&self
->io_semaphore
);
331 jack_ringbuffer_reset(self
->port_add
);
333 jack_deactivate(self
->jack_client
);
335 a2j_stream_detach(self
->stream
+ A2J_PORT_CAPTURE
);
336 a2j_stream_detach(self
->stream
+ A2J_PORT_PLAYBACK
);
338 error
= jack_client_close(self
->jack_client
);
341 a2j_error("Cannot close jack client (%d)", error
);
344 snd_seq_close(self
->seq
);
347 a2j_stream_close(self
, A2J_PORT_PLAYBACK
);
348 a2j_stream_close(self
, A2J_PORT_CAPTURE
);
350 jack_ringbuffer_free(self
->outbound_events
);
351 jack_ringbuffer_free(self
->port_add
);
352 jack_ringbuffer_free(self
->port_del
);
361 a2j_error("Bridge already started");
365 a2j_info("Bridge starting...");
367 a2j_info("Using JACK server '%s'", g_a2j_jack_server_name
);
369 a2j_info("Hardware ports %s be exported.", g_a2j_export_hw_ports
? "will": "will not");
374 a2j_error("a2j_new() failed.");
378 a2j_info("Bridge started");
381 if (a2j_dbus_is_available())
383 a2j_dbus_signal_emit_bridge_started();
396 a2j_error("Bridge already stopped");
400 a2j_info("Bridge stopping...");
405 a2j_info("Bridge stopped");
410 if (a2j_dbus_is_available())
412 a2j_dbus_signal_emit_bridge_stopped();
430 a2j_info("Usage: %s [-j jack-server] [-e | --export-hw] [-u]", self
);
431 a2j_info("Defaults:");
432 a2j_info("-j default");
442 char timestamp_str
[26];
448 ctime_r(&st
.st_mtime
, timestamp_str
);
449 timestamp_str
[24] = 0;
451 g_max_jack_port_name_size
= jack_port_name_size();
453 if (!a2j_paths_init())
459 dbus
= argc
== 2 && strcmp(argv
[1], "dbus") == 0;
464 if (!a2j_log_init(dbus
))
466 goto fail_paths_uninit
;
471 struct option long_opts
[] = { { "export-hw", 0, 0, 'e' }, { 0, 0, 0, 0 } };
473 int option_index
= 0;
475 while ((c
= getopt_long(argc
, argv
, "j:eu", long_opts
, &option_index
)) != -1)
480 g_a2j_jack_server_name
= strdup(optarg
);
483 g_a2j_export_hw_ports
= true;
486 g_disable_port_uniqueness
= true;
501 a2j_info("----------------------------");
504 a2j_info("JACK MIDI <-> ALSA sequencer MIDI bridge, version " A2J_VERSION
505 #if (HAVE_GITVERSION_H)
508 " built on %s", timestamp_str
);
509 a2j_info("Copyright 2006,2007 Dmitry S. Baikov");
510 a2j_info("Copyright 2007,2008,2009,2011,2012 Nedko Arnaudov");
514 a2j_info("----------------------------");
515 a2j_info("Activated.");
522 /* setup our SIGSEGV magic that prints nice stack in our logfile */
528 signal(SIGINT
, &a2j_sigint_handler
);
529 signal(SIGTERM
, &a2j_sigint_handler
);
534 if (!a2j_dbus_init())
536 a2j_error("a2j_dbus_init() failed.");
537 goto fail_uninit_log
;
545 goto fail_uninit_log
;
548 a2j_info("Press ctrl-c to stop the bridge");
551 while (g_keep_walking
)
556 if (!a2j_dbus_run(MAIN_LOOP_SLEEP_INTERVAL
))
558 a2j_warning("Disconnect message was received from D-Bus.");
565 usleep(MAIN_LOOP_SLEEP_INTERVAL
* 1000);
570 g_stop_request
= false;
582 a2j_free_ports(g_a2j
->port_del
);
583 a2j_update_ports(g_a2j
);
597 a2j_info("Deactivated.");
598 a2j_info("----------------------------");