| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843 |
- #include "config.h"
- #include <stdlib.h>
- #include <string.h>
- #include <limits.h>
- #include "midi/base.h"
- #include "alMain.h"
- #include "alError.h"
- #include "alMidi.h"
- #include "evtqueue.h"
- #include "rwlock.h"
- #include "alu.h"
- #ifdef HAVE_FLUIDSYNTH
- #include <fluidsynth.h>
- /* MIDI events */
- #define SYSEX_EVENT (0xF0)
- /* MIDI controllers */
- #define CTRL_BANKSELECT_MSB (0)
- #define CTRL_BANKSELECT_LSB (32)
- #define CTRL_ALLNOTESOFF (123)
- static int getGenInput(ALenum input)
- {
- switch(input)
- {
- case AL_ONE_SOFT: return FLUID_MOD_NONE;
- case AL_NOTEON_VELOCITY_SOFT: return FLUID_MOD_VELOCITY;
- case AL_NOTEON_KEY_SOFT: return FLUID_MOD_KEY;
- case AL_KEYPRESSURE_SOFT: return FLUID_MOD_KEYPRESSURE;
- case AL_CHANNELPRESSURE_SOFT: return FLUID_MOD_CHANNELPRESSURE;
- case AL_PITCHBEND_SOFT: return FLUID_MOD_PITCHWHEEL;
- case AL_PITCHBEND_SENSITIVITY_SOFT: return FLUID_MOD_PITCHWHEELSENS;
- }
- return input&0x7F;
- }
- static int getGenFlags(ALenum input, ALenum type, ALenum form)
- {
- int ret = 0;
- switch(type)
- {
- case AL_UNORM_SOFT: ret |= FLUID_MOD_UNIPOLAR | FLUID_MOD_POSITIVE; break;
- case AL_UNORM_REV_SOFT: ret |= FLUID_MOD_UNIPOLAR | FLUID_MOD_NEGATIVE; break;
- case AL_SNORM_SOFT: ret |= FLUID_MOD_BIPOLAR | FLUID_MOD_POSITIVE; break;
- case AL_SNORM_REV_SOFT: ret |= FLUID_MOD_BIPOLAR | FLUID_MOD_NEGATIVE; break;
- }
- switch(form)
- {
- case AL_LINEAR_SOFT: ret |= FLUID_MOD_LINEAR; break;
- case AL_CONCAVE_SOFT: ret |= FLUID_MOD_CONCAVE; break;
- case AL_CONVEX_SOFT: ret |= FLUID_MOD_CONVEX; break;
- case AL_SWITCH_SOFT: ret |= FLUID_MOD_SWITCH; break;
- }
- /* Source input values less than 128 correspond to a MIDI continuous
- * controller. Otherwise, it's a general controller. */
- if(input < 128) ret |= FLUID_MOD_CC;
- else ret |= FLUID_MOD_GC;
- return ret;
- }
- static enum fluid_gen_type getSf2Gen(ALenum gen)
- {
- switch(gen)
- {
- case AL_MOD_LFO_TO_PITCH_SOFT: return GEN_MODLFOTOPITCH;
- case AL_VIBRATO_LFO_TO_PITCH_SOFT: return GEN_VIBLFOTOPITCH;
- case AL_MOD_ENV_TO_PITCH_SOFT: return GEN_MODENVTOPITCH;
- case AL_FILTER_CUTOFF_SOFT: return GEN_FILTERFC;
- case AL_FILTER_RESONANCE_SOFT: return GEN_FILTERQ;
- case AL_MOD_LFO_TO_FILTER_CUTOFF_SOFT: return GEN_MODLFOTOFILTERFC;
- case AL_MOD_ENV_TO_FILTER_CUTOFF_SOFT: return GEN_MODENVTOFILTERFC;
- case AL_MOD_LFO_TO_VOLUME_SOFT: return GEN_MODLFOTOVOL;
- case AL_CHORUS_SEND_SOFT: return GEN_CHORUSSEND;
- case AL_REVERB_SEND_SOFT: return GEN_REVERBSEND;
- case AL_PAN_SOFT: return GEN_PAN;
- case AL_MOD_LFO_DELAY_SOFT: return GEN_MODLFODELAY;
- case AL_MOD_LFO_FREQUENCY_SOFT: return GEN_MODLFOFREQ;
- case AL_VIBRATO_LFO_DELAY_SOFT: return GEN_VIBLFODELAY;
- case AL_VIBRATO_LFO_FREQUENCY_SOFT: return GEN_VIBLFOFREQ;
- case AL_MOD_ENV_DELAYTIME_SOFT: return GEN_MODENVDELAY;
- case AL_MOD_ENV_ATTACKTIME_SOFT: return GEN_MODENVATTACK;
- case AL_MOD_ENV_HOLDTIME_SOFT: return GEN_MODENVHOLD;
- case AL_MOD_ENV_DECAYTIME_SOFT: return GEN_MODENVDECAY;
- case AL_MOD_ENV_SUSTAINVOLUME_SOFT: return GEN_MODENVSUSTAIN;
- case AL_MOD_ENV_RELEASETIME_SOFT: return GEN_MODENVRELEASE;
- case AL_MOD_ENV_KEY_TO_HOLDTIME_SOFT: return GEN_KEYTOMODENVHOLD;
- case AL_MOD_ENV_KEY_TO_DECAYTIME_SOFT: return GEN_KEYTOMODENVDECAY;
- case AL_VOLUME_ENV_DELAYTIME_SOFT: return GEN_VOLENVDELAY;
- case AL_VOLUME_ENV_ATTACKTIME_SOFT: return GEN_VOLENVATTACK;
- case AL_VOLUME_ENV_HOLDTIME_SOFT: return GEN_VOLENVHOLD;
- case AL_VOLUME_ENV_DECAYTIME_SOFT: return GEN_VOLENVDECAY;
- case AL_VOLUME_ENV_SUSTAINVOLUME_SOFT: return GEN_VOLENVSUSTAIN;
- case AL_VOLUME_ENV_RELEASETIME_SOFT: return GEN_VOLENVRELEASE;
- case AL_VOLUME_ENV_KEY_TO_HOLDTIME_SOFT: return GEN_KEYTOVOLENVHOLD;
- case AL_VOLUME_ENV_KEY_TO_DECAYTIME_SOFT: return GEN_KEYTOVOLENVDECAY;
- case AL_ATTENUATION_SOFT: return GEN_ATTENUATION;
- case AL_TUNING_COARSE_SOFT: return GEN_COARSETUNE;
- case AL_TUNING_FINE_SOFT: return GEN_FINETUNE;
- case AL_TUNING_SCALE_SOFT: return GEN_SCALETUNE;
- }
- ERR("Unhandled generator: 0x%04x\n", gen);
- return 0;
- }
- static int getSf2LoopMode(ALenum mode)
- {
- switch(mode)
- {
- case AL_NONE: return 0;
- case AL_LOOP_CONTINUOUS_SOFT: return 1;
- case AL_LOOP_UNTIL_RELEASE_SOFT: return 3;
- }
- return 0;
- }
- static int getSampleType(ALenum type)
- {
- switch(type)
- {
- case AL_MONO_SOFT: return FLUID_SAMPLETYPE_MONO;
- case AL_RIGHT_SOFT: return FLUID_SAMPLETYPE_RIGHT;
- case AL_LEFT_SOFT: return FLUID_SAMPLETYPE_LEFT;
- }
- return FLUID_SAMPLETYPE_MONO;
- }
- typedef struct FSample {
- DERIVE_FROM_TYPE(fluid_sample_t);
- ALfontsound *Sound;
- fluid_mod_t *Mods;
- ALsizei NumMods;
- } FSample;
- static void FSample_Construct(FSample *self, ALfontsound *sound, ALsoundfont *sfont)
- {
- fluid_sample_t *sample = STATIC_CAST(fluid_sample_t, self);
- memset(sample->name, 0, sizeof(sample->name));
- sample->start = sound->Start;
- sample->end = sound->End;
- sample->loopstart = sound->LoopStart;
- sample->loopend = sound->LoopEnd;
- sample->samplerate = sound->SampleRate;
- sample->origpitch = sound->PitchKey;
- sample->pitchadj = sound->PitchCorrection;
- sample->sampletype = getSampleType(sound->SampleType);
- sample->valid = 1;
- sample->data = sfont->Samples;
- sample->amplitude_that_reaches_noise_floor_is_valid = 0;
- sample->amplitude_that_reaches_noise_floor = 0.0;
- sample->refcount = 0;
- sample->notify = NULL;
- sample->userdata = self;
- self->Sound = sound;
- self->NumMods = 0;
- self->Mods = calloc(sound->ModulatorMap.size, sizeof(self->Mods[0]));
- if(self->Mods)
- {
- ALsizei i;
- self->NumMods = sound->ModulatorMap.size;
- for(i = 0;i < self->NumMods;i++)
- {
- ALsfmodulator *mod = sound->ModulatorMap.array[i].value;
- fluid_mod_set_source1(&self->Mods[i], getGenInput(mod->Source[0].Input),
- getGenFlags(mod->Source[0].Input, mod->Source[0].Type,
- mod->Source[0].Form));
- fluid_mod_set_source2(&self->Mods[i], getGenInput(mod->Source[1].Input),
- getGenFlags(mod->Source[1].Input, mod->Source[1].Type,
- mod->Source[1].Form));
- fluid_mod_set_amount(&self->Mods[i], mod->Amount);
- fluid_mod_set_dest(&self->Mods[i], getSf2Gen(mod->Dest));
- self->Mods[i].next = NULL;
- }
- }
- }
- static void FSample_Destruct(FSample *self)
- {
- free(self->Mods);
- self->Mods = NULL;
- self->NumMods = 0;
- }
- typedef struct FPreset {
- DERIVE_FROM_TYPE(fluid_preset_t);
- char Name[16];
- int Preset;
- int Bank;
- FSample *Samples;
- ALsizei NumSamples;
- } FPreset;
- static char* FPreset_getName(fluid_preset_t *preset);
- static int FPreset_getPreset(fluid_preset_t *preset);
- static int FPreset_getBank(fluid_preset_t *preset);
- static int FPreset_noteOn(fluid_preset_t *preset, fluid_synth_t *synth, int channel, int key, int velocity);
- static void FPreset_Construct(FPreset *self, ALsfpreset *preset, fluid_sfont_t *parent, ALsoundfont *sfont)
- {
- STATIC_CAST(fluid_preset_t, self)->data = self;
- STATIC_CAST(fluid_preset_t, self)->sfont = parent;
- STATIC_CAST(fluid_preset_t, self)->free = NULL;
- STATIC_CAST(fluid_preset_t, self)->get_name = FPreset_getName;
- STATIC_CAST(fluid_preset_t, self)->get_banknum = FPreset_getBank;
- STATIC_CAST(fluid_preset_t, self)->get_num = FPreset_getPreset;
- STATIC_CAST(fluid_preset_t, self)->noteon = FPreset_noteOn;
- STATIC_CAST(fluid_preset_t, self)->notify = NULL;
- memset(self->Name, 0, sizeof(self->Name));
- self->Preset = preset->Preset;
- self->Bank = preset->Bank;
- self->NumSamples = 0;
- self->Samples = calloc(1, preset->NumSounds * sizeof(self->Samples[0]));
- if(self->Samples)
- {
- ALsizei i;
- self->NumSamples = preset->NumSounds;
- for(i = 0;i < self->NumSamples;i++)
- FSample_Construct(&self->Samples[i], preset->Sounds[i], sfont);
- }
- }
- static void FPreset_Destruct(FPreset *self)
- {
- ALsizei i;
- for(i = 0;i < self->NumSamples;i++)
- FSample_Destruct(&self->Samples[i]);
- free(self->Samples);
- self->Samples = NULL;
- self->NumSamples = 0;
- }
- static ALboolean FPreset_canDelete(FPreset *self)
- {
- ALsizei i;
- for(i = 0;i < self->NumSamples;i++)
- {
- if(fluid_sample_refcount(STATIC_CAST(fluid_sample_t, &self->Samples[i])) != 0)
- return AL_FALSE;
- }
- return AL_TRUE;
- }
- static char* FPreset_getName(fluid_preset_t *preset)
- {
- return ((FPreset*)preset->data)->Name;
- }
- static int FPreset_getPreset(fluid_preset_t *preset)
- {
- return ((FPreset*)preset->data)->Preset;
- }
- static int FPreset_getBank(fluid_preset_t *preset)
- {
- return ((FPreset*)preset->data)->Bank;
- }
- static int FPreset_noteOn(fluid_preset_t *preset, fluid_synth_t *synth, int channel, int key, int vel)
- {
- FPreset *self = ((FPreset*)preset->data);
- ALsizei i;
- for(i = 0;i < self->NumSamples;i++)
- {
- FSample *sample = &self->Samples[i];
- ALfontsound *sound = sample->Sound;
- fluid_voice_t *voice;
- ALsizei m;
- if(!(key >= sound->MinKey && key <= sound->MaxKey && vel >= sound->MinVelocity && vel <= sound->MaxVelocity))
- continue;
- voice = fluid_synth_alloc_voice(synth, STATIC_CAST(fluid_sample_t, sample), channel, key, vel);
- if(voice == NULL)
- return FLUID_FAILED;
- fluid_voice_gen_set(voice, GEN_MODLFOTOPITCH, sound->ModLfoToPitch);
- fluid_voice_gen_set(voice, GEN_VIBLFOTOPITCH, sound->VibratoLfoToPitch);
- fluid_voice_gen_set(voice, GEN_MODENVTOPITCH, sound->ModEnvToPitch);
- fluid_voice_gen_set(voice, GEN_FILTERFC, sound->FilterCutoff);
- fluid_voice_gen_set(voice, GEN_FILTERQ, sound->FilterQ);
- fluid_voice_gen_set(voice, GEN_MODLFOTOFILTERFC, sound->ModLfoToFilterCutoff);
- fluid_voice_gen_set(voice, GEN_MODENVTOFILTERFC, sound->ModEnvToFilterCutoff);
- fluid_voice_gen_set(voice, GEN_MODLFOTOVOL, sound->ModLfoToVolume);
- fluid_voice_gen_set(voice, GEN_CHORUSSEND, sound->ChorusSend);
- fluid_voice_gen_set(voice, GEN_REVERBSEND, sound->ReverbSend);
- fluid_voice_gen_set(voice, GEN_PAN, sound->Pan);
- fluid_voice_gen_set(voice, GEN_MODLFODELAY, sound->ModLfo.Delay);
- fluid_voice_gen_set(voice, GEN_MODLFOFREQ, sound->ModLfo.Frequency);
- fluid_voice_gen_set(voice, GEN_VIBLFODELAY, sound->VibratoLfo.Delay);
- fluid_voice_gen_set(voice, GEN_VIBLFOFREQ, sound->VibratoLfo.Frequency);
- fluid_voice_gen_set(voice, GEN_MODENVDELAY, sound->ModEnv.DelayTime);
- fluid_voice_gen_set(voice, GEN_MODENVATTACK, sound->ModEnv.AttackTime);
- fluid_voice_gen_set(voice, GEN_MODENVHOLD, sound->ModEnv.HoldTime);
- fluid_voice_gen_set(voice, GEN_MODENVDECAY, sound->ModEnv.DecayTime);
- fluid_voice_gen_set(voice, GEN_MODENVSUSTAIN, sound->ModEnv.SustainAttn);
- fluid_voice_gen_set(voice, GEN_MODENVRELEASE, sound->ModEnv.ReleaseTime);
- fluid_voice_gen_set(voice, GEN_KEYTOMODENVHOLD, sound->ModEnv.KeyToHoldTime);
- fluid_voice_gen_set(voice, GEN_KEYTOMODENVDECAY, sound->ModEnv.KeyToDecayTime);
- fluid_voice_gen_set(voice, GEN_VOLENVDELAY, sound->VolEnv.DelayTime);
- fluid_voice_gen_set(voice, GEN_VOLENVATTACK, sound->VolEnv.AttackTime);
- fluid_voice_gen_set(voice, GEN_VOLENVHOLD, sound->VolEnv.HoldTime);
- fluid_voice_gen_set(voice, GEN_VOLENVDECAY, sound->VolEnv.DecayTime);
- fluid_voice_gen_set(voice, GEN_VOLENVSUSTAIN, sound->VolEnv.SustainAttn);
- fluid_voice_gen_set(voice, GEN_VOLENVRELEASE, sound->VolEnv.ReleaseTime);
- fluid_voice_gen_set(voice, GEN_KEYTOVOLENVHOLD, sound->VolEnv.KeyToHoldTime);
- fluid_voice_gen_set(voice, GEN_KEYTOVOLENVDECAY, sound->VolEnv.KeyToDecayTime);
- fluid_voice_gen_set(voice, GEN_ATTENUATION, sound->Attenuation);
- fluid_voice_gen_set(voice, GEN_COARSETUNE, sound->CoarseTuning);
- fluid_voice_gen_set(voice, GEN_FINETUNE, sound->FineTuning);
- fluid_voice_gen_set(voice, GEN_SAMPLEMODE, getSf2LoopMode(sound->LoopMode));
- fluid_voice_gen_set(voice, GEN_SCALETUNE, sound->TuningScale);
- fluid_voice_gen_set(voice, GEN_EXCLUSIVECLASS, sound->ExclusiveClass);
- for(m = 0;m < sample->NumMods;m++)
- fluid_voice_add_mod(voice, &sample->Mods[m], FLUID_VOICE_OVERWRITE);
- fluid_synth_start_voice(synth, voice);
- }
- return FLUID_OK;
- }
- typedef struct FSfont {
- DERIVE_FROM_TYPE(fluid_sfont_t);
- char Name[16];
- FPreset *Presets;
- ALsizei NumPresets;
- ALsizei CurrentPos;
- } FSfont;
- static int FSfont_free(fluid_sfont_t *sfont);
- static char* FSfont_getName(fluid_sfont_t *sfont);
- static fluid_preset_t* FSfont_getPreset(fluid_sfont_t *sfont, unsigned int bank, unsigned int prenum);
- static void FSfont_iterStart(fluid_sfont_t *sfont);
- static int FSfont_iterNext(fluid_sfont_t *sfont, fluid_preset_t *preset);
- static void FSfont_Construct(FSfont *self, ALsoundfont *sfont)
- {
- STATIC_CAST(fluid_sfont_t, self)->data = self;
- STATIC_CAST(fluid_sfont_t, self)->id = FLUID_FAILED;
- STATIC_CAST(fluid_sfont_t, self)->free = FSfont_free;
- STATIC_CAST(fluid_sfont_t, self)->get_name = FSfont_getName;
- STATIC_CAST(fluid_sfont_t, self)->get_preset = FSfont_getPreset;
- STATIC_CAST(fluid_sfont_t, self)->iteration_start = FSfont_iterStart;
- STATIC_CAST(fluid_sfont_t, self)->iteration_next = FSfont_iterNext;
- memset(self->Name, 0, sizeof(self->Name));
- self->CurrentPos = 0;
- self->NumPresets = 0;
- self->Presets = calloc(1, sfont->NumPresets * sizeof(self->Presets[0]));
- if(self->Presets)
- {
- ALsizei i;
- self->NumPresets = sfont->NumPresets;
- for(i = 0;i < self->NumPresets;i++)
- FPreset_Construct(&self->Presets[i], sfont->Presets[i], STATIC_CAST(fluid_sfont_t, self), sfont);
- }
- }
- static void FSfont_Destruct(FSfont *self)
- {
- ALsizei i;
- for(i = 0;i < self->NumPresets;i++)
- FPreset_Destruct(&self->Presets[i]);
- free(self->Presets);
- self->Presets = NULL;
- self->NumPresets = 0;
- self->CurrentPos = 0;
- }
- static int FSfont_free(fluid_sfont_t *sfont)
- {
- FSfont *self = STATIC_UPCAST(FSfont, fluid_sfont_t, sfont);
- ALsizei i;
- for(i = 0;i < self->NumPresets;i++)
- {
- if(!FPreset_canDelete(&self->Presets[i]))
- return 1;
- }
- FSfont_Destruct(self);
- free(self);
- return 0;
- }
- static char* FSfont_getName(fluid_sfont_t *sfont)
- {
- return STATIC_UPCAST(FSfont, fluid_sfont_t, sfont)->Name;
- }
- static fluid_preset_t *FSfont_getPreset(fluid_sfont_t *sfont, unsigned int bank, unsigned int prenum)
- {
- FSfont *self = STATIC_UPCAST(FSfont, fluid_sfont_t, sfont);
- ALsizei i;
- for(i = 0;i < self->NumPresets;i++)
- {
- FPreset *preset = &self->Presets[i];
- if(preset->Bank == (int)bank && preset->Preset == (int)prenum)
- return STATIC_CAST(fluid_preset_t, preset);
- }
- return NULL;
- }
- static void FSfont_iterStart(fluid_sfont_t *sfont)
- {
- STATIC_UPCAST(FSfont, fluid_sfont_t, sfont)->CurrentPos = 0;
- }
- static int FSfont_iterNext(fluid_sfont_t *sfont, fluid_preset_t *preset)
- {
- FSfont *self = STATIC_UPCAST(FSfont, fluid_sfont_t, sfont);
- if(self->CurrentPos >= self->NumPresets)
- return 0;
- *preset = *STATIC_CAST(fluid_preset_t, &self->Presets[self->CurrentPos++]);
- preset->free = NULL;
- return 1;
- }
- typedef struct FSynth {
- DERIVE_FROM_TYPE(MidiSynth);
- DERIVE_FROM_TYPE(fluid_sfloader_t);
- fluid_settings_t *Settings;
- fluid_synth_t *Synth;
- int *FontIDs;
- ALsizei NumFontIDs;
- ALboolean ForceGM2BankSelect;
- ALfloat GainScale;
- } FSynth;
- static void FSynth_Construct(FSynth *self, ALCdevice *device);
- static void FSynth_Destruct(FSynth *self);
- static ALboolean FSynth_init(FSynth *self, ALCdevice *device);
- static ALenum FSynth_selectSoundfonts(FSynth *self, ALCcontext *context, ALsizei count, const ALuint *ids);
- static void FSynth_setGain(FSynth *self, ALfloat gain);
- static void FSynth_setState(FSynth *self, ALenum state);
- static void FSynth_stop(FSynth *self);
- static void FSynth_reset(FSynth *self);
- static void FSynth_update(FSynth *self, ALCdevice *device);
- static void FSynth_processQueue(FSynth *self, ALuint64 time);
- static void FSynth_process(FSynth *self, ALuint SamplesToDo, ALfloat (*restrict DryBuffer)[BUFFERSIZE]);
- static void FSynth_Delete(FSynth *self);
- DEFINE_MIDISYNTH_VTABLE(FSynth);
- static fluid_sfont_t *FSynth_loadSfont(fluid_sfloader_t *loader, const char *filename);
- static void FSynth_Construct(FSynth *self, ALCdevice *device)
- {
- MidiSynth_Construct(STATIC_CAST(MidiSynth, self), device);
- SET_VTABLE2(FSynth, MidiSynth, self);
- STATIC_CAST(fluid_sfloader_t, self)->data = self;
- STATIC_CAST(fluid_sfloader_t, self)->free = NULL;
- STATIC_CAST(fluid_sfloader_t, self)->load = FSynth_loadSfont;
- self->Settings = NULL;
- self->Synth = NULL;
- self->FontIDs = NULL;
- self->NumFontIDs = 0;
- self->ForceGM2BankSelect = AL_FALSE;
- self->GainScale = 0.2f;
- }
- static void FSynth_Destruct(FSynth *self)
- {
- ALsizei i;
- for(i = 0;i < self->NumFontIDs;i++)
- fluid_synth_sfunload(self->Synth, self->FontIDs[i], 0);
- free(self->FontIDs);
- self->FontIDs = NULL;
- self->NumFontIDs = 0;
- if(self->Synth != NULL)
- delete_fluid_synth(self->Synth);
- self->Synth = NULL;
- if(self->Settings != NULL)
- delete_fluid_settings(self->Settings);
- self->Settings = NULL;
- MidiSynth_Destruct(STATIC_CAST(MidiSynth, self));
- }
- static ALboolean FSynth_init(FSynth *self, ALCdevice *device)
- {
- ALfloat vol;
- if(ConfigValueFloat("midi", "volume", &vol))
- {
- if(!(vol <= 0.0f))
- {
- ERR("MIDI volume %f clamped to 0\n", vol);
- vol = 0.0f;
- }
- self->GainScale = powf(10.0f, vol / 20.0f);
- }
- self->Settings = new_fluid_settings();
- if(!self->Settings)
- {
- ERR("Failed to create FluidSettings\n");
- return AL_FALSE;
- }
- fluid_settings_setint(self->Settings, "synth.polyphony", 256);
- fluid_settings_setnum(self->Settings, "synth.gain", self->GainScale);
- fluid_settings_setnum(self->Settings, "synth.sample-rate", device->Frequency);
- self->Synth = new_fluid_synth(self->Settings);
- if(!self->Synth)
- {
- ERR("Failed to create FluidSynth\n");
- return AL_FALSE;
- }
- fluid_synth_add_sfloader(self->Synth, STATIC_CAST(fluid_sfloader_t, self));
- return AL_TRUE;
- }
- static fluid_sfont_t *FSynth_loadSfont(fluid_sfloader_t *loader, const char *filename)
- {
- FSynth *self = STATIC_UPCAST(FSynth, fluid_sfloader_t, loader);
- FSfont *sfont;
- int idx;
- if(!filename || sscanf(filename, "_al_internal %d", &idx) != 1)
- return NULL;
- if(idx < 0 || idx >= STATIC_CAST(MidiSynth, self)->NumSoundfonts)
- {
- ERR("Received invalid soundfont index %d (max: %d)\n", idx, STATIC_CAST(MidiSynth, self)->NumSoundfonts);
- return NULL;
- }
- sfont = calloc(1, sizeof(sfont[0]));
- if(!sfont) return NULL;
- FSfont_Construct(sfont, STATIC_CAST(MidiSynth, self)->Soundfonts[idx]);
- return STATIC_CAST(fluid_sfont_t, sfont);
- }
- static ALenum FSynth_selectSoundfonts(FSynth *self, ALCcontext *context, ALsizei count, const ALuint *ids)
- {
- int *fontid;
- ALenum ret;
- ALsizei i;
- ret = MidiSynth_selectSoundfonts(STATIC_CAST(MidiSynth, self), context, count, ids);
- if(ret != AL_NO_ERROR) return ret;
- ALCdevice_Lock(context->Device);
- for(i = 0;i < 16;i++)
- fluid_synth_all_sounds_off(self->Synth, i);
- ALCdevice_Unlock(context->Device);
- fontid = malloc(count * sizeof(fontid[0]));
- if(fontid)
- {
- for(i = 0;i < STATIC_CAST(MidiSynth, self)->NumSoundfonts;i++)
- {
- char name[16];
- snprintf(name, sizeof(name), "_al_internal %d", i);
- fontid[i] = fluid_synth_sfload(self->Synth, name, 0);
- if(fontid[i] == FLUID_FAILED)
- ERR("Failed to load selected soundfont %d\n", i);
- }
- fontid = ExchangePtr((XchgPtr*)&self->FontIDs, fontid);
- count = ExchangeInt(&self->NumFontIDs, count);
- }
- else
- {
- ERR("Failed to allocate space for %d font IDs!\n", count);
- fontid = ExchangePtr((XchgPtr*)&self->FontIDs, NULL);
- count = ExchangeInt(&self->NumFontIDs, 0);
- }
- for(i = 0;i < count;i++)
- fluid_synth_sfunload(self->Synth, fontid[i], 0);
- free(fontid);
- return ret;
- }
- static void FSynth_setGain(FSynth *self, ALfloat gain)
- {
- fluid_settings_setnum(self->Settings, "synth.gain", self->GainScale * gain);
- fluid_synth_set_gain(self->Synth, self->GainScale * gain);
- MidiSynth_setGain(STATIC_CAST(MidiSynth, self), gain);
- }
- static void FSynth_setState(FSynth *self, ALenum state)
- {
- MidiSynth_setState(STATIC_CAST(MidiSynth, self), state);
- }
- static void FSynth_stop(FSynth *self)
- {
- MidiSynth *synth = STATIC_CAST(MidiSynth, self);
- ALsizei chan;
- /* Make sure all pending events are processed. */
- while(!(synth->SamplesToNext >= 1.0))
- {
- ALuint64 time = synth->NextEvtTime;
- if(time == UINT64_MAX)
- break;
- synth->SamplesSinceLast -= (time - synth->LastEvtTime) * synth->SamplesPerTick;
- synth->SamplesSinceLast = maxd(synth->SamplesSinceLast, 0.0);
- synth->LastEvtTime = time;
- FSynth_processQueue(self, time);
- synth->NextEvtTime = MidiSynth_getNextEvtTime(synth);
- if(synth->NextEvtTime != UINT64_MAX)
- synth->SamplesToNext += (synth->NextEvtTime - synth->LastEvtTime) * synth->SamplesPerTick;
- }
- /* All notes off */
- for(chan = 0;chan < 16;chan++)
- fluid_synth_cc(self->Synth, chan, CTRL_ALLNOTESOFF, 0);
- MidiSynth_stop(STATIC_CAST(MidiSynth, self));
- }
- static void FSynth_reset(FSynth *self)
- {
- /* Reset to power-up status. */
- fluid_synth_system_reset(self->Synth);
- MidiSynth_reset(STATIC_CAST(MidiSynth, self));
- }
- static void FSynth_update(FSynth *self, ALCdevice *device)
- {
- fluid_settings_setnum(self->Settings, "synth.sample-rate", device->Frequency);
- fluid_synth_set_sample_rate(self->Synth, device->Frequency);
- MidiSynth_update(STATIC_CAST(MidiSynth, self), device);
- }
- static void FSynth_processQueue(FSynth *self, ALuint64 time)
- {
- EvtQueue *queue = &STATIC_CAST(MidiSynth, self)->EventQueue;
- while(queue->pos < queue->size && queue->events[queue->pos].time <= time)
- {
- const MidiEvent *evt = &queue->events[queue->pos];
- if(evt->event == SYSEX_EVENT)
- {
- static const ALbyte gm2_on[] = { 0x7E, 0x7F, 0x09, 0x03 };
- static const ALbyte gm2_off[] = { 0x7E, 0x7F, 0x09, 0x02 };
- int handled = 0;
- fluid_synth_sysex(self->Synth, evt->param.sysex.data, evt->param.sysex.size, NULL, NULL, &handled, 0);
- if(!handled && evt->param.sysex.size >= (ALsizei)sizeof(gm2_on))
- {
- if(memcmp(evt->param.sysex.data, gm2_on, sizeof(gm2_on)) == 0)
- self->ForceGM2BankSelect = AL_TRUE;
- else if(memcmp(evt->param.sysex.data, gm2_off, sizeof(gm2_off)) == 0)
- self->ForceGM2BankSelect = AL_FALSE;
- }
- }
- else switch((evt->event&0xF0))
- {
- case AL_NOTEOFF_SOFT:
- fluid_synth_noteoff(self->Synth, (evt->event&0x0F), evt->param.val[0]);
- break;
- case AL_NOTEON_SOFT:
- fluid_synth_noteon(self->Synth, (evt->event&0x0F), evt->param.val[0], evt->param.val[1]);
- break;
- case AL_KEYPRESSURE_SOFT:
- break;
- case AL_CONTROLLERCHANGE_SOFT:
- if(self->ForceGM2BankSelect)
- {
- int chan = (evt->event&0x0F);
- if(evt->param.val[0] == CTRL_BANKSELECT_MSB)
- {
- if(evt->param.val[1] == 120 && (chan == 9 || chan == 10))
- fluid_synth_set_channel_type(self->Synth, chan, CHANNEL_TYPE_DRUM);
- else if(evt->param.val[1] == 121)
- fluid_synth_set_channel_type(self->Synth, chan, CHANNEL_TYPE_MELODIC);
- break;
- }
- if(evt->param.val[0] == CTRL_BANKSELECT_LSB)
- {
- fluid_synth_bank_select(self->Synth, chan, evt->param.val[1]);
- break;
- }
- }
- fluid_synth_cc(self->Synth, (evt->event&0x0F), evt->param.val[0], evt->param.val[1]);
- break;
- case AL_PROGRAMCHANGE_SOFT:
- fluid_synth_program_change(self->Synth, (evt->event&0x0F), evt->param.val[0]);
- break;
- case AL_CHANNELPRESSURE_SOFT:
- fluid_synth_channel_pressure(self->Synth, (evt->event&0x0F), evt->param.val[0]);
- break;
- case AL_PITCHBEND_SOFT:
- fluid_synth_pitch_bend(self->Synth, (evt->event&0x0F), (evt->param.val[0]&0x7F) |
- ((evt->param.val[1]&0x7F)<<7));
- break;
- }
- queue->pos++;
- }
- }
- static void FSynth_process(FSynth *self, ALuint SamplesToDo, ALfloat (*restrict DryBuffer)[BUFFERSIZE])
- {
- MidiSynth *synth = STATIC_CAST(MidiSynth, self);
- ALenum state = synth->State;
- ALuint total = 0;
- if(state == AL_INITIAL)
- return;
- if(state != AL_PLAYING)
- {
- fluid_synth_write_float(self->Synth, SamplesToDo, DryBuffer[FrontLeft], 0, 1,
- DryBuffer[FrontRight], 0, 1);
- return;
- }
- while(total < SamplesToDo)
- {
- if(synth->SamplesToNext >= 1.0)
- {
- ALuint todo = minu(SamplesToDo - total, fastf2u(synth->SamplesToNext));
- fluid_synth_write_float(self->Synth, todo,
- &DryBuffer[FrontLeft][total], 0, 1,
- &DryBuffer[FrontRight][total], 0, 1);
- total += todo;
- synth->SamplesSinceLast += todo;
- synth->SamplesToNext -= todo;
- }
- else
- {
- ALuint64 time = synth->NextEvtTime;
- if(time == UINT64_MAX)
- {
- synth->SamplesSinceLast += SamplesToDo-total;
- fluid_synth_write_float(self->Synth, SamplesToDo-total,
- &DryBuffer[FrontLeft][total], 0, 1,
- &DryBuffer[FrontRight][total], 0, 1);
- break;
- }
- synth->SamplesSinceLast -= (time - synth->LastEvtTime) * synth->SamplesPerTick;
- synth->SamplesSinceLast = maxd(synth->SamplesSinceLast, 0.0);
- synth->LastEvtTime = time;
- FSynth_processQueue(self, time);
- synth->NextEvtTime = MidiSynth_getNextEvtTime(synth);
- if(synth->NextEvtTime != UINT64_MAX)
- synth->SamplesToNext += (synth->NextEvtTime - synth->LastEvtTime) * synth->SamplesPerTick;
- }
- }
- }
- static void FSynth_Delete(FSynth *self)
- {
- free(self);
- }
- MidiSynth *FSynth_create(ALCdevice *device)
- {
- FSynth *synth = calloc(1, sizeof(*synth));
- if(!synth)
- {
- ERR("Failed to allocate FSynth\n");
- return NULL;
- }
- FSynth_Construct(synth, device);
- if(FSynth_init(synth, device) == AL_FALSE)
- {
- DELETE_OBJ(STATIC_CAST(MidiSynth, synth));
- return NULL;
- }
- return STATIC_CAST(MidiSynth, synth);
- }
- #else
- MidiSynth *FSynth_create(ALCdevice* UNUSED(device))
- {
- return NULL;
- }
- #endif
|