Allow Python access to engine's master effect.
[calfbox.git] / fluid.c
blobeb2a0a45b25b7cf8d3a8ede441f35deb91b553cb
1 /*
2 Calf Box, an open source musical instrument.
3 Copyright (C) 2010 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"
21 #if USE_FLUIDSYNTH
23 #include "config-api.h"
24 #include "dspmath.h"
25 #include "module.h"
26 #include <glib.h>
27 #include <math.h>
28 #include <memory.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <fluidsynth.h>
33 #define CBOX_FLUIDSYNTH_ERROR cbox_fluidsynth_error_quark()
35 enum CboxFluidsynthError
37 CBOX_FLUIDSYNTH_ERROR_FAILED,
40 GQuark cbox_fluidsynth_error_quark(void)
42 return g_quark_from_string("cbox-fluidsynth-error-quark");
45 static void fluidsynth_process_block(struct cbox_module *module, cbox_sample_t **inputs, cbox_sample_t **outputs);
46 static void fluidsynth_process_event(struct cbox_module *module, const uint8_t *data, uint32_t len);
47 static gboolean fluidsynth_process_cmd(struct cbox_command_target *ct, struct cbox_command_target *fb, struct cbox_osc_command *cmd, GError **error);
48 static void fluidsynth_destroyfunc(struct cbox_module *module);
50 struct fluidsynth_module
52 struct cbox_module module;
54 fluid_settings_t *settings;
55 fluid_synth_t *synth;
56 char *bank_name;
57 int sfid;
58 int output_pairs;
59 int is_multi;
60 float **left_outputs, **right_outputs;
63 static gboolean select_patch_by_name(struct fluidsynth_module *m, int channel, const gchar *preset, GError **error)
65 fluid_sfont_t* sfont = fluid_synth_get_sfont(m->synth, 0);
66 fluid_preset_t tmp;
68 sfont->iteration_start(sfont);
69 while(sfont->iteration_next(sfont, &tmp))
71 // trailing spaces are common in some SF2s
72 const char *pname = tmp.get_name(&tmp);
73 int len = strlen(pname);
74 while (len > 0 && pname[len - 1] == ' ')
75 len--;
77 if (!strncmp(pname, preset, len) && preset[len] == '\0')
79 fluid_synth_program_select(m->synth, channel, m->sfid, tmp.get_banknum(&tmp), tmp.get_num(&tmp));
80 return TRUE;
84 g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Preset not found: %s", preset);
85 return FALSE;
88 MODULE_CREATE_FUNCTION(fluidsynth)
90 int result = 0;
91 int i;
92 const char *bankname = cbox_config_get_string(cfg_section, "sf2");
93 static int inited = 0;
94 if (!inited)
96 inited = 1;
99 struct fluidsynth_module *m = malloc(sizeof(struct fluidsynth_module));
100 int pairs = cbox_config_get_int(cfg_section, "output_pairs", 0);
101 m->output_pairs = pairs ? pairs : 1;
102 m->is_multi = pairs > 0;
103 if (m->output_pairs < 1 || m->output_pairs > 16)
105 free(m);
106 g_set_error(error, CBOX_FLUIDSYNTH_ERROR, CBOX_FLUIDSYNTH_ERROR_FAILED, "Invalid number of output pairs (found %d, supported range 1-16)", m->output_pairs);
107 return NULL;
109 if (pairs == 0)
111 CALL_MODULE_INIT(m, 0, 2 * m->output_pairs, fluidsynth);
112 m->left_outputs = NULL;
113 m->right_outputs = NULL;
115 else
117 g_message("Multichannel mode enabled, %d output pairs, 2 effects", m->output_pairs);
118 CALL_MODULE_INIT(m, 0, 2 * m->output_pairs + 4, fluidsynth);
119 m->left_outputs = malloc(sizeof(float *) * (m->output_pairs + 2));
120 m->right_outputs = malloc(sizeof(float *) * (m->output_pairs + 2));
122 m->module.process_event = fluidsynth_process_event;
123 m->module.process_block = fluidsynth_process_block;
124 m->module.aux_offset = 2 * m->output_pairs;
125 m->settings = new_fluid_settings();
126 fluid_settings_setnum(m->settings, "synth.sample-rate", m->module.srate);
127 fluid_settings_setint(m->settings, "synth.audio-channels", m->output_pairs);
128 fluid_settings_setint(m->settings, "synth.audio-groups", m->output_pairs);
129 m->synth = new_fluid_synth(m->settings);
130 fluid_synth_set_reverb_on(m->synth, cbox_config_get_int(cfg_section, "reverb", 1));
131 fluid_synth_set_chorus_on(m->synth, cbox_config_get_int(cfg_section, "chorus", 1));
133 m->bank_name = NULL;
134 m->sfid = -1;
135 if (bankname)
137 m->bank_name = g_strdup(bankname);
138 g_message("Loading soundfont %s", bankname);
139 result = fluid_synth_sfload(m->synth, bankname, 1);
140 if (result == FLUID_FAILED)
142 g_set_error(error, CBOX_FLUIDSYNTH_ERROR, CBOX_FLUIDSYNTH_ERROR_FAILED, "Failed to load the default bank %s: %s", bankname, fluid_synth_error(m->synth));
143 return NULL;
145 m->sfid = result;
146 g_message("Soundfont %s loaded", bankname);
148 if (bankname)
150 for (i = 0; i < 16; i++)
152 gchar *key = g_strdup_printf("channel%d", i + 1);
153 gchar *preset = cbox_config_get_string(cfg_section, key);
154 fluid_synth_sfont_select(m->synth, i, m->sfid);
155 if (preset)
157 if (!select_patch_by_name(m, i, preset, error))
159 CBOX_DELETE(&m->module);
160 return NULL;
163 g_free(key);
167 return &m->module;
170 void fluidsynth_process_block(struct cbox_module *module, cbox_sample_t **inputs, cbox_sample_t **outputs)
172 struct fluidsynth_module *m = (struct fluidsynth_module *)module;
173 if (!m->is_multi)
174 fluid_synth_write_float(m->synth, CBOX_BLOCK_SIZE, outputs[0], 0, 1, outputs[1], 0, 1);
175 else
177 for (int i = 0; i < 2 + m->output_pairs; i++)
179 m->left_outputs[i] = outputs[2 * i];
180 m->right_outputs[i] = outputs[2 * i + 1];
183 fluid_synth_nwrite_float(m->synth, CBOX_BLOCK_SIZE, m->left_outputs, m->right_outputs, m->left_outputs + m->output_pairs, m->right_outputs + m->output_pairs);
187 void fluidsynth_process_event(struct cbox_module *module, const uint8_t *data, uint32_t len)
189 struct fluidsynth_module *m = (struct fluidsynth_module *)module;
190 if (len > 0)
192 int cmd = data[0] >> 4;
193 int chn = data[0] & 15;
194 switch(cmd)
196 case 8:
197 fluid_synth_noteoff(m->synth, chn, data[1]);
198 break;
200 case 9:
201 fluid_synth_noteon(m->synth, chn, data[1], data[2]);
202 break;
204 case 10:
205 // polyphonic pressure not handled
206 break;
208 case 11:
209 fluid_synth_cc(m->synth, chn, data[1], data[2]);
210 break;
212 case 12:
213 fluid_synth_program_change(m->synth, chn, data[1]);
214 break;
216 case 13:
217 fluid_synth_channel_pressure(m->synth, chn, data[1]);
218 break;
220 case 14:
221 fluid_synth_pitch_bend(m->synth, chn, data[1] + 128 * data[2]);
222 break;
228 gboolean fluidsynth_process_load_patch(struct fluidsynth_module *m, const char *bank_name, GError **error)
230 if (bank_name && !*bank_name)
231 bank_name = NULL;
232 int old_sfid = m->sfid;
233 char *old_bank_name = m->bank_name;
234 if (bank_name)
236 int result = fluid_synth_sfload(m->synth, bank_name, 1);
237 if (result == FLUID_FAILED)
239 g_set_error(error, CBOX_FLUIDSYNTH_ERROR, CBOX_FLUIDSYNTH_ERROR_FAILED, "Failed to load the bank %s: %s", bank_name, fluid_synth_error(m->synth));
240 return FALSE;
242 g_message("Soundfont %s loaded at ID %d", bank_name, result);
243 m->sfid = result;
245 else
246 m->sfid = -1;
247 if (old_sfid != -1)
249 free(old_bank_name);
250 fluid_synth_sfunload(m->synth, old_sfid, 1);
252 if (m->sfid != -1)
254 for (int i = 0; i < 16; i++)
255 fluid_synth_sfont_select(m->synth, i, m->sfid);
257 m->bank_name = bank_name ? g_strdup(bank_name) : NULL;
258 return TRUE;
261 gboolean fluidsynth_process_cmd(struct cbox_command_target *ct, struct cbox_command_target *fb, struct cbox_osc_command *cmd, GError **error)
263 struct fluidsynth_module *m = (struct fluidsynth_module *)ct->user_data;
265 if (!strcmp(cmd->command, "/status") && !strcmp(cmd->arg_types, ""))
267 if (!cbox_check_fb_channel(fb, cmd->command, error))
268 return FALSE;
269 if (!cbox_execute_on(fb, NULL, "/polyphony", "i", error, fluid_synth_get_polyphony(m->synth)))
270 return FALSE;
271 if (!cbox_execute_on(fb, NULL, "/soundfont", "s", error, m->bank_name ? m->bank_name : ""))
272 return FALSE;
273 for (int i = 0; i < 16; i++)
275 fluid_synth_channel_info_t ci;
276 fluid_synth_get_channel_info(m->synth, i, &ci);
277 if (!cbox_execute_on(fb, NULL, "/patch", "iis", error, 1 + i, ci.program + 128 * ci.bank, ci.name))
278 return FALSE;
280 return CBOX_OBJECT_DEFAULT_STATUS(&m->module, fb, error);
282 else if (!strcmp(cmd->command, "/patches") && !strcmp(cmd->arg_types, ""))
284 if (!cbox_check_fb_channel(fb, cmd->command, error))
285 return FALSE;
286 if (m->sfid == -1)
287 return TRUE;
288 fluid_sfont_t* sfont = fluid_synth_get_sfont(m->synth, 0);
289 fluid_preset_t tmp;
291 sfont->iteration_start(sfont);
292 while(sfont->iteration_next(sfont, &tmp))
294 const char *pname = tmp.get_name(&tmp);
295 if (!cbox_execute_on(fb, NULL, "/patch", "is", error, (int)(tmp.get_num(&tmp) + 128 * tmp.get_banknum(&tmp)), pname))
296 return FALSE;
298 return TRUE;
300 else if (!strcmp(cmd->command, "/set_patch") && !strcmp(cmd->arg_types, "ii"))
302 if (m->sfid == -1)
304 g_set_error(error, CBOX_FLUIDSYNTH_ERROR, CBOX_FLUIDSYNTH_ERROR_FAILED, "No soundfont loaded");
305 return FALSE;
307 int channel = CBOX_ARG_I(cmd, 0);
308 if (channel < 1 || channel > 16)
310 g_set_error(error, CBOX_FLUIDSYNTH_ERROR, CBOX_FLUIDSYNTH_ERROR_FAILED, "Invalid channel %d", channel);
311 return FALSE;
313 int value = CBOX_ARG_I(cmd, 1);
314 return fluid_synth_program_select(m->synth, channel - 1, m->sfid, value >> 7, value & 127) == FLUID_OK;
316 else if (!strcmp(cmd->command, "/polyphony") && !strcmp(cmd->arg_types, "i"))
318 int polyphony = CBOX_ARG_I(cmd, 0);
319 if (polyphony < 2 || polyphony > 256)
321 g_set_error(error, CBOX_FLUIDSYNTH_ERROR, CBOX_FLUIDSYNTH_ERROR_FAILED, "Invalid polyphony %d (must be between 2 and 256)", polyphony);
322 return FALSE;
324 return fluid_synth_set_polyphony(m->synth, polyphony) == FLUID_OK;
326 else if (!strcmp(cmd->command, "/load_soundfont") && !strcmp(cmd->arg_types, "s"))
328 return fluidsynth_process_load_patch(m, CBOX_ARG_S(cmd, 0), error);
330 else
331 return cbox_object_default_process_cmd(ct, fb, cmd, error);
332 return TRUE;
335 void fluidsynth_destroyfunc(struct cbox_module *module)
337 struct fluidsynth_module *m = (struct fluidsynth_module *)module;
339 if (m->output_pairs)
341 free(m->left_outputs);
342 free(m->right_outputs);
344 free(m->bank_name);
346 delete_fluid_settings(m->settings);
347 delete_fluid_synth(m->synth);
350 struct cbox_module_livecontroller_metadata fluidsynth_controllers[] = {
351 { -1, cmlc_continuouscc, 1, "Modulation", NULL},
352 { -1, cmlc_continuouscc, 7, "Volume", NULL},
353 { -1, cmlc_continuouscc, 10, "Pan", NULL},
354 { -1, cmlc_continuouscc, 91, "Reverb", NULL},
355 { -1, cmlc_continuouscc, 93, "Chorus", NULL},
356 { -1, cmlc_onoffcc, 64, "Hold", NULL},
357 { -1, cmlc_onoffcc, 66, "Sostenuto", NULL},
360 struct cbox_module_keyrange_metadata fluidsynth_keyranges[] = {
361 { 1, 0, 127, "Channel 1" },
362 { 2, 0, 127, "Channel 2" },
363 { 3, 0, 127, "Channel 3" },
364 { 4, 0, 127, "Channel 4" },
365 { 5, 0, 127, "Channel 5" },
366 { 6, 0, 127, "Channel 6" },
367 { 7, 0, 127, "Channel 7" },
368 { 8, 0, 127, "Channel 8" },
369 { 9, 0, 127, "Channel 9" },
370 { 10, 0, 127, "Channel 10" },
371 { 11, 0, 127, "Channel 11" },
372 { 12, 0, 127, "Channel 12" },
373 { 13, 0, 127, "Channel 13" },
374 { 14, 0, 127, "Channel 14" },
375 { 15, 0, 127, "Channel 15" },
376 { 16, 0, 127, "Channel 16" },
379 DEFINE_MODULE(fluidsynth, 0, 2)
381 #endif