Merge pull request #1 from atsampson/master
[calfbox.git] / instr.c
blob2725bb93e5a04bf7b4eddee634d8b1a950d65a68
1 /*
2 Calf Box, an open source musical instrument.
3 Copyright (C) 2010-2011 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 "auxbus.h"
20 #include "config-api.h"
21 #include "instr.h"
22 #include "module.h"
23 #include "rt.h"
24 #include "scene.h"
25 #include <assert.h>
26 #include <glib.h>
28 CBOX_CLASS_DEFINITION_ROOT(cbox_instrument)
30 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)
32 if (!strcmp(subcmd, "/status") && !strcmp(cmd->arg_types, ""))
34 if (!(cbox_execute_on(fb, NULL, "/gain_linear", "f", error, output->gain) &&
35 cbox_execute_on(fb, NULL, "/gain", "f", error, gain2dB_simple(output->gain)) &&
36 cbox_execute_on(fb, NULL, "/output", "i", error, output->output_bus + 1)))
37 return FALSE;
38 return cbox_module_slot_process_cmd(&output->insert, fb, cmd, subcmd, CBOX_GET_DOCUMENT(instr->scene), instr->scene->rt, instr->scene->engine, error);
40 if (!strcmp(subcmd, "/gain") && !strcmp(cmd->arg_types, "f"))
42 output->gain = dB2gain_simple(CBOX_ARG_F(cmd, 0));
43 return TRUE;
45 if (!strcmp(subcmd, "/output") && !strcmp(cmd->arg_types, "i"))
47 int obus = CBOX_ARG_I(cmd, 0);
48 // XXXKF add error checking
49 output->output_bus = obus - 1;
50 return TRUE;
52 if (!strncmp(subcmd, "/rec_dry/", 9))
53 return cbox_execute_sub(&output->rec_dry.cmd_target, fb, cmd, subcmd + 8, error);
54 if (!strncmp(subcmd, "/rec_wet/", 9))
55 return cbox_execute_sub(&output->rec_wet.cmd_target, fb, cmd, subcmd + 8, error);
56 return cbox_module_slot_process_cmd(&output->insert, fb, cmd, subcmd, CBOX_GET_DOCUMENT(instr->scene), instr->scene->rt, instr->scene->engine, error);
59 static gboolean cbox_instrument_aux_process_cmd(struct cbox_instrument *instr, struct cbox_instrument_output *output, int id, struct cbox_command_target *fb, struct cbox_osc_command *cmd, const char *subcmd, GError **error)
61 if (!strcmp(subcmd, "/status") && !strcmp(cmd->arg_types, ""))
63 if (!cbox_check_fb_channel(fb, cmd->command, error))
64 return FALSE;
65 if (!(cbox_execute_on(fb, NULL, "/gain_linear", "f", error, output->gain) &&
66 cbox_execute_on(fb, NULL, "/gain", "f", error, gain2dB_simple(output->gain)) &&
67 cbox_execute_on(fb, NULL, "/bus", "s", error, instr->aux_output_names[id] ? instr->aux_output_names[id] : "")))
68 return FALSE;
69 return cbox_module_slot_process_cmd(&output->insert, fb, cmd, subcmd, CBOX_GET_DOCUMENT(instr->scene), instr->scene->rt, instr->scene->engine, error);
71 else if (!strcmp(subcmd, "/bus") && !strcmp(cmd->arg_types, "s"))
73 struct cbox_scene *scene = instr->scene;
74 if (!CBOX_ARG_S(cmd, 0))
76 struct cbox_aux_bus *old_bus = cbox_rt_swap_pointers(instr->module->rt, (void **)&instr->aux_outputs[id], NULL);
77 if (old_bus)
78 cbox_aux_bus_unref(old_bus);
79 return TRUE;
81 for (int i = 0; i < scene->aux_bus_count; i++)
83 if (!scene->aux_buses[i])
84 continue;
85 if (!strcmp(scene->aux_buses[i]->name, CBOX_ARG_S(cmd, 0)))
87 g_free(instr->aux_output_names[id]);
88 instr->aux_output_names[id] = g_strdup(scene->aux_buses[i]->name);
89 cbox_aux_bus_ref(scene->aux_buses[i]);
90 struct cbox_aux_bus *old_bus = cbox_rt_swap_pointers(instr->module->rt, (void **)&instr->aux_outputs[id], scene->aux_buses[i]);
91 if (old_bus)
92 cbox_aux_bus_unref(old_bus);
93 return TRUE;
96 g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Unknown aux bus: %s", CBOX_ARG_S(cmd, 0));
97 return FALSE;
99 else if (!strcmp(subcmd, "/output") && !strcmp(cmd->arg_types, "i")) // not supported
101 cbox_set_command_error(error, cmd);
102 return FALSE;
104 else // otherwise, treat just like an command on normal (non-aux) output
105 return cbox_instrument_output_process_cmd(instr, output, fb, cmd, subcmd, error);
108 gboolean cbox_instrument_process_cmd(struct cbox_command_target *ct, struct cbox_command_target *fb, struct cbox_osc_command *cmd, GError **error)
110 struct cbox_instrument *instr = ct->user_data;
111 const char *subcommand = NULL;
112 int index = 0;
113 int aux_offset = instr->module->aux_offset / 2;
114 if (!strcmp(cmd->command, "/status") && !strcmp(cmd->arg_types, ""))
116 if (!cbox_check_fb_channel(fb, cmd->command, error))
117 return FALSE;
118 if (!cbox_execute_on(fb, NULL, "/engine", "s", error, instr->module->engine_name))
119 return FALSE;
120 if (!cbox_execute_on(fb, NULL, "/aux_offset", "i", error, instr->module->aux_offset / 2 + 1))
121 return FALSE;
122 if (!cbox_execute_on(fb, NULL, "/outputs", "i", error, instr->module->outputs / 2))
123 return FALSE;
124 return CBOX_OBJECT_DEFAULT_STATUS(instr, fb, error);
126 else if (cbox_parse_path_part_int(cmd, "/output/", &subcommand, &index, 1, aux_offset, error))
128 if (!subcommand)
129 return FALSE;
130 if (index < 1 || index > 1 + instr->module->aux_offset)
132 g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Invalid position %d (valid are 1..%d)", index, instr->module->aux_offset);
133 return FALSE;
135 return cbox_instrument_output_process_cmd(instr, &instr->outputs[index - 1], fb, cmd, subcommand, error);
137 else if (cbox_parse_path_part_int(cmd, "/aux/", &subcommand, &index, 1, instr->aux_output_count, error))
139 if (!subcommand)
140 return FALSE;
141 int acount = 1 + instr->module->outputs - instr->module->aux_offset;
142 if (index < 1 || index > acount)
144 g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Invalid position %d (valid are 1..%d)", index, acount);
145 return FALSE;
147 return cbox_instrument_aux_process_cmd(instr, &instr->outputs[aux_offset + index - 1], index - 1, fb, cmd, subcommand, error);
149 else
150 if (!strncmp(cmd->command, "/engine/",8))
152 if (!instr->module->cmd_target.process_cmd)
154 g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "The engine %s has no command target defined", instr->module->engine_name);
155 return FALSE;
157 return cbox_execute_sub(&instr->module->cmd_target, fb, cmd, cmd->command + 7, error);
159 else if (!strcmp(cmd->command, "/move_to") && !strcmp(cmd->arg_types, "si"))
161 struct cbox_scene *new_scene = (struct cbox_scene *)CBOX_ARG_O(cmd, 0, instr->scene, cbox_scene, error);
162 if (!new_scene)
163 return FALSE;
164 int dstpos = CBOX_ARG_I(cmd, 1) - 1;
166 if (dstpos < 0 || dstpos > new_scene->layer_count)
168 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);
169 return FALSE;
172 return cbox_scene_move_instrument_to(instr->scene, instr, new_scene, dstpos, error);
174 else
175 return cbox_object_default_process_cmd(ct, fb, cmd, error);
178 void cbox_instrument_destroy_if_unused(struct cbox_instrument *instrument)
180 if (instrument->refcount == 0)
181 CBOX_DELETE(instrument);
184 void cbox_instrument_destroyfunc(struct cbox_objhdr *objhdr)
186 struct cbox_instrument *instrument = CBOX_H2O(objhdr);
187 assert(instrument->refcount == 0);
188 for (int i = 0; i < instrument->module->outputs / 2; i ++)
190 cbox_instrument_output_uninit(&instrument->outputs[i]);
192 free(instrument->outputs);
193 for (int i = 0; i < instrument->aux_output_count; i++)
195 g_free(instrument->aux_output_names[i]);
197 free(instrument->aux_output_names);
198 free(instrument->aux_outputs);
199 CBOX_DELETE(instrument->module);
200 free(instrument);
203 void cbox_instrument_unref_aux_buses(struct cbox_instrument *instrument)
205 for (int j = 0; j < instrument->aux_output_count; j++)
207 if (instrument->aux_outputs[j])
208 cbox_aux_bus_unref(instrument->aux_outputs[j]);
212 void cbox_instrument_disconnect_aux_bus(struct cbox_instrument *instrument, struct cbox_aux_bus *bus)
214 for (int j = 0; j < instrument->aux_output_count; j++)
216 if (instrument->aux_outputs[j] == bus)
218 cbox_aux_bus_unref(instrument->aux_outputs[j]);
219 instrument->aux_outputs[j] = NULL;
224 void cbox_instrument_output_init(struct cbox_instrument_output *output, struct cbox_scene *scene, uint32_t max_numsamples)
226 cbox_recording_source_init(&output->rec_dry, scene, max_numsamples, 2);
227 cbox_recording_source_init(&output->rec_wet, scene, max_numsamples, 2);
228 output->insert = NULL;
229 output->output_bus = 0;
230 output->gain = 1.0;
234 void cbox_instrument_output_uninit(struct cbox_instrument_output *output)
236 cbox_recording_source_uninit(&output->rec_dry);
237 cbox_recording_source_uninit(&output->rec_wet);
238 if (output->insert)
240 CBOX_DELETE(output->insert);
241 output->insert = NULL;