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"
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
;
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);
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] == ' ')
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
));
80 g_set_error(error
, CBOX_MODULE_ERROR
, CBOX_MODULE_ERROR_FAILED
, "Preset not found: %s", preset
);
84 MODULE_CREATE_FUNCTION(fluidsynth
)
88 const char *bankname
= cbox_config_get_string(cfg_section
, "sf2");
89 static int inited
= 0;
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)
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
);
107 CALL_MODULE_INIT(m
, 0, 2 * m
->output_pairs
, fluidsynth
);
108 m
->left_outputs
= NULL
;
109 m
->right_outputs
= NULL
;
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));
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
));
142 g_message("Soundfont %s loaded", 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
);
153 if (!select_patch_by_name(m
, i
, preset
, error
))
155 CBOX_DELETE(&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
;
170 fluid_synth_write_float(m
->synth
, CBOX_BLOCK_SIZE
, outputs
[0], 0, 1, outputs
[1], 0, 1);
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
;
188 int cmd
= data
[0] >> 4;
189 int chn
= data
[0] & 15;
193 fluid_synth_noteoff(m
->synth
, chn
, data
[1]);
197 fluid_synth_noteon(m
->synth
, chn
, data
[1], data
[2]);
201 // polyphonic pressure not handled
205 fluid_synth_cc(m
->synth
, chn
, data
[1], data
[2]);
209 fluid_synth_program_change(m
->synth
, chn
, data
[1]);
213 fluid_synth_channel_pressure(m
->synth
, chn
, data
[1]);
217 fluid_synth_pitch_bend(m
->synth
, chn
, data
[1] + 128 * data
[2]);
224 gboolean
fluidsynth_process_load_patch(struct fluidsynth_module
*m
, const char *bank_name
, GError
**error
)
226 if (bank_name
&& !*bank_name
)
228 int old_sfid
= m
->sfid
;
229 char *old_bank_name
= m
->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
));
238 g_message("Soundfont %s loaded at ID %d", bank_name
, result
);
246 fluid_synth_sfunload(m
->synth
, old_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
;
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
))
265 if (!cbox_execute_on(fb
, NULL
, "/polyphony", "i", error
, fluid_synth_get_polyphony(m
->synth
)))
267 if (!cbox_execute_on(fb
, NULL
, "/soundfont", "s", error
, m
->bank_name
? m
->bank_name
: ""))
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
))
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
))
284 fluid_sfont_t
* sfont
= fluid_synth_get_sfont(m
->synth
, 0);
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
))
296 else if (!strcmp(cmd
->command
, "/set_patch") && !strcmp(cmd
->arg_types
, "ii"))
300 g_set_error(error
, CBOX_FLUIDSYNTH_ERROR
, CBOX_FLUIDSYNTH_ERROR_FAILED
, "No soundfont loaded");
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
);
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
);
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
);
327 return cbox_object_default_process_cmd(ct
, fb
, cmd
, error
);
331 void fluidsynth_destroyfunc(struct cbox_module
*module
)
333 struct fluidsynth_module
*m
= (struct fluidsynth_module
*)module
;
337 free(m
->left_outputs
);
338 free(m
->right_outputs
);
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)