Use an ambisonics-based panning method
[openal-soft.git] / Alc / midi / fluidsynth.c
blobbf774ab1ef83ceae183e05689324864348d5768e
2 #include "config.h"
4 #include <stdlib.h>
5 #include <string.h>
6 #include <limits.h>
8 #include "midi/base.h"
10 #include "alMain.h"
11 #include "alError.h"
12 #include "alMidi.h"
13 #include "alu.h"
14 #include "compat.h"
15 #include "evtqueue.h"
16 #include "rwlock.h"
18 #ifdef HAVE_FLUIDSYNTH
20 #include <fluidsynth.h>
23 #ifdef HAVE_DYNLOAD
24 #define FLUID_FUNCS(MAGIC) \
25 MAGIC(new_fluid_synth); \
26 MAGIC(delete_fluid_synth); \
27 MAGIC(new_fluid_settings); \
28 MAGIC(delete_fluid_settings); \
29 MAGIC(fluid_settings_setint); \
30 MAGIC(fluid_settings_setnum); \
31 MAGIC(fluid_synth_noteon); \
32 MAGIC(fluid_synth_noteoff); \
33 MAGIC(fluid_synth_program_change); \
34 MAGIC(fluid_synth_pitch_bend); \
35 MAGIC(fluid_synth_channel_pressure); \
36 MAGIC(fluid_synth_cc); \
37 MAGIC(fluid_synth_sysex); \
38 MAGIC(fluid_synth_bank_select); \
39 MAGIC(fluid_synth_set_channel_type); \
40 MAGIC(fluid_synth_all_sounds_off); \
41 MAGIC(fluid_synth_system_reset); \
42 MAGIC(fluid_synth_set_gain); \
43 MAGIC(fluid_synth_set_sample_rate); \
44 MAGIC(fluid_synth_write_float); \
45 MAGIC(fluid_synth_add_sfloader); \
46 MAGIC(fluid_synth_sfload); \
47 MAGIC(fluid_synth_sfunload); \
48 MAGIC(fluid_synth_alloc_voice); \
49 MAGIC(fluid_synth_start_voice); \
50 MAGIC(fluid_voice_gen_set); \
51 MAGIC(fluid_voice_add_mod); \
52 MAGIC(fluid_mod_set_source1); \
53 MAGIC(fluid_mod_set_source2); \
54 MAGIC(fluid_mod_set_amount); \
55 MAGIC(fluid_mod_set_dest);
57 void *fsynth_handle = NULL;
58 #define DECL_FUNC(x) __typeof(x) *p##x
59 FLUID_FUNCS(DECL_FUNC)
60 #undef DECL_FUNC
62 #define new_fluid_synth pnew_fluid_synth
63 #define delete_fluid_synth pdelete_fluid_synth
64 #define new_fluid_settings pnew_fluid_settings
65 #define delete_fluid_settings pdelete_fluid_settings
66 #define fluid_settings_setint pfluid_settings_setint
67 #define fluid_settings_setnum pfluid_settings_setnum
68 #define fluid_synth_noteon pfluid_synth_noteon
69 #define fluid_synth_noteoff pfluid_synth_noteoff
70 #define fluid_synth_program_change pfluid_synth_program_change
71 #define fluid_synth_pitch_bend pfluid_synth_pitch_bend
72 #define fluid_synth_channel_pressure pfluid_synth_channel_pressure
73 #define fluid_synth_cc pfluid_synth_cc
74 #define fluid_synth_sysex pfluid_synth_sysex
75 #define fluid_synth_bank_select pfluid_synth_bank_select
76 #define fluid_synth_set_channel_type pfluid_synth_set_channel_type
77 #define fluid_synth_all_sounds_off pfluid_synth_all_sounds_off
78 #define fluid_synth_system_reset pfluid_synth_system_reset
79 #define fluid_synth_set_gain pfluid_synth_set_gain
80 #define fluid_synth_set_sample_rate pfluid_synth_set_sample_rate
81 #define fluid_synth_write_float pfluid_synth_write_float
82 #define fluid_synth_add_sfloader pfluid_synth_add_sfloader
83 #define fluid_synth_sfload pfluid_synth_sfload
84 #define fluid_synth_sfunload pfluid_synth_sfunload
85 #define fluid_synth_alloc_voice pfluid_synth_alloc_voice
86 #define fluid_synth_start_voice pfluid_synth_start_voice
87 #define fluid_voice_gen_set pfluid_voice_gen_set
88 #define fluid_voice_add_mod pfluid_voice_add_mod
89 #define fluid_mod_set_source1 pfluid_mod_set_source1
90 #define fluid_mod_set_source2 pfluid_mod_set_source2
91 #define fluid_mod_set_amount pfluid_mod_set_amount
92 #define fluid_mod_set_dest pfluid_mod_set_dest
94 static ALboolean LoadFSynth(void)
96 ALboolean ret = AL_TRUE;
97 if(!fsynth_handle)
99 fsynth_handle = LoadLib("libfluidsynth.so.1");
100 if(!fsynth_handle) return AL_FALSE;
102 #define LOAD_FUNC(x) do { \
103 p##x = GetSymbol(fsynth_handle, #x); \
104 if(!p##x) ret = AL_FALSE; \
105 } while(0)
106 FLUID_FUNCS(LOAD_FUNC)
107 #undef LOAD_FUNC
109 if(ret == AL_FALSE)
111 CloseLib(fsynth_handle);
112 fsynth_handle = NULL;
115 return ret;
117 #else
118 static inline ALboolean LoadFSynth(void) { return AL_TRUE; }
119 #endif
122 /* MIDI events */
123 #define SYSEX_EVENT (0xF0)
125 /* MIDI controllers */
126 #define CTRL_BANKSELECT_MSB (0)
127 #define CTRL_BANKSELECT_LSB (32)
128 #define CTRL_ALLNOTESOFF (123)
131 static int getModInput(ALenum input)
133 switch(input)
135 case AL_ONE_SOFT: return FLUID_MOD_NONE;
136 case AL_NOTEON_VELOCITY_SOFT: return FLUID_MOD_VELOCITY;
137 case AL_NOTEON_KEY_SOFT: return FLUID_MOD_KEY;
138 case AL_KEYPRESSURE_SOFT: return FLUID_MOD_KEYPRESSURE;
139 case AL_CHANNELPRESSURE_SOFT: return FLUID_MOD_CHANNELPRESSURE;
140 case AL_PITCHBEND_SOFT: return FLUID_MOD_PITCHWHEEL;
141 case AL_PITCHBEND_SENSITIVITY_SOFT: return FLUID_MOD_PITCHWHEELSENS;
143 return input&0x7F;
146 static int getModFlags(ALenum input, ALenum type, ALenum form)
148 int ret = 0;
150 switch(type)
152 case AL_UNORM_SOFT: ret |= FLUID_MOD_UNIPOLAR | FLUID_MOD_POSITIVE; break;
153 case AL_UNORM_REV_SOFT: ret |= FLUID_MOD_UNIPOLAR | FLUID_MOD_NEGATIVE; break;
154 case AL_SNORM_SOFT: ret |= FLUID_MOD_BIPOLAR | FLUID_MOD_POSITIVE; break;
155 case AL_SNORM_REV_SOFT: ret |= FLUID_MOD_BIPOLAR | FLUID_MOD_NEGATIVE; break;
157 switch(form)
159 case AL_LINEAR_SOFT: ret |= FLUID_MOD_LINEAR; break;
160 case AL_CONCAVE_SOFT: ret |= FLUID_MOD_CONCAVE; break;
161 case AL_CONVEX_SOFT: ret |= FLUID_MOD_CONVEX; break;
162 case AL_SWITCH_SOFT: ret |= FLUID_MOD_SWITCH; break;
164 /* Source input values less than 128 correspond to a MIDI continuous
165 * controller. Otherwise, it's a general controller. */
166 if(input < 128) ret |= FLUID_MOD_CC;
167 else ret |= FLUID_MOD_GC;
169 return ret;
172 static enum fluid_gen_type getModDest(ALenum gen)
174 switch(gen)
176 case AL_MOD_LFO_TO_PITCH_SOFT: return GEN_MODLFOTOPITCH;
177 case AL_VIBRATO_LFO_TO_PITCH_SOFT: return GEN_VIBLFOTOPITCH;
178 case AL_MOD_ENV_TO_PITCH_SOFT: return GEN_MODENVTOPITCH;
179 case AL_FILTER_CUTOFF_SOFT: return GEN_FILTERFC;
180 case AL_FILTER_RESONANCE_SOFT: return GEN_FILTERQ;
181 case AL_MOD_LFO_TO_FILTER_CUTOFF_SOFT: return GEN_MODLFOTOFILTERFC;
182 case AL_MOD_ENV_TO_FILTER_CUTOFF_SOFT: return GEN_MODENVTOFILTERFC;
183 case AL_MOD_LFO_TO_VOLUME_SOFT: return GEN_MODLFOTOVOL;
184 case AL_CHORUS_SEND_SOFT: return GEN_CHORUSSEND;
185 case AL_REVERB_SEND_SOFT: return GEN_REVERBSEND;
186 case AL_PAN_SOFT: return GEN_PAN;
187 case AL_MOD_LFO_DELAY_SOFT: return GEN_MODLFODELAY;
188 case AL_MOD_LFO_FREQUENCY_SOFT: return GEN_MODLFOFREQ;
189 case AL_VIBRATO_LFO_DELAY_SOFT: return GEN_VIBLFODELAY;
190 case AL_VIBRATO_LFO_FREQUENCY_SOFT: return GEN_VIBLFOFREQ;
191 case AL_MOD_ENV_DELAYTIME_SOFT: return GEN_MODENVDELAY;
192 case AL_MOD_ENV_ATTACKTIME_SOFT: return GEN_MODENVATTACK;
193 case AL_MOD_ENV_HOLDTIME_SOFT: return GEN_MODENVHOLD;
194 case AL_MOD_ENV_DECAYTIME_SOFT: return GEN_MODENVDECAY;
195 case AL_MOD_ENV_SUSTAINVOLUME_SOFT: return GEN_MODENVSUSTAIN;
196 case AL_MOD_ENV_RELEASETIME_SOFT: return GEN_MODENVRELEASE;
197 case AL_MOD_ENV_KEY_TO_HOLDTIME_SOFT: return GEN_KEYTOMODENVHOLD;
198 case AL_MOD_ENV_KEY_TO_DECAYTIME_SOFT: return GEN_KEYTOMODENVDECAY;
199 case AL_VOLUME_ENV_DELAYTIME_SOFT: return GEN_VOLENVDELAY;
200 case AL_VOLUME_ENV_ATTACKTIME_SOFT: return GEN_VOLENVATTACK;
201 case AL_VOLUME_ENV_HOLDTIME_SOFT: return GEN_VOLENVHOLD;
202 case AL_VOLUME_ENV_DECAYTIME_SOFT: return GEN_VOLENVDECAY;
203 case AL_VOLUME_ENV_SUSTAINVOLUME_SOFT: return GEN_VOLENVSUSTAIN;
204 case AL_VOLUME_ENV_RELEASETIME_SOFT: return GEN_VOLENVRELEASE;
205 case AL_VOLUME_ENV_KEY_TO_HOLDTIME_SOFT: return GEN_KEYTOVOLENVHOLD;
206 case AL_VOLUME_ENV_KEY_TO_DECAYTIME_SOFT: return GEN_KEYTOVOLENVDECAY;
207 case AL_ATTENUATION_SOFT: return GEN_ATTENUATION;
208 case AL_TUNING_COARSE_SOFT: return GEN_COARSETUNE;
209 case AL_TUNING_FINE_SOFT: return GEN_FINETUNE;
210 case AL_TUNING_SCALE_SOFT: return GEN_SCALETUNE;
212 ERR("Unhandled generator: 0x%04x\n", gen);
213 return 0;
216 static int getSf2LoopMode(ALenum mode)
218 switch(mode)
220 case AL_NONE: return 0;
221 case AL_LOOP_CONTINUOUS_SOFT: return 1;
222 case AL_LOOP_UNTIL_RELEASE_SOFT: return 3;
224 return 0;
227 static int getSampleType(ALenum type)
229 switch(type)
231 case AL_MONO_SOFT: return FLUID_SAMPLETYPE_MONO;
232 case AL_RIGHT_SOFT: return FLUID_SAMPLETYPE_RIGHT;
233 case AL_LEFT_SOFT: return FLUID_SAMPLETYPE_LEFT;
235 return FLUID_SAMPLETYPE_MONO;
238 typedef struct FSample {
239 DERIVE_FROM_TYPE(fluid_sample_t);
241 ALfontsound *Sound;
243 fluid_mod_t *Mods;
244 ALsizei NumMods;
245 } FSample;
247 static void FSample_Construct(FSample *self, ALfontsound *sound)
249 fluid_sample_t *sample = STATIC_CAST(fluid_sample_t, self);
250 ALbuffer *buffer = ATOMIC_LOAD(&sound->Buffer);
252 memset(sample->name, 0, sizeof(sample->name));
253 sample->start = sound->Start;
254 sample->end = sound->End;
255 sample->loopstart = sound->LoopStart;
256 sample->loopend = sound->LoopEnd;
257 sample->samplerate = sound->SampleRate;
258 sample->origpitch = sound->PitchKey;
259 sample->pitchadj = sound->PitchCorrection;
260 sample->sampletype = getSampleType(sound->SampleType);
261 sample->valid = !!buffer;
262 sample->data = buffer ? buffer->data : NULL;
264 sample->amplitude_that_reaches_noise_floor_is_valid = 0;
265 sample->amplitude_that_reaches_noise_floor = 0.0;
267 sample->refcount = 0;
269 sample->notify = NULL;
271 sample->userdata = self;
273 self->Sound = sound;
275 self->NumMods = 0;
276 self->Mods = calloc(sound->ModulatorMap.size*4, sizeof(fluid_mod_t[4]));
277 if(self->Mods)
279 ALsizei i, j, k;
281 for(i = j = 0;i < sound->ModulatorMap.size;i++)
283 ALsfmodulator *mod = sound->ModulatorMap.array[i].value;
284 for(k = 0;k < 4;k++,mod++)
286 if(mod->Dest == AL_NONE)
287 continue;
288 fluid_mod_set_source1(&self->Mods[j], getModInput(mod->Source[0].Input),
289 getModFlags(mod->Source[0].Input, mod->Source[0].Type,
290 mod->Source[0].Form));
291 fluid_mod_set_source2(&self->Mods[j], getModInput(mod->Source[1].Input),
292 getModFlags(mod->Source[1].Input, mod->Source[1].Type,
293 mod->Source[1].Form));
294 fluid_mod_set_amount(&self->Mods[j], mod->Amount);
295 fluid_mod_set_dest(&self->Mods[j], getModDest(mod->Dest));
296 self->Mods[j++].next = NULL;
299 self->NumMods = j;
303 static void FSample_Destruct(FSample *self)
305 free(self->Mods);
306 self->Mods = NULL;
307 self->NumMods = 0;
311 typedef struct FPreset {
312 DERIVE_FROM_TYPE(fluid_preset_t);
314 char Name[16];
316 int Preset;
317 int Bank;
319 FSample *Samples;
320 ALsizei NumSamples;
321 } FPreset;
323 static char* FPreset_getName(fluid_preset_t *preset);
324 static int FPreset_getPreset(fluid_preset_t *preset);
325 static int FPreset_getBank(fluid_preset_t *preset);
326 static int FPreset_noteOn(fluid_preset_t *preset, fluid_synth_t *synth, int channel, int key, int velocity);
328 static void FPreset_Construct(FPreset *self, ALsfpreset *preset, fluid_sfont_t *parent)
330 STATIC_CAST(fluid_preset_t, self)->data = self;
331 STATIC_CAST(fluid_preset_t, self)->sfont = parent;
332 STATIC_CAST(fluid_preset_t, self)->free = NULL;
333 STATIC_CAST(fluid_preset_t, self)->get_name = FPreset_getName;
334 STATIC_CAST(fluid_preset_t, self)->get_banknum = FPreset_getBank;
335 STATIC_CAST(fluid_preset_t, self)->get_num = FPreset_getPreset;
336 STATIC_CAST(fluid_preset_t, self)->noteon = FPreset_noteOn;
337 STATIC_CAST(fluid_preset_t, self)->notify = NULL;
339 memset(self->Name, 0, sizeof(self->Name));
340 self->Preset = preset->Preset;
341 self->Bank = preset->Bank;
343 self->NumSamples = 0;
344 self->Samples = calloc(1, preset->NumSounds * sizeof(self->Samples[0]));
345 if(self->Samples)
347 ALsizei i;
348 self->NumSamples = preset->NumSounds;
349 for(i = 0;i < self->NumSamples;i++)
350 FSample_Construct(&self->Samples[i], preset->Sounds[i]);
354 static void FPreset_Destruct(FPreset *self)
356 ALsizei i;
358 for(i = 0;i < self->NumSamples;i++)
359 FSample_Destruct(&self->Samples[i]);
360 free(self->Samples);
361 self->Samples = NULL;
362 self->NumSamples = 0;
365 static ALboolean FPreset_canDelete(FPreset *self)
367 ALsizei i;
368 for(i = 0;i < self->NumSamples;i++)
370 if(fluid_sample_refcount(STATIC_CAST(fluid_sample_t, &self->Samples[i])) != 0)
371 return AL_FALSE;
373 return AL_TRUE;
376 static char* FPreset_getName(fluid_preset_t *preset)
378 return ((FPreset*)preset->data)->Name;
381 static int FPreset_getPreset(fluid_preset_t *preset)
383 return ((FPreset*)preset->data)->Preset;
386 static int FPreset_getBank(fluid_preset_t *preset)
388 return ((FPreset*)preset->data)->Bank;
391 static int FPreset_noteOn(fluid_preset_t *preset, fluid_synth_t *synth, int channel, int key, int vel)
393 FPreset *self = ((FPreset*)preset->data);
394 ALsizei i;
396 for(i = 0;i < self->NumSamples;i++)
398 FSample *sample = &self->Samples[i];
399 ALfontsound *sound = sample->Sound;
400 fluid_voice_t *voice;
401 ALsizei m;
403 if(!(key >= sound->MinKey && key <= sound->MaxKey && vel >= sound->MinVelocity && vel <= sound->MaxVelocity))
404 continue;
406 voice = fluid_synth_alloc_voice(synth, STATIC_CAST(fluid_sample_t, sample), channel, key, vel);
407 if(voice == NULL) return FLUID_FAILED;
409 fluid_voice_gen_set(voice, GEN_MODLFOTOPITCH, sound->ModLfoToPitch);
410 fluid_voice_gen_set(voice, GEN_VIBLFOTOPITCH, sound->VibratoLfoToPitch);
411 fluid_voice_gen_set(voice, GEN_MODENVTOPITCH, sound->ModEnvToPitch);
412 fluid_voice_gen_set(voice, GEN_FILTERFC, sound->FilterCutoff);
413 fluid_voice_gen_set(voice, GEN_FILTERQ, sound->FilterQ);
414 fluid_voice_gen_set(voice, GEN_MODLFOTOFILTERFC, sound->ModLfoToFilterCutoff);
415 fluid_voice_gen_set(voice, GEN_MODENVTOFILTERFC, sound->ModEnvToFilterCutoff);
416 fluid_voice_gen_set(voice, GEN_MODLFOTOVOL, sound->ModLfoToVolume);
417 fluid_voice_gen_set(voice, GEN_CHORUSSEND, sound->ChorusSend);
418 fluid_voice_gen_set(voice, GEN_REVERBSEND, sound->ReverbSend);
419 fluid_voice_gen_set(voice, GEN_PAN, sound->Pan);
420 fluid_voice_gen_set(voice, GEN_MODLFODELAY, sound->ModLfo.Delay);
421 fluid_voice_gen_set(voice, GEN_MODLFOFREQ, sound->ModLfo.Frequency);
422 fluid_voice_gen_set(voice, GEN_VIBLFODELAY, sound->VibratoLfo.Delay);
423 fluid_voice_gen_set(voice, GEN_VIBLFOFREQ, sound->VibratoLfo.Frequency);
424 fluid_voice_gen_set(voice, GEN_MODENVDELAY, sound->ModEnv.DelayTime);
425 fluid_voice_gen_set(voice, GEN_MODENVATTACK, sound->ModEnv.AttackTime);
426 fluid_voice_gen_set(voice, GEN_MODENVHOLD, sound->ModEnv.HoldTime);
427 fluid_voice_gen_set(voice, GEN_MODENVDECAY, sound->ModEnv.DecayTime);
428 fluid_voice_gen_set(voice, GEN_MODENVSUSTAIN, sound->ModEnv.SustainAttn);
429 fluid_voice_gen_set(voice, GEN_MODENVRELEASE, sound->ModEnv.ReleaseTime);
430 fluid_voice_gen_set(voice, GEN_KEYTOMODENVHOLD, sound->ModEnv.KeyToHoldTime);
431 fluid_voice_gen_set(voice, GEN_KEYTOMODENVDECAY, sound->ModEnv.KeyToDecayTime);
432 fluid_voice_gen_set(voice, GEN_VOLENVDELAY, sound->VolEnv.DelayTime);
433 fluid_voice_gen_set(voice, GEN_VOLENVATTACK, sound->VolEnv.AttackTime);
434 fluid_voice_gen_set(voice, GEN_VOLENVHOLD, sound->VolEnv.HoldTime);
435 fluid_voice_gen_set(voice, GEN_VOLENVDECAY, sound->VolEnv.DecayTime);
436 fluid_voice_gen_set(voice, GEN_VOLENVSUSTAIN, sound->VolEnv.SustainAttn);
437 fluid_voice_gen_set(voice, GEN_VOLENVRELEASE, sound->VolEnv.ReleaseTime);
438 fluid_voice_gen_set(voice, GEN_KEYTOVOLENVHOLD, sound->VolEnv.KeyToHoldTime);
439 fluid_voice_gen_set(voice, GEN_KEYTOVOLENVDECAY, sound->VolEnv.KeyToDecayTime);
440 fluid_voice_gen_set(voice, GEN_ATTENUATION, sound->Attenuation);
441 fluid_voice_gen_set(voice, GEN_COARSETUNE, sound->CoarseTuning);
442 fluid_voice_gen_set(voice, GEN_FINETUNE, sound->FineTuning);
443 fluid_voice_gen_set(voice, GEN_SAMPLEMODE, getSf2LoopMode(sound->LoopMode));
444 fluid_voice_gen_set(voice, GEN_SCALETUNE, sound->TuningScale);
445 fluid_voice_gen_set(voice, GEN_EXCLUSIVECLASS, sound->ExclusiveClass);
446 for(m = 0;m < sample->NumMods;m++)
447 fluid_voice_add_mod(voice, &sample->Mods[m], FLUID_VOICE_OVERWRITE);
449 fluid_synth_start_voice(synth, voice);
452 return FLUID_OK;
456 typedef struct FSfont {
457 DERIVE_FROM_TYPE(fluid_sfont_t);
459 char Name[16];
461 FPreset *Presets;
462 ALsizei NumPresets;
464 ALsizei CurrentPos;
465 } FSfont;
467 static int FSfont_free(fluid_sfont_t *sfont);
468 static char* FSfont_getName(fluid_sfont_t *sfont);
469 static fluid_preset_t* FSfont_getPreset(fluid_sfont_t *sfont, unsigned int bank, unsigned int prenum);
470 static void FSfont_iterStart(fluid_sfont_t *sfont);
471 static int FSfont_iterNext(fluid_sfont_t *sfont, fluid_preset_t *preset);
473 static void FSfont_Construct(FSfont *self, ALsoundfont *sfont)
475 STATIC_CAST(fluid_sfont_t, self)->data = self;
476 STATIC_CAST(fluid_sfont_t, self)->id = FLUID_FAILED;
477 STATIC_CAST(fluid_sfont_t, self)->free = FSfont_free;
478 STATIC_CAST(fluid_sfont_t, self)->get_name = FSfont_getName;
479 STATIC_CAST(fluid_sfont_t, self)->get_preset = FSfont_getPreset;
480 STATIC_CAST(fluid_sfont_t, self)->iteration_start = FSfont_iterStart;
481 STATIC_CAST(fluid_sfont_t, self)->iteration_next = FSfont_iterNext;
483 memset(self->Name, 0, sizeof(self->Name));
484 self->CurrentPos = 0;
485 self->NumPresets = 0;
486 self->Presets = calloc(1, sfont->NumPresets * sizeof(self->Presets[0]));
487 if(self->Presets)
489 ALsizei i;
490 self->NumPresets = sfont->NumPresets;
491 for(i = 0;i < self->NumPresets;i++)
492 FPreset_Construct(&self->Presets[i], sfont->Presets[i], STATIC_CAST(fluid_sfont_t, self));
496 static void FSfont_Destruct(FSfont *self)
498 ALsizei i;
500 for(i = 0;i < self->NumPresets;i++)
501 FPreset_Destruct(&self->Presets[i]);
502 free(self->Presets);
503 self->Presets = NULL;
504 self->NumPresets = 0;
505 self->CurrentPos = 0;
508 static int FSfont_free(fluid_sfont_t *sfont)
510 FSfont *self = STATIC_UPCAST(FSfont, fluid_sfont_t, sfont);
511 ALsizei i;
513 for(i = 0;i < self->NumPresets;i++)
515 if(!FPreset_canDelete(&self->Presets[i]))
516 return 1;
519 FSfont_Destruct(self);
520 free(self);
521 return 0;
524 static char* FSfont_getName(fluid_sfont_t *sfont)
526 return STATIC_UPCAST(FSfont, fluid_sfont_t, sfont)->Name;
529 static fluid_preset_t *FSfont_getPreset(fluid_sfont_t *sfont, unsigned int bank, unsigned int prenum)
531 FSfont *self = STATIC_UPCAST(FSfont, fluid_sfont_t, sfont);
532 ALsizei i;
534 for(i = 0;i < self->NumPresets;i++)
536 FPreset *preset = &self->Presets[i];
537 if(preset->Bank == (int)bank && preset->Preset == (int)prenum)
538 return STATIC_CAST(fluid_preset_t, preset);
541 return NULL;
544 static void FSfont_iterStart(fluid_sfont_t *sfont)
546 STATIC_UPCAST(FSfont, fluid_sfont_t, sfont)->CurrentPos = 0;
549 static int FSfont_iterNext(fluid_sfont_t *sfont, fluid_preset_t *preset)
551 FSfont *self = STATIC_UPCAST(FSfont, fluid_sfont_t, sfont);
552 if(self->CurrentPos >= self->NumPresets)
553 return 0;
554 *preset = *STATIC_CAST(fluid_preset_t, &self->Presets[self->CurrentPos++]);
555 preset->free = NULL;
556 return 1;
560 typedef struct FSynth {
561 DERIVE_FROM_TYPE(MidiSynth);
562 DERIVE_FROM_TYPE(fluid_sfloader_t);
564 fluid_settings_t *Settings;
565 fluid_synth_t *Synth;
566 int *FontIDs;
567 ALsizei NumFontIDs;
569 ALboolean ForceGM2BankSelect;
570 ALfloat GainScale;
571 } FSynth;
573 static void FSynth_Construct(FSynth *self, ALCdevice *device);
574 static void FSynth_Destruct(FSynth *self);
575 static ALboolean FSynth_init(FSynth *self, ALCdevice *device);
576 static ALenum FSynth_selectSoundfonts(FSynth *self, ALCcontext *context, ALsizei count, const ALuint *ids);
577 static void FSynth_setGain(FSynth *self, ALfloat gain);
578 static void FSynth_stop(FSynth *self);
579 static void FSynth_reset(FSynth *self);
580 static void FSynth_update(FSynth *self, ALCdevice *device);
581 static void FSynth_processQueue(FSynth *self, ALuint64 time);
582 static void FSynth_process(FSynth *self, ALuint SamplesToDo, ALfloat (*restrict DryBuffer)[BUFFERSIZE]);
583 DECLARE_DEFAULT_ALLOCATORS(FSynth)
584 DEFINE_MIDISYNTH_VTABLE(FSynth);
586 static fluid_sfont_t *FSynth_loadSfont(fluid_sfloader_t *loader, const char *filename);
589 static void FSynth_Construct(FSynth *self, ALCdevice *device)
591 MidiSynth_Construct(STATIC_CAST(MidiSynth, self), device);
592 SET_VTABLE2(FSynth, MidiSynth, self);
594 STATIC_CAST(fluid_sfloader_t, self)->data = self;
595 STATIC_CAST(fluid_sfloader_t, self)->free = NULL;
596 STATIC_CAST(fluid_sfloader_t, self)->load = FSynth_loadSfont;
598 self->Settings = NULL;
599 self->Synth = NULL;
600 self->FontIDs = NULL;
601 self->NumFontIDs = 0;
602 self->ForceGM2BankSelect = AL_FALSE;
603 self->GainScale = 0.2f;
606 static void FSynth_Destruct(FSynth *self)
608 ALsizei i;
610 for(i = 0;i < self->NumFontIDs;i++)
611 fluid_synth_sfunload(self->Synth, self->FontIDs[i], 0);
612 free(self->FontIDs);
613 self->FontIDs = NULL;
614 self->NumFontIDs = 0;
616 if(self->Synth != NULL)
617 delete_fluid_synth(self->Synth);
618 self->Synth = NULL;
620 if(self->Settings != NULL)
621 delete_fluid_settings(self->Settings);
622 self->Settings = NULL;
624 MidiSynth_Destruct(STATIC_CAST(MidiSynth, self));
627 static ALboolean FSynth_init(FSynth *self, ALCdevice *device)
629 ALfloat vol;
631 if(ConfigValueFloat("midi", "volume", &vol))
633 if(!(vol <= 0.0f))
635 ERR("MIDI volume %f clamped to 0\n", vol);
636 vol = 0.0f;
638 self->GainScale = powf(10.0f, vol / 20.0f);
641 self->Settings = new_fluid_settings();
642 if(!self->Settings)
644 ERR("Failed to create FluidSettings\n");
645 return AL_FALSE;
648 fluid_settings_setint(self->Settings, "synth.polyphony", 256);
649 fluid_settings_setnum(self->Settings, "synth.gain", self->GainScale);
650 fluid_settings_setnum(self->Settings, "synth.sample-rate", device->Frequency);
652 self->Synth = new_fluid_synth(self->Settings);
653 if(!self->Synth)
655 ERR("Failed to create FluidSynth\n");
656 return AL_FALSE;
659 fluid_synth_add_sfloader(self->Synth, STATIC_CAST(fluid_sfloader_t, self));
661 return AL_TRUE;
665 static fluid_sfont_t *FSynth_loadSfont(fluid_sfloader_t *loader, const char *filename)
667 FSynth *self = STATIC_UPCAST(FSynth, fluid_sfloader_t, loader);
668 FSfont *sfont;
669 int idx;
671 if(!filename || sscanf(filename, "_al_internal %d", &idx) != 1)
672 return NULL;
673 if(idx < 0 || idx >= STATIC_CAST(MidiSynth, self)->NumSoundfonts)
675 ERR("Received invalid soundfont index %d (max: %d)\n", idx, STATIC_CAST(MidiSynth, self)->NumSoundfonts);
676 return NULL;
679 sfont = calloc(1, sizeof(sfont[0]));
680 if(!sfont) return NULL;
682 FSfont_Construct(sfont, STATIC_CAST(MidiSynth, self)->Soundfonts[idx]);
683 return STATIC_CAST(fluid_sfont_t, sfont);
686 static ALenum FSynth_selectSoundfonts(FSynth *self, ALCcontext *context, ALsizei count, const ALuint *ids)
688 int *fontid;
689 ALenum ret;
690 ALsizei i;
692 ret = MidiSynth_selectSoundfonts(STATIC_CAST(MidiSynth, self), context, count, ids);
693 if(ret != AL_NO_ERROR) return ret;
695 ALCdevice_Lock(context->Device);
696 for(i = 0;i < 16;i++)
697 fluid_synth_all_sounds_off(self->Synth, i);
698 ALCdevice_Unlock(context->Device);
700 fontid = malloc(count * sizeof(fontid[0]));
701 if(fontid)
703 for(i = 0;i < STATIC_CAST(MidiSynth, self)->NumSoundfonts;i++)
705 char name[16];
706 snprintf(name, sizeof(name), "_al_internal %d", i);
708 fontid[i] = fluid_synth_sfload(self->Synth, name, 0);
709 if(fontid[i] == FLUID_FAILED)
710 ERR("Failed to load selected soundfont %d\n", i);
713 fontid = ExchangePtr((XchgPtr*)&self->FontIDs, fontid);
714 count = ExchangeInt(&self->NumFontIDs, count);
716 else
718 ERR("Failed to allocate space for %d font IDs!\n", count);
719 fontid = ExchangePtr((XchgPtr*)&self->FontIDs, NULL);
720 count = ExchangeInt(&self->NumFontIDs, 0);
723 for(i = 0;i < count;i++)
724 fluid_synth_sfunload(self->Synth, fontid[i], 0);
725 free(fontid);
727 return ret;
731 static void FSynth_setGain(FSynth *self, ALfloat gain)
733 fluid_settings_setnum(self->Settings, "synth.gain", self->GainScale * gain);
734 fluid_synth_set_gain(self->Synth, self->GainScale * gain);
735 MidiSynth_setGain(STATIC_CAST(MidiSynth, self), gain);
739 static void FSynth_stop(FSynth *self)
741 MidiSynth *synth = STATIC_CAST(MidiSynth, self);
742 ALuint64 curtime;
743 ALsizei chan;
745 /* Make sure all pending events are processed. */
746 curtime = MidiSynth_getTime(synth);
747 FSynth_processQueue(self, curtime);
749 /* All notes off */
750 for(chan = 0;chan < 16;chan++)
751 fluid_synth_cc(self->Synth, chan, CTRL_ALLNOTESOFF, 0);
753 MidiSynth_stop(STATIC_CAST(MidiSynth, self));
756 static void FSynth_reset(FSynth *self)
758 /* Reset to power-up status. */
759 fluid_synth_system_reset(self->Synth);
761 MidiSynth_reset(STATIC_CAST(MidiSynth, self));
765 static void FSynth_update(FSynth *self, ALCdevice *device)
767 fluid_settings_setnum(self->Settings, "synth.sample-rate", device->Frequency);
768 fluid_synth_set_sample_rate(self->Synth, device->Frequency);
769 MidiSynth_update(STATIC_CAST(MidiSynth, self), device);
773 static void FSynth_processQueue(FSynth *self, ALuint64 time)
775 EvtQueue *queue = &STATIC_CAST(MidiSynth, self)->EventQueue;
777 while(queue->pos < queue->size && queue->events[queue->pos].time <= time)
779 const MidiEvent *evt = &queue->events[queue->pos];
781 if(evt->event == SYSEX_EVENT)
783 static const ALbyte gm2_on[] = { 0x7E, 0x7F, 0x09, 0x03 };
784 static const ALbyte gm2_off[] = { 0x7E, 0x7F, 0x09, 0x02 };
785 int handled = 0;
787 fluid_synth_sysex(self->Synth, evt->param.sysex.data, evt->param.sysex.size, NULL, NULL, &handled, 0);
788 if(!handled && evt->param.sysex.size >= (ALsizei)sizeof(gm2_on))
790 if(memcmp(evt->param.sysex.data, gm2_on, sizeof(gm2_on)) == 0)
791 self->ForceGM2BankSelect = AL_TRUE;
792 else if(memcmp(evt->param.sysex.data, gm2_off, sizeof(gm2_off)) == 0)
793 self->ForceGM2BankSelect = AL_FALSE;
796 else switch((evt->event&0xF0))
798 case AL_NOTEOFF_SOFT:
799 fluid_synth_noteoff(self->Synth, (evt->event&0x0F), evt->param.val[0]);
800 break;
801 case AL_NOTEON_SOFT:
802 fluid_synth_noteon(self->Synth, (evt->event&0x0F), evt->param.val[0], evt->param.val[1]);
803 break;
804 case AL_KEYPRESSURE_SOFT:
805 break;
807 case AL_CONTROLLERCHANGE_SOFT:
808 if(self->ForceGM2BankSelect)
810 int chan = (evt->event&0x0F);
811 if(evt->param.val[0] == CTRL_BANKSELECT_MSB)
813 if(evt->param.val[1] == 120 && (chan == 9 || chan == 10))
814 fluid_synth_set_channel_type(self->Synth, chan, CHANNEL_TYPE_DRUM);
815 else if(evt->param.val[1] == 121)
816 fluid_synth_set_channel_type(self->Synth, chan, CHANNEL_TYPE_MELODIC);
817 break;
819 if(evt->param.val[0] == CTRL_BANKSELECT_LSB)
821 fluid_synth_bank_select(self->Synth, chan, evt->param.val[1]);
822 break;
825 fluid_synth_cc(self->Synth, (evt->event&0x0F), evt->param.val[0], evt->param.val[1]);
826 break;
827 case AL_PROGRAMCHANGE_SOFT:
828 fluid_synth_program_change(self->Synth, (evt->event&0x0F), evt->param.val[0]);
829 break;
831 case AL_CHANNELPRESSURE_SOFT:
832 fluid_synth_channel_pressure(self->Synth, (evt->event&0x0F), evt->param.val[0]);
833 break;
835 case AL_PITCHBEND_SOFT:
836 fluid_synth_pitch_bend(self->Synth, (evt->event&0x0F), (evt->param.val[0]&0x7F) |
837 ((evt->param.val[1]&0x7F)<<7));
838 break;
841 queue->pos++;
845 static void FSynth_process(FSynth *self, ALuint SamplesToDo, ALfloat (*restrict DryBuffer)[BUFFERSIZE])
847 MidiSynth *synth = STATIC_CAST(MidiSynth, self);
848 ALenum state = synth->State;
849 ALuint64 curtime;
850 ALuint total = 0;
852 if(state == AL_INITIAL)
853 return;
854 if(state != AL_PLAYING)
856 fluid_synth_write_float(self->Synth, SamplesToDo, DryBuffer[FrontLeft], 0, 1,
857 DryBuffer[FrontRight], 0, 1);
858 return;
861 curtime = MidiSynth_getTime(synth);
862 while(total < SamplesToDo)
864 ALuint64 time, diff;
865 ALint tonext;
867 time = MidiSynth_getNextEvtTime(synth);
868 diff = maxu64(time, curtime) - curtime;
869 if(diff >= MIDI_CLOCK_RES || time == UINT64_MAX)
871 /* If there's no pending event, or if it's more than 1 second
872 * away, do as many samples as we can. */
873 tonext = INT_MAX;
875 else
877 /* Figure out how many samples until the next event. */
878 tonext = (ALint)((diff*synth->SampleRate + (MIDI_CLOCK_RES-1)) / MIDI_CLOCK_RES);
879 tonext -= total;
882 if(tonext > 0)
884 ALuint todo = minu(tonext, SamplesToDo-total);
885 fluid_synth_write_float(self->Synth, todo, DryBuffer[FrontLeft], total, 1,
886 DryBuffer[FrontRight], total, 1);
887 total += todo;
888 tonext -= todo;
890 if(total < SamplesToDo && tonext <= 0)
891 FSynth_processQueue(self, time);
894 synth->SamplesDone += SamplesToDo;
895 synth->ClockBase += (synth->SamplesDone/synth->SampleRate) * MIDI_CLOCK_RES;
896 synth->SamplesDone %= synth->SampleRate;
900 MidiSynth *FSynth_create(ALCdevice *device)
902 FSynth *synth;
904 if(!LoadFSynth())
905 return NULL;
907 synth = FSynth_New(sizeof(*synth));
908 if(!synth)
910 ERR("Failed to allocate FSynth\n");
911 return NULL;
913 memset(synth, 0, sizeof(*synth));
914 FSynth_Construct(synth, device);
916 if(FSynth_init(synth, device) == AL_FALSE)
918 DELETE_OBJ(STATIC_CAST(MidiSynth, synth));
919 return NULL;
922 return STATIC_CAST(MidiSynth, synth);
925 #else
927 MidiSynth *FSynth_create(ALCdevice* UNUSED(device))
929 return NULL;
932 #endif