wscript: Use WafToolchainFlags; Bump version to 10
[a2jmidid.git] / a2jmidid.c
blob6059ca838bc4d28fc380dc81e9c2ee6695cc5461
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;
69 bool g_filter_note_on = true;
71 bool g_a2j_export_hw_ports = false;
72 char * g_a2j_jack_server_name = "default";
74 static
75 void
76 a2j_sigint_handler(
77 int i)
79 g_keep_walking = false;
82 static
83 bool
84 a2j_stream_init(
85 struct a2j * self,
86 int dir)
88 struct a2j_stream *str = &self->stream[dir];
90 str->new_ports = jack_ringbuffer_create(MAX_PORTS * sizeof(struct a2j_port *));
91 if (str->new_ports == NULL)
93 return false;
96 snd_midi_event_new(MAX_EVENT_SIZE, &str->codec);
97 INIT_LIST_HEAD(&str->list);
99 return true;
102 static
103 void
104 a2j_stream_attach(
105 struct a2j_stream * stream_ptr)
109 static
110 void
111 a2j_stream_detach(
112 struct a2j_stream * stream_ptr)
114 struct a2j_port * port_ptr;
115 struct list_head * node_ptr;
117 while (!list_empty(&stream_ptr->list))
119 node_ptr = stream_ptr->list.next;
120 list_del(node_ptr);
121 port_ptr = list_entry(node_ptr, struct a2j_port, siblings);
122 a2j_info("port deleted: %s", port_ptr->name);
123 a2j_port_free(port_ptr);
127 static
128 void
129 a2j_stream_close(
130 struct a2j * self,
131 int dir)
133 struct a2j_stream *str = &self->stream[dir];
135 if (str->codec)
136 snd_midi_event_free(str->codec);
137 if (str->new_ports)
138 jack_ringbuffer_free(str->new_ports);
141 struct a2j * a2j_new(void)
143 int error;
144 void * thread_status;
146 struct a2j *self = calloc(1, sizeof(struct a2j));
147 a2j_debug("midi: new");
148 if (!self)
150 a2j_error("calloc() failed to allocate a2j struct");
151 goto fail;
154 self->port_add = jack_ringbuffer_create(2 * MAX_PORTS * sizeof(snd_seq_addr_t));
155 if (self->port_add == NULL)
157 goto free_self;
160 self->port_del = jack_ringbuffer_create(2 * MAX_PORTS * sizeof(struct a2j_port *));
161 if (self->port_del == NULL)
163 goto free_ringbuffer_add;
166 self->outbound_events = jack_ringbuffer_create(MAX_EVENT_SIZE * 16 * sizeof(struct a2j_delivery_event));
167 if (self->outbound_events == NULL)
169 goto free_ringbuffer_del;
172 if (!a2j_stream_init(self, A2J_PORT_CAPTURE))
174 goto free_ringbuffer_outbound;
177 if (!a2j_stream_init(self, A2J_PORT_PLAYBACK))
179 goto close_capture_stream;
182 error = snd_seq_open(&self->seq, "hw", SND_SEQ_OPEN_DUPLEX, 0);
183 if (error < 0)
185 a2j_error("failed to open alsa seq");
186 goto close_playback_stream;
189 error = snd_seq_set_client_name(self->seq, "a2jmidid");
190 if (error < 0)
192 a2j_error("snd_seq_set_client_name() failed");
193 goto close_seq_client;
196 self->port_id = snd_seq_create_simple_port(
197 self->seq,
198 "port",
199 SND_SEQ_PORT_CAP_READ|SND_SEQ_PORT_CAP_WRITE
200 #ifndef DEBUG
201 |SND_SEQ_PORT_CAP_NO_EXPORT
202 #endif
203 ,SND_SEQ_PORT_TYPE_APPLICATION);
204 if (self->port_id < 0)
206 a2j_error("snd_seq_create_simple_port() failed");
207 goto close_seq_client;
210 self->client_id = snd_seq_client_id(self->seq);
211 if (self->client_id < 0)
213 a2j_error("snd_seq_client_id() failed");
214 goto close_seq_client;
217 self->queue = snd_seq_alloc_queue(self->seq);
218 if (self->queue < 0)
220 a2j_error("snd_seq_alloc_queue() failed");
221 goto close_seq_client;
224 snd_seq_start_queue(self->seq, self->queue, 0);
226 a2j_stream_attach(self->stream + A2J_PORT_CAPTURE);
227 a2j_stream_attach(self->stream + A2J_PORT_PLAYBACK);
229 error = snd_seq_nonblock(self->seq, 1);
230 if (error < 0)
232 a2j_error("snd_seq_nonblock() failed");
233 goto close_seq_client;
236 snd_seq_drop_input(self->seq);
238 a2j_add_ports(&self->stream[A2J_PORT_CAPTURE]);
239 a2j_add_ports(&self->stream[A2J_PORT_PLAYBACK]);
241 self->jack_client = a2j_jack_client_create(self, A2J_JACK_CLIENT_NAME, g_a2j_jack_server_name);
242 if (self->jack_client == NULL)
244 goto free_self;
247 if (sem_init(&self->io_semaphore, 0, 0) < 0)
249 a2j_error("can't create IO semaphore");
250 goto close_jack_client;
253 if (jack_activate(self->jack_client))
255 a2j_error("can't activate jack client");
256 goto sem_destroy;
259 g_keep_alsa_walking = true;
261 if (pthread_create(&self->alsa_input_thread, NULL, a2j_alsa_input_thread, self) < 0)
263 a2j_error("cannot start ALSA input thread");
264 goto sem_destroy;
267 /* wake the poll loop in the alsa input thread so initial ports are fetched */
268 error = snd_seq_connect_from(self->seq, self->port_id, SND_SEQ_CLIENT_SYSTEM, SND_SEQ_PORT_SYSTEM_ANNOUNCE);
269 if (error < 0)
271 a2j_error("snd_seq_connect_from() failed");
272 goto join_input_thread;
275 if (pthread_create(&self->alsa_output_thread, NULL, a2j_alsa_output_thread, self) < 0)
277 a2j_error("cannot start ALSA output thread");
278 goto disconnect;
281 return self;
283 disconnect:
284 g_keep_alsa_walking = false; /* tell alsa threads to stop */
285 snd_seq_disconnect_from(self->seq, self->port_id, SND_SEQ_CLIENT_SYSTEM, SND_SEQ_PORT_SYSTEM_ANNOUNCE);
286 join_input_thread:
287 pthread_join(self->alsa_input_thread, &thread_status);
288 sem_destroy:
289 sem_destroy(&self->io_semaphore);
290 close_jack_client:
291 error = jack_client_close(self->jack_client);
292 if (error != 0)
294 a2j_error("Cannot close jack client");
296 close_seq_client:
297 snd_seq_close(self->seq);
298 close_playback_stream:
299 a2j_stream_close(self, A2J_PORT_PLAYBACK);
300 close_capture_stream:
301 a2j_stream_close(self, A2J_PORT_CAPTURE);
302 free_ringbuffer_outbound:
303 jack_ringbuffer_free(self->outbound_events);
304 free_ringbuffer_del:
305 jack_ringbuffer_free(self->port_del);
306 free_ringbuffer_add:
307 jack_ringbuffer_free(self->port_add);
308 free_self:
309 free(self);
310 fail:
311 return NULL;
314 static void a2j_destroy(struct a2j * self)
316 int error;
317 void * thread_status;
319 a2j_debug("midi: delete");
321 g_keep_alsa_walking = false; /* tell alsa threads to stop */
323 /* do something that we need to do anyway and will wake the input thread, then join */
324 snd_seq_disconnect_from(self->seq, self->port_id, SND_SEQ_CLIENT_SYSTEM, SND_SEQ_PORT_SYSTEM_ANNOUNCE);
325 pthread_join(self->alsa_input_thread, &thread_status);
327 /* wake output thread and join, then destroy the semaphore */
328 sem_post(&self->io_semaphore);
329 pthread_join(self->alsa_output_thread, &thread_status);
330 sem_destroy(&self->io_semaphore);
332 jack_ringbuffer_reset(self->port_add);
334 jack_deactivate(self->jack_client);
336 a2j_stream_detach(self->stream + A2J_PORT_CAPTURE);
337 a2j_stream_detach(self->stream + A2J_PORT_PLAYBACK);
339 error = jack_client_close(self->jack_client);
340 if (error != 0)
342 a2j_error("Cannot close jack client (%d)", error);
345 snd_seq_close(self->seq);
346 self->seq = NULL;
348 a2j_stream_close(self, A2J_PORT_PLAYBACK);
349 a2j_stream_close(self, A2J_PORT_CAPTURE);
351 jack_ringbuffer_free(self->outbound_events);
352 jack_ringbuffer_free(self->port_add);
353 jack_ringbuffer_free(self->port_del);
355 free(self);
358 bool a2j_start(void)
360 if (g_started)
362 a2j_error("Bridge already started");
363 return false;
366 a2j_info("Bridge starting...");
368 a2j_info("Using JACK server '%s'", g_a2j_jack_server_name);
370 a2j_info("Hardware ports %s be exported.", g_a2j_export_hw_ports ? "will": "will not");
372 g_a2j = a2j_new();
373 if (g_a2j == NULL)
375 a2j_error("a2j_new() failed.");
376 return false;
379 a2j_info("Bridge started");
381 #if HAVE_DBUS_1
382 if (a2j_dbus_is_available())
384 a2j_dbus_signal_emit_bridge_started();
386 #endif
388 g_started = true;
390 return true;
393 bool a2j_stop(void)
395 if (!g_started)
397 a2j_error("Bridge already stopped");
398 return false;
401 a2j_info("Bridge stopping...");
403 a2j_destroy(g_a2j);
404 g_a2j = NULL;
406 a2j_info("Bridge stopped");
408 g_started = false;
410 #if HAVE_DBUS_1
411 if (a2j_dbus_is_available())
413 a2j_dbus_signal_emit_bridge_stopped();
415 #endif
417 return true;
420 bool
421 a2j_is_started()
423 return g_started;
426 static
427 void
428 a2j_help(
429 const char * self)
431 a2j_info("Usage: %s [-j jack-server] [-e | --export-hw] [-u] [-n]", self);
432 a2j_info("Defaults:");
433 a2j_info("-j default");
437 main(
438 int argc,
439 char *argv[])
441 bool dbus;
442 struct stat st;
443 char timestamp_str[26];
445 //test_list_sort();
447 st.st_mtime = 0;
448 stat(argv[0], &st);
449 ctime_r(&st.st_mtime, timestamp_str);
450 timestamp_str[24] = 0;
452 g_max_jack_port_name_size = jack_port_name_size();
454 if (!a2j_paths_init())
456 goto fail;
459 #if HAVE_DBUS_1
460 dbus = argc == 2 && strcmp(argv[1], "dbus") == 0;
461 #else
462 dbus = false;
463 #endif
465 if (!a2j_log_init(dbus))
467 goto fail_paths_uninit;
470 if (!dbus)
472 struct option long_opts[] = { { "export-hw", 0, 0, 'e' }, { 0, 0, 0, 0 } };
474 int option_index = 0;
475 int c;
476 while ((c = getopt_long(argc, argv, "j:eu", long_opts, &option_index)) != -1)
478 switch (c)
480 case 'j':
481 g_a2j_jack_server_name = strdup(optarg);
482 break;
483 case 'e':
484 g_a2j_export_hw_ports = true;
485 break;
486 case 'u':
487 g_disable_port_uniqueness = true;
488 break;
489 case 'n':
490 g_filter_note_on = false;
491 break;
492 default:
493 a2j_help(argv[0]);
494 return 1;
498 else
500 //a2j_conf_load();
503 if (dbus)
505 a2j_info("----------------------------");
508 a2j_info("JACK MIDI <-> ALSA sequencer MIDI bridge, version " A2J_VERSION
509 #if (HAVE_GITVERSION_H)
510 " (" GIT_VERSION ")"
511 #endif
512 " built on %s", timestamp_str);
513 a2j_info("Copyright 2006,2007 Dmitry S. Baikov");
514 a2j_info("Copyright 2007,2008,2009,2011,2012 Nedko Arnaudov");
516 if (dbus)
518 a2j_info("----------------------------");
519 a2j_info("Activated.");
521 else
523 a2j_info("");
526 /* setup our SIGSEGV magic that prints nice stack in our logfile */
527 if (dbus)
529 setup_siginfo();
532 signal(SIGINT, &a2j_sigint_handler);
533 signal(SIGTERM, &a2j_sigint_handler);
535 if (dbus)
537 #if HAVE_DBUS_1
538 if (!a2j_dbus_init())
540 a2j_error("a2j_dbus_init() failed.");
541 goto fail_uninit_log;
543 #endif
545 else
547 if (!a2j_start())
549 goto fail_uninit_log;
552 a2j_info("Press ctrl-c to stop the bridge");
555 while (g_keep_walking)
557 if (dbus)
559 #if HAVE_DBUS_1
560 if (!a2j_dbus_run(MAIN_LOOP_SLEEP_INTERVAL))
562 a2j_warning("Disconnect message was received from D-Bus.");
563 break;
565 #endif
567 else
569 usleep(MAIN_LOOP_SLEEP_INTERVAL * 1000);
572 if (g_stop_request)
574 g_stop_request = false;
576 a2j_stop();
578 if (!dbus)
580 break;
584 if (g_started)
586 a2j_free_ports(g_a2j->port_del);
587 a2j_update_ports(g_a2j);
591 if (g_started)
593 a2j_stop();
596 #if HAVE_DBUS_1
597 if (dbus)
599 a2j_dbus_uninit();
601 a2j_info("Deactivated.");
602 a2j_info("----------------------------");
604 #endif
606 fail_uninit_log:
607 a2j_log_uninit();
609 fail_paths_uninit:
610 a2j_paths_uninit();
612 fail:
613 return 0;