We're including config.h everywhere, so we should pass compatible compiler options.
[calfbox.git] / instr.c
bloba9bb60f9fc87b9c6e0d55f3708ceb9c034b34798
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
160 return cbox_object_default_process_cmd(ct, fb, cmd, error);
163 void cbox_instrument_destroy_if_unused(struct cbox_instrument *instrument)
165 if (instrument->refcount == 0)
166 CBOX_DELETE(instrument);
169 void cbox_instrument_destroyfunc(struct cbox_objhdr *objhdr)
171 struct cbox_instrument *instrument = CBOX_H2O(objhdr);
172 assert(instrument->refcount == 0);
173 for (int i = 0; i < instrument->module->outputs / 2; i ++)
175 cbox_instrument_output_uninit(&instrument->outputs[i]);
177 free(instrument->outputs);
178 for (int i = 0; i < instrument->aux_output_count; i++)
180 g_free(instrument->aux_output_names[i]);
182 free(instrument->aux_output_names);
183 free(instrument->aux_outputs);
184 CBOX_DELETE(instrument->module);
185 free(instrument);
188 void cbox_instrument_unref_aux_buses(struct cbox_instrument *instrument)
190 for (int j = 0; j < instrument->aux_output_count; j++)
192 if (instrument->aux_outputs[j])
193 cbox_aux_bus_unref(instrument->aux_outputs[j]);
197 void cbox_instrument_disconnect_aux_bus(struct cbox_instrument *instrument, struct cbox_aux_bus *bus)
199 for (int j = 0; j < instrument->aux_output_count; j++)
201 if (instrument->aux_outputs[j] == bus)
203 cbox_aux_bus_unref(instrument->aux_outputs[j]);
204 instrument->aux_outputs[j] = NULL;
209 void cbox_instrument_output_init(struct cbox_instrument_output *output, struct cbox_scene *scene, uint32_t max_numsamples)
211 cbox_recording_source_init(&output->rec_dry, scene, max_numsamples, 2);
212 cbox_recording_source_init(&output->rec_wet, scene, max_numsamples, 2);
213 output->insert = NULL;
214 output->output_bus = 0;
215 output->gain = 1.0;
219 void cbox_instrument_output_uninit(struct cbox_instrument_output *output)
221 cbox_recording_source_uninit(&output->rec_dry);
222 cbox_recording_source_uninit(&output->rec_wet);
223 if (output->insert)
225 CBOX_DELETE(output->insert);
226 output->insert = NULL;