Use a proper struct for envelope properties
[openal-soft.git] / Alc / midi / fluidsynth.c
blobbe3c0da7ab583b24d635a8b2f95d5b6f224b4171
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 "evtqueue.h"
14 #include "rwlock.h"
15 #include "alu.h"
17 #ifdef HAVE_FLUIDSYNTH
19 #include <fluidsynth.h>
22 /* MIDI events */
23 #define SYSEX_EVENT (0xF0)
25 /* MIDI controllers */
26 #define CTRL_BANKSELECT_MSB (0)
27 #define CTRL_BANKSELECT_LSB (32)
28 #define CTRL_ALLNOTESOFF (123)
31 static int getGenInput(ALenum input)
33 switch(input)
35 case AL_ONE_SOFT: return FLUID_MOD_NONE;
36 case AL_NOTEON_VELOCITY_SOFT: return FLUID_MOD_VELOCITY;
37 case AL_NOTEON_KEY_SOFT: return FLUID_MOD_KEY;
38 case AL_AFTERTOUCH_SOFT: return FLUID_MOD_KEYPRESSURE;
39 case AL_CHANNELPRESSURE_SOFT: return FLUID_MOD_CHANNELPRESSURE;
40 case AL_PITCHBEND_SOFT: return FLUID_MOD_PITCHWHEEL;
41 case AL_PITCHBEND_SENSITIVITY_SOFT: return FLUID_MOD_PITCHWHEELSENS;
43 return input&0x7F;
46 static int getGenFlags(ALenum input, ALenum type, ALenum form)
48 int ret = 0;
50 switch(type)
52 case AL_UNORM_SOFT: ret |= FLUID_MOD_UNIPOLAR | FLUID_MOD_POSITIVE; break;
53 case AL_UNORM_REV_SOFT: ret |= FLUID_MOD_UNIPOLAR | FLUID_MOD_NEGATIVE; break;
54 case AL_SNORM_SOFT: ret |= FLUID_MOD_BIPOLAR | FLUID_MOD_POSITIVE; break;
55 case AL_SNORM_REV_SOFT: ret |= FLUID_MOD_BIPOLAR | FLUID_MOD_NEGATIVE; break;
57 switch(form)
59 case AL_LINEAR_SOFT: ret |= FLUID_MOD_LINEAR; break;
60 case AL_CONCAVE_SOFT: ret |= FLUID_MOD_CONCAVE; break;
61 case AL_CONVEX_SOFT: ret |= FLUID_MOD_CONVEX; break;
62 case AL_SWITCH_SOFT: ret |= FLUID_MOD_SWITCH; break;
64 /* Source input values less than 128 correspond to a MIDI continuous
65 * controller. Otherwise, it's a general controller. */
66 if(input < 128) ret |= FLUID_MOD_CC;
67 else ret |= FLUID_MOD_GC;
69 return ret;
72 static enum fluid_gen_type getSf2Gen(ALenum gen)
74 switch(gen)
76 case AL_MOD_LFO_TO_PITCH_SOFT: return GEN_MODLFOTOPITCH;
77 case AL_VIBRATO_LFO_TO_PITCH_SOFT: return GEN_VIBLFOTOPITCH;
78 case AL_MOD_ENV_TO_PITCH_SOFT: return GEN_MODENVTOPITCH;
79 case AL_FILTER_CUTOFF_SOFT: return GEN_FILTERFC;
80 case AL_FILTER_RESONANCE_SOFT: return GEN_FILTERQ;
81 case AL_MOD_LFO_TO_FILTER_CUTOFF_SOFT: return GEN_MODLFOTOFILTERFC;
82 case AL_MOD_ENV_TO_FILTER_CUTOFF_SOFT: return GEN_MODENVTOFILTERFC;
83 case AL_MOD_LFO_TO_VOLUME_SOFT: return GEN_MODLFOTOVOL;
84 case AL_CHORUS_SEND_SOFT: return GEN_CHORUSSEND;
85 case AL_REVERB_SEND_SOFT: return GEN_REVERBSEND;
86 case AL_PAN_SOFT: return GEN_PAN;
87 case AL_MOD_LFO_DELAY_SOFT: return GEN_MODLFODELAY;
88 case AL_MOD_LFO_FREQUENCY_SOFT: return GEN_MODLFOFREQ;
89 case AL_VIBRATO_LFO_DELAY_SOFT: return GEN_VIBLFODELAY;
90 case AL_VIBRATO_LFO_FREQUENCY_SOFT: return GEN_VIBLFOFREQ;
91 case AL_MOD_ENV_DELAYTIME_SOFT: return GEN_MODENVDELAY;
92 case AL_MOD_ENV_ATTACKTIME_SOFT: return GEN_MODENVATTACK;
93 case AL_MOD_ENV_HOLDTIME_SOFT: return GEN_MODENVHOLD;
94 case AL_MOD_ENV_DECAYTIME_SOFT: return GEN_MODENVDECAY;
95 case AL_MOD_ENV_SUSTAINVOLUME_SOFT: return GEN_MODENVSUSTAIN;
96 case AL_MOD_ENV_RELEASETIME_SOFT: return GEN_MODENVRELEASE;
97 case AL_MOD_ENV_KEY_TO_HOLDTIME_SOFT: return GEN_KEYTOMODENVHOLD;
98 case AL_MOD_ENV_KEY_TO_DECAYTIME_SOFT: return GEN_KEYTOMODENVDECAY;
99 case AL_VOLUME_ENV_DELAYTIME_SOFT: return GEN_VOLENVDELAY;
100 case AL_VOLUME_ENV_ATTACKTIME_SOFT: return GEN_VOLENVATTACK;
101 case AL_VOLUME_ENV_HOLDTIME_SOFT: return GEN_VOLENVHOLD;
102 case AL_VOLUME_ENV_DECAYTIME_SOFT: return GEN_VOLENVDECAY;
103 case AL_VOLUME_ENV_SUSTAINVOLUME_SOFT: return GEN_VOLENVSUSTAIN;
104 case AL_VOLUME_ENV_RELEASETIME_SOFT: return GEN_VOLENVRELEASE;
105 case AL_VOLUME_ENV_KEY_TO_HOLDTIME_SOFT: return GEN_KEYTOVOLENVHOLD;
106 case AL_VOLUME_ENV_KEY_TO_DECAYTIME_SOFT: return GEN_KEYTOVOLENVDECAY;
107 case AL_ATTENUATION_SOFT: return GEN_ATTENUATION;
108 case AL_TUNING_COARSE_SOFT: return GEN_COARSETUNE;
109 case AL_TUNING_FINE_SOFT: return GEN_FINETUNE;
110 case AL_TUNING_SCALE_SOFT: return GEN_SCALETUNE;
112 ERR("Unhandled generator: 0x%04x\n", gen);
113 return 0;
116 static int getSf2LoopMode(ALenum mode)
118 switch(mode)
120 case AL_NONE: return 0;
121 case AL_LOOP_CONTINUOUS_SOFT: return 1;
122 case AL_LOOP_UNTIL_RELEASE_SOFT: return 3;
124 return 0;
127 static int getSampleType(ALenum type)
129 switch(type)
131 case AL_MONO_SOFT: return FLUID_SAMPLETYPE_MONO;
132 case AL_RIGHT_SOFT: return FLUID_SAMPLETYPE_RIGHT;
133 case AL_LEFT_SOFT: return FLUID_SAMPLETYPE_LEFT;
135 return FLUID_SAMPLETYPE_MONO;
138 typedef struct FSample {
139 DERIVE_FROM_TYPE(fluid_sample_t);
141 ALfontsound *Sound;
143 fluid_mod_t *Mods;
144 ALsizei NumMods;
145 } FSample;
147 static void FSample_Construct(FSample *self, ALfontsound *sound, ALsoundfont *sfont)
149 fluid_sample_t *sample = STATIC_CAST(fluid_sample_t, self);
150 memset(sample->name, 0, sizeof(sample->name));
151 sample->start = sound->Start;
152 sample->end = sound->End;
153 sample->loopstart = sound->LoopStart;
154 sample->loopend = sound->LoopEnd;
155 sample->samplerate = sound->SampleRate;
156 sample->origpitch = sound->PitchKey;
157 sample->pitchadj = sound->PitchCorrection;
158 sample->sampletype = getSampleType(sound->SampleType);
159 sample->valid = 1;
160 sample->data = sfont->Samples;
162 sample->amplitude_that_reaches_noise_floor_is_valid = 0;
163 sample->amplitude_that_reaches_noise_floor = 0.0;
165 sample->refcount = 0;
167 sample->notify = NULL;
169 sample->userdata = self;
171 self->Sound = sound;
173 self->NumMods = 0;
174 self->Mods = calloc(sound->ModulatorMap.size, sizeof(self->Mods[0]));
175 if(self->Mods)
177 ALsizei i;
179 self->NumMods = sound->ModulatorMap.size;
180 for(i = 0;i < self->NumMods;i++)
182 ALsfmodulator *mod = sound->ModulatorMap.array[i].value;
183 fluid_mod_set_source1(&self->Mods[i], getGenInput(mod->Source[0].Input),
184 getGenFlags(mod->Source[0].Input, mod->Source[0].Type,
185 mod->Source[0].Form));
186 fluid_mod_set_source2(&self->Mods[i], getGenInput(mod->Source[1].Input),
187 getGenFlags(mod->Source[1].Input, mod->Source[1].Type,
188 mod->Source[1].Form));
189 fluid_mod_set_amount(&self->Mods[i], mod->Amount);
190 fluid_mod_set_dest(&self->Mods[i], getSf2Gen(mod->Dest));
191 self->Mods[i].next = NULL;
196 static void FSample_Destruct(FSample *self)
198 free(self->Mods);
199 self->Mods = NULL;
200 self->NumMods = 0;
204 typedef struct FPreset {
205 DERIVE_FROM_TYPE(fluid_preset_t);
207 char Name[16];
209 int Preset;
210 int Bank;
212 FSample *Samples;
213 ALsizei NumSamples;
214 } FPreset;
216 static char* FPreset_getName(fluid_preset_t *preset);
217 static int FPreset_getPreset(fluid_preset_t *preset);
218 static int FPreset_getBank(fluid_preset_t *preset);
219 static int FPreset_noteOn(fluid_preset_t *preset, fluid_synth_t *synth, int channel, int key, int velocity);
221 static void FPreset_Construct(FPreset *self, ALsfpreset *preset, fluid_sfont_t *parent, ALsoundfont *sfont)
223 STATIC_CAST(fluid_preset_t, self)->data = self;
224 STATIC_CAST(fluid_preset_t, self)->sfont = parent;
225 STATIC_CAST(fluid_preset_t, self)->free = NULL;
226 STATIC_CAST(fluid_preset_t, self)->get_name = FPreset_getName;
227 STATIC_CAST(fluid_preset_t, self)->get_banknum = FPreset_getBank;
228 STATIC_CAST(fluid_preset_t, self)->get_num = FPreset_getPreset;
229 STATIC_CAST(fluid_preset_t, self)->noteon = FPreset_noteOn;
230 STATIC_CAST(fluid_preset_t, self)->notify = NULL;
232 memset(self->Name, 0, sizeof(self->Name));
233 self->Preset = preset->Preset;
234 self->Bank = preset->Bank;
236 self->NumSamples = 0;
237 self->Samples = calloc(1, preset->NumSounds * sizeof(self->Samples[0]));
238 if(self->Samples)
240 ALsizei i;
241 self->NumSamples = preset->NumSounds;
242 for(i = 0;i < self->NumSamples;i++)
243 FSample_Construct(&self->Samples[i], preset->Sounds[i], sfont);
247 static void FPreset_Destruct(FPreset *self)
249 ALsizei i;
251 for(i = 0;i < self->NumSamples;i++)
252 FSample_Destruct(&self->Samples[i]);
253 free(self->Samples);
254 self->Samples = NULL;
255 self->NumSamples = 0;
258 static ALboolean FPreset_canDelete(FPreset *self)
260 ALsizei i;
262 for(i = 0;i < self->NumSamples;i++)
264 if(fluid_sample_refcount(STATIC_CAST(fluid_sample_t, &self->Samples[i])) != 0)
265 return AL_FALSE;
267 return AL_TRUE;
270 static char* FPreset_getName(fluid_preset_t *preset)
272 return ((FPreset*)preset->data)->Name;
275 static int FPreset_getPreset(fluid_preset_t *preset)
277 return ((FPreset*)preset->data)->Preset;
280 static int FPreset_getBank(fluid_preset_t *preset)
282 return ((FPreset*)preset->data)->Bank;
285 static int FPreset_noteOn(fluid_preset_t *preset, fluid_synth_t *synth, int channel, int key, int vel)
287 FPreset *self = ((FPreset*)preset->data);
288 ALsizei i;
290 for(i = 0;i < self->NumSamples;i++)
292 FSample *sample = &self->Samples[i];
293 ALfontsound *sound = sample->Sound;
294 fluid_voice_t *voice;
295 ALsizei m;
297 if(!(key >= sound->MinKey && key <= sound->MaxKey && vel >= sound->MinVelocity && vel <= sound->MaxVelocity))
298 continue;
300 voice = fluid_synth_alloc_voice(synth, STATIC_CAST(fluid_sample_t, sample), channel, key, vel);
301 if(voice == NULL)
302 return FLUID_FAILED;
304 fluid_voice_gen_set(voice, GEN_MODLFOTOPITCH, sound->ModLfoToPitch);
305 fluid_voice_gen_set(voice, GEN_VIBLFOTOPITCH, sound->VibratoLfoToPitch);
306 fluid_voice_gen_set(voice, GEN_MODENVTOPITCH, sound->ModEnvToPitch);
307 fluid_voice_gen_set(voice, GEN_FILTERFC, sound->FilterCutoff);
308 fluid_voice_gen_set(voice, GEN_FILTERQ, sound->FilterQ);
309 fluid_voice_gen_set(voice, GEN_MODLFOTOFILTERFC, sound->ModLfoToFilterCutoff);
310 fluid_voice_gen_set(voice, GEN_MODENVTOFILTERFC, sound->ModEnvToFilterCutoff);
311 fluid_voice_gen_set(voice, GEN_MODLFOTOVOL, sound->ModLfoToVolume);
312 fluid_voice_gen_set(voice, GEN_CHORUSSEND, sound->ChorusSend);
313 fluid_voice_gen_set(voice, GEN_REVERBSEND, sound->ReverbSend);
314 fluid_voice_gen_set(voice, GEN_PAN, sound->Pan);
315 fluid_voice_gen_set(voice, GEN_MODLFODELAY, sound->ModLfo.Delay);
316 fluid_voice_gen_set(voice, GEN_MODLFOFREQ, sound->ModLfo.Frequency);
317 fluid_voice_gen_set(voice, GEN_VIBLFODELAY, sound->VibratoLfo.Delay);
318 fluid_voice_gen_set(voice, GEN_VIBLFOFREQ, sound->VibratoLfo.Frequency);
319 fluid_voice_gen_set(voice, GEN_MODENVDELAY, sound->ModEnv.DelayTime);
320 fluid_voice_gen_set(voice, GEN_MODENVATTACK, sound->ModEnv.AttackTime);
321 fluid_voice_gen_set(voice, GEN_MODENVHOLD, sound->ModEnv.HoldTime);
322 fluid_voice_gen_set(voice, GEN_MODENVDECAY, sound->ModEnv.DecayTime);
323 fluid_voice_gen_set(voice, GEN_MODENVSUSTAIN, sound->ModEnv.SustainAttn);
324 fluid_voice_gen_set(voice, GEN_MODENVRELEASE, sound->ModEnv.ReleaseTime);
325 fluid_voice_gen_set(voice, GEN_KEYTOMODENVHOLD, sound->ModEnv.KeyToHoldTime);
326 fluid_voice_gen_set(voice, GEN_KEYTOMODENVDECAY, sound->ModEnv.KeyToDecayTime);
327 fluid_voice_gen_set(voice, GEN_VOLENVDELAY, sound->VolEnv.DelayTime);
328 fluid_voice_gen_set(voice, GEN_VOLENVATTACK, sound->VolEnv.AttackTime);
329 fluid_voice_gen_set(voice, GEN_VOLENVHOLD, sound->VolEnv.HoldTime);
330 fluid_voice_gen_set(voice, GEN_VOLENVDECAY, sound->VolEnv.DecayTime);
331 fluid_voice_gen_set(voice, GEN_VOLENVSUSTAIN, sound->VolEnv.SustainAttn);
332 fluid_voice_gen_set(voice, GEN_VOLENVRELEASE, sound->VolEnv.ReleaseTime);
333 fluid_voice_gen_set(voice, GEN_KEYTOVOLENVHOLD, sound->VolEnv.KeyToHoldTime);
334 fluid_voice_gen_set(voice, GEN_KEYTOVOLENVDECAY, sound->VolEnv.KeyToDecayTime);
335 fluid_voice_gen_set(voice, GEN_ATTENUATION, sound->Attenuation);
336 fluid_voice_gen_set(voice, GEN_COARSETUNE, sound->CoarseTuning);
337 fluid_voice_gen_set(voice, GEN_FINETUNE, sound->FineTuning);
338 fluid_voice_gen_set(voice, GEN_SAMPLEMODE, getSf2LoopMode(sound->LoopMode));
339 fluid_voice_gen_set(voice, GEN_SCALETUNE, sound->TuningScale);
340 fluid_voice_gen_set(voice, GEN_EXCLUSIVECLASS, sound->ExclusiveClass);
341 for(m = 0;m < sample->NumMods;m++)
342 fluid_voice_add_mod(voice, &sample->Mods[m], FLUID_VOICE_OVERWRITE);
344 fluid_synth_start_voice(synth, voice);
347 return FLUID_OK;
351 typedef struct FSfont {
352 DERIVE_FROM_TYPE(fluid_sfont_t);
354 char Name[16];
356 FPreset *Presets;
357 ALsizei NumPresets;
359 ALsizei CurrentPos;
360 } FSfont;
362 static int FSfont_free(fluid_sfont_t *sfont);
363 static char* FSfont_getName(fluid_sfont_t *sfont);
364 static fluid_preset_t* FSfont_getPreset(fluid_sfont_t *sfont, unsigned int bank, unsigned int prenum);
365 static void FSfont_iterStart(fluid_sfont_t *sfont);
366 static int FSfont_iterNext(fluid_sfont_t *sfont, fluid_preset_t *preset);
368 static void FSfont_Construct(FSfont *self, ALsoundfont *sfont)
370 STATIC_CAST(fluid_sfont_t, self)->data = self;
371 STATIC_CAST(fluid_sfont_t, self)->id = FLUID_FAILED;
372 STATIC_CAST(fluid_sfont_t, self)->free = FSfont_free;
373 STATIC_CAST(fluid_sfont_t, self)->get_name = FSfont_getName;
374 STATIC_CAST(fluid_sfont_t, self)->get_preset = FSfont_getPreset;
375 STATIC_CAST(fluid_sfont_t, self)->iteration_start = FSfont_iterStart;
376 STATIC_CAST(fluid_sfont_t, self)->iteration_next = FSfont_iterNext;
378 memset(self->Name, 0, sizeof(self->Name));
379 self->CurrentPos = 0;
380 self->NumPresets = 0;
381 self->Presets = calloc(1, sfont->NumPresets * sizeof(self->Presets[0]));
382 if(self->Presets)
384 ALsizei i;
385 self->NumPresets = sfont->NumPresets;
386 for(i = 0;i < self->NumPresets;i++)
387 FPreset_Construct(&self->Presets[i], sfont->Presets[i], STATIC_CAST(fluid_sfont_t, self), sfont);
391 static void FSfont_Destruct(FSfont *self)
393 ALsizei i;
395 for(i = 0;i < self->NumPresets;i++)
396 FPreset_Destruct(&self->Presets[i]);
397 free(self->Presets);
398 self->Presets = NULL;
399 self->NumPresets = 0;
400 self->CurrentPos = 0;
403 static int FSfont_free(fluid_sfont_t *sfont)
405 FSfont *self = STATIC_UPCAST(FSfont, fluid_sfont_t, sfont);
406 ALsizei i;
408 for(i = 0;i < self->NumPresets;i++)
410 if(!FPreset_canDelete(&self->Presets[i]))
411 return 1;
414 FSfont_Destruct(self);
415 free(self);
416 return 0;
419 static char* FSfont_getName(fluid_sfont_t *sfont)
421 return STATIC_UPCAST(FSfont, fluid_sfont_t, sfont)->Name;
424 static fluid_preset_t *FSfont_getPreset(fluid_sfont_t *sfont, unsigned int bank, unsigned int prenum)
426 FSfont *self = STATIC_UPCAST(FSfont, fluid_sfont_t, sfont);
427 ALsizei i;
429 for(i = 0;i < self->NumPresets;i++)
431 FPreset *preset = &self->Presets[i];
432 if(preset->Bank == (int)bank && preset->Preset == (int)prenum)
433 return STATIC_CAST(fluid_preset_t, preset);
436 return NULL;
439 static void FSfont_iterStart(fluid_sfont_t *sfont)
441 STATIC_UPCAST(FSfont, fluid_sfont_t, sfont)->CurrentPos = 0;
444 static int FSfont_iterNext(fluid_sfont_t *sfont, fluid_preset_t *preset)
446 FSfont *self = STATIC_UPCAST(FSfont, fluid_sfont_t, sfont);
447 if(self->CurrentPos >= self->NumPresets)
448 return 0;
449 *preset = *STATIC_CAST(fluid_preset_t, &self->Presets[self->CurrentPos++]);
450 preset->free = NULL;
451 return 1;
455 typedef struct FSynth {
456 DERIVE_FROM_TYPE(MidiSynth);
457 DERIVE_FROM_TYPE(fluid_sfloader_t);
459 fluid_settings_t *Settings;
460 fluid_synth_t *Synth;
461 int *FontIDs;
462 ALsizei NumFontIDs;
464 ALboolean ForceGM2BankSelect;
465 } FSynth;
467 static void FSynth_Construct(FSynth *self, ALCdevice *device);
468 static void FSynth_Destruct(FSynth *self);
469 static ALboolean FSynth_init(FSynth *self, ALCdevice *device);
470 static ALenum FSynth_selectSoundfonts(FSynth *self, ALCcontext *context, ALsizei count, const ALuint *ids);
471 static void FSynth_setGain(FSynth *self, ALfloat gain);
472 static void FSynth_setState(FSynth *self, ALenum state);
473 static void FSynth_stop(FSynth *self);
474 static void FSynth_reset(FSynth *self);
475 static void FSynth_update(FSynth *self, ALCdevice *device);
476 static void FSynth_processQueue(FSynth *self, ALuint64 time);
477 static void FSynth_process(FSynth *self, ALuint SamplesToDo, ALfloat (*restrict DryBuffer)[BUFFERSIZE]);
478 static void FSynth_Delete(FSynth *self);
479 DEFINE_MIDISYNTH_VTABLE(FSynth);
481 static fluid_sfont_t *FSynth_loadSfont(fluid_sfloader_t *loader, const char *filename);
484 static void FSynth_Construct(FSynth *self, ALCdevice *device)
486 MidiSynth_Construct(STATIC_CAST(MidiSynth, self), device);
487 SET_VTABLE2(FSynth, MidiSynth, self);
489 STATIC_CAST(fluid_sfloader_t, self)->data = self;
490 STATIC_CAST(fluid_sfloader_t, self)->free = NULL;
491 STATIC_CAST(fluid_sfloader_t, self)->load = FSynth_loadSfont;
493 self->Settings = NULL;
494 self->Synth = NULL;
495 self->FontIDs = NULL;
496 self->NumFontIDs = 0;
497 self->ForceGM2BankSelect = AL_FALSE;
500 static void FSynth_Destruct(FSynth *self)
502 ALsizei i;
504 for(i = 0;i < self->NumFontIDs;i++)
505 fluid_synth_sfunload(self->Synth, self->FontIDs[i], 0);
506 free(self->FontIDs);
507 self->FontIDs = NULL;
508 self->NumFontIDs = 0;
510 if(self->Synth != NULL)
511 delete_fluid_synth(self->Synth);
512 self->Synth = NULL;
514 if(self->Settings != NULL)
515 delete_fluid_settings(self->Settings);
516 self->Settings = NULL;
518 MidiSynth_Destruct(STATIC_CAST(MidiSynth, self));
521 static ALboolean FSynth_init(FSynth *self, ALCdevice *device)
523 self->Settings = new_fluid_settings();
524 if(!self->Settings)
526 ERR("Failed to create FluidSettings\n");
527 return AL_FALSE;
530 fluid_settings_setint(self->Settings, "synth.polyphony", 256);
531 fluid_settings_setnum(self->Settings, "synth.sample-rate", device->Frequency);
533 self->Synth = new_fluid_synth(self->Settings);
534 if(!self->Synth)
536 ERR("Failed to create FluidSynth\n");
537 return AL_FALSE;
540 fluid_synth_add_sfloader(self->Synth, STATIC_CAST(fluid_sfloader_t, self));
542 return AL_TRUE;
546 static fluid_sfont_t *FSynth_loadSfont(fluid_sfloader_t *loader, const char *filename)
548 FSynth *self = STATIC_UPCAST(FSynth, fluid_sfloader_t, loader);
549 FSfont *sfont;
550 int idx;
552 if(!filename || sscanf(filename, "_al_internal %d", &idx) != 1)
553 return NULL;
554 if(idx < 0 || idx >= STATIC_CAST(MidiSynth, self)->NumSoundfonts)
556 ERR("Received invalid soundfont index %d (max: %d)\n", idx, STATIC_CAST(MidiSynth, self)->NumSoundfonts);
557 return NULL;
560 sfont = calloc(1, sizeof(sfont[0]));
561 if(!sfont) return NULL;
563 FSfont_Construct(sfont, STATIC_CAST(MidiSynth, self)->Soundfonts[idx]);
564 return STATIC_CAST(fluid_sfont_t, sfont);
567 static ALenum FSynth_selectSoundfonts(FSynth *self, ALCcontext *context, ALsizei count, const ALuint *ids)
569 int *fontid;
570 ALenum ret;
571 ALsizei i;
573 ret = MidiSynth_selectSoundfonts(STATIC_CAST(MidiSynth, self), context, count, ids);
574 if(ret != AL_NO_ERROR) return ret;
576 ALCdevice_Lock(context->Device);
577 for(i = 0;i < 16;i++)
578 fluid_synth_all_sounds_off(self->Synth, i);
579 ALCdevice_Unlock(context->Device);
581 fontid = malloc(count * sizeof(fontid[0]));
582 if(fontid)
584 for(i = 0;i < STATIC_CAST(MidiSynth, self)->NumSoundfonts;i++)
586 char name[16];
587 snprintf(name, sizeof(name), "_al_internal %d", i);
589 fontid[i] = fluid_synth_sfload(self->Synth, name, 0);
590 if(fontid[i] == FLUID_FAILED)
591 ERR("Failed to load selected soundfont %d\n", i);
594 fontid = ExchangePtr((XchgPtr*)&self->FontIDs, fontid);
595 count = ExchangeInt(&self->NumFontIDs, count);
597 else
599 ERR("Failed to allocate space for %d font IDs!\n", count);
600 fontid = ExchangePtr((XchgPtr*)&self->FontIDs, NULL);
601 count = ExchangeInt(&self->NumFontIDs, 0);
604 for(i = 0;i < count;i++)
605 fluid_synth_sfunload(self->Synth, fontid[i], 0);
606 free(fontid);
608 return ret;
612 static void FSynth_setGain(FSynth *self, ALfloat gain)
614 /* Scale gain by an additional 0.2 (-14dB), to help keep the mix from clipping. */
615 fluid_settings_setnum(self->Settings, "synth.gain", 0.2 * gain);
616 fluid_synth_set_gain(self->Synth, 0.2f * gain);
617 MidiSynth_setGain(STATIC_CAST(MidiSynth, self), gain);
621 static void FSynth_setState(FSynth *self, ALenum state)
623 MidiSynth_setState(STATIC_CAST(MidiSynth, self), state);
626 static void FSynth_stop(FSynth *self)
628 MidiSynth *synth = STATIC_CAST(MidiSynth, self);
629 ALsizei chan;
631 /* Make sure all pending events are processed. */
632 while(!(synth->SamplesToNext >= 1.0))
634 ALuint64 time = synth->NextEvtTime;
635 if(time == UINT64_MAX)
636 break;
638 synth->SamplesSinceLast -= (time - synth->LastEvtTime) * synth->SamplesPerTick;
639 synth->SamplesSinceLast = maxd(synth->SamplesSinceLast, 0.0);
640 synth->LastEvtTime = time;
641 FSynth_processQueue(self, time);
643 synth->NextEvtTime = MidiSynth_getNextEvtTime(synth);
644 if(synth->NextEvtTime != UINT64_MAX)
645 synth->SamplesToNext += (synth->NextEvtTime - synth->LastEvtTime) * synth->SamplesPerTick;
648 /* All notes off */
649 for(chan = 0;chan < 16;chan++)
650 fluid_synth_cc(self->Synth, chan, CTRL_ALLNOTESOFF, 0);
652 MidiSynth_stop(STATIC_CAST(MidiSynth, self));
655 static void FSynth_reset(FSynth *self)
657 /* Reset to power-up status. */
658 fluid_synth_system_reset(self->Synth);
660 MidiSynth_reset(STATIC_CAST(MidiSynth, self));
664 static void FSynth_update(FSynth *self, ALCdevice *device)
666 fluid_settings_setnum(self->Settings, "synth.sample-rate", device->Frequency);
667 fluid_synth_set_sample_rate(self->Synth, device->Frequency);
668 MidiSynth_update(STATIC_CAST(MidiSynth, self), device);
672 static void FSynth_processQueue(FSynth *self, ALuint64 time)
674 EvtQueue *queue = &STATIC_CAST(MidiSynth, self)->EventQueue;
676 while(queue->pos < queue->size && queue->events[queue->pos].time <= time)
678 const MidiEvent *evt = &queue->events[queue->pos];
680 if(evt->event == SYSEX_EVENT)
682 static const ALbyte gm2_on[] = { 0x7E, 0x7F, 0x09, 0x03 };
683 static const ALbyte gm2_off[] = { 0x7E, 0x7F, 0x09, 0x02 };
684 int handled = 0;
686 fluid_synth_sysex(self->Synth, evt->param.sysex.data, evt->param.sysex.size, NULL, NULL, &handled, 0);
687 if(!handled && evt->param.sysex.size >= (ALsizei)sizeof(gm2_on))
689 if(memcmp(evt->param.sysex.data, gm2_on, sizeof(gm2_on)) == 0)
690 self->ForceGM2BankSelect = AL_TRUE;
691 else if(memcmp(evt->param.sysex.data, gm2_off, sizeof(gm2_off)) == 0)
692 self->ForceGM2BankSelect = AL_FALSE;
695 else switch((evt->event&0xF0))
697 case AL_NOTEOFF_SOFT:
698 fluid_synth_noteoff(self->Synth, (evt->event&0x0F), evt->param.val[0]);
699 break;
700 case AL_NOTEON_SOFT:
701 fluid_synth_noteon(self->Synth, (evt->event&0x0F), evt->param.val[0], evt->param.val[1]);
702 break;
703 case AL_AFTERTOUCH_SOFT:
704 break;
706 case AL_CONTROLLERCHANGE_SOFT:
707 if(self->ForceGM2BankSelect)
709 int chan = (evt->event&0x0F);
710 if(evt->param.val[0] == CTRL_BANKSELECT_MSB)
712 if(evt->param.val[1] == 120 && (chan == 9 || chan == 10))
713 fluid_synth_set_channel_type(self->Synth, chan, CHANNEL_TYPE_DRUM);
714 else if(evt->param.val[1] == 121)
715 fluid_synth_set_channel_type(self->Synth, chan, CHANNEL_TYPE_MELODIC);
716 break;
718 if(evt->param.val[0] == CTRL_BANKSELECT_LSB)
720 fluid_synth_bank_select(self->Synth, chan, evt->param.val[1]);
721 break;
724 fluid_synth_cc(self->Synth, (evt->event&0x0F), evt->param.val[0], evt->param.val[1]);
725 break;
726 case AL_PROGRAMCHANGE_SOFT:
727 fluid_synth_program_change(self->Synth, (evt->event&0x0F), evt->param.val[0]);
728 break;
730 case AL_CHANNELPRESSURE_SOFT:
731 fluid_synth_channel_pressure(self->Synth, (evt->event&0x0F), evt->param.val[0]);
732 break;
734 case AL_PITCHBEND_SOFT:
735 fluid_synth_pitch_bend(self->Synth, (evt->event&0x0F), (evt->param.val[0]&0x7F) |
736 ((evt->param.val[1]&0x7F)<<7));
737 break;
740 queue->pos++;
744 static void FSynth_process(FSynth *self, ALuint SamplesToDo, ALfloat (*restrict DryBuffer)[BUFFERSIZE])
746 MidiSynth *synth = STATIC_CAST(MidiSynth, self);
747 ALenum state = synth->State;
748 ALuint total = 0;
750 if(state == AL_INITIAL)
751 return;
752 if(state != AL_PLAYING)
754 fluid_synth_write_float(self->Synth, SamplesToDo, DryBuffer[FrontLeft], 0, 1,
755 DryBuffer[FrontRight], 0, 1);
756 return;
759 while(total < SamplesToDo)
761 if(synth->SamplesToNext >= 1.0)
763 ALuint todo = minu(SamplesToDo - total, fastf2u(synth->SamplesToNext));
765 fluid_synth_write_float(self->Synth, todo,
766 &DryBuffer[FrontLeft][total], 0, 1,
767 &DryBuffer[FrontRight][total], 0, 1);
768 total += todo;
769 synth->SamplesSinceLast += todo;
770 synth->SamplesToNext -= todo;
772 else
774 ALuint64 time = synth->NextEvtTime;
775 if(time == UINT64_MAX)
777 synth->SamplesSinceLast += SamplesToDo-total;
778 fluid_synth_write_float(self->Synth, SamplesToDo-total,
779 &DryBuffer[FrontLeft][total], 0, 1,
780 &DryBuffer[FrontRight][total], 0, 1);
781 break;
784 synth->SamplesSinceLast -= (time - synth->LastEvtTime) * synth->SamplesPerTick;
785 synth->SamplesSinceLast = maxd(synth->SamplesSinceLast, 0.0);
786 synth->LastEvtTime = time;
787 FSynth_processQueue(self, time);
789 synth->NextEvtTime = MidiSynth_getNextEvtTime(synth);
790 if(synth->NextEvtTime != UINT64_MAX)
791 synth->SamplesToNext += (synth->NextEvtTime - synth->LastEvtTime) * synth->SamplesPerTick;
797 static void FSynth_Delete(FSynth *self)
799 free(self);
803 MidiSynth *FSynth_create(ALCdevice *device)
805 FSynth *synth = calloc(1, sizeof(*synth));
806 if(!synth)
808 ERR("Failed to allocate FSynth\n");
809 return NULL;
811 FSynth_Construct(synth, device);
813 if(FSynth_init(synth, device) == AL_FALSE)
815 DELETE_OBJ(STATIC_CAST(MidiSynth, synth));
816 return NULL;
819 return STATIC_CAST(MidiSynth, synth);
822 #else
824 MidiSynth *FSynth_create(ALCdevice* UNUSED(device))
826 return NULL;
829 #endif