static gboolean cbox_instrument_output_process_cmd(struct cbox_instrument *instr, struct cbox_instrument_output *output, struct cbox_command_target *fb, struct cbox_osc_command *cmd, const char *subcmd, GError **error) { if (!strcmp(subcmd, "/status") && !strcmp(cmd->arg_types, "")) { if (!(cbox_execute_on(fb, NULL, "/gain_linear", "f", error, output->gain) && cbox_execute_on(fb, NULL, "/gain", "f", error, gain2dB_simple(output->gain)) && cbox_execute_on(fb, NULL, "/output", "i", error, output->output_bus + 1))) return FALSE; return cbox_module_slot_process_cmd(&output->insert, fb, cmd, subcmd, CBOX_GET_DOCUMENT(instr->scene), instr->scene->rt, instr->scene->engine, error); } if (!strcmp(subcmd, "/gain") && !strcmp(cmd->arg_types, "f")) { output->gain = dB2gain_simple(CBOX_ARG_F(cmd, 0)); return TRUE; } if (!strcmp(subcmd, "/output") && !strcmp(cmd->arg_types, "i")) { int obus = CBOX_ARG_I(cmd, 0); // XXXKF add error checking output->output_bus = obus - 1; return TRUE; } if (!strncmp(subcmd, "/rec_dry/", 9)) return cbox_execute_sub(&output->rec_dry.cmd_target, fb, cmd, subcmd + 8, error); if (!strncmp(subcmd, "/rec_wet/", 9)) return cbox_execute_sub(&output->rec_wet.cmd_target, fb, cmd, subcmd + 8, error); return cbox_module_slot_process_cmd(&output->insert, fb, cmd, subcmd, CBOX_GET_DOCUMENT(instr->scene), instr->scene->rt, instr->scene->engine, error); }
static gboolean cbox_jack_io_process_cmd(struct cbox_command_target *ct, struct cbox_command_target *fb, struct cbox_osc_command *cmd, GError **error) { struct cbox_jack_io_impl *jii = (struct cbox_jack_io_impl *)ct->user_data; struct cbox_io *io = jii->ioi.pio; gboolean handled = FALSE; if (!strcmp(cmd->command, "/status") && !strcmp(cmd->arg_types, "")) { if (!cbox_check_fb_channel(fb, cmd->command, error)) return FALSE; return cbox_execute_on(fb, NULL, "/client_type", "s", error, "JACK") && cbox_execute_on(fb, NULL, "/client_name", "s", error, jii->client_name) && cbox_io_process_cmd(io, fb, cmd, error, &handled); } else if (!strcmp(cmd->command, "/rename_midi_port") && !strcmp(cmd->arg_types, "ss")) { const char *uuidstr = CBOX_ARG_S(cmd, 0); const char *new_name = CBOX_ARG_S(cmd, 1); struct cbox_uuid uuid; if (!cbox_uuid_fromstring(&uuid, uuidstr, error)) return FALSE; struct cbox_midi_input *midiin = cbox_io_get_midi_input(io, NULL, &uuid); struct cbox_midi_output *midiout = cbox_io_get_midi_output(io, NULL, &uuid); if (!midiout && !midiin) { g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Port '%s' not found", uuidstr); return FALSE; } jack_port_t *port = midiout ? ((struct cbox_jack_midi_output *)midiout)->port : ((struct cbox_jack_midi_input *)midiin)->port; char **pname = midiout ? &midiout->name : &midiin->name; if (0 != jack_port_set_name(port, new_name)) { g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Cannot set port name to '%s'", new_name); return FALSE; } g_free(*pname); *pname = g_strdup(new_name); return TRUE; } else if (!strcmp(cmd->command, "/autoconnect") && !strcmp(cmd->arg_types, "ss")) { const char *uuidstr = CBOX_ARG_S(cmd, 0); const char *spec = CBOX_ARG_S(cmd, 1); struct cbox_uuid uuid; if (!cbox_uuid_fromstring(&uuid, uuidstr, error)) return FALSE; struct cbox_midi_output *midiout = cbox_io_get_midi_output(io, NULL, &uuid); if (midiout) { cbox_jack_midi_output_set_autoconnect((struct cbox_jack_midi_output *)midiout, spec); return TRUE; } struct cbox_midi_input *midiin = cbox_io_get_midi_input(io, NULL, &uuid); if (midiin) { cbox_jack_midi_input_set_autoconnect((struct cbox_jack_midi_input *)midiin, spec); return TRUE; } g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Port '%s' not found", uuidstr); return FALSE; } else if (!strcmp(cmd->command, "/disconnect_midi_port") && !strcmp(cmd->arg_types, "s")) { const char *uuidstr = CBOX_ARG_S(cmd, 0); struct cbox_uuid uuid; if (!cbox_uuid_fromstring(&uuid, uuidstr, error)) return FALSE; struct cbox_midi_input *midiin = cbox_io_get_midi_input(io, NULL, &uuid); struct cbox_midi_output *midiout = cbox_io_get_midi_output(io, NULL, &uuid); if (!midiout && !midiin) { g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Port '%s' not found", uuidstr); return FALSE; } jack_port_t *port = midiout ? ((struct cbox_jack_midi_output *)midiout)->port : ((struct cbox_jack_midi_input *)midiin)->port; jack_port_disconnect(jii->client, port); return TRUE; } else if (!strcmp(cmd->command, "/port_connect") && !strcmp(cmd->arg_types, "ss")) { const char *port_from = CBOX_ARG_S(cmd, 0); const char *port_to = CBOX_ARG_S(cmd, 1); int res = jack_connect(jii->client, port_from, port_to); if (res == EEXIST) res = 0; if (res) g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Cannot connect port '%s' to '%s'", port_from, port_to); return res == 0; } else if (!strcmp(cmd->command, "/port_disconnect") && !strcmp(cmd->arg_types, "ss")) { const char *port_from = CBOX_ARG_S(cmd, 0); const char *port_to = CBOX_ARG_S(cmd, 1); int res = jack_disconnect(jii->client, port_from, port_to); if (res) g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Cannot disconnect port '%s' from '%s'", port_from, port_to); return res == 0; } else if (!strcmp(cmd->command, "/get_connected_ports") && !strcmp(cmd->arg_types, "s")) { if (!cbox_check_fb_channel(fb, cmd->command, error)) return FALSE; const char *name = CBOX_ARG_S(cmd, 0); jack_port_t *port = jack_port_by_name(jii->client, name); if (!port) { g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Port '%s' not found", name); return FALSE; } const char** ports = jack_port_get_all_connections(jii->client, port); for (int i = 0; ports && ports[i]; i++) { if (!cbox_execute_on(fb, NULL, "/port", "s", error, ports[i])) return FALSE; } jack_free(ports); return TRUE; } else if (!strcmp(cmd->command, "/get_ports") && !strcmp(cmd->arg_types, "ssi")) { if (!cbox_check_fb_channel(fb, cmd->command, error)) return FALSE; const char *mask = CBOX_ARG_S(cmd, 0); const char *type = CBOX_ARG_S(cmd, 1); uint32_t flags = CBOX_ARG_I(cmd, 2); const char** ports = jack_get_ports(jii->client, mask, type, flags); for (int i = 0; ports && ports[i]; i++) { if (!cbox_execute_on(fb, NULL, "/port", "s", error, ports[i])) return FALSE; } jack_free(ports); return TRUE; } else { gboolean result = cbox_io_process_cmd(io, fb, cmd, error, &handled); if (!handled) 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); return result; } }
gboolean cbox_module_slot_process_cmd(struct cbox_module **psm, struct cbox_command_target *fb, struct cbox_osc_command *cmd, const char *subcmd, struct cbox_document *doc, struct cbox_rt *rt, struct cbox_engine *engine, GError **error) { struct cbox_module *sm = *psm; if (!strcmp(subcmd, "/status") && !strcmp(cmd->arg_types, "")) { if (!cbox_check_fb_channel(fb, cmd->command, error)) return FALSE; if (!(cbox_execute_on(fb, NULL, "/insert_engine", "s", error, sm ? sm->engine_name : "") && cbox_execute_on(fb, NULL, "/insert_preset", "s", error, sm ? sm->instance_name : "") && cbox_execute_on(fb, NULL, "/bypass", "i", error, sm ? sm->bypass : 0))) return FALSE; return TRUE; } if (!strcmp(subcmd, "/insert_preset") && !strcmp(cmd->arg_types, "s")) { struct cbox_module *effect = cbox_module_new_from_fx_preset(CBOX_ARG_S(cmd, 0), doc, rt, engine, error); if (!effect) return FALSE; cbox_rt_swap_pointers(rt, (void **)psm, effect); return TRUE; } if (!strcmp(subcmd, "/insert_engine") && !strcmp(cmd->arg_types, "s")) { struct cbox_module *effect = NULL; if (*CBOX_ARG_S(cmd, 0)) { struct cbox_module_manifest *manifest = cbox_module_manifest_get_by_name(CBOX_ARG_S(cmd, 0)); if (!manifest) { g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "No effect engine '%s'", CBOX_ARG_S(cmd, 0)); return FALSE; } effect = cbox_module_manifest_create_module(manifest, NULL, doc, rt, engine, "unnamed", error); if (!effect) return FALSE; } cbox_rt_swap_pointers(rt, (void **)psm, effect); return TRUE; } if (!sm) { g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "No engine on module in path '%s'", cmd->command); return FALSE; } if (!strncmp(subcmd, "/engine/", 8)) { if (!sm->cmd_target.process_cmd) { g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "The engine %s has no command target defined", sm->engine_name); return FALSE; } return cbox_execute_sub(&sm->cmd_target, fb, cmd, subcmd + 7, error); } if (!strcmp(subcmd, "/set_bypass") && !strcmp(cmd->arg_types, "i")) { sm->bypass = CBOX_ARG_I(cmd, 0); return TRUE; } return cbox_object_default_process_cmd(&sm->cmd_target, fb, cmd, error); }
static gboolean cbox_engine_process_cmd(struct cbox_command_target *ct, struct cbox_command_target *fb, struct cbox_osc_command *cmd, GError **error) { struct cbox_engine *engine = ct->user_data; if (!strcmp(cmd->command, "/status") && !strcmp(cmd->arg_types, "")) { for (int i = 0; i < engine->scene_count; i++) { if (!cbox_execute_on(fb, NULL, "/scene", "o", error, engine->scenes[i])) return FALSE; } return CBOX_OBJECT_DEFAULT_STATUS(engine, fb, error); } else if (!strcmp(cmd->command, "/render_stereo") && !strcmp(cmd->arg_types, "i")) { if (!cbox_check_fb_channel(fb, cmd->command, error)) return FALSE; if (engine->rt && engine->rt->io) { g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Cannot use render function in real-time mode."); return FALSE; } struct cbox_midi_buffer midibuf_song; cbox_midi_buffer_init(&midibuf_song); int nframes = CBOX_ARG_I(cmd, 0); float *data = malloc(2 * nframes * sizeof(float)); float *data_i = malloc(2 * nframes * sizeof(float)); float *buffers[2] = { data, data + nframes }; for (int i = 0; i < nframes; i++) { buffers[0][i] = 0.f; buffers[1][i] = 0.f; } cbox_engine_process(engine, NULL, nframes, buffers); for (int i = 0; i < nframes; i++) { data_i[i * 2] = buffers[0][i]; data_i[i * 2 + 1] = buffers[1][i]; } free(data); if (!cbox_execute_on(fb, NULL, "/data", "b", error, cbox_blob_new_acquire_data(data_i, nframes * 2 * sizeof(float)))) return FALSE; return TRUE; } else if (!strncmp(cmd->command, "/master_effect/",15)) { return cbox_module_slot_process_cmd(&engine->effect, fb, cmd, cmd->command + 14, CBOX_GET_DOCUMENT(engine), engine->rt, engine, error); } else if (!strcmp(cmd->command, "/new_scene") && !strcmp(cmd->arg_types, "")) { if (!cbox_check_fb_channel(fb, cmd->command, error)) return FALSE; struct cbox_scene *s = cbox_scene_new(CBOX_GET_DOCUMENT(engine), engine); return s ? cbox_execute_on(fb, NULL, "/uuid", "o", error, s) : FALSE; } else if (!strcmp(cmd->command, "/new_recorder") && !strcmp(cmd->arg_types, "s")) { if (!cbox_check_fb_channel(fb, cmd->command, error)) return FALSE; struct cbox_recorder *rec = cbox_recorder_new_stream(engine, engine->rt, CBOX_ARG_S(cmd, 0)); return rec ? cbox_execute_on(fb, NULL, "/uuid", "o", error, rec) : FALSE; } else return cbox_object_default_process_cmd(ct, fb, cmd, error); }
gboolean cbox_song_process_cmd(struct cbox_command_target *ct, struct cbox_command_target *fb, struct cbox_osc_command *cmd, GError **error) { struct cbox_song *song = ct->user_data; if (!strcmp(cmd->command, "/status") && !strcmp(cmd->arg_types, "")) { if (!cbox_check_fb_channel(fb, cmd->command, error)) return FALSE; for(GList *p = song->tracks; p; p = g_list_next(p)) { struct cbox_track *trk = p->data; if (!cbox_execute_on(fb, NULL, "/track", "sio", error, trk->name, g_list_length(trk->items), trk)) return FALSE; } for(GList *p = song->patterns; p; p = g_list_next(p)) { struct cbox_midi_pattern *pat = p->data; if (!cbox_execute_on(fb, NULL, "/pattern", "sio", error, pat->name, pat->loop_end, pat)) return FALSE; } uint32_t pos = 0; for(GList *p = song->master_track_items; p; p = g_list_next(p)) { struct cbox_master_track_item *mti = p->data; // Omit dummy item at 0 position. if (pos || (mti->timesig_num && mti->timesig_denom) || mti->tempo) { if (!cbox_execute_on(fb, NULL, "/mti", "ifii", error, pos, mti->tempo, mti->timesig_num, mti->timesig_denom)) return FALSE; } pos += mti->duration_ppqn; } return cbox_execute_on(fb, NULL, "/loop_start", "i", error, (int)song->loop_start_ppqn) && cbox_execute_on(fb, NULL, "/loop_end", "i", error, (int)song->loop_end_ppqn) && CBOX_OBJECT_DEFAULT_STATUS(song, fb, error); } else if (!strcmp(cmd->command, "/set_loop") && !strcmp(cmd->arg_types, "ii")) { song->loop_start_ppqn = CBOX_ARG_I(cmd, 0); song->loop_end_ppqn = CBOX_ARG_I(cmd, 1); return TRUE; } else if (!strcmp(cmd->command, "/set_mti") && !strcmp(cmd->arg_types, "ifii")) { cbox_song_set_mti(song, CBOX_ARG_I(cmd, 0), CBOX_ARG_F(cmd, 1), CBOX_ARG_I(cmd, 2), CBOX_ARG_I(cmd, 3)); return TRUE; } else if (!strcmp(cmd->command, "/clear") && !strcmp(cmd->arg_types, "")) { cbox_song_clear(song); return TRUE; } else if (!strcmp(cmd->command, "/add_track") && !strcmp(cmd->arg_types, "")) { if (!cbox_check_fb_channel(fb, cmd->command, error)) return FALSE; struct cbox_track *track = cbox_track_new(CBOX_GET_DOCUMENT(song)); cbox_song_add_track(song, track); if (!cbox_execute_on(fb, NULL, "/uuid", "o", error, track)) { CBOX_DELETE(track); return FALSE; } return TRUE; } else if (!strcmp(cmd->command, "/load_pattern") && !strcmp(cmd->arg_types, "si")) { if (!cbox_check_fb_channel(fb, cmd->command, error)) return FALSE; struct cbox_midi_pattern *pattern = cbox_midi_pattern_load(song, CBOX_ARG_S(cmd, 0), CBOX_ARG_I(cmd, 1), app.engine->master->ppqn_factor); if (!cbox_execute_on(fb, NULL, "/uuid", "o", error, pattern)) { CBOX_DELETE(pattern); return FALSE; } return TRUE; } else if (!strcmp(cmd->command, "/load_track") && !strcmp(cmd->arg_types, "si")) { if (!cbox_check_fb_channel(fb, cmd->command, error)) return FALSE; struct cbox_midi_pattern *pattern = cbox_midi_pattern_load_track(song, CBOX_ARG_S(cmd, 0), CBOX_ARG_I(cmd, 1), app.engine->master->ppqn_factor); if (!cbox_execute_on(fb, NULL, "/uuid", "o", error, pattern)) { CBOX_DELETE(pattern); return FALSE; } return TRUE; } else if (!strcmp(cmd->command, "/load_metronome") && !strcmp(cmd->arg_types, "i")) { if (!cbox_check_fb_channel(fb, cmd->command, error)) return FALSE; struct cbox_midi_pattern *pattern = cbox_midi_pattern_new_metronome(song, CBOX_ARG_I(cmd, 0), app.engine->master->ppqn_factor); if (!cbox_execute_on(fb, NULL, "/uuid", "o", error, pattern)) { CBOX_DELETE(pattern); return FALSE; } return TRUE; } else if (!strcmp(cmd->command, "/load_blob") && !strcmp(cmd->arg_types, "bi")) { if (!cbox_check_fb_channel(fb, cmd->command, error)) return FALSE; struct cbox_midi_pattern *pattern = cbox_midi_pattern_new_from_blob(song, CBOX_ARG_B(cmd, 0), CBOX_ARG_I(cmd, 1), app.engine->master->ppqn_factor); if (!cbox_execute_on(fb, NULL, "/uuid", "o", error, pattern)) { CBOX_DELETE(pattern); return FALSE; } return TRUE; } else return cbox_object_default_process_cmd(ct, fb, cmd, error); return TRUE; }
gboolean cbox_layer_process_cmd(struct cbox_command_target *ct, struct cbox_command_target *fb, struct cbox_osc_command *cmd, GError **error) { struct cbox_layer *layer = ct->user_data; if (!strcmp(cmd->command, "/status") && !strcmp(cmd->arg_types, "")) { if (!cbox_check_fb_channel(fb, cmd->command, error)) return FALSE; if (!(cbox_execute_on(fb, NULL, "/enable", "i", error, (int)layer->enabled) && cbox_execute_on(fb, NULL, "/instrument_name", "s", error, layer->instrument->module->instance_name) && cbox_execute_on(fb, NULL, "/instrument_uuid", "o", error, layer->instrument) && cbox_execute_on(fb, NULL, "/consume", "i", error, (int)layer->consume) && cbox_execute_on(fb, NULL, "/ignore_scene_transpose", "i", error, (int)layer->ignore_scene_transpose) && cbox_execute_on(fb, NULL, "/ignore_program_changes", "i", error, (int)layer->ignore_program_changes) && cbox_execute_on(fb, NULL, "/disable_aftertouch", "i", error, (int)layer->disable_aftertouch) && cbox_execute_on(fb, NULL, "/transpose", "i", error, (int)layer->transpose) && cbox_execute_on(fb, NULL, "/fixed_note", "i", error, (int)layer->fixed_note) && cbox_execute_on(fb, NULL, "/low_note", "i", error, (int)layer->low_note) && cbox_execute_on(fb, NULL, "/high_note", "i", error, (int)layer->high_note) && cbox_execute_on(fb, NULL, "/in_channel", "i", error, layer->in_channel + 1) && cbox_execute_on(fb, NULL, "/out_channel", "i", error, layer->out_channel + 1) && CBOX_OBJECT_DEFAULT_STATUS(layer, fb, error))) return FALSE; return TRUE; } else if (!strcmp(cmd->command, "/enable") && !strcmp(cmd->arg_types, "i")) { layer->enabled = 0 != CBOX_ARG_I(cmd, 0); return TRUE; } else if (!strcmp(cmd->command, "/consume") && !strcmp(cmd->arg_types, "i")) { layer->consume = 0 != CBOX_ARG_I(cmd, 0); return TRUE; } else if (!strcmp(cmd->command, "/ignore_scene_transpose") && !strcmp(cmd->arg_types, "i")) { layer->ignore_scene_transpose = 0 != CBOX_ARG_I(cmd, 0); return TRUE; } else if (!strcmp(cmd->command, "/ignore_program_changes") && !strcmp(cmd->arg_types, "i")) { layer->ignore_program_changes = 0 != CBOX_ARG_I(cmd, 0); return TRUE; } else if (!strcmp(cmd->command, "/disable_aftertouch") && !strcmp(cmd->arg_types, "i")) { layer->disable_aftertouch = 0 != CBOX_ARG_I(cmd, 0); return TRUE; } else if (!strcmp(cmd->command, "/transpose") && !strcmp(cmd->arg_types, "i")) { layer->transpose = CBOX_ARG_I(cmd, 0); return TRUE; } else if (!strcmp(cmd->command, "/fixed_note") && !strcmp(cmd->arg_types, "i")) { layer->fixed_note = CBOX_ARG_I(cmd, 0); return TRUE; } else if (!strcmp(cmd->command, "/low_note") && !strcmp(cmd->arg_types, "i")) { layer->low_note = CBOX_ARG_I(cmd, 0); return TRUE; } else if (!strcmp(cmd->command, "/high_note") && !strcmp(cmd->arg_types, "i")) { layer->high_note = CBOX_ARG_I(cmd, 0); return TRUE; } else if (!strcmp(cmd->command, "/in_channel") && !strcmp(cmd->arg_types, "i")) { layer->in_channel = CBOX_ARG_I(cmd, 0) - 1; return TRUE; } else if (!strcmp(cmd->command, "/out_channel") && !strcmp(cmd->arg_types, "i")) { layer->out_channel = CBOX_ARG_I(cmd, 0) - 1; return TRUE; } else // otherwise, treat just like an command on normal (non-aux) output return cbox_object_default_process_cmd(ct, fb, cmd, error); }
static gboolean cbox_jack_io_process_cmd(struct cbox_command_target *ct, struct cbox_command_target *fb, struct cbox_osc_command *cmd, GError **error) { struct cbox_jack_io_impl *jii = (struct cbox_jack_io_impl *)ct->user_data; struct cbox_io *io = jii->ioi.pio; gboolean handled = FALSE; if (!strcmp(cmd->command, "/status") && !strcmp(cmd->arg_types, "")) { if (!cbox_check_fb_channel(fb, cmd->command, error)) return FALSE; return cbox_execute_on(fb, NULL, "/client_type", "s", error, "JACK") && cbox_execute_on(fb, NULL, "/client_name", "s", error, jii->client_name) && cbox_execute_on(fb, NULL, "/external_tempo", "i", error, jii->external_tempo) && cbox_io_process_cmd(io, fb, cmd, error, &handled); } else if (!strcmp(cmd->command, "/rename_midi_port") && !strcmp(cmd->arg_types, "ss")) { const char *uuidstr = CBOX_ARG_S(cmd, 0); const char *new_name = CBOX_ARG_S(cmd, 1); struct cbox_uuid uuid; if (!cbox_uuid_fromstring(&uuid, uuidstr, error)) return FALSE; struct cbox_midi_input *midiin = cbox_io_get_midi_input(io, NULL, &uuid); struct cbox_midi_output *midiout = cbox_io_get_midi_output(io, NULL, &uuid); if (!midiout && !midiin) { g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Port '%s' not found", uuidstr); return FALSE; } jack_port_t *port = midiout ? ((struct cbox_jack_midi_output *)midiout)->port : ((struct cbox_jack_midi_input *)midiin)->port; char **pname = midiout ? &midiout->name : &midiin->name; if (0 != jack_port_rename_fn(jii->client, port, new_name)) { g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Cannot set port name to '%s'", new_name); return FALSE; } g_free(*pname); *pname = g_strdup(new_name); return TRUE; } else if (!strcmp(cmd->command, "/rename_audio_port") && !strcmp(cmd->arg_types, "ss")) { const char *uuidstr = CBOX_ARG_S(cmd, 0); const char *new_name = CBOX_ARG_S(cmd, 1); struct cbox_uuid uuid; if (!cbox_uuid_fromstring(&uuid, uuidstr, error)) return FALSE; struct cbox_audio_output *audioout = cbox_io_get_audio_output(io, NULL, &uuid); if (!audioout) { g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Port '%s' not found", uuidstr); return FALSE; } if (0 != jack_port_rename_fn(jii->client, ((struct cbox_jack_audio_output *)audioout)->port, new_name)) { g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Cannot set port name to '%s'", new_name); return FALSE; } g_free(audioout->name); audioout->name = g_strdup(new_name); return TRUE; } else if (!strcmp(cmd->command, "/autoconnect") && !strcmp(cmd->arg_types, "ss")) { const char *uuidstr = CBOX_ARG_S(cmd, 0); const char *spec = CBOX_ARG_S(cmd, 1); struct cbox_uuid uuid; if (!cbox_uuid_fromstring(&uuid, uuidstr, error)) return FALSE; struct cbox_midi_output *midiout = cbox_io_get_midi_output(io, NULL, &uuid); if (midiout) { cbox_jack_midi_output_set_autoconnect((struct cbox_jack_midi_output *)midiout, spec); return TRUE; } struct cbox_midi_input *midiin = cbox_io_get_midi_input(io, NULL, &uuid); if (midiin) { cbox_jack_midi_input_set_autoconnect((struct cbox_jack_midi_input *)midiin, spec); return TRUE; } struct cbox_audio_output *audioout = cbox_io_get_audio_output(io, NULL, &uuid); if (audioout) { cbox_jack_audio_output_set_autoconnect((struct cbox_jack_audio_output *)audioout, spec); return TRUE; } g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Port '%s' not found", uuidstr); return FALSE; } else if (!strcmp(cmd->command, "/disconnect_audio_output") && !strcmp(cmd->arg_types, "s")) { const char *uuidstr = CBOX_ARG_S(cmd, 0); struct cbox_uuid uuid; if (!cbox_uuid_fromstring(&uuid, uuidstr, error)) return FALSE; struct cbox_audio_output *audioout = cbox_io_get_audio_output(io, NULL, &uuid); if (!audioout) { g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Port '%s' not found", uuidstr); return FALSE; } jack_port_disconnect(jii->client, ((struct cbox_jack_audio_output *)audioout)->port); return TRUE; } else if (!strncmp(cmd->command, "/disconnect_midi_", 17) && !strcmp(cmd->arg_types, "s")) { bool is_both = !strcmp(cmd->command + 17, "port"); bool is_in = is_both || !strcmp(cmd->command + 17, "input"); bool is_out = is_both || !strcmp(cmd->command + 17, "output"); if (is_in || is_out) { const char *uuidstr = CBOX_ARG_S(cmd, 0); struct cbox_uuid uuid; if (!cbox_uuid_fromstring(&uuid, uuidstr, error)) return FALSE; struct cbox_midi_input *midiin = is_in ? cbox_io_get_midi_input(io, NULL, &uuid) : NULL; struct cbox_midi_output *midiout = is_out ? cbox_io_get_midi_output(io, NULL, &uuid) : NULL; if (!midiout && !midiin) { g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Port '%s' not found", uuidstr); return FALSE; } jack_port_t *port = midiout ? ((struct cbox_jack_midi_output *)midiout)->port : ((struct cbox_jack_midi_input *)midiin)->port; jack_port_disconnect(jii->client, port); return TRUE; } } if (!strcmp(cmd->command, "/port_connect") && !strcmp(cmd->arg_types, "ss")) { const char *port_from = CBOX_ARG_S(cmd, 0); const char *port_to = CBOX_ARG_S(cmd, 1); int res = jack_connect(jii->client, port_from, port_to); if (res == EEXIST) res = 0; if (res) g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Cannot connect port '%s' to '%s'", port_from, port_to); return res == 0; } else if (!strcmp(cmd->command, "/port_disconnect") && !strcmp(cmd->arg_types, "ss")) { const char *port_from = CBOX_ARG_S(cmd, 0); const char *port_to = CBOX_ARG_S(cmd, 1); int res = jack_disconnect(jii->client, port_from, port_to); if (res) g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Cannot disconnect port '%s' from '%s'", port_from, port_to); return res == 0; } else if (!strcmp(cmd->command, "/get_connected_ports") && !strcmp(cmd->arg_types, "s")) { if (!cbox_check_fb_channel(fb, cmd->command, error)) return FALSE; const char *name = CBOX_ARG_S(cmd, 0); jack_port_t *port = NULL; if (!strchr(name, ':')) { // try UUID struct cbox_uuid uuid; if (!cbox_uuid_fromstring(&uuid, name, error)) return FALSE; struct cbox_midi_output *midiout = cbox_io_get_midi_output(io, NULL, &uuid); if (midiout) port = ((struct cbox_jack_midi_output *)midiout)->port; else { struct cbox_midi_input *midiin = cbox_io_get_midi_input(io, NULL, &uuid); if (midiin) port = ((struct cbox_jack_midi_input *)midiin)->port; } } else port = jack_port_by_name(jii->client, name); if (!port) { g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Port '%s' not found", name); return FALSE; } const char** ports = jack_port_get_all_connections(jii->client, port); for (int i = 0; ports && ports[i]; i++) { if (!cbox_execute_on(fb, NULL, "/port", "s", error, ports[i])) return FALSE; } jack_free(ports); return TRUE; } else if (!strcmp(cmd->command, "/get_ports") && !strcmp(cmd->arg_types, "ssi")) { if (!cbox_check_fb_channel(fb, cmd->command, error)) return FALSE; const char *mask = CBOX_ARG_S(cmd, 0); const char *type = CBOX_ARG_S(cmd, 1); uint32_t flags = CBOX_ARG_I(cmd, 2); const char** ports = jack_get_ports(jii->client, mask, type, flags); for (int i = 0; ports && ports[i]; i++) { if (!cbox_execute_on(fb, NULL, "/port", "s", error, ports[i])) return FALSE; } jack_free(ports); return TRUE; } else if (!strcmp(cmd->command, "/external_tempo") && !strcmp(cmd->arg_types, "i")) { jii->external_tempo = CBOX_ARG_I(cmd, 0); return TRUE; } //Metadata else if (!strcmp(cmd->command, "/set_property") && !strcmp(cmd->arg_types, "ssss")) //parameters: "client:port", key, value, type according to jack_property_t (empty or NULL for string) { const char *name = CBOX_ARG_S(cmd, 0); const char *key = CBOX_ARG_S(cmd, 1); const char *value = CBOX_ARG_S(cmd, 2); const char *type = CBOX_ARG_S(cmd, 3); jack_uuid_t subject; if (!cbox_jack_io_get_jack_uuid_from_name(jii, name, &subject, error)) //error message set inside return FALSE; if (jack_set_property(jii->client, subject, key, value, type)) // 0 on success { g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Set property key:'%s' value: '%s' to port '%s' was not successful", key, value, name); return FALSE; } return TRUE; } else if (!strcmp(cmd->command, "/get_property") && !strcmp(cmd->arg_types, "ss")) //parameters: "client:port", key //returns python key, value and type as strings { const char *name = CBOX_ARG_S(cmd, 0); const char *key = CBOX_ARG_S(cmd, 1); jack_uuid_t subject; if (!cbox_jack_io_get_jack_uuid_from_name(jii, name, &subject, error)) //error message set inside return FALSE; char* value = NULL; char* type = NULL; if (jack_get_property(subject, key, &value, &type)) // 0 on success, -1 if the subject has no key property. { g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Port '%s' does not have key '%s'", name, key); return FALSE; } char* returntype; //We need to call jack_free on type in any case so it can't be our own data. if (type == NULL) returntype = ""; else returntype = type; if (!cbox_execute_on(fb, NULL, "/value", "ss", error, value, returntype)) //send return values to Python. return FALSE; jack_free(value); jack_free(type); return TRUE; } else if (!strcmp(cmd->command, "/get_properties") && !strcmp(cmd->arg_types, "s")) //parameters: "client:port" { const char *name = CBOX_ARG_S(cmd, 0); jack_uuid_t subject; if (!cbox_jack_io_get_jack_uuid_from_name(jii, name, &subject, error)) //error message set inside return FALSE; jack_description_t desc; if (!jack_get_properties(subject, &desc)) // 0 on success, -1 if no subject with any properties exists. { g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Port '%s' with uuid '%lli' does not have any properties", name, (long long)subject); return FALSE; } const char *returntype; for (uint32_t i = 0; i<desc.property_cnt ; i++) { if (desc.properties[i].type == NULL) returntype = ""; else returntype = desc.properties[i].type; if (!cbox_execute_on(fb, NULL, "/properties", "sss", error, desc.properties[i].key, desc.properties[i].data, returntype)) return FALSE; } jack_free_description(&desc, 0); //if non-zero desc will also be passed to free() return TRUE; } else if (!strcmp(cmd->command, "/get_all_properties") && !strcmp(cmd->arg_types, "")) { jack_description_t *descs; int counter; counter = jack_get_all_properties(&descs); const char *returntype; for (int j = 0; j < counter; j++) { jack_description_t *one_desc = &descs[j]; for (uint32_t i = 0; i < one_desc->property_cnt ; i++) { if (one_desc->properties[i].type == NULL) returntype = ""; else returntype = one_desc->properties[i].type; /* index = jack_uuid_to_index(one_desc->subject) portid = jack_port_by_id(jii->client, index); portname = jack_port_name(port); */ if (!cbox_execute_on(fb, NULL, "/all_properties", "ssss", error, jack_port_name(jack_port_by_id(jii->client, jack_uuid_to_index(one_desc->subject))), one_desc->properties[i].key, one_desc->properties[i].data, returntype)) return FALSE; } jack_free_description(one_desc, 0); //if non-zero one_desc will also be passed to free() } jack_free(descs); return TRUE; } else if (!strcmp(cmd->command, "/remove_property") && !strcmp(cmd->arg_types, "ss")) { const char *name = CBOX_ARG_S(cmd, 0); const char *key = CBOX_ARG_S(cmd, 1); jack_uuid_t subject; if (!cbox_jack_io_get_jack_uuid_from_name(jii, name, &subject, error)) //error message set inside return FALSE; if (jack_remove_property(jii->client, subject, key)) // 0 on success, -1 otherwise { g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Could not remove port '%s' key '%s'", name, key); return FALSE; } return TRUE; } else if (!strcmp(cmd->command, "/remove_properties") && !strcmp(cmd->arg_types, "s")) { const char *name = CBOX_ARG_S(cmd, 0); jack_uuid_t subject; if (!cbox_jack_io_get_jack_uuid_from_name(jii, name, &subject, error)) //error message set inside return FALSE; if (jack_remove_properties(jii->client, subject) == -1) // number of removed properties returned, -1 on error { g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Could not remove properties of port '%s'", name); return FALSE; } return TRUE; } else if (!strcmp(cmd->command, "/remove_all_properties") && !strcmp(cmd->arg_types, "")) { if (jack_remove_all_properties(jii->client)) // 0 on success, -1 otherwise { g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Remove all JACK properties was not successful"); return FALSE; } return TRUE; } else { gboolean result = cbox_io_process_cmd(io, fb, cmd, error, &handled); if (!handled) 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); return result; } }
gboolean fxchain_process_cmd(struct cbox_command_target *ct, struct cbox_command_target *fb, struct cbox_osc_command *cmd, GError **error) { struct fxchain_module *m = (struct fxchain_module *)ct->user_data; const char *subcommand = NULL; int index = 0; //EFFECT_PARAM("/module_count", "i", stages, int, , 1, 12) else if (!strcmp(cmd->command, "/status") && !strcmp(cmd->arg_types, "")) { if (!cbox_check_fb_channel(fb, cmd->command, error)) return FALSE; for (uint32_t i = 0; i < m->module_count; i++) { gboolean res = FALSE; if (m->modules[i]) res = cbox_execute_on(fb, NULL, "/module", "ss", error, m->modules[i]->engine_name, m->modules[i]->instance_name); else res = cbox_execute_on(fb, NULL, "/module", "ss", error, "", ""); if (!res) return FALSE; res = cbox_execute_on(fb, NULL, "/bypass", "ii", error, i + 1, m->modules[i] ? m->modules[i]->bypass : 0); } return CBOX_OBJECT_DEFAULT_STATUS(&m->module, fb, error); } else if (cbox_parse_path_part_int(cmd, "/module/", &subcommand, &index, 1, m->module_count, error)) { if (!subcommand) return FALSE; return cbox_module_slot_process_cmd(&m->modules[index - 1], fb, cmd, subcommand, CBOX_GET_DOCUMENT(&m->module), m->module.rt, m->module.engine, error); } else if (!strcmp(cmd->command, "/insert") && !strcmp(cmd->arg_types, "i")) { int pos = CBOX_ARG_I(cmd, 0) - 1; struct cbox_module **new_modules = malloc((m->module_count + 1) * sizeof(struct cbox_module *)); memcpy(new_modules, m->modules, pos * sizeof(struct cbox_module *)); new_modules[pos] = NULL; memcpy(new_modules + pos + 1, m->modules + pos, (m->module_count - pos) * sizeof(struct cbox_module *)); void *old_modules = cbox_rt_swap_pointers_and_update_count(m->module.rt, (void **)&m->modules, new_modules, &m->module_count, m->module_count + 1); free(old_modules); return TRUE; } else if (!strcmp(cmd->command, "/delete") && !strcmp(cmd->arg_types, "i")) { int pos = CBOX_ARG_I(cmd, 0) - 1; struct cbox_module **new_modules = malloc((m->module_count + 1) * sizeof(struct cbox_module *)); memcpy(new_modules, m->modules, pos * sizeof(struct cbox_module *)); memcpy(new_modules + pos, m->modules + pos + 1, (m->module_count - pos - 1) * sizeof(struct cbox_module *)); struct cbox_module *deleted_module = m->modules[pos]; void *old_modules = cbox_rt_swap_pointers_and_update_count(m->module.rt, (void **)&m->modules, new_modules, &m->module_count, m->module_count - 1); free(old_modules); if (deleted_module) CBOX_DELETE(deleted_module); return TRUE; } else if (!strcmp(cmd->command, "/move") && !strcmp(cmd->arg_types, "ii")) { int oldpos = CBOX_ARG_I(cmd, 0) - 1; int newpos = CBOX_ARG_I(cmd, 1) - 1; fxchain_move(m, oldpos, newpos); } else return cbox_object_default_process_cmd(ct, fb, cmd, error); return TRUE; }
gboolean cbox_instrument_process_cmd(struct cbox_command_target *ct, struct cbox_command_target *fb, struct cbox_osc_command *cmd, GError **error) { struct cbox_instrument *instr = ct->user_data; const char *subcommand = NULL; int index = 0; int aux_offset = instr->module->aux_offset / 2; if (!strcmp(cmd->command, "/status") && !strcmp(cmd->arg_types, "")) { if (!cbox_check_fb_channel(fb, cmd->command, error)) return FALSE; if (!cbox_execute_on(fb, NULL, "/engine", "s", error, instr->module->engine_name)) return FALSE; if (!cbox_execute_on(fb, NULL, "/aux_offset", "i", error, instr->module->aux_offset / 2 + 1)) return FALSE; if (!cbox_execute_on(fb, NULL, "/outputs", "i", error, instr->module->outputs / 2)) return FALSE; return CBOX_OBJECT_DEFAULT_STATUS(instr, fb, error); } else if (cbox_parse_path_part_int(cmd, "/output/", &subcommand, &index, 1, aux_offset, error)) { if (!subcommand) return FALSE; if (index < 1 || index > 1 + instr->module->aux_offset) { g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Invalid position %d (valid are 1..%d)", index, instr->module->aux_offset); return FALSE; } return cbox_instrument_output_process_cmd(instr, &instr->outputs[index - 1], fb, cmd, subcommand, error); } else if (cbox_parse_path_part_int(cmd, "/aux/", &subcommand, &index, 1, instr->aux_output_count, error)) { if (!subcommand) return FALSE; int acount = 1 + instr->module->outputs - instr->module->aux_offset; if (index < 1 || index > acount) { g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Invalid position %d (valid are 1..%d)", index, acount); return FALSE; } return cbox_instrument_aux_process_cmd(instr, &instr->outputs[aux_offset + index - 1], index - 1, fb, cmd, subcommand, error); } else if (!strncmp(cmd->command, "/engine/",8)) { if (!instr->module->cmd_target.process_cmd) { g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "The engine %s has no command target defined", instr->module->engine_name); return FALSE; } return cbox_execute_sub(&instr->module->cmd_target, fb, cmd, cmd->command + 7, error); } else if (!strcmp(cmd->command, "/move_to") && !strcmp(cmd->arg_types, "si")) { struct cbox_scene *new_scene = (struct cbox_scene *)CBOX_ARG_O(cmd, 0, instr->scene, cbox_scene, error); if (!new_scene) return FALSE; int dstpos = CBOX_ARG_I(cmd, 1) - 1; if (dstpos < 0 || dstpos > new_scene->layer_count) { g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Invalid position %d (valid are 1..%d or 0 for append)", dstpos + 1, 1 + new_scene->layer_count); return FALSE; } return cbox_scene_move_instrument_to(instr->scene, instr, new_scene, dstpos, error); } else return cbox_object_default_process_cmd(ct, fb, cmd, error); }