diff options
Diffstat (limited to 'OpenAL32/alMidi.c')
-rw-r--r-- | OpenAL32/alMidi.c | 347 |
1 files changed, 13 insertions, 334 deletions
diff --git a/OpenAL32/alMidi.c b/OpenAL32/alMidi.c index c288b3c7..dda4c655 100644 --- a/OpenAL32/alMidi.c +++ b/OpenAL32/alMidi.c @@ -151,316 +151,6 @@ ALenum MidiSynth_insertSysExEvent(MidiSynth *self, ALuint64 time, const ALbyte * } -#ifdef HAVE_FLUIDSYNTH - -#include <fluidsynth.h> - -typedef struct FSynth { - DERIVE_FROM_TYPE(MidiSynth); - - fluid_settings_t *Settings; - fluid_synth_t *Synth; - int FontID; - - ALboolean ForceGM2BankSelect; -} FSynth; - -static void FSynth_Construct(FSynth *self, ALCdevice *device); -static void FSynth_Destruct(FSynth *self); -static ALboolean FSynth_init(FSynth *self, ALCdevice *device); -static ALboolean FSynth_isSoundfont(FSynth *self, const char *filename); -static ALenum FSynth_loadSoundfont(FSynth *self, const char *filename); -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 void FSynth_Construct(FSynth *self, ALCdevice *device) -{ - MidiSynth_Construct(STATIC_CAST(MidiSynth, self), device); - SET_VTABLE2(FSynth, MidiSynth, self); - - self->Settings = NULL; - self->Synth = NULL; - self->FontID = FLUID_FAILED; - self->ForceGM2BankSelect = AL_FALSE; -} - -static void FSynth_Destruct(FSynth *self) -{ - if(self->FontID != FLUID_FAILED) - fluid_synth_sfunload(self->Synth, self->FontID, 0); - self->FontID = FLUID_FAILED; - - 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) -{ - 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.sample-rate", device->Frequency); - - self->Synth = new_fluid_synth(self->Settings); - if(!self->Synth) - { - ERR("Failed to create FluidSynth\n"); - return AL_FALSE; - } - - return AL_TRUE; -} - - -static ALboolean FSynth_isSoundfont(FSynth *self, const char *filename) -{ - filename = MidiSynth_getFontName(STATIC_CAST(MidiSynth, self), filename); - if(!filename[0]) return AL_FALSE; - - if(!fluid_is_soundfont(filename)) - return AL_FALSE; - return AL_TRUE; -} - -static ALenum FSynth_loadSoundfont(FSynth *self, const char *filename) -{ - int fontid; - - filename = MidiSynth_getFontName(STATIC_CAST(MidiSynth, self), filename); - if(!filename[0]) return AL_INVALID_VALUE; - - fontid = fluid_synth_sfload(self->Synth, filename, 1); - if(fontid == FLUID_FAILED) - { - ERR("Failed to load soundfont '%s'\n", filename); - return AL_INVALID_VALUE; - } - - if(self->FontID != FLUID_FAILED) - fluid_synth_sfunload(self->Synth, self->FontID, 1); - self->FontID = fontid; - - return AL_NO_ERROR; -} - - -static void FSynth_setGain(FSynth *self, ALfloat gain) -{ - /* Scale gain by an additional 0.2 (-14dB), to help keep the mix from clipping. */ - fluid_settings_setnum(self->Settings, "synth.gain", 0.2 * gain); - fluid_synth_set_gain(self->Synth, 0.2f * gain); - MidiSynth_setGain(STATIC_CAST(MidiSynth, self), gain); -} - - -static void FSynth_setState(FSynth *self, ALenum state) -{ - if(state == AL_PLAYING && self->FontID == FLUID_FAILED) - FSynth_loadSoundfont(self, NULL); - - 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_AFTERTOUCH_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); -} - - -#endif /* HAVE_FLUIDSYNTH */ - - typedef struct DSynth { DERIVE_FROM_TYPE(MidiSynth); } DSynth; @@ -566,35 +256,24 @@ static void DSynth_Delete(DSynth *self) } -MidiSynth *SynthCreate(ALCdevice *device) +MidiSynth *DSynth_create(ALCdevice *device) { -#ifdef HAVE_FLUIDSYNTH + DSynth *synth = calloc(1, sizeof(*synth)); + if(!synth) { - FSynth *synth = calloc(1, sizeof(*synth)); - if(!synth) - ERR("Failed to allocate FSynth\n"); - else - { - FSynth_Construct(synth, device); - if(FSynth_init(synth, device)) - return STATIC_CAST(MidiSynth, synth); - DELETE_OBJ(STATIC_CAST(MidiSynth, synth)); - } + ERR("Failed to allocate DSynth\n"); + return NULL; } -#endif + DSynth_Construct(synth, device); + return STATIC_CAST(MidiSynth, synth); +} - { - DSynth *synth = calloc(1, sizeof(*synth)); - if(!synth) - ERR("Failed to allocate DSynth\n"); - else - { - DSynth_Construct(synth, device); - return STATIC_CAST(MidiSynth, synth); - } - } - return NULL; +MidiSynth *SynthCreate(ALCdevice *device) +{ + MidiSynth *synth = FSynth_create(device); + if(!synth) synth = DSynth_create(device); + return synth; } |