Merge pull request #1 from atsampson/master
[calfbox.git] / layer.c
blob375ce7dd1ff0b3cad1eb0c8aa609a650724c6b46
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 "config-api.h"
20 #include "errors.h"
21 #include "instr.h"
22 #include "layer.h"
23 #include "midi.h"
24 #include "module.h"
25 #include "rt.h"
26 #include "scene.h"
27 #include <glib.h>
29 gboolean cbox_layer_load(struct cbox_layer *layer, const char *name, GError **error)
31 const char *cv = NULL;
32 struct cbox_instrument *instr = NULL;
33 gchar *section = g_strdup_printf("layer:%s", name);
35 if (!cbox_config_has_section(section))
37 g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Missing section for layer %s", name);
38 goto error;
41 cv = cbox_config_get_string(section, "instrument");
42 if (!cv)
44 g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Instrument not specified for layer %s", name);
45 goto error;
47 instr = cbox_scene_get_instrument_by_name(layer->scene, cv, TRUE, error);
48 if (!instr)
50 cbox_force_error(error);
51 g_prefix_error(error, "Cannot get instrument %s for layer %s: ", cv, name);
52 goto error;
55 layer->enabled = cbox_config_get_int(section, "enabled", TRUE);
56 layer->low_note = 0;
57 layer->high_note = 127;
59 cv = cbox_config_get_string(section, "low_note");
60 if (cv)
61 layer->low_note = note_from_string(cv);
63 cv = cbox_config_get_string(section, "high_note");
64 if (cv)
65 layer->high_note = note_from_string(cv);
67 layer->transpose = cbox_config_get_int(section, "transpose", 0);
68 layer->fixed_note = cbox_config_get_int(section, "fixed_note", -1);
69 layer->in_channel = cbox_config_get_int(section, "in_channel", 0) - 1;
70 layer->out_channel = cbox_config_get_int(section, "out_channel", 0) - 1;
71 layer->disable_aftertouch = !cbox_config_get_int(section, "aftertouch", TRUE);
72 layer->invert_sustain = cbox_config_get_int(section, "invert_sustain", FALSE);
73 layer->consume = cbox_config_get_int(section, "consume", FALSE);
74 layer->ignore_scene_transpose = cbox_config_get_int(section, "ignore_scene_transpose", FALSE);
75 layer->ignore_program_changes = cbox_config_get_int(section, "ignore_program_changes", FALSE);
76 g_free(section);
78 cbox_layer_set_instrument(layer, instr);
80 return 1;
82 error:
83 if (instr)
84 cbox_instrument_destroy_if_unused(instr);
86 g_free(section);
87 return 0;
90 void cbox_layer_set_instrument(struct cbox_layer *layer, struct cbox_instrument *instrument)
92 if (layer->instrument)
94 layer->instrument->refcount--;
95 cbox_instrument_destroy_if_unused(layer->instrument);
96 layer->instrument = NULL;
98 layer->instrument = instrument;
99 layer->instrument->refcount++;
102 static gboolean cbox_layer_process_cmd(struct cbox_command_target *ct, struct cbox_command_target *fb, struct cbox_osc_command *cmd, GError **error);
104 static void cbox_layer_destroyfunc(struct cbox_objhdr *objhdr)
106 struct cbox_layer *layer = CBOX_H2O(objhdr);
107 if (layer->instrument && !--(layer->instrument->refcount))
109 if (layer->instrument->scene)
110 cbox_scene_remove_instrument(layer->instrument->scene, layer->instrument);
112 cbox_instrument_destroy_if_unused(layer->instrument);
114 free(layer);
117 gboolean cbox_layer_process_cmd(struct cbox_command_target *ct, struct cbox_command_target *fb, struct cbox_osc_command *cmd, GError **error)
119 struct cbox_layer *layer = ct->user_data;
120 if (!strcmp(cmd->command, "/status") && !strcmp(cmd->arg_types, ""))
122 if (!cbox_check_fb_channel(fb, cmd->command, error))
123 return FALSE;
125 if (!(cbox_execute_on(fb, NULL, "/enable", "i", error, (int)layer->enabled) &&
126 cbox_execute_on(fb, NULL, "/instrument_name", "s", error, layer->instrument->module->instance_name) &&
127 cbox_execute_on(fb, NULL, "/instrument_uuid", "o", error, layer->instrument) &&
128 cbox_execute_on(fb, NULL, "/consume", "i", error, (int)layer->consume) &&
129 cbox_execute_on(fb, NULL, "/ignore_scene_transpose", "i", error, (int)layer->ignore_scene_transpose) &&
130 cbox_execute_on(fb, NULL, "/ignore_program_changes", "i", error, (int)layer->ignore_program_changes) &&
131 cbox_execute_on(fb, NULL, "/disable_aftertouch", "i", error, (int)layer->disable_aftertouch) &&
132 cbox_execute_on(fb, NULL, "/transpose", "i", error, (int)layer->transpose) &&
133 cbox_execute_on(fb, NULL, "/fixed_note", "i", error, (int)layer->fixed_note) &&
134 cbox_execute_on(fb, NULL, "/low_note", "i", error, (int)layer->low_note) &&
135 cbox_execute_on(fb, NULL, "/high_note", "i", error, (int)layer->high_note) &&
136 cbox_execute_on(fb, NULL, "/in_channel", "i", error, layer->in_channel + 1) &&
137 cbox_execute_on(fb, NULL, "/out_channel", "i", error, layer->out_channel + 1) &&
138 CBOX_OBJECT_DEFAULT_STATUS(layer, fb, error)))
139 return FALSE;
140 return TRUE;
142 else if (!strcmp(cmd->command, "/enable") && !strcmp(cmd->arg_types, "i"))
144 layer->enabled = 0 != CBOX_ARG_I(cmd, 0);
145 return TRUE;
147 else if (!strcmp(cmd->command, "/consume") && !strcmp(cmd->arg_types, "i"))
149 layer->consume = 0 != CBOX_ARG_I(cmd, 0);
150 return TRUE;
152 else if (!strcmp(cmd->command, "/ignore_scene_transpose") && !strcmp(cmd->arg_types, "i"))
154 layer->ignore_scene_transpose = 0 != CBOX_ARG_I(cmd, 0);
155 return TRUE;
157 else if (!strcmp(cmd->command, "/ignore_program_changes") && !strcmp(cmd->arg_types, "i"))
159 layer->ignore_program_changes = 0 != CBOX_ARG_I(cmd, 0);
160 return TRUE;
162 else if (!strcmp(cmd->command, "/disable_aftertouch") && !strcmp(cmd->arg_types, "i"))
164 layer->disable_aftertouch = 0 != CBOX_ARG_I(cmd, 0);
165 return TRUE;
167 else if (!strcmp(cmd->command, "/transpose") && !strcmp(cmd->arg_types, "i"))
169 layer->transpose = CBOX_ARG_I(cmd, 0);
170 return TRUE;
172 else if (!strcmp(cmd->command, "/fixed_note") && !strcmp(cmd->arg_types, "i"))
174 layer->fixed_note = CBOX_ARG_I(cmd, 0);
175 return TRUE;
177 else if (!strcmp(cmd->command, "/low_note") && !strcmp(cmd->arg_types, "i"))
179 layer->low_note = CBOX_ARG_I(cmd, 0);
180 return TRUE;
182 else if (!strcmp(cmd->command, "/high_note") && !strcmp(cmd->arg_types, "i"))
184 layer->high_note = CBOX_ARG_I(cmd, 0);
185 return TRUE;
187 else if (!strcmp(cmd->command, "/in_channel") && !strcmp(cmd->arg_types, "i"))
189 layer->in_channel = CBOX_ARG_I(cmd, 0) - 1;
190 return TRUE;
192 else if (!strcmp(cmd->command, "/out_channel") && !strcmp(cmd->arg_types, "i"))
194 layer->out_channel = CBOX_ARG_I(cmd, 0) - 1;
195 return TRUE;
197 else // otherwise, treat just like an command on normal (non-aux) output
198 return cbox_object_default_process_cmd(ct, fb, cmd, error);
201 CBOX_CLASS_DEFINITION_ROOT(cbox_layer)
203 struct cbox_layer *cbox_layer_new(struct cbox_scene *scene)
205 struct cbox_document *doc = CBOX_GET_DOCUMENT(scene);
206 struct cbox_layer *l = malloc(sizeof(struct cbox_layer));
208 CBOX_OBJECT_HEADER_INIT(l, cbox_layer, doc);
209 cbox_command_target_init(&l->cmd_target, cbox_layer_process_cmd, l);
210 l->enabled = TRUE;
211 l->instrument = NULL;
212 l->low_note = 0;
213 l->high_note = 127;
215 l->transpose = 0;
216 l->fixed_note = -1;
217 l->in_channel = -1;
218 l->out_channel = -1;
219 l->disable_aftertouch = FALSE;
220 l->invert_sustain = FALSE;
221 l->consume = FALSE;
222 l->ignore_scene_transpose = FALSE;
223 l->ignore_program_changes = FALSE;
224 l->scene = scene;
225 CBOX_OBJECT_REGISTER(l);
226 return l;
229 struct cbox_layer *cbox_layer_new_with_instrument(struct cbox_scene *scene, const char *instrument_name, GError **error)
231 struct cbox_layer *layer = cbox_layer_new(scene);
232 struct cbox_instrument *instr = NULL;
233 if (!layer) goto error;
234 instr = cbox_scene_get_instrument_by_name(scene, instrument_name, TRUE, error);
235 if (!instr)
237 cbox_force_error(error);
238 g_prefix_error(error, "Cannot get instrument %s for new layer: ", instrument_name);
239 CBOX_DELETE(layer);
240 return NULL;
242 cbox_layer_set_instrument(layer, instr);
243 return layer;
245 error:
246 CBOX_DELETE(layer);
247 if (instr)
248 cbox_instrument_destroy_if_unused(instr);
249 return NULL;
252 struct cbox_layer *cbox_layer_new_from_config(struct cbox_scene *scene, const char *layer_name, GError **error)
254 struct cbox_layer *layer = cbox_layer_new(scene);
255 if (!layer)
256 goto error;
258 layer->scene = scene;
259 if (!cbox_layer_load(layer, layer_name, error))
260 goto error;
262 return layer;
264 error:
265 CBOX_DELETE(layer);
266 return NULL;