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"
55 #include "gitversion.h"
56 #include "dbus_iface_control.h"
58 #define MAIN_LOOP_SLEEP_INTERVAL 50 // in milliseconds
60 bool g_keep_walking
= true;
61 bool g_keep_alsa_walking
= false;
62 bool g_stop_request
= false;
63 static bool g_started
= false;
64 struct a2j
* g_a2j
= NULL
;
65 size_t g_max_jack_port_name_size
;
66 bool g_disable_port_uniqueness
= false;
68 bool g_a2j_export_hw_ports
= false;
69 char * g_a2j_jack_server_name
= "default";
76 g_keep_walking
= false;
85 struct a2j_stream
*str
= &self
->stream
[dir
];
87 str
->new_ports
= jack_ringbuffer_create(MAX_PORTS
* sizeof(struct a2j_port
*));
88 if (str
->new_ports
== NULL
)
93 snd_midi_event_new(MAX_EVENT_SIZE
, &str
->codec
);
94 INIT_LIST_HEAD(&str
->list
);
102 struct a2j_stream
* stream_ptr
)
109 struct a2j_stream
* stream_ptr
)
111 struct a2j_port
* port_ptr
;
112 struct list_head
* node_ptr
;
114 while (!list_empty(&stream_ptr
->list
))
116 node_ptr
= stream_ptr
->list
.next
;
118 port_ptr
= list_entry(node_ptr
, struct a2j_port
, siblings
);
119 a2j_info("port deleted: %s", port_ptr
->name
);
120 a2j_port_free(port_ptr
);
130 struct a2j_stream
*str
= &self
->stream
[dir
];
133 snd_midi_event_free(str
->codec
);
135 jack_ringbuffer_free(str
->new_ports
);
138 struct a2j
* a2j_new(void)
141 void * thread_status
;
143 struct a2j
*self
= calloc(1, sizeof(struct a2j
));
144 a2j_debug("midi: new");
147 a2j_error("calloc() failed to allocate a2j struct");
151 self
->port_add
= jack_ringbuffer_create(2 * MAX_PORTS
* sizeof(snd_seq_addr_t
));
152 if (self
->port_add
== NULL
)
157 self
->port_del
= jack_ringbuffer_create(2 * MAX_PORTS
* sizeof(struct a2j_port
*));
158 if (self
->port_del
== NULL
)
160 goto free_ringbuffer_add
;
163 self
->outbound_events
= jack_ringbuffer_create(MAX_EVENT_SIZE
* 16 * sizeof(struct a2j_delivery_event
));
164 if (self
->outbound_events
== NULL
)
166 goto free_ringbuffer_del
;
169 if (!a2j_stream_init(self
, A2J_PORT_CAPTURE
))
171 goto free_ringbuffer_outbound
;
174 if (!a2j_stream_init(self
, A2J_PORT_PLAYBACK
))
176 goto close_capture_stream
;
179 error
= snd_seq_open(&self
->seq
, "hw", SND_SEQ_OPEN_DUPLEX
, 0);
182 a2j_error("failed to open alsa seq");
183 goto close_playback_stream
;
186 error
= snd_seq_set_client_name(self
->seq
, "a2jmidid");
189 a2j_error("snd_seq_set_client_name() failed");
190 goto close_seq_client
;
193 self
->port_id
= snd_seq_create_simple_port(
196 SND_SEQ_PORT_CAP_READ
|SND_SEQ_PORT_CAP_WRITE
198 |SND_SEQ_PORT_CAP_NO_EXPORT
200 ,SND_SEQ_PORT_TYPE_APPLICATION
);
201 if (self
->port_id
< 0)
203 a2j_error("snd_seq_create_simple_port() failed");
204 goto close_seq_client
;
207 self
->client_id
= snd_seq_client_id(self
->seq
);
208 if (self
->client_id
< 0)
210 a2j_error("snd_seq_client_id() failed");
211 goto close_seq_client
;
214 self
->queue
= snd_seq_alloc_queue(self
->seq
);
217 a2j_error("snd_seq_alloc_queue() failed");
218 goto close_seq_client
;
221 snd_seq_start_queue(self
->seq
, self
->queue
, 0);
223 a2j_stream_attach(self
->stream
+ A2J_PORT_CAPTURE
);
224 a2j_stream_attach(self
->stream
+ A2J_PORT_PLAYBACK
);
226 error
= snd_seq_nonblock(self
->seq
, 1);
229 a2j_error("snd_seq_nonblock() failed");
230 goto close_seq_client
;
233 snd_seq_drop_input(self
->seq
);
235 a2j_add_ports(&self
->stream
[A2J_PORT_CAPTURE
]);
236 a2j_add_ports(&self
->stream
[A2J_PORT_PLAYBACK
]);
238 self
->jack_client
= a2j_jack_client_create(self
, A2J_JACK_CLIENT_NAME
, g_a2j_jack_server_name
);
239 if (self
->jack_client
== NULL
)
244 if (sem_init(&self
->io_semaphore
, 0, 0) < 0)
246 a2j_error("can't create IO semaphore");
247 goto close_jack_client
;
250 if (jack_activate(self
->jack_client
))
252 a2j_error("can't activate jack client");
256 g_keep_alsa_walking
= true;
258 if (pthread_create(&self
->alsa_input_thread
, NULL
, a2j_alsa_input_thread
, self
) < 0)
260 a2j_error("cannot start ALSA input thread");
264 /* wake the poll loop in the alsa input thread so initial ports are fetched */
265 error
= snd_seq_connect_from(self
->seq
, self
->port_id
, SND_SEQ_CLIENT_SYSTEM
, SND_SEQ_PORT_SYSTEM_ANNOUNCE
);
268 a2j_error("snd_seq_connect_from() failed");
269 goto join_input_thread
;
272 if (pthread_create(&self
->alsa_output_thread
, NULL
, a2j_alsa_output_thread
, self
) < 0)
274 a2j_error("cannot start ALSA output thread");
281 g_keep_alsa_walking
= false; /* tell alsa threads to stop */
282 snd_seq_disconnect_from(self
->seq
, self
->port_id
, SND_SEQ_CLIENT_SYSTEM
, SND_SEQ_PORT_SYSTEM_ANNOUNCE
);
284 pthread_join(self
->alsa_input_thread
, &thread_status
);
286 sem_destroy(&self
->io_semaphore
);
288 error
= jack_client_close(self
->jack_client
);
291 a2j_error("Cannot close jack client");
294 snd_seq_close(self
->seq
);
295 close_playback_stream
:
296 a2j_stream_close(self
, A2J_PORT_PLAYBACK
);
297 close_capture_stream
:
298 a2j_stream_close(self
, A2J_PORT_CAPTURE
);
299 free_ringbuffer_outbound
:
300 jack_ringbuffer_free(self
->outbound_events
);
302 jack_ringbuffer_free(self
->port_del
);
304 jack_ringbuffer_free(self
->port_add
);
311 static void a2j_destroy(struct a2j
* self
)
314 void * thread_status
;
316 a2j_debug("midi: delete");
318 g_keep_alsa_walking
= false; /* tell alsa threads to stop */
320 /* do something that we need to do anyway and will wake the input thread, then join */
321 snd_seq_disconnect_from(self
->seq
, self
->port_id
, SND_SEQ_CLIENT_SYSTEM
, SND_SEQ_PORT_SYSTEM_ANNOUNCE
);
322 pthread_join(self
->alsa_input_thread
, &thread_status
);
324 /* wake output thread and join, then destroy the semaphore */
325 sem_post(&self
->io_semaphore
);
326 pthread_join(self
->alsa_output_thread
, &thread_status
);
327 sem_destroy(&self
->io_semaphore
);
329 jack_ringbuffer_reset(self
->port_add
);
331 jack_deactivate(self
->jack_client
);
333 a2j_stream_detach(self
->stream
+ A2J_PORT_CAPTURE
);
334 a2j_stream_detach(self
->stream
+ A2J_PORT_PLAYBACK
);
336 error
= jack_client_close(self
->jack_client
);
339 a2j_error("Cannot close jack client (%d)", error
);
342 snd_seq_close(self
->seq
);
345 a2j_stream_close(self
, A2J_PORT_PLAYBACK
);
346 a2j_stream_close(self
, A2J_PORT_CAPTURE
);
348 jack_ringbuffer_free(self
->outbound_events
);
349 jack_ringbuffer_free(self
->port_add
);
350 jack_ringbuffer_free(self
->port_del
);
359 a2j_error("Bridge already started");
363 a2j_info("Bridge starting...");
365 a2j_info("Using JACK server '%s'", g_a2j_jack_server_name
);
367 a2j_info("Hardware ports %s be exported.", g_a2j_export_hw_ports
? "will": "will not");
372 a2j_error("a2j_new() failed.");
376 a2j_info("Bridge started");
379 if (a2j_dbus_is_available())
381 a2j_dbus_signal_emit_bridge_started();
394 a2j_error("Bridge already stopped");
398 a2j_info("Bridge stopping...");
403 a2j_info("Bridge stopped");
408 if (a2j_dbus_is_available())
410 a2j_dbus_signal_emit_bridge_stopped();
428 a2j_info("Usage: %s [-j jack-server] [-e | --export-hw] [-u]", self
);
429 a2j_info("Defaults:");
430 a2j_info("-j default");
440 char timestamp_str
[26];
446 ctime_r(&st
.st_mtime
, timestamp_str
);
447 timestamp_str
[24] = 0;
449 g_max_jack_port_name_size
= jack_port_name_size();
451 if (!a2j_paths_init())
457 dbus
= argc
== 2 && strcmp(argv
[1], "dbus") == 0;
462 if (!a2j_log_init(dbus
))
464 goto fail_paths_uninit
;
469 struct option long_opts
[] = { { "export-hw", 0, 0, 'e' }, { 0, 0, 0, 0 } };
471 int option_index
= 0;
473 while ((c
= getopt_long(argc
, argv
, "j:eu", long_opts
, &option_index
)) != -1)
478 g_a2j_jack_server_name
= strdup(optarg
);
481 g_a2j_export_hw_ports
= true;
484 g_disable_port_uniqueness
= true;
499 a2j_info("----------------------------");
502 a2j_info("JACK MIDI <-> ALSA sequencer MIDI bridge, version " A2J_VERSION
" (" GIT_VERSION
") built on %s", timestamp_str
);
503 a2j_info("Copyright 2006,2007 Dmitry S. Baikov");
504 a2j_info("Copyright 2007,2008,2009,2011 Nedko Arnaudov");
508 a2j_info("----------------------------");
509 a2j_info("Activated.");
516 /* setup our SIGSEGV magic that prints nice stack in our logfile */
522 signal(SIGINT
, &a2j_sigint_handler
);
523 signal(SIGTERM
, &a2j_sigint_handler
);
528 if (!a2j_dbus_init())
530 a2j_error("a2j_dbus_init() failed.");
531 goto fail_uninit_log
;
539 goto fail_uninit_log
;
542 a2j_info("Press ctrl-c to stop the bridge");
545 while (g_keep_walking
)
550 if (!a2j_dbus_run(MAIN_LOOP_SLEEP_INTERVAL
))
552 a2j_warning("Disconnect message was received from D-Bus.");
559 usleep(MAIN_LOOP_SLEEP_INTERVAL
* 1000);
564 g_stop_request
= false;
576 a2j_free_ports(g_a2j
->port_del
);
577 a2j_update_ports(g_a2j
);
591 a2j_info("Deactivated.");
592 a2j_info("----------------------------");