New mini toggles
[calf.git] / src / fluidsynth.cpp
blobc5d307d765dadbc6eb67bc037a9387700ea0247c
1 /* Calf DSP Library
2 * Fluidsynth wrapper
4 * Copyright (C) 2001-2007 Krzysztof Foltman
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General
17 * Public License along with this program; if not, write to the
18 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301 USA
21 #include <calf/giface.h>
22 #include <calf/modules_dev.h>
23 #include <calf/utils.h>
24 #include <string.h>
26 #if ENABLE_EXPERIMENTAL
28 using namespace dsp;
29 using namespace calf_plugins;
30 using namespace std;
32 fluidsynth_audio_module::fluidsynth_audio_module()
34 settings = NULL;
35 synth = NULL;
36 status_serial = 1;
37 std::fill(set_presets, set_presets + 16, -1);
38 std::fill(last_selected_presets, last_selected_presets + 16, -1);
41 void fluidsynth_audio_module::post_instantiate(uint32_t sr)
43 srate = sr;
44 settings = new_fluid_settings();
45 synth = create_synth(sfid);
46 soundfont_loaded = sfid != -1;
49 void fluidsynth_audio_module::activate()
53 void fluidsynth_audio_module::deactivate()
57 fluid_synth_t *fluidsynth_audio_module::create_synth(int &new_sfid)
59 std::fill(set_presets, set_presets + 16, -1);
60 fluid_settings_t *new_settings = new_fluid_settings();
61 fluid_settings_setnum(new_settings, "synth.sample-rate", srate);
62 fluid_synth_t *s = new_fluid_synth(new_settings);
63 if (!soundfont.empty())
65 int sid = fluid_synth_sfload(s, soundfont.c_str(), 1);
66 if (sid == -1)
68 delete_fluid_synth(s);
69 return NULL;
71 assert(sid >= 0);
72 printf("sid=%d\n", sid);
73 fluid_synth_sfont_select(s, 0, sid);
74 new_sfid = sid;
76 fluid_sfont_t* sfont = fluid_synth_get_sfont(s, 0);
77 soundfont_name = (*sfont->get_name)(sfont);
79 sfont->iteration_start(sfont);
81 string preset_list;
82 fluid_preset_t tmp;
83 int first_preset = -1;
84 while(sfont->iteration_next(sfont, &tmp))
86 string pname = tmp.get_name(&tmp);
87 int bank = tmp.get_banknum(&tmp);
88 int num = tmp.get_num(&tmp);
89 int id = num + 128 * bank;
90 sf_preset_names[id] = pname;
91 preset_list += calf_utils::i2s(id) + "\t" + pname + "\n";
92 if (first_preset == -1)
93 first_preset = id;
95 if (first_preset != -1)
97 fluid_synth_bank_select(s, 0, first_preset >> 7);
98 fluid_synth_program_change(s, 0, first_preset & 127);
100 soundfont_preset_list = preset_list;
102 else
103 new_sfid = -1;
104 return s;
107 void fluidsynth_audio_module::note_on(int channel, int note, int vel)
109 fluid_synth_noteon(synth, channel, note, vel);
112 void fluidsynth_audio_module::note_off(int channel, int note, int vel)
114 fluid_synth_noteoff(synth, channel, note);
117 void fluidsynth_audio_module::control_change(int channel, int controller, int value)
119 fluid_synth_cc(synth, channel, controller, value);
121 if (controller == 0 || controller == 32)
122 update_preset_num(channel);
125 void fluidsynth_audio_module::program_change(int channel, int program)
127 fluid_synth_program_change(synth, channel, program);
129 update_preset_num(channel);
133 void fluidsynth_audio_module::update_preset_num(int channel)
135 fluid_preset_t *p = fluid_synth_get_channel_preset(synth, channel);
136 if (p)
137 last_selected_presets[channel] = p->get_num(p) + 128 * p->get_banknum(p);
138 else
139 last_selected_presets[channel] = -1;
140 status_serial++;
143 void fluidsynth_audio_module::select_preset_in_channel(int channel, int new_preset)
145 fluid_synth_bank_select(synth, channel, new_preset >> 7);
146 fluid_synth_program_change(synth, channel, new_preset & 127);
147 last_selected_presets[channel] = new_preset;
150 uint32_t fluidsynth_audio_module::process(uint32_t offset, uint32_t nsamples, uint32_t inputs_mask, uint32_t outputs_mask)
152 static const int interp_lens[] = { 0, 1, 4, 7 };
153 for (int i = 0; i < 16; ++i)
155 int new_preset = set_presets[i];
156 if (new_preset != -1 && soundfont_loaded)
158 // XXXKF yeah there's a tiny chance of race here, have to live with it until I write some utility classes for lock-free data passing
159 set_presets[i] = -1;
160 select_preset_in_channel(i, new_preset);
163 if (!soundfont_loaded)
165 // Reset selected presets array to 'no preset'
166 std::fill(last_selected_presets, last_selected_presets + 16, -1);
168 fluid_synth_set_interp_method(synth, -1, interp_lens[dsp::clip<int>(fastf2i_drm(*params[par_interpolation]), 0, 3)]);
169 fluid_synth_set_reverb_on(synth, *params[par_reverb] > 0);
170 fluid_synth_set_chorus_on(synth, *params[par_chorus] > 0);
171 fluid_synth_set_gain(synth, *params[par_master]);
172 fluid_synth_write_float(synth, nsamples, outs[0], offset, 1, outs[1], offset, 1);
173 return 3;
176 char *fluidsynth_audio_module::configure(const char *key, const char *value)
178 if (!strncmp(key, "preset_key_set", 14))
180 int ch = atoi(key + 14);
181 if (ch > 0)
182 ch--;
183 if (ch >= 0 && ch <= 15)
184 set_presets[ch] = value ? atoi(value) : 0;
185 return NULL;
187 if (!strcmp(key, "soundfont"))
189 if (value && *value)
191 printf("Loading %s\n", value);
192 soundfont = value;
194 else
196 printf("Creating a blank synth\n");
197 soundfont.clear();
199 // First synth not yet created - defer creation up to post_instantiate
200 if (!synth)
201 return NULL;
202 int newsfid = -1;
203 fluid_synth_t *new_synth = create_synth(newsfid);
204 soundfont_loaded = newsfid != -1;
206 status_serial++;
208 if (new_synth)
210 synth = new_synth;
211 sfid = newsfid;
212 for (int i = 0; i < 16; ++i)
213 update_preset_num(i);
215 else
216 return strdup("Cannot load a soundfont");
217 // XXXKF memory leak
219 return NULL;
222 void fluidsynth_audio_module::send_configures(send_configure_iface *sci)
224 sci->send_configure("soundfont", soundfont.c_str());
225 sci->send_configure("preset_key_set", calf_utils::i2s(last_selected_presets[0]).c_str());
226 for (int i = 1; i < 16; ++i)
228 string key = "preset_key_set" + calf_utils::i2s(i + 1);
229 sci->send_configure(key.c_str(), calf_utils::i2s(last_selected_presets[i]).c_str());
233 int fluidsynth_audio_module::send_status_updates(send_updates_iface *sui, int last_serial)
235 int cur_serial = status_serial;
236 if (cur_serial != last_serial)
238 sui->send_status("sf_name", soundfont_name.c_str());
239 sui->send_status("preset_list", soundfont_preset_list.c_str());
240 for (int i = 0; i < 16; ++i)
242 string id = i ? calf_utils::i2s(i + 1) : string();
243 string key = "preset_key" + id;
244 sui->send_status(key.c_str(), calf_utils::i2s(last_selected_presets[i]).c_str());
245 key = "preset_name" + id;
246 map<uint32_t, string>::const_iterator it = sf_preset_names.find(last_selected_presets[i]);
247 if (it == sf_preset_names.end())
248 sui->send_status(key.c_str(), "");
249 else
250 sui->send_status(key.c_str(), it->second.c_str());
253 return cur_serial;
256 fluidsynth_audio_module::~fluidsynth_audio_module()
258 if (synth) {
259 delete_fluid_synth(synth);
260 synth = NULL;
262 if (settings) {
263 // delete_fluid_settings(settings);
264 settings = NULL;
268 #endif