Fix automatic to-string conversion for status objects.
[calfbox.git] / jackio.c
blobd3b34cbde70d6f084c20c9cd7045a5b3f0d9e8fc
1 /*
2 Calf Box, an open source musical instrument.
3 Copyright (C) 2010-2012 Krzysztof Foltman
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
19 #include "config.h"
20 #include "config-api.h"
21 #include "errors.h"
22 #include "hwcfg.h"
23 #include "io.h"
24 #include "meter.h"
25 #include "midi.h"
26 #include "mididest.h"
27 #include "recsrc.h"
29 #include <errno.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <glib.h>
33 #include <jack/ringbuffer.h>
34 #include <jack/types.h>
35 #include <jack/midiport.h>
37 struct cbox_jack_io_impl
39 struct cbox_io_impl ioi;
41 jack_client_t *client;
42 jack_port_t **inputs;
43 jack_port_t **outputs;
44 jack_port_t *midi;
45 char *error_str; // set to non-NULL if client has been booted out by JACK
46 char *client_name;
48 jack_ringbuffer_t *rb_autoconnect;
51 ///////////////////////////////////////////////////////////////////////////////
53 struct cbox_jack_midi_input
55 struct cbox_midi_input hdr;
56 gchar *autoconnect_spec;
57 jack_port_t *port;
58 struct cbox_jack_io_impl *jii;
61 struct cbox_jack_midi_output
63 struct cbox_midi_output hdr;
64 gchar *autoconnect_spec;
65 jack_port_t *port;
66 struct cbox_jack_io_impl *jii;
69 static struct cbox_midi_input *cbox_jackio_create_midi_in(struct cbox_io_impl *impl, const char *name, GError **error);
70 static struct cbox_midi_output *cbox_jackio_create_midi_out(struct cbox_io_impl *impl, const char *name, GError **error);
71 static void cbox_jackio_destroy_midi_in(struct cbox_io_impl *ioi, struct cbox_midi_input *midiin);
72 static void cbox_jackio_destroy_midi_out(struct cbox_io_impl *ioi, struct cbox_midi_output *midiout);
73 static void cbox_jack_midi_output_set_autoconnect(struct cbox_jack_midi_output *jmo, const gchar *autoconnect_spec);
75 void cbox_jack_midi_input_destroy(struct cbox_jack_midi_input *jmi)
77 if (jmi->port)
79 jack_port_unregister(jmi->jii->client, jmi->port);
80 jmi->port = NULL;
82 g_free(jmi->hdr.name);
83 g_free(jmi->autoconnect_spec);
84 free(jmi);
87 void cbox_jack_midi_output_destroy(struct cbox_jack_midi_output *jmo)
89 if (jmo->port)
91 jack_port_unregister(jmo->jii->client, jmo->port);
92 jmo->port = NULL;
94 g_free(jmo->hdr.name);
95 g_free(jmo->autoconnect_spec);
96 free(jmo);
99 ///////////////////////////////////////////////////////////////////////////////
101 static int process_cb(jack_nframes_t nframes, void *arg)
103 struct cbox_jack_io_impl *jii = arg;
104 struct cbox_io *io = jii->ioi.pio;
105 struct cbox_io_callbacks *cb = io->cb;
107 io->io_env.buffer_size = nframes;
108 for (int i = 0; i < io->input_count; i++)
109 io->input_buffers[i] = jack_port_get_buffer(jii->inputs[i], nframes);
110 for (int i = 0; i < io->output_count; i++)
112 io->output_buffers[i] = jack_port_get_buffer(jii->outputs[i], nframes);
113 for (int j = 0; j < nframes; j ++)
114 io->output_buffers[i][j] = 0.f;
116 cb->process(cb->user_data, io, nframes);
117 for (int i = 0; i < io->input_count; i++)
118 io->input_buffers[i] = NULL;
119 for (int i = 0; i < io->output_count; i++)
120 io->output_buffers[i] = NULL;
121 for (GSList *p = io->midi_outputs; p; p = g_slist_next(p))
123 struct cbox_jack_midi_output *midiout = p->data;
125 void *pbuf = jack_port_get_buffer(midiout->port, nframes);
126 jack_midi_clear_buffer(pbuf);
128 cbox_midi_merger_render(&midiout->hdr.merger);
129 if (midiout->hdr.buffer.count)
131 uint8_t tmp_data[4];
132 for (int i = 0; i < midiout->hdr.buffer.count; i++)
134 const struct cbox_midi_event *event = cbox_midi_buffer_get_event(&midiout->hdr.buffer, i);
135 const uint8_t *pdata = cbox_midi_event_get_data(event);
136 if ((pdata[0] & 0xF0) == 0x90 && !pdata[2] && event->size == 3)
138 tmp_data[0] = pdata[0] & ~0x10;
139 tmp_data[1] = pdata[1];
140 tmp_data[2] = pdata[2];
141 pdata = tmp_data;
143 if (jack_midi_event_write(pbuf, event->time, pdata, event->size))
145 g_warning("MIDI buffer overflow on JACK output port '%s'", midiout->hdr.name);
146 break;
151 return 0;
154 static void autoconnect_port(jack_client_t *client, const char *port, const char *use_name, int is_cbox_input, const jack_port_t *only_connect_port, struct cbox_command_target *fb)
156 int res;
157 if (only_connect_port)
159 jack_port_t *right;
160 right = jack_port_by_name(client, use_name);
161 if (only_connect_port != right)
162 return;
165 const char *pfrom = is_cbox_input ? use_name : port;
166 const char *pto = !is_cbox_input ? use_name : port;
168 res = jack_connect(client, pfrom, pto);
169 if (res == EEXIST)
170 res = 0;
171 gboolean suppressed = FALSE;
172 if (fb)
174 if (!res)
175 suppressed = cbox_execute_on(fb, NULL, "/io/jack/connected", "ss", NULL, pfrom, pto);
176 else
177 suppressed = cbox_execute_on(fb, NULL, "/io/jack/connect_failed", "sss", NULL, pfrom, pto, (res == EEXIST ? "already connected" : "failed"));
179 if (!suppressed)
180 g_message("Connect: %s %s %s (%s)", port, is_cbox_input ? "<-" : "->", use_name, res == 0 ? "success" : (res == EEXIST ? "already connected" : "failed"));
183 static void autoconnect_by_spec(jack_client_t *client, const char *port, const char *orig_spec, int is_cbox_input, int is_midi, const jack_port_t *only_connect_port, struct cbox_command_target *fb)
185 char *name, *copy_spec, *dpos;
186 const char *use_name;
188 copy_spec = g_strdup(orig_spec);
189 name = copy_spec;
190 do {
191 dpos = strchr(name, ';');
192 if (dpos)
193 *dpos = '\0';
195 use_name = name;
196 if (use_name[0] == '#')
198 char *endptr = NULL;
199 long portidx = strtol(use_name + 1, &endptr, 10) - 1;
200 if (endptr == use_name + strlen(use_name))
202 const char **names = jack_get_ports(client, ".*", is_midi ? JACK_DEFAULT_MIDI_TYPE : JACK_DEFAULT_AUDIO_TYPE, is_cbox_input ? JackPortIsOutput : JackPortIsInput);
203 int i;
204 for (i = 0; i < portidx && names[i]; i++)
207 if (names[i])
208 autoconnect_port(client, port, names[i], is_cbox_input, only_connect_port, fb);
209 else
210 g_message("Connect: unmatched port index %d", (int)portidx);
212 jack_free(names);
215 else if (use_name[0] == '~' || use_name[0] == '*')
217 const char **names = jack_get_ports(client, use_name + 1, is_midi ? JACK_DEFAULT_MIDI_TYPE : JACK_DEFAULT_AUDIO_TYPE, is_cbox_input ? JackPortIsOutput : JackPortIsInput);
219 if (names && names[0])
221 if (use_name[0] == '*')
223 int i;
224 for (i = 0; names[i]; i++)
225 autoconnect_port(client, port, names[i], is_cbox_input, only_connect_port, fb);
227 else
228 autoconnect_port(client, port, names[0], is_cbox_input, only_connect_port, fb);
230 else
231 g_message("Connect: unmatched port regexp %s", use_name);
232 jack_free(names);
234 else
235 autoconnect_port(client, port, use_name, is_cbox_input, only_connect_port, fb);
237 if (dpos)
238 name = dpos + 1;
239 } while(dpos);
240 g_free(copy_spec);
243 static void autoconnect_by_var(jack_client_t *client, const char *port, const char *config_var, int is_cbox_input, int is_midi, const jack_port_t *only_connect_port, struct cbox_command_target *fb)
245 const char *orig_spec = cbox_config_get_string(cbox_io_section, config_var);
246 if (orig_spec)
247 autoconnect_by_spec(client, port, orig_spec, is_cbox_input, is_midi, only_connect_port, fb);
250 static void port_connect_cb(jack_port_id_t port, int registered, void *arg)
252 struct cbox_jack_io_impl *jii = arg;
253 if (registered)
255 jack_port_t *portobj = jack_port_by_id(jii->client, port);
257 jack_ringbuffer_write(jii->rb_autoconnect, (char *)&portobj, sizeof(portobj));
261 static void port_autoconnect(struct cbox_jack_io_impl *jii, jack_port_t *portobj, struct cbox_command_target *fb)
263 struct cbox_io *io = jii->ioi.pio;
265 for (int i = 0; i < io->output_count; i++)
267 gchar *cbox_port = g_strdup_printf("%s:out_%d", jii->client_name, 1 + i);
268 gchar *config_key = g_strdup_printf("out_%d", 1 + i);
269 autoconnect_by_var(jii->client, cbox_port, config_key, 0, 0, portobj, fb);
270 g_free(cbox_port);
271 g_free(config_key);
273 for (int i = 0; i < io->input_count; i++)
275 gchar *cbox_port = g_strdup_printf("%s:in_%d", jii->client_name, 1 + i);
276 gchar *config_key = g_strdup_printf("in_%d", 1 + i);
277 autoconnect_by_var(jii->client, cbox_port, config_key, 1, 0, portobj, fb);
278 g_free(cbox_port);
279 g_free(config_key);
281 for (GSList *p = io->midi_outputs; p; p = g_slist_next(p))
283 struct cbox_jack_midi_output *midiout = p->data;
284 if (midiout->autoconnect_spec)
286 gchar *cbox_port = g_strdup_printf("%s:%s", jii->client_name, midiout->hdr.name);
287 autoconnect_by_spec(jii->client, cbox_port, midiout->autoconnect_spec, 0, 1, portobj, fb);
288 g_free(cbox_port);
291 for (GSList *p = io->midi_inputs; p; p = g_slist_next(p))
293 struct cbox_jack_midi_input *midiin = p->data;
294 if (midiin->autoconnect_spec)
296 gchar *cbox_port = g_strdup_printf("%s:%s", jii->client_name, midiin->hdr.name);
297 autoconnect_by_spec(jii->client, cbox_port, midiin->autoconnect_spec, 1, 1, portobj, fb);
298 g_free(cbox_port);
301 gchar *cbox_port = g_strdup_printf("%s:midi", jii->client_name);
302 autoconnect_by_var(jii->client, cbox_port, "midi", 1, 1, portobj, fb);
303 g_free(cbox_port);
306 int cbox_jackio_get_sample_rate(struct cbox_io_impl *impl)
308 struct cbox_jack_io_impl *jii = (struct cbox_jack_io_impl *)impl;
310 return jack_get_sample_rate(jii->client);
313 gboolean cbox_jackio_get_status(struct cbox_io_impl *impl, GError **error)
315 struct cbox_jack_io_impl *jii = (struct cbox_jack_io_impl *)impl;
316 if (!jii->error_str)
317 return TRUE;
318 g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "%s", jii->error_str);
319 return FALSE;
322 static void client_shutdown_cb(jack_status_t code, const char *reason, void *arg)
324 struct cbox_jack_io_impl *jii = arg;
325 struct cbox_io *io = jii->ioi.pio;
326 jii->error_str = g_strdup(reason);
327 if (io->cb && io->cb->on_disconnected)
328 (io->cb->on_disconnected)(io->cb->user_data);
331 gboolean cbox_jackio_start(struct cbox_io_impl *impl, struct cbox_command_target *fb, GError **error)
333 struct cbox_jack_io_impl *jii = (struct cbox_jack_io_impl *)impl;
335 jack_set_process_callback(jii->client, process_cb, jii);
336 jack_set_port_registration_callback(jii->client, port_connect_cb, jii);
337 jack_on_info_shutdown(jii->client, client_shutdown_cb, jii);
338 jack_activate(jii->client);
340 if (cbox_config_has_section(cbox_io_section))
341 port_autoconnect(jii, NULL, fb);
343 return TRUE;
346 gboolean cbox_jackio_stop(struct cbox_io_impl *impl, GError **error)
348 struct cbox_jack_io_impl *jii = (struct cbox_jack_io_impl *)impl;
350 if (jii->error_str)
352 g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "%s", jii->error_str);
353 return FALSE;
355 jack_deactivate(jii->client);
356 return TRUE;
359 void cbox_jackio_poll_ports(struct cbox_io_impl *impl, struct cbox_command_target *fb)
361 struct cbox_jack_io_impl *jii = (struct cbox_jack_io_impl *)impl;
363 while (jack_ringbuffer_read_space(jii->rb_autoconnect) >= sizeof(jack_port_t *))
365 jack_port_t *portobj;
366 jack_ringbuffer_read(jii->rb_autoconnect, (char *)&portobj, sizeof(portobj));
367 port_autoconnect(jii, portobj, fb);
371 int cbox_jackio_get_midi_data(struct cbox_io_impl *impl, struct cbox_midi_buffer *destination)
373 struct cbox_jack_io_impl *jii = (struct cbox_jack_io_impl *)impl;
375 jack_port_t *port = jii->midi;
376 void *midi = jack_port_get_buffer(port, jii->ioi.pio->io_env.buffer_size);
377 uint32_t event_count = jack_midi_get_event_count(midi);
379 cbox_midi_buffer_clear(destination);
380 for (uint32_t i = 0; i < event_count; i++)
382 jack_midi_event_t event;
384 if (!jack_midi_event_get(&event, midi, i))
386 if (!cbox_midi_buffer_write_event(destination, event.time, event.buffer, event.size))
387 return -i;
389 else
390 return -i;
393 return event_count;
396 void cbox_jackio_destroy(struct cbox_io_impl *impl)
398 struct cbox_jack_io_impl *jii = (struct cbox_jack_io_impl *)impl;
399 struct cbox_io *io = impl->pio;
400 if (jii->client)
402 if (jii->error_str)
404 g_free(jii->error_str);
405 jii->error_str = NULL;
407 else
409 for (int i = 0; i < io->input_count; i++)
410 jack_port_unregister(jii->client, jii->inputs[i]);
411 free(jii->inputs);
412 for (int i = 0; i < io->output_count; i++)
413 jack_port_unregister(jii->client, jii->outputs[i]);
414 free(jii->outputs);
415 if (jii->midi)
416 jack_port_unregister(jii->client, jii->midi);
418 if (jii->client_name)
420 free(jii->client_name);
421 jii->client_name = NULL;
423 cbox_io_destroy_all_midi_ports(io);
425 jack_ringbuffer_free(jii->rb_autoconnect);
426 jack_client_close(jii->client);
428 free(jii);
431 gboolean cbox_jackio_cycle(struct cbox_io_impl *impl, struct cbox_command_target *fb, GError **error)
433 struct cbox_io *io = impl->pio;
434 struct cbox_io_callbacks *cb = io->cb;
435 cbox_io_close(io);
437 // XXXKF use params structure some day
438 if (!cbox_io_init_jack(io, NULL, fb, error))
439 return FALSE;
441 cbox_io_start(io, cb, fb);
442 if (cb->on_reconnected)
443 (cb->on_reconnected)(cb->user_data);
444 return TRUE;
449 ///////////////////////////////////////////////////////////////////////////////
451 struct cbox_midi_input *cbox_jackio_create_midi_in(struct cbox_io_impl *impl, const char *name, GError **error)
453 struct cbox_jack_io_impl *jii = (struct cbox_jack_io_impl *)impl;
454 jack_port_t *port = jack_port_register(jii->client, name, JACK_DEFAULT_MIDI_TYPE, JackPortIsInput, 0);
455 if (!port)
457 g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Cannot create input MIDI port '%s'", name);
458 return FALSE;
460 struct cbox_jack_midi_input *input = calloc(1, sizeof(struct cbox_jack_midi_input));
461 input->hdr.name = g_strdup(name);
462 input->hdr.removing = FALSE;
463 input->port = port;
464 input->jii = jii;
465 cbox_uuid_generate(&input->hdr.uuid);
466 cbox_midi_buffer_init(&input->hdr.buffer);
468 return (struct cbox_midi_input *)input;
471 struct cbox_midi_output *cbox_jackio_create_midi_out(struct cbox_io_impl *impl, const char *name, GError **error)
473 struct cbox_jack_io_impl *jii = (struct cbox_jack_io_impl *)impl;
474 jack_port_t *port = jack_port_register(jii->client, name, JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput, 0);
475 if (!port)
477 g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Cannot create output MIDI port '%s'", name);
478 return FALSE;
480 struct cbox_jack_midi_output *output = calloc(1, sizeof(struct cbox_jack_midi_output));
481 output->hdr.name = g_strdup(name);
482 output->hdr.removing = FALSE;
483 output->port = port;
484 output->jii = jii;
485 cbox_uuid_generate(&output->hdr.uuid);
486 cbox_midi_buffer_init(&output->hdr.buffer);
487 cbox_midi_merger_init(&output->hdr.merger, &output->hdr.buffer);
489 return (struct cbox_midi_output *)output;
492 void cbox_jack_midi_input_set_autoconnect(struct cbox_jack_midi_input *jmi, const gchar *autoconnect_spec)
494 if (jmi->autoconnect_spec)
495 g_free(jmi->autoconnect_spec);
496 jmi->autoconnect_spec = autoconnect_spec && *autoconnect_spec ? g_strdup(autoconnect_spec) : NULL;
497 if (jmi->autoconnect_spec)
499 gchar *cbox_port = g_strdup_printf("%s:%s", jmi->jii->client_name, jmi->hdr.name);
500 autoconnect_by_spec(jmi->jii->client, cbox_port, jmi->autoconnect_spec, 1, 1, NULL, NULL);
501 g_free(cbox_port);
505 void cbox_jack_midi_output_set_autoconnect(struct cbox_jack_midi_output *jmo, const gchar *autoconnect_spec)
507 if (jmo->autoconnect_spec)
508 g_free(jmo->autoconnect_spec);
509 jmo->autoconnect_spec = autoconnect_spec && *autoconnect_spec ? g_strdup(autoconnect_spec) : NULL;
510 if (jmo->autoconnect_spec)
512 gchar *cbox_port = g_strdup_printf("%s:%s", jmo->jii->client_name, jmo->hdr.name);
513 autoconnect_by_spec(jmo->jii->client, cbox_port, jmo->autoconnect_spec, 0, 1, NULL, NULL);
514 g_free(cbox_port);
518 void cbox_jackio_destroy_midi_in(struct cbox_io_impl *ioi, struct cbox_midi_input *midiin)
520 cbox_jack_midi_input_destroy((struct cbox_jack_midi_input *)midiin);
523 void cbox_jackio_destroy_midi_out(struct cbox_io_impl *ioi, struct cbox_midi_output *midiout)
525 cbox_jack_midi_output_destroy((struct cbox_jack_midi_output *)midiout);
528 static gboolean cbox_jack_io_process_cmd(struct cbox_command_target *ct, struct cbox_command_target *fb, struct cbox_osc_command *cmd, GError **error)
530 struct cbox_jack_io_impl *jii = (struct cbox_jack_io_impl *)ct->user_data;
531 struct cbox_io *io = jii->ioi.pio;
532 gboolean handled = FALSE;
533 if (!strcmp(cmd->command, "/status") && !strcmp(cmd->arg_types, ""))
535 if (!cbox_check_fb_channel(fb, cmd->command, error))
536 return FALSE;
537 return cbox_execute_on(fb, NULL, "/client_type", "s", error, "JACK") &&
538 cbox_execute_on(fb, NULL, "/client_name", "s", error, jii->client_name) &&
539 cbox_io_process_cmd(io, fb, cmd, error, &handled);
541 else if (!strcmp(cmd->command, "/rename_midi_port") && !strcmp(cmd->arg_types, "ss"))
543 const char *uuidstr = CBOX_ARG_S(cmd, 0);
544 const char *new_name = CBOX_ARG_S(cmd, 1);
545 struct cbox_uuid uuid;
546 if (!cbox_uuid_fromstring(&uuid, uuidstr, error))
547 return FALSE;
548 struct cbox_midi_input *midiin = cbox_io_get_midi_input(io, NULL, &uuid);
549 struct cbox_midi_output *midiout = cbox_io_get_midi_output(io, NULL, &uuid);
550 if (!midiout && !midiin)
552 g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Port '%s' not found", uuidstr);
553 return FALSE;
555 jack_port_t *port = midiout ? ((struct cbox_jack_midi_output *)midiout)->port
556 : ((struct cbox_jack_midi_input *)midiin)->port;
557 char **pname = midiout ? &midiout->name : &midiin->name;
558 if (0 != jack_port_set_name(port, new_name))
560 g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Cannot set port name to '%s'", new_name);
561 return FALSE;
563 g_free(*pname);
564 *pname = g_strdup(new_name);
565 return TRUE;
567 else if (!strcmp(cmd->command, "/autoconnect") && !strcmp(cmd->arg_types, "ss"))
569 const char *uuidstr = CBOX_ARG_S(cmd, 0);
570 const char *spec = CBOX_ARG_S(cmd, 1);
571 struct cbox_uuid uuid;
572 if (!cbox_uuid_fromstring(&uuid, uuidstr, error))
573 return FALSE;
574 struct cbox_midi_output *midiout = cbox_io_get_midi_output(io, NULL, &uuid);
575 if (midiout)
577 cbox_jack_midi_output_set_autoconnect((struct cbox_jack_midi_output *)midiout, spec);
578 return TRUE;
580 struct cbox_midi_input *midiin = cbox_io_get_midi_input(io, NULL, &uuid);
581 if (midiin)
583 cbox_jack_midi_input_set_autoconnect((struct cbox_jack_midi_input *)midiin, spec);
584 return TRUE;
586 g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Port '%s' not found", uuidstr);
587 return FALSE;
589 else if (!strcmp(cmd->command, "/disconnect_midi_port") && !strcmp(cmd->arg_types, "s"))
591 const char *uuidstr = CBOX_ARG_S(cmd, 0);
592 struct cbox_uuid uuid;
593 if (!cbox_uuid_fromstring(&uuid, uuidstr, error))
594 return FALSE;
595 struct cbox_midi_input *midiin = cbox_io_get_midi_input(io, NULL, &uuid);
596 struct cbox_midi_output *midiout = cbox_io_get_midi_output(io, NULL, &uuid);
597 if (!midiout && !midiin)
599 g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Port '%s' not found", uuidstr);
600 return FALSE;
602 jack_port_t *port = midiout ? ((struct cbox_jack_midi_output *)midiout)->port
603 : ((struct cbox_jack_midi_input *)midiin)->port;
604 jack_port_disconnect(jii->client, port);
605 return TRUE;
607 else if (!strcmp(cmd->command, "/port_connect") && !strcmp(cmd->arg_types, "ss"))
609 const char *port_from = CBOX_ARG_S(cmd, 0);
610 const char *port_to = CBOX_ARG_S(cmd, 1);
611 int res = jack_connect(jii->client, port_from, port_to);
612 if (res == EEXIST)
613 res = 0;
614 if (res)
615 g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Cannot connect port '%s' to '%s'", port_from, port_to);
616 return res == 0;
618 else if (!strcmp(cmd->command, "/port_disconnect") && !strcmp(cmd->arg_types, "ss"))
620 const char *port_from = CBOX_ARG_S(cmd, 0);
621 const char *port_to = CBOX_ARG_S(cmd, 1);
622 int res = jack_disconnect(jii->client, port_from, port_to);
623 if (res)
624 g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Cannot disconnect port '%s' from '%s'", port_from, port_to);
625 return res == 0;
627 else if (!strcmp(cmd->command, "/get_ports") && !strcmp(cmd->arg_types, "ssi"))
629 if (!cbox_check_fb_channel(fb, cmd->command, error))
630 return FALSE;
631 const char *mask = CBOX_ARG_S(cmd, 0);
632 const char *type = CBOX_ARG_S(cmd, 1);
633 uint32_t flags = CBOX_ARG_I(cmd, 2);
634 const char** ports = jack_get_ports(jii->client, mask, type, flags);
635 for (int i = 0; ports && ports[i]; i++)
637 if (!cbox_execute_on(fb, NULL, "/port", "s", error, ports[i]))
638 return FALSE;
641 return TRUE;
643 else
645 gboolean result = cbox_io_process_cmd(io, fb, cmd, error, &handled);
646 if (!handled)
647 g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Unknown combination of target path and argument: '%s', '%s'", cmd->command, cmd->arg_types);
648 return result;
652 ///////////////////////////////////////////////////////////////////////////////
654 gboolean cbox_io_init_jack(struct cbox_io *io, struct cbox_open_params *const params, struct cbox_command_target *fb, GError **error)
656 const char *client_name = cbox_config_get_string_with_default("io", "client_name", "cbox");
658 jack_client_t *client = NULL;
659 jack_status_t status = 0;
660 client = jack_client_open(client_name, JackNoStartServer, &status);
661 if (client == NULL)
663 if (!cbox_hwcfg_setup_jack())
665 g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Cannot set up JACK server configuration based on current hardware");
666 return FALSE;
669 status = 0;
670 client = jack_client_open(client_name, 0, &status);
672 if (client == NULL)
674 g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Cannot create JACK instance");
675 return FALSE;
678 // XXXKF would use a callback instead
679 io->io_env.buffer_size = jack_get_buffer_size(client);
680 io->cb = NULL;
681 io->input_count = cbox_config_get_int("io", "inputs", 0);
682 io->input_buffers = malloc(sizeof(float *) * io->input_count);
683 io->output_count = cbox_config_get_int("io", "outputs", 2);
684 io->output_buffers = malloc(sizeof(float *) * io->output_count);
686 struct cbox_jack_io_impl *jii = malloc(sizeof(struct cbox_jack_io_impl));
687 io->impl = &jii->ioi;
689 cbox_command_target_init(&io->cmd_target, cbox_jack_io_process_cmd, jii);
690 jii->ioi.pio = io;
691 jii->ioi.getsampleratefunc = cbox_jackio_get_sample_rate;
692 jii->ioi.startfunc = cbox_jackio_start;
693 jii->ioi.stopfunc = cbox_jackio_stop;
694 jii->ioi.getstatusfunc = cbox_jackio_get_status;
695 jii->ioi.pollfunc = cbox_jackio_poll_ports;
696 jii->ioi.cyclefunc = cbox_jackio_cycle;
697 jii->ioi.getmidifunc = cbox_jackio_get_midi_data;
698 jii->ioi.createmidiinfunc = cbox_jackio_create_midi_in;
699 jii->ioi.destroymidiinfunc = cbox_jackio_destroy_midi_in;
700 jii->ioi.createmidioutfunc = cbox_jackio_create_midi_out;
701 jii->ioi.destroymidioutfunc = cbox_jackio_destroy_midi_out;
702 jii->ioi.destroyfunc = cbox_jackio_destroy;
704 jii->client_name = g_strdup(jack_get_client_name(client));
705 jii->client = client;
706 jii->rb_autoconnect = jack_ringbuffer_create(sizeof(jack_port_t *) * 128);
707 jii->error_str = NULL;
709 jii->inputs = malloc(sizeof(jack_port_t *) * io->input_count);
710 jii->outputs = malloc(sizeof(jack_port_t *) * io->output_count);
711 for (int i = 0; i < io->input_count; i++)
712 jii->inputs[i] = NULL;
713 for (int i = 0; i < io->output_count; i++)
714 jii->outputs[i] = NULL;
715 for (int i = 0; i < io->input_count; i++)
717 gchar *name = g_strdup_printf("in_%d", 1 + i);
718 jii->inputs[i] = jack_port_register(jii->client, name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0);
719 if (!jii->inputs[i])
721 g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Cannot create input port %d (%s)", i, name);
722 g_free(name);
723 goto cleanup;
725 g_free(name);
727 for (int i = 0; i < io->output_count; i++)
729 gchar *name = g_strdup_printf("out_%d", 1 + i);
730 jii->outputs[i] = jack_port_register(jii->client, name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
731 if (!jii->outputs[i])
733 g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Cannot create output port %d (%s)", i, name);
734 g_free(name);
735 goto cleanup;
737 g_free(name);
739 jii->midi = jack_port_register(jii->client, "midi", JACK_DEFAULT_MIDI_TYPE, JackPortIsInput, 0);
741 if (!jii->midi)
743 g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Cannot create MIDI port");
744 return FALSE;
746 if (fb)
747 cbox_execute_on(fb, NULL, "/io/jack_client_name", "s", NULL, jii->client_name);
749 cbox_io_poll_ports(io, fb);
751 return TRUE;
753 cleanup:
754 if (jii->inputs)
756 for (int i = 0; i < io->input_count; i++)
757 free(jii->inputs[i]);
758 free(jii->inputs);
760 if (jii->outputs)
762 for (int i = 0; i < io->output_count; i++)
763 free(jii->outputs[i]);
764 free(jii->outputs);
766 cbox_io_destroy_all_midi_ports(io);
767 if (jii->client_name)
768 free(jii->client_name);
769 jack_client_close(jii->client);
770 free(jii);
771 io->impl = NULL;
772 return FALSE;