NEWS -> CHANGELOG.rst -> NEWS.rst
[a2jmidid.git] / a2jmidid.c
blobc090fecb3f3abf7ab8e81e00ff5fbb91a783ae52
1 /*
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
21 #include "config.h"
23 #include <signal.h>
24 #include <semaphore.h>
25 #include <stdbool.h>
26 #include <sys/stat.h>
27 #include <pthread.h>
29 #include <alsa/asoundlib.h>
31 #include <jack/jack.h>
32 #include <jack/midiport.h>
33 #include <jack/ringbuffer.h>
35 #if HAVE_DBUS_1
36 # include <dbus/dbus.h>
37 #endif
39 #include <getopt.h>
41 #include "list.h"
42 #include "structs.h"
43 #include "port.h"
44 #include "port_thread.h"
45 #include "port_hash.h"
46 #include "log.h"
47 #if HAVE_DBUS_1
48 # include "dbus.h"
49 #endif
50 #include "a2jmidid.h"
51 #include "paths.h"
52 #include "conf.h"
53 #include "jack.h"
54 #include "../siginfo/siginfo.h"
55 #if HAVE_GITVERSION_H
56 #include "gitversion.h"
57 #endif
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";
73 static
74 void
75 a2j_sigint_handler(
76 int i)
78 g_keep_walking = false;
81 static
82 bool
83 a2j_stream_init(
84 struct a2j * self,
85 int dir)
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)
92 return false;
95 snd_midi_event_new(MAX_EVENT_SIZE, &str->codec);
96 INIT_LIST_HEAD(&str->list);
98 return true;
101 static
102 void
103 a2j_stream_attach(
104 struct a2j_stream * stream_ptr)
108 static
109 void
110 a2j_stream_detach(
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;
119 list_del(node_ptr);
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);
126 static
127 void
128 a2j_stream_close(
129 struct a2j * self,
130 int dir)
132 struct a2j_stream *str = &self->stream[dir];
134 if (str->codec)
135 snd_midi_event_free(str->codec);
136 if (str->new_ports)
137 jack_ringbuffer_free(str->new_ports);
140 struct a2j * a2j_new(void)
142 int error;
143 void * thread_status;
145 struct a2j *self = calloc(1, sizeof(struct a2j));
146 a2j_debug("midi: new");
147 if (!self)
149 a2j_error("calloc() failed to allocate a2j struct");
150 goto fail;
153 self->port_add = jack_ringbuffer_create(2 * MAX_PORTS * sizeof(snd_seq_addr_t));
154 if (self->port_add == NULL)
156 goto free_self;
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);
182 if (error < 0)
184 a2j_error("failed to open alsa seq");
185 goto close_playback_stream;
188 error = snd_seq_set_client_name(self->seq, "a2jmidid");
189 if (error < 0)
191 a2j_error("snd_seq_set_client_name() failed");
192 goto close_seq_client;
195 self->port_id = snd_seq_create_simple_port(
196 self->seq,
197 "port",
198 SND_SEQ_PORT_CAP_READ|SND_SEQ_PORT_CAP_WRITE
199 #ifndef DEBUG
200 |SND_SEQ_PORT_CAP_NO_EXPORT
201 #endif
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);
217 if (self->queue < 0)
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);
229 if (error < 0)
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)
243 goto free_self;
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");
255 goto sem_destroy;
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");
263 goto sem_destroy;
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);
268 if (error < 0)
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");
277 goto disconnect;
280 return self;
282 disconnect:
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);
285 join_input_thread:
286 pthread_join(self->alsa_input_thread, &thread_status);
287 sem_destroy:
288 sem_destroy(&self->io_semaphore);
289 close_jack_client:
290 error = jack_client_close(self->jack_client);
291 if (error != 0)
293 a2j_error("Cannot close jack client");
295 close_seq_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);
303 free_ringbuffer_del:
304 jack_ringbuffer_free(self->port_del);
305 free_ringbuffer_add:
306 jack_ringbuffer_free(self->port_add);
307 free_self:
308 free(self);
309 fail:
310 return NULL;
313 static void a2j_destroy(struct a2j * self)
315 int error;
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);
339 if (error != 0)
341 a2j_error("Cannot close jack client (%d)", error);
344 snd_seq_close(self->seq);
345 self->seq = NULL;
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);
354 free(self);
357 bool a2j_start(void)
359 if (g_started)
361 a2j_error("Bridge already started");
362 return false;
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");
371 g_a2j = a2j_new();
372 if (g_a2j == NULL)
374 a2j_error("a2j_new() failed.");
375 return false;
378 a2j_info("Bridge started");
380 #if HAVE_DBUS_1
381 if (a2j_dbus_is_available())
383 a2j_dbus_signal_emit_bridge_started();
385 #endif
387 g_started = true;
389 return true;
392 bool a2j_stop(void)
394 if (!g_started)
396 a2j_error("Bridge already stopped");
397 return false;
400 a2j_info("Bridge stopping...");
402 a2j_destroy(g_a2j);
403 g_a2j = NULL;
405 a2j_info("Bridge stopped");
407 g_started = false;
409 #if HAVE_DBUS_1
410 if (a2j_dbus_is_available())
412 a2j_dbus_signal_emit_bridge_stopped();
414 #endif
416 return true;
419 bool
420 a2j_is_started()
422 return g_started;
425 static
426 void
427 a2j_help(
428 const char * self)
430 a2j_info("Usage: %s [-j jack-server] [-e | --export-hw] [-u]", self);
431 a2j_info("Defaults:");
432 a2j_info("-j default");
436 main(
437 int argc,
438 char *argv[])
440 bool dbus;
441 struct stat st;
442 char timestamp_str[26];
444 //test_list_sort();
446 st.st_mtime = 0;
447 stat(argv[0], &st);
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())
455 goto fail;
458 #if HAVE_DBUS_1
459 dbus = argc == 2 && strcmp(argv[1], "dbus") == 0;
460 #else
461 dbus = false;
462 #endif
464 if (!a2j_log_init(dbus))
466 goto fail_paths_uninit;
469 if (!dbus)
471 struct option long_opts[] = { { "export-hw", 0, 0, 'e' }, { 0, 0, 0, 0 } };
473 int option_index = 0;
474 int c;
475 while ((c = getopt_long(argc, argv, "j:eu", long_opts, &option_index)) != -1)
477 switch (c)
479 case 'j':
480 g_a2j_jack_server_name = strdup(optarg);
481 break;
482 case 'e':
483 g_a2j_export_hw_ports = true;
484 break;
485 case 'u':
486 g_disable_port_uniqueness = true;
487 break;
488 default:
489 a2j_help(argv[0]);
490 return 1;
494 else
496 //a2j_conf_load();
499 if (dbus)
501 a2j_info("----------------------------");
504 a2j_info("JACK MIDI <-> ALSA sequencer MIDI bridge, version " A2J_VERSION
505 #if (HAVE_GITVERSION_H)
506 " (" GIT_VERSION ")"
507 #endif
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");
512 if (dbus)
514 a2j_info("----------------------------");
515 a2j_info("Activated.");
517 else
519 a2j_info("");
522 /* setup our SIGSEGV magic that prints nice stack in our logfile */
523 if (dbus)
525 setup_siginfo();
528 signal(SIGINT, &a2j_sigint_handler);
529 signal(SIGTERM, &a2j_sigint_handler);
531 if (dbus)
533 #if HAVE_DBUS_1
534 if (!a2j_dbus_init())
536 a2j_error("a2j_dbus_init() failed.");
537 goto fail_uninit_log;
539 #endif
541 else
543 if (!a2j_start())
545 goto fail_uninit_log;
548 a2j_info("Press ctrl-c to stop the bridge");
551 while (g_keep_walking)
553 if (dbus)
555 #if HAVE_DBUS_1
556 if (!a2j_dbus_run(MAIN_LOOP_SLEEP_INTERVAL))
558 a2j_warning("Disconnect message was received from D-Bus.");
559 break;
561 #endif
563 else
565 usleep(MAIN_LOOP_SLEEP_INTERVAL * 1000);
568 if (g_stop_request)
570 g_stop_request = false;
572 a2j_stop();
574 if (!dbus)
576 break;
580 if (g_started)
582 a2j_free_ports(g_a2j->port_del);
583 a2j_update_ports(g_a2j);
587 if (g_started)
589 a2j_stop();
592 #if HAVE_DBUS_1
593 if (dbus)
595 a2j_dbus_uninit();
597 a2j_info("Deactivated.");
598 a2j_info("----------------------------");
600 #endif
602 fail_uninit_log:
603 a2j_log_uninit();
605 fail_paths_uninit:
606 a2j_paths_uninit();
608 fail:
609 return 0;