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/>.
23 #include "config-api.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
;
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);
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] == ' ')
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
));
84 g_set_error(error
, CBOX_MODULE_ERROR
, CBOX_MODULE_ERROR_FAILED
, "Preset not found: %s", preset
);
88 MODULE_CREATE_FUNCTION(fluidsynth
)
92 const char *bankname
= cbox_config_get_string(cfg_section
, "sf2");
93 static int inited
= 0;
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)
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
);
111 CALL_MODULE_INIT(m
, 0, 2 * m
->output_pairs
, fluidsynth
);
112 m
->left_outputs
= NULL
;
113 m
->right_outputs
= NULL
;
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));
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
));
146 g_message("Soundfont %s loaded", 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
);
157 if (!select_patch_by_name(m
, i
, preset
, error
))
159 CBOX_DELETE(&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
;
174 fluid_synth_write_float(m
->synth
, CBOX_BLOCK_SIZE
, outputs
[0], 0, 1, outputs
[1], 0, 1);
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
;
192 int cmd
= data
[0] >> 4;
193 int chn
= data
[0] & 15;
197 fluid_synth_noteoff(m
->synth
, chn
, data
[1]);
201 fluid_synth_noteon(m
->synth
, chn
, data
[1], data
[2]);
205 // polyphonic pressure not handled
209 fluid_synth_cc(m
->synth
, chn
, data
[1], data
[2]);
213 fluid_synth_program_change(m
->synth
, chn
, data
[1]);
217 fluid_synth_channel_pressure(m
->synth
, chn
, data
[1]);
221 fluid_synth_pitch_bend(m
->synth
, chn
, data
[1] + 128 * data
[2]);
228 gboolean
fluidsynth_process_load_patch(struct fluidsynth_module
*m
, const char *bank_name
, GError
**error
)
230 if (bank_name
&& !*bank_name
)
232 int old_sfid
= m
->sfid
;
233 char *old_bank_name
= m
->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
));
242 g_message("Soundfont %s loaded at ID %d", bank_name
, result
);
250 fluid_synth_sfunload(m
->synth
, old_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
;
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
))
269 if (!cbox_execute_on(fb
, NULL
, "/polyphony", "i", error
, fluid_synth_get_polyphony(m
->synth
)))
271 if (!cbox_execute_on(fb
, NULL
, "/soundfont", "s", error
, m
->bank_name
? m
->bank_name
: ""))
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
))
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
))
288 fluid_sfont_t
* sfont
= fluid_synth_get_sfont(m
->synth
, 0);
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
))
300 else if (!strcmp(cmd
->command
, "/set_patch") && !strcmp(cmd
->arg_types
, "ii"))
304 g_set_error(error
, CBOX_FLUIDSYNTH_ERROR
, CBOX_FLUIDSYNTH_ERROR_FAILED
, "No soundfont loaded");
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
);
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
);
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
);
331 return cbox_object_default_process_cmd(ct
, fb
, cmd
, error
);
335 void fluidsynth_destroyfunc(struct cbox_module
*module
)
337 struct fluidsynth_module
*m
= (struct fluidsynth_module
*)module
;
341 free(m
->left_outputs
);
342 free(m
->right_outputs
);
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)