Make sure program changes end up before notes on the same tick.
[calfbox.git] / fluid.c
blob23e41598f5fcfae98ab072025aa2a7d90cff08d0
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-api.h"
20 #include "dspmath.h"
21 #include "module.h"
22 #include <glib.h>
23 #include <math.h>
24 #include <memory.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <fluidsynth.h>
29 #define CBOX_FLUIDSYNTH_ERROR cbox_fluidsynth_error_quark()
31 enum CboxFluidsynthError
33 CBOX_FLUIDSYNTH_ERROR_FAILED,
36 GQuark cbox_fluidsynth_error_quark(void)
38 return g_quark_from_string("cbox-fluidsynth-error-quark");
41 static void fluidsynth_process_block(struct cbox_module *module, cbox_sample_t **inputs, cbox_sample_t **outputs);
42 static void fluidsynth_process_event(struct cbox_module *module, const uint8_t *data, uint32_t len);
43 static gboolean fluidsynth_process_cmd(struct cbox_command_target *ct, struct cbox_command_target *fb, struct cbox_osc_command *cmd, GError **error);
44 static void fluidsynth_destroyfunc(struct cbox_module *module);
46 struct fluidsynth_module
48 struct cbox_module module;
50 fluid_settings_t *settings;
51 fluid_synth_t *synth;
52 char *bank_name;
53 int sfid;
54 int output_pairs;
55 int is_multi;
56 float **left_outputs, **right_outputs;
59 static gboolean select_patch_by_name(struct fluidsynth_module *m, int channel, const gchar *preset, GError **error)
61 fluid_sfont_t* sfont = fluid_synth_get_sfont(m->synth, 0);
62 fluid_preset_t tmp;
64 sfont->iteration_start(sfont);
65 while(sfont->iteration_next(sfont, &tmp))
67 // trailing spaces are common in some SF2s
68 const char *pname = tmp.get_name(&tmp);
69 int len = strlen(pname);
70 while (len > 0 && pname[len - 1] == ' ')
71 len--;
73 if (!strncmp(pname, preset, len) && preset[len] == '\0')
75 fluid_synth_program_select(m->synth, channel, m->sfid, tmp.get_banknum(&tmp), tmp.get_num(&tmp));
76 return TRUE;
80 g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Preset not found: %s", preset);
81 return FALSE;
84 MODULE_CREATE_FUNCTION(fluidsynth)
86 int result = 0;
87 int i;
88 const char *bankname = cbox_config_get_string(cfg_section, "sf2");
89 static int inited = 0;
90 if (!inited)
92 inited = 1;
95 struct fluidsynth_module *m = malloc(sizeof(struct fluidsynth_module));
96 int pairs = cbox_config_get_int(cfg_section, "output_pairs", 0);
97 m->output_pairs = pairs ? pairs : 1;
98 m->is_multi = pairs > 0;
99 if (m->output_pairs < 1 || m->output_pairs > 16)
101 free(m);
102 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);
103 return NULL;
105 if (pairs == 0)
107 CALL_MODULE_INIT(m, 0, 2 * m->output_pairs, fluidsynth);
108 m->left_outputs = NULL;
109 m->right_outputs = NULL;
111 else
113 g_message("Multichannel mode enabled, %d output pairs, 2 effects", m->output_pairs);
114 CALL_MODULE_INIT(m, 0, 2 * m->output_pairs + 4, fluidsynth);
115 m->left_outputs = malloc(sizeof(float *) * (m->output_pairs + 2));
116 m->right_outputs = malloc(sizeof(float *) * (m->output_pairs + 2));
118 m->module.process_event = fluidsynth_process_event;
119 m->module.process_block = fluidsynth_process_block;
120 m->module.aux_offset = 2 * m->output_pairs;
121 m->settings = new_fluid_settings();
122 fluid_settings_setnum(m->settings, "synth.sample-rate", m->module.srate);
123 fluid_settings_setint(m->settings, "synth.audio-channels", m->output_pairs);
124 fluid_settings_setint(m->settings, "synth.audio-groups", m->output_pairs);
125 m->synth = new_fluid_synth(m->settings);
126 fluid_synth_set_reverb_on(m->synth, cbox_config_get_int(cfg_section, "reverb", 1));
127 fluid_synth_set_chorus_on(m->synth, cbox_config_get_int(cfg_section, "chorus", 1));
129 m->bank_name = NULL;
130 m->sfid = -1;
131 if (bankname)
133 m->bank_name = g_strdup(bankname);
134 g_message("Loading soundfont %s", bankname);
135 result = fluid_synth_sfload(m->synth, bankname, 1);
136 if (result == FLUID_FAILED)
138 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));
139 return NULL;
141 m->sfid = result;
142 g_message("Soundfont %s loaded", bankname);
144 if (bankname)
146 for (i = 0; i < 16; i++)
148 gchar *key = g_strdup_printf("channel%d", i + 1);
149 gchar *preset = cbox_config_get_string(cfg_section, key);
150 fluid_synth_sfont_select(m->synth, i, m->sfid);
151 if (preset)
153 if (!select_patch_by_name(m, i, preset, error))
155 CBOX_DELETE(&m->module);
156 return NULL;
159 g_free(key);
163 return &m->module;
166 void fluidsynth_process_block(struct cbox_module *module, cbox_sample_t **inputs, cbox_sample_t **outputs)
168 struct fluidsynth_module *m = (struct fluidsynth_module *)module;
169 if (!m->is_multi)
170 fluid_synth_write_float(m->synth, CBOX_BLOCK_SIZE, outputs[0], 0, 1, outputs[1], 0, 1);
171 else
173 for (int i = 0; i < 2 + m->output_pairs; i++)
175 m->left_outputs[i] = outputs[2 * i];
176 m->right_outputs[i] = outputs[2 * i + 1];
179 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);
183 void fluidsynth_process_event(struct cbox_module *module, const uint8_t *data, uint32_t len)
185 struct fluidsynth_module *m = (struct fluidsynth_module *)module;
186 if (len > 0)
188 int cmd = data[0] >> 4;
189 int chn = data[0] & 15;
190 switch(cmd)
192 case 8:
193 fluid_synth_noteoff(m->synth, chn, data[1]);
194 break;
196 case 9:
197 fluid_synth_noteon(m->synth, chn, data[1], data[2]);
198 break;
200 case 10:
201 // polyphonic pressure not handled
202 break;
204 case 11:
205 fluid_synth_cc(m->synth, chn, data[1], data[2]);
206 break;
208 case 12:
209 fluid_synth_program_change(m->synth, chn, data[1]);
210 break;
212 case 13:
213 fluid_synth_channel_pressure(m->synth, chn, data[1]);
214 break;
216 case 14:
217 fluid_synth_pitch_bend(m->synth, chn, data[1] + 128 * data[2]);
218 break;
224 gboolean fluidsynth_process_load_patch(struct fluidsynth_module *m, const char *bank_name, GError **error)
226 if (bank_name && !*bank_name)
227 bank_name = NULL;
228 int old_sfid = m->sfid;
229 char *old_bank_name = m->bank_name;
230 if (bank_name)
232 int result = fluid_synth_sfload(m->synth, bank_name, 1);
233 if (result == FLUID_FAILED)
235 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));
236 return FALSE;
238 g_message("Soundfont %s loaded at ID %d", bank_name, result);
239 m->sfid = result;
241 else
242 m->sfid = -1;
243 if (old_sfid != -1)
245 free(old_bank_name);
246 fluid_synth_sfunload(m->synth, old_sfid, 1);
248 if (m->sfid != -1)
250 for (int i = 0; i < 16; i++)
251 fluid_synth_sfont_select(m->synth, i, m->sfid);
253 m->bank_name = bank_name ? g_strdup(bank_name) : NULL;
254 return TRUE;
257 gboolean fluidsynth_process_cmd(struct cbox_command_target *ct, struct cbox_command_target *fb, struct cbox_osc_command *cmd, GError **error)
259 struct fluidsynth_module *m = (struct fluidsynth_module *)ct->user_data;
261 if (!strcmp(cmd->command, "/status") && !strcmp(cmd->arg_types, ""))
263 if (!cbox_check_fb_channel(fb, cmd->command, error))
264 return FALSE;
265 if (!cbox_execute_on(fb, NULL, "/polyphony", "i", error, fluid_synth_get_polyphony(m->synth)))
266 return FALSE;
267 if (!cbox_execute_on(fb, NULL, "/soundfont", "s", error, m->bank_name ? m->bank_name : ""))
268 return FALSE;
269 for (int i = 0; i < 16; i++)
271 fluid_synth_channel_info_t ci;
272 fluid_synth_get_channel_info(m->synth, i, &ci);
273 if (!cbox_execute_on(fb, NULL, "/patch", "iis", error, 1 + i, ci.program + 128 * ci.bank, ci.name))
274 return FALSE;
276 return CBOX_OBJECT_DEFAULT_STATUS(&m->module, fb, error);
278 else if (!strcmp(cmd->command, "/patches") && !strcmp(cmd->arg_types, ""))
280 if (!cbox_check_fb_channel(fb, cmd->command, error))
281 return FALSE;
282 if (m->sfid == -1)
283 return TRUE;
284 fluid_sfont_t* sfont = fluid_synth_get_sfont(m->synth, 0);
285 fluid_preset_t tmp;
287 sfont->iteration_start(sfont);
288 while(sfont->iteration_next(sfont, &tmp))
290 const char *pname = tmp.get_name(&tmp);
291 if (!cbox_execute_on(fb, NULL, "/patch", "is", error, (int)(tmp.get_num(&tmp) + 128 * tmp.get_banknum(&tmp)), pname))
292 return FALSE;
294 return TRUE;
296 else if (!strcmp(cmd->command, "/set_patch") && !strcmp(cmd->arg_types, "ii"))
298 if (m->sfid == -1)
300 g_set_error(error, CBOX_FLUIDSYNTH_ERROR, CBOX_FLUIDSYNTH_ERROR_FAILED, "No soundfont loaded");
301 return FALSE;
303 int channel = CBOX_ARG_I(cmd, 0);
304 if (channel < 1 || channel > 16)
306 g_set_error(error, CBOX_FLUIDSYNTH_ERROR, CBOX_FLUIDSYNTH_ERROR_FAILED, "Invalid channel %d", channel);
307 return FALSE;
309 int value = CBOX_ARG_I(cmd, 1);
310 return fluid_synth_program_select(m->synth, channel - 1, m->sfid, value >> 7, value & 127) == FLUID_OK;
312 else if (!strcmp(cmd->command, "/polyphony") && !strcmp(cmd->arg_types, "i"))
314 int polyphony = CBOX_ARG_I(cmd, 0);
315 if (polyphony < 2 || polyphony > 256)
317 g_set_error(error, CBOX_FLUIDSYNTH_ERROR, CBOX_FLUIDSYNTH_ERROR_FAILED, "Invalid polyphony %d (must be between 2 and 256)", polyphony);
318 return FALSE;
320 return fluid_synth_set_polyphony(m->synth, polyphony) == FLUID_OK;
322 else if (!strcmp(cmd->command, "/load_soundfont") && !strcmp(cmd->arg_types, "s"))
324 return fluidsynth_process_load_patch(m, CBOX_ARG_S(cmd, 0), error);
326 else
327 return cbox_object_default_process_cmd(ct, fb, cmd, error);
328 return TRUE;
331 void fluidsynth_destroyfunc(struct cbox_module *module)
333 struct fluidsynth_module *m = (struct fluidsynth_module *)module;
335 if (m->output_pairs)
337 free(m->left_outputs);
338 free(m->right_outputs);
340 free(m->bank_name);
342 delete_fluid_settings(m->settings);
343 delete_fluid_synth(m->synth);
346 struct cbox_module_livecontroller_metadata fluidsynth_controllers[] = {
347 { -1, cmlc_continuouscc, 1, "Modulation", NULL},
348 { -1, cmlc_continuouscc, 7, "Volume", NULL},
349 { -1, cmlc_continuouscc, 10, "Pan", NULL},
350 { -1, cmlc_continuouscc, 91, "Reverb", NULL},
351 { -1, cmlc_continuouscc, 93, "Chorus", NULL},
352 { -1, cmlc_onoffcc, 64, "Hold", NULL},
353 { -1, cmlc_onoffcc, 66, "Sostenuto", NULL},
356 struct cbox_module_keyrange_metadata fluidsynth_keyranges[] = {
357 { 1, 0, 127, "Channel 1" },
358 { 2, 0, 127, "Channel 2" },
359 { 3, 0, 127, "Channel 3" },
360 { 4, 0, 127, "Channel 4" },
361 { 5, 0, 127, "Channel 5" },
362 { 6, 0, 127, "Channel 6" },
363 { 7, 0, 127, "Channel 7" },
364 { 8, 0, 127, "Channel 8" },
365 { 9, 0, 127, "Channel 9" },
366 { 10, 0, 127, "Channel 10" },
367 { 11, 0, 127, "Channel 11" },
368 { 12, 0, 127, "Channel 12" },
369 { 13, 0, 127, "Channel 13" },
370 { 14, 0, 127, "Channel 14" },
371 { 15, 0, 127, "Channel 15" },
372 { 16, 0, 127, "Channel 16" },
375 DEFINE_MODULE(fluidsynth, 0, 2)