diff options
author | Chris Robinson <[email protected]> | 2015-10-20 17:41:53 -0700 |
---|---|---|
committer | Chris Robinson <[email protected]> | 2015-10-20 18:01:27 -0700 |
commit | 6689c61ff474657109c5a73827b8733aba7dfd45 (patch) | |
tree | 3c9a3371b1be3085ec4a298148bd45ebf495c44f /Alc/midi | |
parent | d9a77a7edc309f399ce257f4b69d240008f47b49 (diff) |
Remove the MIDI code
The extension's not going anywhere, and it can't do anything fluidsynth can't.
The code maintenance and bloat is not worth keeping around, and ideally the AL
API would be able to facilitate MIDI-like behavior anyway (envelopes, start-at-
time, etc).
Diffstat (limited to 'Alc/midi')
-rw-r--r-- | Alc/midi/base.c | 244 | ||||
-rw-r--r-- | Alc/midi/base.h | 133 | ||||
-rw-r--r-- | Alc/midi/dummy.c | 76 | ||||
-rw-r--r-- | Alc/midi/fluidsynth.c | 934 | ||||
-rw-r--r-- | Alc/midi/sf2load.c | 1373 | ||||
-rw-r--r-- | Alc/midi/soft.c | 139 |
6 files changed, 0 insertions, 2899 deletions
diff --git a/Alc/midi/base.c b/Alc/midi/base.c deleted file mode 100644 index cab85c1a..00000000 --- a/Alc/midi/base.c +++ /dev/null @@ -1,244 +0,0 @@ - -#include "config.h" - -#include <stdlib.h> -#include <string.h> -#include <limits.h> - -#include "midi/base.h" - -#include "alMidi.h" -#include "alMain.h" -#include "alError.h" -#include "alThunk.h" -#include "evtqueue.h" -#include "rwlock.h" -#include "alu.h" - - -extern inline ALboolean IsValidCtrlInput(int cc); - -extern inline size_t Reader_read(Reader *self, void *buf, size_t len); - - -/* MIDI events */ -#define SYSEX_EVENT (0xF0) - - -void InitEvtQueue(EvtQueue *queue) -{ - queue->events = NULL; - queue->maxsize = 0; - queue->size = 0; - queue->pos = 0; -} - -void ResetEvtQueue(EvtQueue *queue) -{ - ALsizei i; - for(i = 0;i < queue->size;i++) - { - if(queue->events[i].event == SYSEX_EVENT) - { - free(queue->events[i].param.sysex.data); - queue->events[i].param.sysex.data = NULL; - } - } - - free(queue->events); - queue->events = NULL; - queue->maxsize = 0; - queue->size = 0; - queue->pos = 0; -} - -ALenum InsertEvtQueue(EvtQueue *queue, const MidiEvent *evt) -{ - ALsizei pos; - - if(queue->maxsize == queue->size) - { - if(queue->pos > 0) - { - /* Queue has some stale entries, remove them to make space for more - * events. */ - for(pos = 0;pos < queue->pos;pos++) - { - if(queue->events[pos].event == SYSEX_EVENT) - { - free(queue->events[pos].param.sysex.data); - queue->events[pos].param.sysex.data = NULL; - } - } - memmove(&queue->events[0], &queue->events[queue->pos], - (queue->size-queue->pos)*sizeof(queue->events[0])); - queue->size -= queue->pos; - queue->pos = 0; - } - else - { - /* Queue is full, double the allocated space. */ - void *temp = NULL; - ALsizei newsize; - - newsize = (queue->maxsize ? (queue->maxsize<<1) : 16); - if(newsize > queue->maxsize) - temp = realloc(queue->events, newsize * sizeof(queue->events[0])); - if(!temp) - return AL_OUT_OF_MEMORY; - - queue->events = temp; - queue->maxsize = newsize; - } - } - - pos = queue->pos; - if(queue->size > 0) - { - ALsizei high = queue->size - 1; - while(pos < high) - { - ALsizei mid = pos + (high-pos)/2; - if(queue->events[mid].time < evt->time) - pos = mid + 1; - else - high = mid; - } - while(pos < queue->size && queue->events[pos].time <= evt->time) - pos++; - - if(pos < queue->size) - memmove(&queue->events[pos+1], &queue->events[pos], - (queue->size-pos)*sizeof(queue->events[0])); - } - - queue->events[pos] = *evt; - queue->size++; - - return AL_NO_ERROR; -} - - -void MidiSynth_Construct(MidiSynth *self, ALCdevice *device) -{ - InitEvtQueue(&self->EventQueue); - - RWLockInit(&self->Lock); - - self->Soundfonts = NULL; - self->NumSoundfonts = 0; - - self->Gain = 1.0f; - self->State = AL_INITIAL; - - self->ClockBase = 0; - self->SamplesDone = 0; - self->SampleRate = device->Frequency; -} - -void MidiSynth_Destruct(MidiSynth *self) -{ - ALsizei i; - - for(i = 0;i < self->NumSoundfonts;i++) - DecrementRef(&self->Soundfonts[i]->ref); - free(self->Soundfonts); - self->Soundfonts = NULL; - self->NumSoundfonts = 0; - - ResetEvtQueue(&self->EventQueue); -} - - -ALenum MidiSynth_selectSoundfonts(MidiSynth *self, ALCcontext *context, ALsizei count, const ALuint *ids) -{ - ALCdevice *device = context->Device; - ALsoundfont **sfonts; - ALsizei i; - - if(self->State != AL_INITIAL && self->State != AL_STOPPED) - return AL_INVALID_OPERATION; - - sfonts = calloc(1, count * sizeof(sfonts[0])); - if(!sfonts) return AL_OUT_OF_MEMORY; - - for(i = 0;i < count;i++) - { - if(ids[i] == 0) - sfonts[i] = ALsoundfont_getDefSoundfont(context); - else if(!(sfonts[i]=LookupSfont(device, ids[i]))) - { - free(sfonts); - return AL_INVALID_VALUE; - } - } - - for(i = 0;i < count;i++) - IncrementRef(&sfonts[i]->ref); - sfonts = ExchangePtr((XchgPtr*)&self->Soundfonts, sfonts); - count = ExchangeInt(&self->NumSoundfonts, count); - - for(i = 0;i < count;i++) - DecrementRef(&sfonts[i]->ref); - free(sfonts); - - return AL_NO_ERROR; -} - -extern inline void MidiSynth_setGain(MidiSynth *self, ALfloat gain); -extern inline ALfloat MidiSynth_getGain(const MidiSynth *self); -extern inline void MidiSynth_setState(MidiSynth *self, ALenum state); -extern inline ALenum MidiSynth_getState(const MidiSynth *self); - -void MidiSynth_stop(MidiSynth *self) -{ - ResetEvtQueue(&self->EventQueue); - - self->ClockBase = 0; - self->SamplesDone = 0; -} - -extern inline void MidiSynth_reset(MidiSynth *self); -extern inline ALuint64 MidiSynth_getTime(const MidiSynth *self); -extern inline ALuint64 MidiSynth_getNextEvtTime(const MidiSynth *self); - -void MidiSynth_setSampleRate(MidiSynth *self, ALuint srate) -{ - if(self->SampleRate != srate) - { - self->ClockBase += self->SamplesDone * MIDI_CLOCK_RES / self->SampleRate; - self->SamplesDone = 0; - self->SampleRate = srate; - } -} - -extern inline void MidiSynth_update(MidiSynth *self, ALCdevice *device); - -ALenum MidiSynth_insertEvent(MidiSynth *self, ALuint64 time, ALuint event, ALsizei param1, ALsizei param2) -{ - MidiEvent entry; - entry.time = time; - entry.event = event; - entry.param.val[0] = param1; - entry.param.val[1] = param2; - return InsertEvtQueue(&self->EventQueue, &entry); -} - -ALenum MidiSynth_insertSysExEvent(MidiSynth *self, ALuint64 time, const ALbyte *data, ALsizei size) -{ - MidiEvent entry; - ALenum err; - - entry.time = time; - entry.event = SYSEX_EVENT; - entry.param.sysex.size = size; - entry.param.sysex.data = malloc(size); - if(!entry.param.sysex.data) - return AL_OUT_OF_MEMORY; - memcpy(entry.param.sysex.data, data, size); - - err = InsertEvtQueue(&self->EventQueue, &entry); - if(err != AL_NO_ERROR) - free(entry.param.sysex.data); - return err; -} diff --git a/Alc/midi/base.h b/Alc/midi/base.h deleted file mode 100644 index 823e3802..00000000 --- a/Alc/midi/base.h +++ /dev/null @@ -1,133 +0,0 @@ -#ifndef AL_MIDI_BASE_H -#define AL_MIDI_BASE_H - -#include "alMain.h" -#include "atomic.h" -#include "evtqueue.h" - -#ifdef __cplusplus -extern "C" { -#endif - -struct ALsoundfont; - -typedef size_t (*ReaderCb)(void *ptr, size_t size, void *stream); -typedef struct Reader { - ReaderCb cb; - void *ptr; - int error; -} Reader; -inline size_t Reader_read(Reader *self, void *buf, size_t len) -{ - size_t got = (!self->error) ? self->cb(buf, len, self->ptr) : 0; - if(got < len) self->error = 1; - return got; -} -#define READERR(x_) ((x_)->error) - -ALboolean loadSf2(Reader *stream, struct ALsoundfont *sfont, ALCcontext *context); - - -#define MIDI_CLOCK_RES U64(1000000000) - - -struct MidiSynthVtable; - -typedef struct MidiSynth { - EvtQueue EventQueue; - - ALuint64 ClockBase; - ALuint SamplesDone; - ALuint SampleRate; - - /* NOTE: This rwlock is for the state and soundfont. The EventQueue and - * related must instead use the device lock as they're used in the mixer - * thread. - */ - RWLock Lock; - - struct ALsoundfont **Soundfonts; - ALsizei NumSoundfonts; - - volatile ALfloat Gain; - volatile ALenum State; - - const struct MidiSynthVtable *vtbl; -} MidiSynth; - -void MidiSynth_Construct(MidiSynth *self, ALCdevice *device); -void MidiSynth_Destruct(MidiSynth *self); -ALenum MidiSynth_selectSoundfonts(MidiSynth *self, ALCcontext *context, ALsizei count, const ALuint *ids); -inline void MidiSynth_setGain(MidiSynth *self, ALfloat gain) { self->Gain = gain; } -inline ALfloat MidiSynth_getGain(const MidiSynth *self) { return self->Gain; } -inline void MidiSynth_setState(MidiSynth *self, ALenum state) { self->State = state; } -inline ALenum MidiSynth_getState(const MidiSynth *self) { return self->State; } -void MidiSynth_stop(MidiSynth *self); -inline void MidiSynth_reset(MidiSynth *self) { MidiSynth_stop(self); } -inline ALuint64 MidiSynth_getTime(const MidiSynth *self) -{ return self->ClockBase + (self->SamplesDone*MIDI_CLOCK_RES/self->SampleRate); } -inline ALuint64 MidiSynth_getNextEvtTime(const MidiSynth *self) -{ - if(self->EventQueue.pos == self->EventQueue.size) - return UINT64_MAX; - return self->EventQueue.events[self->EventQueue.pos].time; -} -void MidiSynth_setSampleRate(MidiSynth *self, ALuint srate); -inline void MidiSynth_update(MidiSynth *self, ALCdevice *device) -{ MidiSynth_setSampleRate(self, device->Frequency); } -ALenum MidiSynth_insertEvent(MidiSynth *self, ALuint64 time, ALuint event, ALsizei param1, ALsizei param2); -ALenum MidiSynth_insertSysExEvent(MidiSynth *self, ALuint64 time, const ALbyte *data, ALsizei size); - - -struct MidiSynthVtable { - void (*const Destruct)(MidiSynth *self); - - ALenum (*const selectSoundfonts)(MidiSynth *self, ALCcontext *context, ALsizei count, const ALuint *ids); - - void (*const setGain)(MidiSynth *self, ALfloat gain); - - void (*const stop)(MidiSynth *self); - void (*const reset)(MidiSynth *self); - - void (*const update)(MidiSynth *self, ALCdevice *device); - void (*const process)(MidiSynth *self, ALuint samples, ALfloat (*restrict DryBuffer)[BUFFERSIZE], ALuint NumChannels); - - void (*const Delete)(void *ptr); -}; - -#define DEFINE_MIDISYNTH_VTABLE(T) \ -DECLARE_THUNK(T, MidiSynth, void, Destruct) \ -DECLARE_THUNK3(T, MidiSynth, ALenum, selectSoundfonts, ALCcontext*, ALsizei, const ALuint*) \ -DECLARE_THUNK1(T, MidiSynth, void, setGain, ALfloat) \ -DECLARE_THUNK(T, MidiSynth, void, stop) \ -DECLARE_THUNK(T, MidiSynth, void, reset) \ -DECLARE_THUNK1(T, MidiSynth, void, update, ALCdevice*) \ -DECLARE_THUNK3(T, MidiSynth, void, process, ALuint, ALfloatBUFFERSIZE*restrict, ALuint) \ -static void T##_MidiSynth_Delete(void *ptr) \ -{ T##_Delete(STATIC_UPCAST(T, MidiSynth, (MidiSynth*)ptr)); } \ - \ -static const struct MidiSynthVtable T##_MidiSynth_vtable = { \ - T##_MidiSynth_Destruct, \ - \ - T##_MidiSynth_selectSoundfonts, \ - T##_MidiSynth_setGain, \ - T##_MidiSynth_stop, \ - T##_MidiSynth_reset, \ - T##_MidiSynth_update, \ - T##_MidiSynth_process, \ - \ - T##_MidiSynth_Delete, \ -} - - -MidiSynth *SSynth_create(ALCdevice *device); -MidiSynth *FSynth_create(ALCdevice *device); -MidiSynth *DSynth_create(ALCdevice *device); - -MidiSynth *SynthCreate(ALCdevice *device); - -#ifdef __cplusplus -} -#endif - -#endif /* AL_MIDI_BASE_H */ diff --git a/Alc/midi/dummy.c b/Alc/midi/dummy.c deleted file mode 100644 index 23c0d2cb..00000000 --- a/Alc/midi/dummy.c +++ /dev/null @@ -1,76 +0,0 @@ - -#include "config.h" - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <limits.h> - -#include "alMain.h" -#include "alError.h" -#include "evtqueue.h" -#include "rwlock.h" -#include "alu.h" - -#include "midi/base.h" - -typedef struct DSynth { - DERIVE_FROM_TYPE(MidiSynth); -} DSynth; - -static void DSynth_Construct(DSynth *self, ALCdevice *device); -static DECLARE_FORWARD(DSynth, MidiSynth, void, Destruct) -static DECLARE_FORWARD3(DSynth, MidiSynth, ALenum, selectSoundfonts, ALCcontext*, ALsizei, const ALuint*) -static DECLARE_FORWARD1(DSynth, MidiSynth, void, setGain, ALfloat) -static DECLARE_FORWARD(DSynth, MidiSynth, void, stop) -static DECLARE_FORWARD(DSynth, MidiSynth, void, reset) -static DECLARE_FORWARD1(DSynth, MidiSynth, void, update, ALCdevice*) -static void DSynth_process(DSynth *self, ALuint SamplesToDo, ALfloat (*restrict DryBuffer)[BUFFERSIZE], ALuint NumChannels); -DECLARE_DEFAULT_ALLOCATORS(DSynth) -DEFINE_MIDISYNTH_VTABLE(DSynth); - - -static void DSynth_Construct(DSynth *self, ALCdevice *device) -{ - MidiSynth_Construct(STATIC_CAST(MidiSynth, self), device); - SET_VTABLE2(DSynth, MidiSynth, self); -} - - -static void DSynth_processQueue(DSynth *self, ALuint64 time) -{ - EvtQueue *queue = &STATIC_CAST(MidiSynth, self)->EventQueue; - - while(queue->pos < queue->size && queue->events[queue->pos].time <= time) - queue->pos++; -} - -static void DSynth_process(DSynth *self, ALuint SamplesToDo, ALfloatBUFFERSIZE*restrict UNUSED(DryBuffer), ALuint UNUSED(NumChannels)) -{ - MidiSynth *synth = STATIC_CAST(MidiSynth, self); - ALuint64 curtime; - - if(synth->State != AL_PLAYING) - return; - - synth->SamplesDone += SamplesToDo; - synth->ClockBase += (synth->SamplesDone/synth->SampleRate) * MIDI_CLOCK_RES; - synth->SamplesDone %= synth->SampleRate; - - curtime = MidiSynth_getTime(synth); - DSynth_processQueue(self, maxi64(curtime-1, 0)); -} - - -MidiSynth *DSynth_create(ALCdevice *device) -{ - DSynth *synth; - - NEW_OBJ(synth, DSynth)(device); - if(!synth) - { - ERR("Failed to allocate DSynth\n"); - return NULL; - } - return STATIC_CAST(MidiSynth, synth); -} diff --git a/Alc/midi/fluidsynth.c b/Alc/midi/fluidsynth.c deleted file mode 100644 index 2236c812..00000000 --- a/Alc/midi/fluidsynth.c +++ /dev/null @@ -1,934 +0,0 @@ - -#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 "alu.h" -#include "compat.h" -#include "evtqueue.h" -#include "rwlock.h" - -#ifdef HAVE_FLUIDSYNTH - -#include <fluidsynth.h> - - -#ifdef HAVE_DYNLOAD -#define FLUID_FUNCS(MAGIC) \ - MAGIC(new_fluid_synth); \ - MAGIC(delete_fluid_synth); \ - MAGIC(new_fluid_settings); \ - MAGIC(delete_fluid_settings); \ - MAGIC(fluid_settings_setint); \ - MAGIC(fluid_settings_setnum); \ - MAGIC(fluid_synth_noteon); \ - MAGIC(fluid_synth_noteoff); \ - MAGIC(fluid_synth_program_change); \ - MAGIC(fluid_synth_pitch_bend); \ - MAGIC(fluid_synth_channel_pressure); \ - MAGIC(fluid_synth_cc); \ - MAGIC(fluid_synth_sysex); \ - MAGIC(fluid_synth_bank_select); \ - MAGIC(fluid_synth_set_channel_type); \ - MAGIC(fluid_synth_all_sounds_off); \ - MAGIC(fluid_synth_system_reset); \ - MAGIC(fluid_synth_set_gain); \ - MAGIC(fluid_synth_set_sample_rate); \ - MAGIC(fluid_synth_write_float); \ - MAGIC(fluid_synth_add_sfloader); \ - MAGIC(fluid_synth_sfload); \ - MAGIC(fluid_synth_sfunload); \ - MAGIC(fluid_synth_alloc_voice); \ - MAGIC(fluid_synth_start_voice); \ - MAGIC(fluid_voice_gen_set); \ - MAGIC(fluid_voice_add_mod); \ - MAGIC(fluid_mod_set_source1); \ - MAGIC(fluid_mod_set_source2); \ - MAGIC(fluid_mod_set_amount); \ - MAGIC(fluid_mod_set_dest); - -void *fsynth_handle = NULL; -#define DECL_FUNC(x) __typeof(x) *p##x -FLUID_FUNCS(DECL_FUNC) -#undef DECL_FUNC - -#define new_fluid_synth pnew_fluid_synth -#define delete_fluid_synth pdelete_fluid_synth -#define new_fluid_settings pnew_fluid_settings -#define delete_fluid_settings pdelete_fluid_settings -#define fluid_settings_setint pfluid_settings_setint -#define fluid_settings_setnum pfluid_settings_setnum -#define fluid_synth_noteon pfluid_synth_noteon -#define fluid_synth_noteoff pfluid_synth_noteoff -#define fluid_synth_program_change pfluid_synth_program_change -#define fluid_synth_pitch_bend pfluid_synth_pitch_bend -#define fluid_synth_channel_pressure pfluid_synth_channel_pressure -#define fluid_synth_cc pfluid_synth_cc -#define fluid_synth_sysex pfluid_synth_sysex -#define fluid_synth_bank_select pfluid_synth_bank_select -#define fluid_synth_set_channel_type pfluid_synth_set_channel_type -#define fluid_synth_all_sounds_off pfluid_synth_all_sounds_off -#define fluid_synth_system_reset pfluid_synth_system_reset -#define fluid_synth_set_gain pfluid_synth_set_gain -#define fluid_synth_set_sample_rate pfluid_synth_set_sample_rate -#define fluid_synth_write_float pfluid_synth_write_float -#define fluid_synth_add_sfloader pfluid_synth_add_sfloader -#define fluid_synth_sfload pfluid_synth_sfload -#define fluid_synth_sfunload pfluid_synth_sfunload -#define fluid_synth_alloc_voice pfluid_synth_alloc_voice -#define fluid_synth_start_voice pfluid_synth_start_voice -#define fluid_voice_gen_set pfluid_voice_gen_set -#define fluid_voice_add_mod pfluid_voice_add_mod -#define fluid_mod_set_source1 pfluid_mod_set_source1 -#define fluid_mod_set_source2 pfluid_mod_set_source2 -#define fluid_mod_set_amount pfluid_mod_set_amount -#define fluid_mod_set_dest pfluid_mod_set_dest - -static ALboolean LoadFSynth(void) -{ - ALboolean ret = AL_TRUE; - if(!fsynth_handle) - { - fsynth_handle = LoadLib("libfluidsynth.so.1"); - if(!fsynth_handle) return AL_FALSE; - -#define LOAD_FUNC(x) do { \ - p##x = GetSymbol(fsynth_handle, #x); \ - if(!p##x) ret = AL_FALSE; \ -} while(0) - FLUID_FUNCS(LOAD_FUNC) -#undef LOAD_FUNC - - if(ret == AL_FALSE) - { - CloseLib(fsynth_handle); - fsynth_handle = NULL; - } - } - return ret; -} -#else -static inline ALboolean LoadFSynth(void) { return AL_TRUE; } -#endif - - -/* MIDI events */ -#define SYSEX_EVENT (0xF0) - -/* MIDI controllers */ -#define CTRL_BANKSELECT_MSB (0) -#define CTRL_BANKSELECT_LSB (32) -#define CTRL_ALLNOTESOFF (123) - - -static int getModInput(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 getModFlags(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 getModDest(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) -{ - fluid_sample_t *sample = STATIC_CAST(fluid_sample_t, self); - ALbuffer *buffer = ATOMIC_LOAD(&sound->Buffer); - - 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 = !!buffer; - sample->data = buffer ? buffer->data : NULL; - - 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*4, sizeof(fluid_mod_t[4])); - if(self->Mods) - { - ALsizei i, j, k; - - for(i = j = 0;i < sound->ModulatorMap.size;i++) - { - ALsfmodulator *mod = sound->ModulatorMap.array[i].value; - for(k = 0;k < 4;k++,mod++) - { - if(mod->Dest == AL_NONE) - continue; - fluid_mod_set_source1(&self->Mods[j], getModInput(mod->Source[0].Input), - getModFlags(mod->Source[0].Input, mod->Source[0].Type, - mod->Source[0].Form)); - fluid_mod_set_source2(&self->Mods[j], getModInput(mod->Source[1].Input), - getModFlags(mod->Source[1].Input, mod->Source[1].Type, - mod->Source[1].Form)); - fluid_mod_set_amount(&self->Mods[j], mod->Amount); - fluid_mod_set_dest(&self->Mods[j], getModDest(mod->Dest)); - self->Mods[j++].next = NULL; - } - } - self->NumMods = j; - } -} - -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) -{ - 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]); - } -} - -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)); - } -} - -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_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], ALuint NumChannels); -DECLARE_DEFAULT_ALLOCATORS(FSynth) -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(NULL, "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 = self->FontIDs; - count = self->NumFontIDs; - self->FontIDs = NULL; - 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_stop(FSynth *self) -{ - MidiSynth *synth = STATIC_CAST(MidiSynth, self); - ALuint64 curtime; - ALsizei chan; - - /* Make sure all pending events are processed. */ - curtime = MidiSynth_getTime(synth); - FSynth_processQueue(self, curtime); - - /* 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], ALuint NumChannels) -{ - MidiSynth *synth = STATIC_CAST(MidiSynth, self); - ALfloat *LeftBuffer = DryBuffer[0]; - ALfloat *RightBuffer = DryBuffer[(NumChannels > 1) ? 1 : 0]; - ALenum state = synth->State; - ALuint64 curtime; - ALuint total = 0; - - if(state == AL_INITIAL) - return; - if(state != AL_PLAYING) - { - fluid_synth_write_float(self->Synth, SamplesToDo, LeftBuffer, 0, 1, - RightBuffer, 0, 1); - return; - } - - curtime = MidiSynth_getTime(synth); - while(total < SamplesToDo) - { - ALuint64 time, diff; - ALint tonext; - - time = MidiSynth_getNextEvtTime(synth); - diff = maxu64(time, curtime) - curtime; - if(diff >= MIDI_CLOCK_RES || time == UINT64_MAX) - { - /* If there's no pending event, or if it's more than 1 second - * away, do as many samples as we can. */ - tonext = INT_MAX; - } - else - { - /* Figure out how many samples until the next event. */ - tonext = (ALint)((diff*synth->SampleRate + (MIDI_CLOCK_RES-1)) / MIDI_CLOCK_RES); - tonext -= total; - } - - if(tonext > 0) - { - ALuint todo = minu(tonext, SamplesToDo-total); - fluid_synth_write_float(self->Synth, todo, LeftBuffer, total, 1, - RightBuffer, total, 1); - total += todo; - tonext -= todo; - } - if(total < SamplesToDo && tonext <= 0) - FSynth_processQueue(self, time); - } - - synth->SamplesDone += SamplesToDo; - synth->ClockBase += (synth->SamplesDone/synth->SampleRate) * MIDI_CLOCK_RES; - synth->SamplesDone %= synth->SampleRate; -} - - -MidiSynth *FSynth_create(ALCdevice *device) -{ - FSynth *synth; - - if(!LoadFSynth()) - return NULL; - - NEW_OBJ(synth, FSynth)(device); - if(!synth) - { - ERR("Failed to allocate FSynth\n"); - return NULL; - } - - 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 diff --git a/Alc/midi/sf2load.c b/Alc/midi/sf2load.c deleted file mode 100644 index 31f6ee02..00000000 --- a/Alc/midi/sf2load.c +++ /dev/null @@ -1,1373 +0,0 @@ - -#include "config.h" - -#include <stdio.h> -#include <stdlib.h> - -#include "alMain.h" -#include "alMidi.h" -#include "alError.h" -#include "alu.h" - -#include "midi/base.h" - - -static ALuint read_le32(Reader *stream) -{ - ALubyte buf[4]; - if(Reader_read(stream, buf, 4) != 4) - return 0; - return (buf[3]<<24) | (buf[2]<<16) | (buf[1]<<8) | buf[0]; -} -static ALushort read_le16(Reader *stream) -{ - ALubyte buf[2]; - if(Reader_read(stream, buf, 2) != 2) - return 0; - return (buf[1]<<8) | buf[0]; -} -static ALubyte read_8(Reader *stream) -{ - ALubyte buf[1]; - if(Reader_read(stream, buf, 1) != 1) - return 0; - return buf[0]; -} -static void skip(Reader *stream, ALuint amt) -{ - while(amt > 0 && !READERR(stream)) - { - char buf[4096]; - amt -= Reader_read(stream, buf, minu(sizeof(buf), amt)); - } -} - -typedef struct Generator { - ALushort mGenerator; - ALushort mAmount; -} Generator; -static void Generator_read(Generator *self, Reader *stream) -{ - self->mGenerator = read_le16(stream); - self->mAmount = read_le16(stream); -} - -static const ALint DefaultGenValue[60] = { - 0, /* 0 - startAddrOffset */ - 0, /* 1 - endAddrOffset */ - 0, /* 2 - startloopAddrOffset */ - 0, /* 3 - endloopAddrOffset */ - 0, /* 4 - startAddrCoarseOffset */ - 0, /* 5 - modLfoToPitch */ - 0, /* 6 - vibLfoToPitch */ - 0, /* 7 - modEnvToPitch */ - 13500, /* 8 - initialFilterFc */ - 0, /* 9 - initialFilterQ */ - 0, /* 10 - modLfoToFilterFc */ - 0, /* 11 - modEnvToFilterFc */ - 0, /* 12 - endAddrCoarseOffset */ - 0, /* 13 - modLfoToVolume */ - 0, /* 14 - */ - 0, /* 15 - chorusEffectsSend */ - 0, /* 16 - reverbEffectsSend */ - 0, /* 17 - pan */ - 0, /* 18 - */ - 0, /* 19 - */ - 0, /* 20 - */ - -12000, /* 21 - delayModLFO */ - 0, /* 22 - freqModLFO */ - -12000, /* 23 - delayVibLFO */ - 0, /* 24 - freqVibLFO */ - -12000, /* 25 - delayModEnv */ - -12000, /* 26 - attackModEnv */ - -12000, /* 27 - holdModEnv */ - -12000, /* 28 - decayModEnv */ - 0, /* 29 - sustainModEnv */ - -12000, /* 30 - releaseModEnv */ - 0, /* 31 - keynumToModEnvHold */ - 0, /* 32 - keynumToModEnvDecay */ - -12000, /* 33 - delayVolEnv */ - -12000, /* 34 - attackVolEnv */ - -12000, /* 35 - holdVolEnv */ - -12000, /* 36 - decayVolEnv */ - 0, /* 37 - sustainVolEnv */ - -12000, /* 38 - releaseVolEnv */ - 0, /* 39 - keynumToVolEnvHold */ - 0, /* 40 - keynumToVolEnvDecay */ - 0, /* 41 - */ - 0, /* 42 - */ - 0, /* 43 - keyRange */ - 0, /* 44 - velRange */ - 0, /* 45 - startloopAddrCoarseOffset */ - 0, /* 46 - keynum */ - 0, /* 47 - velocity */ - 0, /* 48 - initialAttenuation */ - 0, /* 49 - */ - 0, /* 50 - endloopAddrCoarseOffset */ - 0, /* 51 - corseTune */ - 0, /* 52 - fineTune */ - 0, /* 53 - */ - 0, /* 54 - sampleModes */ - 0, /* 55 - */ - 100, /* 56 - scaleTuning */ - 0, /* 57 - exclusiveClass */ - 0, /* 58 - overridingRootKey */ - 0, /* 59 - */ -}; - -typedef struct Modulator { - ALushort mSrcOp; - ALushort mDstOp; - ALshort mAmount; - ALushort mAmtSrcOp; - ALushort mTransOp; -} Modulator; -static void Modulator_read(Modulator *self, Reader *stream) -{ - self->mSrcOp = read_le16(stream); - self->mDstOp = read_le16(stream); - self->mAmount = read_le16(stream); - self->mAmtSrcOp = read_le16(stream); - self->mTransOp = read_le16(stream); -} - -typedef struct Zone { - ALushort mGenIdx; - ALushort mModIdx; -} Zone; -static void Zone_read(Zone *self, Reader *stream) -{ - self->mGenIdx = read_le16(stream); - self->mModIdx = read_le16(stream); -} - -typedef struct PresetHeader { - ALchar mName[20]; - ALushort mPreset; /* MIDI program number */ - ALushort mBank; - ALushort mZoneIdx; - ALuint mLibrary; - ALuint mGenre; - ALuint mMorphology; -} PresetHeader; -static void PresetHeader_read(PresetHeader *self, Reader *stream) -{ - Reader_read(stream, self->mName, sizeof(self->mName)); - self->mPreset = read_le16(stream); - self->mBank = read_le16(stream); - self->mZoneIdx = read_le16(stream); - self->mLibrary = read_le32(stream); - self->mGenre = read_le32(stream); - self->mMorphology = read_le32(stream); -} - -typedef struct InstrumentHeader { - ALchar mName[20]; - ALushort mZoneIdx; -} InstrumentHeader; -static void InstrumentHeader_read(InstrumentHeader *self, Reader *stream) -{ - Reader_read(stream, self->mName, sizeof(self->mName)); - self->mZoneIdx = read_le16(stream); -} - -typedef struct SampleHeader { - ALchar mName[20]; - ALuint mStart; - ALuint mEnd; - ALuint mStartloop; - ALuint mEndloop; - ALuint mSampleRate; - ALubyte mOriginalKey; - ALbyte mCorrection; - ALushort mSampleLink; - ALushort mSampleType; -} SampleHeader; -static void SampleHeader_read(SampleHeader *self, Reader *stream) -{ - Reader_read(stream, self->mName, sizeof(self->mName)); - self->mStart = read_le32(stream); - self->mEnd = read_le32(stream); - self->mStartloop = read_le32(stream); - self->mEndloop = read_le32(stream); - self->mSampleRate = read_le32(stream); - self->mOriginalKey = read_8(stream); - self->mCorrection = read_8(stream); - self->mSampleLink = read_le16(stream); - self->mSampleType = read_le16(stream); -} - - -typedef struct Soundfont { - ALuint ifil; - ALchar *irom; - - PresetHeader *phdr; - ALsizei phdr_size; - - Zone *pbag; - ALsizei pbag_size; - Modulator *pmod; - ALsizei pmod_size; - Generator *pgen; - ALsizei pgen_size; - - InstrumentHeader *inst; - ALsizei inst_size; - - Zone *ibag; - ALsizei ibag_size; - Modulator *imod; - ALsizei imod_size; - Generator *igen; - ALsizei igen_size; - - SampleHeader *shdr; - ALsizei shdr_size; -} Soundfont; - -static void Soundfont_Construct(Soundfont *self) -{ - self->ifil = 0; - self->irom = NULL; - - self->phdr = NULL; - self->phdr_size = 0; - - self->pbag = NULL; - self->pbag_size = 0; - self->pmod = NULL; - self->pmod_size = 0; - self->pgen = NULL; - self->pgen_size = 0; - - self->inst = NULL; - self->inst_size = 0; - - self->ibag = NULL; - self->ibag_size = 0; - self->imod = NULL; - self->imod_size = 0; - self->igen = NULL; - self->igen_size = 0; - - self->shdr = NULL; - self->shdr_size = 0; -} - -static void Soundfont_Destruct(Soundfont *self) -{ - free(self->irom); - self->irom = NULL; - - free(self->phdr); - self->phdr = NULL; - self->phdr_size = 0; - - free(self->pbag); - self->pbag = NULL; - self->pbag_size = 0; - free(self->pmod); - self->pmod = NULL; - self->pmod_size = 0; - free(self->pgen); - self->pgen = NULL; - self->pgen_size = 0; - - free(self->inst); - self->inst = NULL; - self->inst_size = 0; - - free(self->ibag); - self->ibag = NULL; - self->ibag_size = 0; - free(self->imod); - self->imod = NULL; - self->imod_size = 0; - free(self->igen); - self->igen = NULL; - self->igen_size = 0; - - free(self->shdr); - self->shdr = NULL; - self->shdr_size = 0; -} - - -#define FOURCC(a,b,c,d) ((a) | ((b)<<8) | ((c)<<16) | ((d)<<24)) -#define FOURCCFMT "%c%c%c%c" -#define FOURCCARGS(x) (char)((x)&0xff), (char)(((x)>>8)&0xff), (char)(((x)>>16)&0xff), (char)(((x)>>24)&0xff) -typedef struct RiffHdr { - ALuint mCode; - ALuint mSize; -} RiffHdr; -static void RiffHdr_read(RiffHdr *self, Reader *stream) -{ - self->mCode = read_le32(stream); - self->mSize = read_le32(stream); -} - - -typedef struct GenModList { - VECTOR(Generator) gens; - VECTOR(Modulator) mods; -} GenModList; - -static void GenModList_Construct(GenModList *self) -{ - VECTOR_INIT(self->gens); - VECTOR_INIT(self->mods); -} - -static void GenModList_Destruct(GenModList *self) -{ - VECTOR_DEINIT(self->mods); - VECTOR_DEINIT(self->gens); -} - -static GenModList GenModList_clone(const GenModList *self) -{ - GenModList ret; - - GenModList_Construct(&ret); - - VECTOR_INSERT(ret.gens, VECTOR_ITER_END(ret.gens), - VECTOR_ITER_BEGIN(self->gens), VECTOR_ITER_END(self->gens) - ); - VECTOR_INSERT(ret.mods, VECTOR_ITER_END(ret.mods), - VECTOR_ITER_BEGIN(self->mods), VECTOR_ITER_END(self->mods) - ); - - return ret; -} - -static void GenModList_insertGen(GenModList *self, const Generator *gen, ALboolean ispreset) -{ - Generator *i; -#define MATCH_GENERATOR(i) ((i)->mGenerator == gen->mGenerator) - VECTOR_FIND_IF(i, Generator, self->gens, MATCH_GENERATOR); - if(i != VECTOR_ITER_END(self->gens)) - { - i->mAmount = gen->mAmount; - return; - } -#undef MATCH_GENERATOR - - if(ispreset && - (gen->mGenerator == 0 || gen->mGenerator == 1 || gen->mGenerator == 2 || - gen->mGenerator == 3 || gen->mGenerator == 4 || gen->mGenerator == 12 || - gen->mGenerator == 45 || gen->mGenerator == 46 || gen->mGenerator == 47 || - gen->mGenerator == 50 || gen->mGenerator == 54 || gen->mGenerator == 57 || - gen->mGenerator == 58)) - return; - - if(VECTOR_PUSH_BACK(self->gens, *gen) == AL_FALSE) - { - ERR("Failed to insert generator (from "SZFMT" elements)\n", VECTOR_SIZE(self->gens)); - return; - } -} -static void GenModList_accumGen(GenModList *self, const Generator *gen) -{ - Generator *i; -#define MATCH_GENERATOR(i) ((i)->mGenerator == gen->mGenerator) - VECTOR_FIND_IF(i, Generator, self->gens, MATCH_GENERATOR); - if(i != VECTOR_ITER_END(self->gens)) - { - if(gen->mGenerator == 43 || gen->mGenerator == 44) - { - /* Range generators accumulate by taking the intersection of the - * two ranges. - */ - ALushort low = maxu(i->mAmount&0x00ff, gen->mAmount&0x00ff); - ALushort high = minu(i->mAmount&0xff00, gen->mAmount&0xff00); - i->mAmount = low | high; - } - else - i->mAmount += gen->mAmount; - return; - } -#undef MATCH_GENERATOR - - if(VECTOR_PUSH_BACK(self->gens, *gen) == AL_FALSE) - { - ERR("Failed to insert generator (from "SZFMT" elements)\n", VECTOR_SIZE(self->gens)); - return; - } - if(gen->mGenerator < 60) - VECTOR_BACK(self->gens).mAmount += DefaultGenValue[gen->mGenerator]; -} - -static void GenModList_insertMod(GenModList *self, const Modulator *mod) -{ - Modulator *i; -#define MATCH_MODULATOR(i) ((i)->mDstOp == mod->mDstOp && (i)->mSrcOp == mod->mSrcOp && \ - (i)->mAmtSrcOp == mod->mAmtSrcOp && (i)->mTransOp == mod->mTransOp) - VECTOR_FIND_IF(i, Modulator, self->mods, MATCH_MODULATOR); - if(i != VECTOR_ITER_END(self->mods)) - { - i->mAmount = mod->mAmount; - return; - } -#undef MATCH_MODULATOR - - if(VECTOR_PUSH_BACK(self->mods, *mod) == AL_FALSE) - { - ERR("Failed to insert modulator (from "SZFMT" elements)\n", VECTOR_SIZE(self->mods)); - return; - } -} -static void GenModList_accumMod(GenModList *self, const Modulator *mod) -{ - Modulator *i; -#define MATCH_MODULATOR(i) ((i)->mDstOp == mod->mDstOp && (i)->mSrcOp == mod->mSrcOp && \ - (i)->mAmtSrcOp == mod->mAmtSrcOp && (i)->mTransOp == mod->mTransOp) - VECTOR_FIND_IF(i, Modulator, self->mods, MATCH_MODULATOR); - if(i != VECTOR_ITER_END(self->mods)) - { - i->mAmount += mod->mAmount; - return; - } -#undef MATCH_MODULATOR - - if(VECTOR_PUSH_BACK(self->mods, *mod) == AL_FALSE) - { - ERR("Failed to insert modulator (from "SZFMT" elements)\n", VECTOR_SIZE(self->mods)); - return; - } - - if(mod->mSrcOp == 0x0502 && mod->mDstOp == 48 && mod->mAmtSrcOp == 0 && mod->mTransOp == 0) - VECTOR_BACK(self->mods).mAmount += 960; - else if(mod->mSrcOp == 0x0102 && mod->mDstOp == 8 && mod->mAmtSrcOp == 0 && mod->mTransOp == 0) - VECTOR_BACK(self->mods).mAmount += -2400; - else if(mod->mSrcOp == 0x000D && mod->mDstOp == 6 && mod->mAmtSrcOp == 0 && mod->mTransOp == 0) - VECTOR_BACK(self->mods).mAmount += 50; - else if(mod->mSrcOp == 0x0081 && mod->mDstOp == 6 && mod->mAmtSrcOp == 0 && mod->mTransOp == 0) - VECTOR_BACK(self->mods).mAmount += 50; - else if(mod->mSrcOp == 0x0582 && mod->mDstOp == 48 && mod->mAmtSrcOp == 0 && mod->mTransOp == 0) - VECTOR_BACK(self->mods).mAmount += 960; - else if(mod->mSrcOp == 0x028A && mod->mDstOp == 17 && mod->mAmtSrcOp == 0 && mod->mTransOp == 0) - VECTOR_BACK(self->mods).mAmount += 1000; - else if(mod->mSrcOp == 0x058B && mod->mDstOp == 48 && mod->mAmtSrcOp == 0 && mod->mTransOp == 0) - VECTOR_BACK(self->mods).mAmount += 960; - else if(mod->mSrcOp == 0x00DB && mod->mDstOp == 16 && mod->mAmtSrcOp == 0 && mod->mTransOp == 0) - VECTOR_BACK(self->mods).mAmount += 200; - else if(mod->mSrcOp == 0x00DD && mod->mDstOp == 15 && mod->mAmtSrcOp == 0 && mod->mTransOp == 0) - VECTOR_BACK(self->mods).mAmount += 200; - /*else if(mod->mSrcOp == 0x020E && mod->mDstOp == ?initialpitch? && mod->mAmtSrcOp == 0x0010 && mod->mTransOp == 0) - VECTOR_BACK(self->mods).mAmount += 12700;*/ -} - - -#define ERROR_GOTO(lbl_, ...) do { \ - ERR(__VA_ARGS__); \ - goto lbl_; \ -} while(0) - -static ALboolean ensureFontSanity(const Soundfont *sfont) -{ - ALsizei i; - - for(i = 0;i < sfont->phdr_size;i++) - { - if(sfont->phdr[i].mZoneIdx >= sfont->pbag_size) - { - WARN("Preset %d has invalid zone index %d (max: %d)\n", i, - sfont->phdr[i].mZoneIdx, sfont->pbag_size); - return AL_FALSE; - } - if(i+1 < sfont->phdr_size && sfont->phdr[i+1].mZoneIdx < sfont->phdr[i].mZoneIdx) - { - WARN("Preset %d has invalid zone index (%d does not follow %d)\n", i+1, - sfont->phdr[i+1].mZoneIdx, sfont->phdr[i].mZoneIdx); - return AL_FALSE; - } - } - - for(i = 0;i < sfont->pbag_size;i++) - { - if(sfont->pbag[i].mGenIdx >= sfont->pgen_size) - { - WARN("Preset zone %d has invalid generator index %d (max: %d)\n", i, - sfont->pbag[i].mGenIdx, sfont->pgen_size); - return AL_FALSE; - } - if(i+1 < sfont->pbag_size && sfont->pbag[i+1].mGenIdx < sfont->pbag[i].mGenIdx) - { - WARN("Preset zone %d has invalid generator index (%d does not follow %d)\n", i+1, - sfont->pbag[i+1].mGenIdx, sfont->pbag[i].mGenIdx); - return AL_FALSE; - } - if(sfont->pbag[i].mModIdx >= sfont->pmod_size) - { - WARN("Preset zone %d has invalid modulator index %d (max: %d)\n", i, - sfont->pbag[i].mModIdx, sfont->pmod_size); - return AL_FALSE; - } - if(i+1 < sfont->pbag_size && sfont->pbag[i+1].mModIdx < sfont->pbag[i].mModIdx) - { - WARN("Preset zone %d has invalid modulator index (%d does not follow %d)\n", i+1, - sfont->pbag[i+1].mModIdx, sfont->pbag[i].mModIdx); - return AL_FALSE; - } - } - - - for(i = 0;i < sfont->inst_size;i++) - { - if(sfont->inst[i].mZoneIdx >= sfont->ibag_size) - { - WARN("Instrument %d has invalid zone index %d (max: %d)\n", i, - sfont->inst[i].mZoneIdx, sfont->ibag_size); - return AL_FALSE; - } - if(i+1 < sfont->inst_size && sfont->inst[i+1].mZoneIdx < sfont->inst[i].mZoneIdx) - { - WARN("Instrument %d has invalid zone index (%d does not follow %d)\n", i+1, - sfont->inst[i+1].mZoneIdx, sfont->inst[i].mZoneIdx); - return AL_FALSE; - } - } - - for(i = 0;i < sfont->ibag_size;i++) - { - if(sfont->ibag[i].mGenIdx >= sfont->igen_size) - { - WARN("Instrument zone %d has invalid generator index %d (max: %d)\n", i, - sfont->ibag[i].mGenIdx, sfont->igen_size); - return AL_FALSE; - } - if(i+1 < sfont->ibag_size && sfont->ibag[i+1].mGenIdx < sfont->ibag[i].mGenIdx) - { - WARN("Instrument zone %d has invalid generator index (%d does not follow %d)\n", i+1, - sfont->ibag[i+1].mGenIdx, sfont->ibag[i].mGenIdx); - return AL_FALSE; - } - if(sfont->ibag[i].mModIdx >= sfont->imod_size) - { - WARN("Instrument zone %d has invalid modulator index %d (max: %d)\n", i, - sfont->ibag[i].mModIdx, sfont->imod_size); - return AL_FALSE; - } - if(i+1 < sfont->ibag_size && sfont->ibag[i+1].mModIdx < sfont->ibag[i].mModIdx) - { - WARN("Instrument zone %d has invalid modulator index (%d does not follow %d)\n", i+1, - sfont->ibag[i+1].mModIdx, sfont->ibag[i].mModIdx); - return AL_FALSE; - } - } - - - for(i = 0;i < sfont->shdr_size-1;i++) - { - if((sfont->shdr[i].mSampleType&0x8000) && sfont->irom == NULL) - { - WARN("Sample header %d has ROM sample type without an irom sub-chunk\n", i); - return AL_FALSE; - } - } - - - return AL_TRUE; -} - -static ALboolean checkZone(const GenModList *zone, const PresetHeader *preset, const InstrumentHeader *inst, const SampleHeader *samp) -{ - Generator *gen = VECTOR_ITER_BEGIN(zone->gens); - Generator *gen_end = VECTOR_ITER_END(zone->gens); - for(;gen != gen_end;gen++) - { - if(gen->mGenerator == 43 || gen->mGenerator == 44) - { - int high = gen->mAmount>>8; - int low = gen->mAmount&0xff; - - if(!(low >= 0 && high <= 127 && high >= low)) - { - TRACE("Preset \"%s\", inst \"%s\", sample \"%s\": invalid %s range %d...%d\n", - preset->mName, inst->mName, samp->mName, - (gen->mGenerator == 43) ? "key" : - (gen->mGenerator == 44) ? "velocity" : "(unknown)", - low, high); - return AL_FALSE; - } - } - } - - return AL_TRUE; -} - -static ALenum getModSrcInput(int input) -{ - if(input == 0) return AL_ONE_SOFT; - if(input == 2) return AL_NOTEON_VELOCITY_SOFT; - if(input == 3) return AL_NOTEON_KEY_SOFT; - if(input == 10) return AL_KEYPRESSURE_SOFT; - if(input == 13) return AL_CHANNELPRESSURE_SOFT; - if(input == 14) return AL_PITCHBEND_SOFT; - if(input == 16) return AL_PITCHBEND_SENSITIVITY_SOFT; - if((input&0x80)) - { - if(IsValidCtrlInput(input^0x80)) - return input^0x80; - } - ERR("Unhandled modulator source input: 0x%02x\n", input); - return AL_INVALID; -} - -static ALenum getModSrcType(int type) -{ - if(type == 0x0000) return AL_UNORM_SOFT; - if(type == 0x0100) return AL_UNORM_REV_SOFT; - if(type == 0x0200) return AL_SNORM_SOFT; - if(type == 0x0300) return AL_SNORM_REV_SOFT; - ERR("Unhandled modulator source type: 0x%04x\n", type); - return AL_INVALID; -} - -static ALenum getModSrcForm(int form) -{ - if(form == 0x0000) return AL_LINEAR_SOFT; - if(form == 0x0400) return AL_CONCAVE_SOFT; - if(form == 0x0800) return AL_CONVEX_SOFT; - if(form == 0x0C00) return AL_SWITCH_SOFT; - ERR("Unhandled modulator source form: 0x%04x\n", form); - return AL_INVALID; -} - -static ALenum getModTransOp(int op) -{ - if(op == 0) return AL_LINEAR_SOFT; - if(op == 2) return AL_ABSOLUTE_SOFT; - ERR("Unhandled modulator transform op: 0x%04x\n", op); - return AL_INVALID; -} - -static ALenum getLoopMode(int mode) -{ - if(mode == 0) return AL_NONE; - if(mode == 1) return AL_LOOP_CONTINUOUS_SOFT; - if(mode == 3) return AL_LOOP_UNTIL_RELEASE_SOFT; - ERR("Unhandled loop mode: %d\n", mode); - return AL_NONE; -} - -static ALenum getSampleType(int type) -{ - if(type == 1) return AL_MONO_SOFT; - if(type == 2) return AL_RIGHT_SOFT; - if(type == 4) return AL_LEFT_SOFT; - if(type == 8) - { - WARN("Sample type \"linked\" ignored; pretending mono\n"); - return AL_MONO_SOFT; - } - ERR("Unhandled sample type: 0x%04x\n", type); - return AL_MONO_SOFT; -} - -static void fillZone(ALfontsound *sound, ALCcontext *context, const GenModList *zone) -{ - static const ALenum Gen2Param[60] = { - 0, /* 0 - startAddrOffset */ - 0, /* 1 - endAddrOffset */ - 0, /* 2 - startloopAddrOffset */ - 0, /* 3 - endloopAddrOffset */ - 0, /* 4 - startAddrCoarseOffset */ - AL_MOD_LFO_TO_PITCH_SOFT, /* 5 - modLfoToPitch */ - AL_VIBRATO_LFO_TO_PITCH_SOFT, /* 6 - vibLfoToPitch */ - AL_MOD_ENV_TO_PITCH_SOFT, /* 7 - modEnvToPitch */ - AL_FILTER_CUTOFF_SOFT, /* 8 - initialFilterFc */ - AL_FILTER_RESONANCE_SOFT, /* 9 - initialFilterQ */ - AL_MOD_LFO_TO_FILTER_CUTOFF_SOFT, /* 10 - modLfoToFilterFc */ - AL_MOD_ENV_TO_FILTER_CUTOFF_SOFT, /* 11 - modEnvToFilterFc */ - 0, /* 12 - endAddrCoarseOffset */ - AL_MOD_LFO_TO_VOLUME_SOFT, /* 13 - modLfoToVolume */ - 0, /* 14 - */ - AL_CHORUS_SEND_SOFT, /* 15 - chorusEffectsSend */ - AL_REVERB_SEND_SOFT, /* 16 - reverbEffectsSend */ - AL_PAN_SOFT, /* 17 - pan */ - 0, /* 18 - */ - 0, /* 19 - */ - 0, /* 20 - */ - AL_MOD_LFO_DELAY_SOFT, /* 21 - delayModLFO */ - AL_MOD_LFO_FREQUENCY_SOFT, /* 22 - freqModLFO */ - AL_VIBRATO_LFO_DELAY_SOFT, /* 23 - delayVibLFO */ - AL_VIBRATO_LFO_FREQUENCY_SOFT, /* 24 - freqVibLFO */ - AL_MOD_ENV_DELAYTIME_SOFT, /* 25 - delayModEnv */ - AL_MOD_ENV_ATTACKTIME_SOFT, /* 26 - attackModEnv */ - AL_MOD_ENV_HOLDTIME_SOFT, /* 27 - holdModEnv */ - AL_MOD_ENV_DECAYTIME_SOFT, /* 28 - decayModEnv */ - AL_MOD_ENV_SUSTAINVOLUME_SOFT, /* 29 - sustainModEnv */ - AL_MOD_ENV_RELEASETIME_SOFT, /* 30 - releaseModEnv */ - AL_MOD_ENV_KEY_TO_HOLDTIME_SOFT, /* 31 - keynumToModEnvHold */ - AL_MOD_ENV_KEY_TO_DECAYTIME_SOFT, /* 32 - keynumToModEnvDecay */ - AL_VOLUME_ENV_DELAYTIME_SOFT, /* 33 - delayVolEnv */ - AL_VOLUME_ENV_ATTACKTIME_SOFT, /* 34 - attackVolEnv */ - AL_VOLUME_ENV_HOLDTIME_SOFT, /* 35 - holdVolEnv */ - AL_VOLUME_ENV_DECAYTIME_SOFT, /* 36 - decayVolEnv */ - AL_VOLUME_ENV_SUSTAINVOLUME_SOFT, /* 37 - sustainVolEnv */ - AL_VOLUME_ENV_RELEASETIME_SOFT, /* 38 - releaseVolEnv */ - AL_VOLUME_ENV_KEY_TO_HOLDTIME_SOFT, /* 39 - keynumToVolEnvHold */ - AL_VOLUME_ENV_KEY_TO_DECAYTIME_SOFT, /* 40 - keynumToVolEnvDecay */ - 0, /* 41 - */ - 0, /* 42 - */ - AL_KEY_RANGE_SOFT, /* 43 - keyRange */ - AL_VELOCITY_RANGE_SOFT, /* 44 - velRange */ - 0, /* 45 - startloopAddrCoarseOffset */ - 0, /* 46 - keynum */ - 0, /* 47 - velocity */ - AL_ATTENUATION_SOFT, /* 48 - initialAttenuation */ - 0, /* 49 - */ - 0, /* 50 - endloopAddrCoarseOffset */ - AL_TUNING_COARSE_SOFT, /* 51 - corseTune */ - AL_TUNING_FINE_SOFT, /* 52 - fineTune */ - 0, /* 53 - */ - AL_LOOP_MODE_SOFT, /* 54 - sampleModes */ - 0, /* 55 - */ - AL_TUNING_SCALE_SOFT, /* 56 - scaleTuning */ - AL_EXCLUSIVE_CLASS_SOFT, /* 57 - exclusiveClass */ - AL_BASE_KEY_SOFT, /* 58 - overridingRootKey */ - 0, /* 59 - */ - }; - const Generator *gen, *gen_end; - const Modulator *mod, *mod_end; - - mod = VECTOR_ITER_BEGIN(zone->mods); - mod_end = VECTOR_ITER_END(zone->mods); - for(;mod != mod_end;mod++) - { - ALenum src0in = getModSrcInput(mod->mSrcOp&0xFF); - ALenum src0type = getModSrcType(mod->mSrcOp&0x0300); - ALenum src0form = getModSrcForm(mod->mSrcOp&0xFC00); - ALenum src1in = getModSrcInput(mod->mAmtSrcOp&0xFF); - ALenum src1type = getModSrcType(mod->mAmtSrcOp&0x0300); - ALenum src1form = getModSrcForm(mod->mAmtSrcOp&0xFC00); - ALenum trans = getModTransOp(mod->mTransOp); - ALenum dst = (mod->mDstOp < 60) ? Gen2Param[mod->mDstOp] : 0; - if(!dst || dst == AL_KEY_RANGE_SOFT || dst == AL_VELOCITY_RANGE_SOFT || - dst == AL_LOOP_MODE_SOFT || dst == AL_EXCLUSIVE_CLASS_SOFT || - dst == AL_BASE_KEY_SOFT) - ERR("Unhandled modulator destination: %d\n", mod->mDstOp); - else if(src0in != AL_INVALID && src0form != AL_INVALID && src0type != AL_INVALID && - src1in != AL_INVALID && src1form != AL_INVALID && src1type != AL_INVALID && - trans != AL_INVALID) - { - ALsizei idx = (ALsizei)(mod - VECTOR_ITER_BEGIN(zone->mods)); - ALfontsound_setModStagei(sound, context, idx, AL_SOURCE0_INPUT_SOFT, src0in); - ALfontsound_setModStagei(sound, context, idx, AL_SOURCE0_TYPE_SOFT, src0type); - ALfontsound_setModStagei(sound, context, idx, AL_SOURCE0_FORM_SOFT, src0form); - ALfontsound_setModStagei(sound, context, idx, AL_SOURCE1_INPUT_SOFT, src1in); - ALfontsound_setModStagei(sound, context, idx, AL_SOURCE1_TYPE_SOFT, src1type); - ALfontsound_setModStagei(sound, context, idx, AL_SOURCE1_FORM_SOFT, src1form); - ALfontsound_setModStagei(sound, context, idx, AL_AMOUNT_SOFT, mod->mAmount); - ALfontsound_setModStagei(sound, context, idx, AL_TRANSFORM_OP_SOFT, trans); - ALfontsound_setModStagei(sound, context, idx, AL_DESTINATION_SOFT, dst); - } - } - - gen = VECTOR_ITER_BEGIN(zone->gens); - gen_end = VECTOR_ITER_END(zone->gens); - for(;gen != gen_end;gen++) - { - ALint value = (ALshort)gen->mAmount; - if(gen->mGenerator == 0) - sound->Start += value; - else if(gen->mGenerator == 1) - sound->End += value; - else if(gen->mGenerator == 2) - sound->LoopStart += value; - else if(gen->mGenerator == 3) - sound->LoopEnd += value; - else if(gen->mGenerator == 4) - sound->Start += value<<15; - else if(gen->mGenerator == 12) - sound->End += value<<15; - else if(gen->mGenerator == 45) - sound->LoopStart += value<<15; - else if(gen->mGenerator == 50) - sound->LoopEnd += value<<15; - else if(gen->mGenerator == 43) - { - sound->MinKey = mini((value&0xff), 127); - sound->MaxKey = mini(((value>>8)&0xff), 127); - } - else if(gen->mGenerator == 44) - { - sound->MinVelocity = mini((value&0xff), 127); - sound->MaxVelocity = mini(((value>>8)&0xff), 127); - } - else - { - ALenum param = 0; - if(gen->mGenerator < 60) - param = Gen2Param[gen->mGenerator]; - if(param) - { - if(param == AL_BASE_KEY_SOFT) - { - if(!(value >= 0 && value <= 127)) - { - if(value != -1) - WARN("Invalid overridingRootKey generator value %d\n", value); - continue; - } - } - if(param == AL_FILTER_RESONANCE_SOFT || param == AL_ATTENUATION_SOFT) - value = maxi(0, value); - else if(param == AL_CHORUS_SEND_SOFT || param == AL_REVERB_SEND_SOFT) - value = clampi(value, 0, 1000); - else if(param == AL_LOOP_MODE_SOFT) - value = getLoopMode(value); - ALfontsound_setPropi(sound, context, param, value); - } - else - { - static ALuint warned[65536/32]; - if(!(warned[gen->mGenerator/32]&(1<<(gen->mGenerator&31)))) - { - warned[gen->mGenerator/32] |= 1<<(gen->mGenerator&31); - ERR("Unhandled generator %d\n", gen->mGenerator); - } - } - } - } -} - -static void processInstrument(ALfontsound ***sounds, ALsizei *sounds_size, ALCcontext *context, ALbuffer *buffer, InstrumentHeader *inst, const PresetHeader *preset, const Soundfont *sfont, const GenModList *pzone) -{ - const Generator *gen, *gen_end; - const Modulator *mod, *mod_end; - const Zone *zone, *zone_end; - GenModList gzone; - ALvoid *temp; - - if((inst+1)->mZoneIdx == inst->mZoneIdx) - ERR("Instrument with no zones!"); - - GenModList_Construct(&gzone); - zone = sfont->ibag + inst->mZoneIdx; - zone_end = sfont->ibag + (inst+1)->mZoneIdx; - if(zone_end-zone > 1) - { - gen = sfont->igen + zone->mGenIdx; - gen_end = sfont->igen + (zone+1)->mGenIdx; - - // If no generators, or last generator is not a sample, this is a global zone - for(;gen != gen_end;gen++) - { - if(gen->mGenerator == 53) - break; - } - - if(gen == gen_end) - { - gen = sfont->igen + zone->mGenIdx; - gen_end = sfont->igen + (zone+1)->mGenIdx; - for(;gen != gen_end;gen++) - GenModList_insertGen(&gzone, gen, AL_FALSE); - - mod = sfont->imod + zone->mModIdx; - mod_end = sfont->imod + (zone+1)->mModIdx; - for(;mod != mod_end;mod++) - GenModList_insertMod(&gzone, mod); - - zone++; - } - } - - temp = realloc(*sounds, (zone_end-zone + *sounds_size)*sizeof((*sounds)[0])); - if(!temp) - { - ERR("Failed reallocating fontsound storage to %d elements (from %d)\n", - (ALsizei)(zone_end-zone) + *sounds_size, *sounds_size); - return; - } - *sounds = temp; - for(;zone != zone_end;zone++) - { - GenModList lzone = GenModList_clone(&gzone); - mod = sfont->imod + zone->mModIdx; - mod_end = sfont->imod + (zone+1)->mModIdx; - for(;mod != mod_end;mod++) - GenModList_insertMod(&lzone, mod); - - gen = sfont->igen + zone->mGenIdx; - gen_end = sfont->igen + (zone+1)->mGenIdx; - for(;gen != gen_end;gen++) - { - if(gen->mGenerator == 53) - { - const SampleHeader *samp; - ALfontsound *sound; - - if(gen->mAmount >= sfont->shdr_size-1) - { - ERR("Generator %ld has invalid sample ID (%d of %d)\n", - (long)(gen-sfont->igen), gen->mAmount, sfont->shdr_size-1); - break; - } - samp = &sfont->shdr[gen->mAmount]; - - gen = VECTOR_ITER_BEGIN(pzone->gens); - gen_end = VECTOR_ITER_END(pzone->gens); - for(;gen != gen_end;gen++) - GenModList_accumGen(&lzone, gen); - - mod = VECTOR_ITER_BEGIN(pzone->mods); - mod_end = VECTOR_ITER_END(pzone->mods); - for(;mod != mod_end;mod++) - GenModList_accumMod(&lzone, mod); - - if(!checkZone(&lzone, preset, inst, samp)) - break; - /* Ignore ROM samples for now. */ - if((samp->mSampleType&0x8000)) - break; - - sound = NewFontsound(context); - (*sounds)[(*sounds_size)++] = sound; - ALfontsound_setPropi(sound, context, AL_BUFFER, buffer->id); - ALfontsound_setPropi(sound, context, AL_SAMPLE_START_SOFT, samp->mStart); - ALfontsound_setPropi(sound, context, AL_SAMPLE_END_SOFT, samp->mEnd); - ALfontsound_setPropi(sound, context, AL_SAMPLE_LOOP_START_SOFT, samp->mStartloop); - ALfontsound_setPropi(sound, context, AL_SAMPLE_LOOP_END_SOFT, samp->mEndloop); - ALfontsound_setPropi(sound, context, AL_SAMPLE_RATE_SOFT, samp->mSampleRate); - ALfontsound_setPropi(sound, context, AL_BASE_KEY_SOFT, (samp->mOriginalKey <= 127) ? samp->mOriginalKey : 60); - ALfontsound_setPropi(sound, context, AL_KEY_CORRECTION_SOFT, samp->mCorrection); - ALfontsound_setPropi(sound, context, AL_SAMPLE_TYPE_SOFT, getSampleType(samp->mSampleType&0x7fff)); - fillZone(sound, context, &lzone); - - break; - } - GenModList_insertGen(&lzone, gen, AL_FALSE); - } - - GenModList_Destruct(&lzone); - } - - GenModList_Destruct(&gzone); -} - -static ALuint printStringChunk(Reader *stream, const RiffHdr *chnk, const char *title) -{ - ALuint len = 0; - if(chnk->mSize == 0 || (chnk->mSize&1)) - ERR("Invalid "FOURCCFMT" size: %d\n", FOURCCARGS(chnk->mCode), chnk->mSize); - else - { - char *str = calloc(1, chnk->mSize+1); - len = (ALuint)Reader_read(stream, str, chnk->mSize); - - TRACE("%s: %s\n", title, str); - free(str); - } - return len; -} - -ALboolean loadSf2(Reader *stream, ALsoundfont *soundfont, ALCcontext *context) -{ - ALsfpreset **presets = NULL; - ALsizei presets_size = 0; - ALbuffer *buffer = NULL; - ALuint ltype; - Soundfont sfont; - RiffHdr riff; - RiffHdr list; - ALsizei i; - - Soundfont_Construct(&sfont); - - RiffHdr_read(&riff, stream); - if(riff.mCode != FOURCC('R','I','F','F')) - ERROR_GOTO(error, "Invalid Format, expected RIFF got '"FOURCCFMT"'\n", FOURCCARGS(riff.mCode)); - if((ltype=read_le32(stream)) != FOURCC('s','f','b','k')) - ERROR_GOTO(error, "Invalid Format, expected sfbk got '"FOURCCFMT"'\n", FOURCCARGS(ltype)); - - if(READERR(stream) != 0) - ERROR_GOTO(error, "Error reading file header\n"); - - RiffHdr_read(&list, stream); - if(list.mCode != FOURCC('L','I','S','T')) - ERROR_GOTO(error, "Invalid Format, expected LIST (INFO) got '"FOURCCFMT"'\n", FOURCCARGS(list.mCode)); - if((ltype=read_le32(stream)) != FOURCC('I','N','F','O')) - ERROR_GOTO(error, "Invalid Format, expected INFO got '"FOURCCFMT"'\n", FOURCCARGS(ltype)); - list.mSize -= 4; - while(list.mSize > 0 && !READERR(stream)) - { - RiffHdr chnk; - - if(list.mSize < 8) - { - WARN("Unexpected end of INFO list (%u extra bytes)\n", list.mSize); - skip(stream, list.mSize); - list.mSize = 0; - break; - } - - RiffHdr_read(&chnk, stream); - list.mSize -= 8; - if(list.mSize < chnk.mSize) - { - WARN("INFO sub-chunk '"FOURCCFMT"' has %u bytes, but only %u bytes remain\n", - FOURCCARGS(chnk.mCode), chnk.mSize, list.mSize); - skip(stream, list.mSize); - list.mSize = 0; - break; - } - list.mSize -= chnk.mSize; - - if(chnk.mCode == FOURCC('i','f','i','l')) - { - if(chnk.mSize != 4) - ERR("Invalid ifil chunk size: %d\n", chnk.mSize); - else - { - ALushort major = read_le16(stream); - ALushort minor = read_le16(stream); - chnk.mSize -= 4; - - if(major != 2) - ERROR_GOTO(error, "Unsupported SF2 format version: %d.%02d\n", major, minor); - TRACE("SF2 format version: %d.%02d\n", major, minor); - - sfont.ifil = (major<<16) | minor; - } - } - else if(chnk.mCode == FOURCC('i','r','o','m')) - { - if(chnk.mSize == 0 || (chnk.mSize&1)) - ERR("Invalid irom size: %d\n", chnk.mSize); - else - { - free(sfont.irom); - sfont.irom = calloc(1, chnk.mSize+1); - chnk.mSize -= Reader_read(stream, sfont.irom, chnk.mSize); - - TRACE("SF2 ROM ID: %s\n", sfont.irom); - } - } - else - { - static const struct { - ALuint code; - char title[16]; - } listinfos[] = { - { FOURCC('i','s','n','g'), "Engine ID" }, - { FOURCC('I','N','A','M'), "Name" }, - { FOURCC('I','C','R','D'), "Creation Date" }, - { FOURCC('I','E','N','G'), "Creator" }, - { FOURCC('I','P','R','D'), "Product ID" }, - { FOURCC('I','C','O','P'), "Copyright" }, - { FOURCC('I','C','M','T'), "Comment" }, - { FOURCC('I','S','F','T'), "Created With" }, - { 0, "" }, - }; - - for(i = 0;listinfos[i].code;i++) - { - if(listinfos[i].code == chnk.mCode) - { - chnk.mSize -= printStringChunk(stream, &chnk, listinfos[i].title); - break; - } - } - if(!listinfos[i].code) - TRACE("Skipping INFO sub-chunk '"FOURCCFMT"' (%u bytes)\n", FOURCCARGS(chnk.mCode), chnk.mSize); - } - skip(stream, chnk.mSize); - } - - if(READERR(stream) != 0) - ERROR_GOTO(error, "Error reading INFO chunk\n"); - if(sfont.ifil == 0) - ERROR_GOTO(error, "Missing ifil sub-chunk\n"); - - RiffHdr_read(&list, stream); - if(list.mCode != FOURCC('L','I','S','T')) - ERROR_GOTO(error, "Invalid Format, expected LIST (sdta) got '"FOURCCFMT"'\n", FOURCCARGS(list.mCode)); - if((ltype=read_le32(stream)) != FOURCC('s','d','t','a')) - ERROR_GOTO(error, "Invalid Format, expected sdta got '"FOURCCFMT"'\n", FOURCCARGS(ltype)); - list.mSize -= 4; - { - ALbyte *ptr; - RiffHdr smpl; - ALenum err; - - RiffHdr_read(&smpl, stream); - if(smpl.mCode != FOURCC('s','m','p','l')) - ERROR_GOTO(error, "Invalid Format, expected smpl got '"FOURCCFMT"'\n", FOURCCARGS(smpl.mCode)); - list.mSize -= 8; - - if(smpl.mSize > list.mSize) - ERROR_GOTO(error, "Invalid Format, sample chunk size mismatch\n"); - list.mSize -= smpl.mSize; - - buffer = NewBuffer(context); - if(!buffer) - SET_ERROR_AND_GOTO(context, AL_OUT_OF_MEMORY, error); - /* Sample rate is unimportant, the individual fontsounds will specify it. */ - if((err=LoadData(buffer, 22050, AL_MONO16_SOFT, smpl.mSize/2, UserFmtMono, UserFmtShort, NULL, 1, AL_FALSE)) != AL_NO_ERROR) - SET_ERROR_AND_GOTO(context, err, error); - - ptr = buffer->data; - if(IS_LITTLE_ENDIAN) - smpl.mSize -= (ALuint)Reader_read(stream, ptr, smpl.mSize); - else - { - ALuint total = 0; - while(total < smpl.mSize && !READERR(stream)) - { - ALbyte buf[4096]; - ALuint todo = minu(smpl.mSize-total, sizeof(buf)); - ALuint i; - - smpl.mSize -= (ALuint)Reader_read(stream, buf, todo); - for(i = 0;i < todo;i++) - ptr[total+i] = buf[i^1]; - - total += todo; - } - } - - skip(stream, list.mSize); - } - - if(READERR(stream) != 0) - ERROR_GOTO(error, "Error reading sdta chunk\n"); - - RiffHdr_read(&list, stream); - if(list.mCode != FOURCC('L','I','S','T')) - ERROR_GOTO(error, "Invalid Format, expected LIST (pdta) got '"FOURCCFMT"'\n", FOURCCARGS(list.mCode)); - if((ltype=read_le32(stream)) != FOURCC('p','d','t','a')) - ERROR_GOTO(error, "Invalid Format, expected pdta got '"FOURCCFMT"'\n", FOURCCARGS(ltype)); - - // - RiffHdr_read(&list, stream); - if(list.mCode != FOURCC('p','h','d','r')) - ERROR_GOTO(error, "Invalid Format, expected phdr got '"FOURCCFMT"'\n", FOURCCARGS(list.mCode)); - if((list.mSize%38) != 0 || list.mSize == 0) - ERROR_GOTO(error, "Invalid Format, bad phdr size: %u\n", list.mSize); - sfont.phdr_size = list.mSize/38; - sfont.phdr = calloc(sfont.phdr_size, sizeof(sfont.phdr[0])); - for(i = 0;i < sfont.phdr_size;i++) - PresetHeader_read(&sfont.phdr[i], stream); - - RiffHdr_read(&list, stream); - if(list.mCode != FOURCC('p','b','a','g')) - ERROR_GOTO(error, "Invalid Format, expected pbag got '"FOURCCFMT"'\n", FOURCCARGS(list.mCode)); - if((list.mSize%4) != 0 || list.mSize == 0) - ERROR_GOTO(error, "Invalid Format, bad pbag size: %u\n", list.mSize); - sfont.pbag_size = list.mSize/4; - sfont.pbag = calloc(sfont.pbag_size, sizeof(sfont.pbag[0])); - for(i = 0;i < sfont.pbag_size;i++) - Zone_read(&sfont.pbag[i], stream); - - RiffHdr_read(&list, stream); - if(list.mCode != FOURCC('p','m','o','d')) - ERROR_GOTO(error, "Invalid Format, expected pmod got '"FOURCCFMT"'\n", FOURCCARGS(list.mCode)); - if((list.mSize%10) != 0 || list.mSize == 0) - ERROR_GOTO(error, "Invalid Format, bad pmod size: %u\n", list.mSize); - sfont.pmod_size = list.mSize/10; - sfont.pmod = calloc(sfont.pmod_size, sizeof(sfont.pmod[0])); - for(i = 0;i < sfont.pmod_size;i++) - Modulator_read(&sfont.pmod[i], stream); - - RiffHdr_read(&list, stream); - if(list.mCode != FOURCC('p','g','e','n')) - ERROR_GOTO(error, "Invalid Format, expected pgen got '"FOURCCFMT"'\n", FOURCCARGS(list.mCode)); - if((list.mSize%4) != 0 || list.mSize == 0) - ERROR_GOTO(error, "Invalid Format, bad pgen size: %u\n", list.mSize); - sfont.pgen_size = list.mSize/4; - sfont.pgen = calloc(sfont.pgen_size, sizeof(sfont.pgen[0])); - for(i = 0;i < sfont.pgen_size;i++) - Generator_read(&sfont.pgen[i], stream); - - // - RiffHdr_read(&list, stream); - if(list.mCode != FOURCC('i','n','s','t')) - ERROR_GOTO(error, "Invalid Format, expected inst got '"FOURCCFMT"'\n", FOURCCARGS(list.mCode)); - if((list.mSize%22) != 0 || list.mSize == 0) - ERROR_GOTO(error, "Invalid Format, bad inst size: %u\n", list.mSize); - sfont.inst_size = list.mSize/22; - sfont.inst = calloc(sfont.inst_size, sizeof(sfont.inst[0])); - for(i = 0;i < sfont.inst_size;i++) - InstrumentHeader_read(&sfont.inst[i], stream); - - RiffHdr_read(&list, stream); - if(list.mCode != FOURCC('i','b','a','g')) - ERROR_GOTO(error, "Invalid Format, expected ibag got '"FOURCCFMT"'\n", FOURCCARGS(list.mCode)); - if((list.mSize%4) != 0 || list.mSize == 0) - ERROR_GOTO(error, "Invalid Format, bad ibag size: %u\n", list.mSize); - sfont.ibag_size = list.mSize/4; - sfont.ibag = calloc(sfont.ibag_size, sizeof(sfont.ibag[0])); - for(i = 0;i < sfont.ibag_size;i++) - Zone_read(&sfont.ibag[i], stream); - - RiffHdr_read(&list, stream); - if(list.mCode != FOURCC('i','m','o','d')) - ERROR_GOTO(error, "Invalid Format, expected imod got '"FOURCCFMT"'\n", FOURCCARGS(list.mCode)); - if((list.mSize%10) != 0 || list.mSize == 0) - ERROR_GOTO(error, "Invalid Format, bad imod size: %u\n", list.mSize); - sfont.imod_size = list.mSize/10; - sfont.imod = calloc(sfont.imod_size, sizeof(sfont.imod[0])); - for(i = 0;i < sfont.imod_size;i++) - Modulator_read(&sfont.imod[i], stream); - - RiffHdr_read(&list, stream); - if(list.mCode != FOURCC('i','g','e','n')) - ERROR_GOTO(error, "Invalid Format, expected igen got '"FOURCCFMT"'\n", FOURCCARGS(list.mCode)); - if((list.mSize%4) != 0 || list.mSize == 0) - ERROR_GOTO(error, "Invalid Format, bad igen size: %u\n", list.mSize); - sfont.igen_size = list.mSize/4; - sfont.igen = calloc(sfont.igen_size, sizeof(sfont.igen[0])); - for(i = 0;i < sfont.igen_size;i++) - Generator_read(&sfont.igen[i], stream); - - // - RiffHdr_read(&list, stream); - if(list.mCode != FOURCC('s','h','d','r')) - ERROR_GOTO(error, "Invalid Format, expected shdr got '"FOURCCFMT"'\n", FOURCCARGS(list.mCode)); - if((list.mSize%46) != 0 || list.mSize == 0) - ERROR_GOTO(error, "Invalid Format, bad shdr size: %u\n", list.mSize); - sfont.shdr_size = list.mSize/46; - sfont.shdr = calloc(sfont.shdr_size, sizeof(sfont.shdr[0])); - for(i = 0;i < sfont.shdr_size;i++) - SampleHeader_read(&sfont.shdr[i], stream); - - if(READERR(stream) != 0) - ERROR_GOTO(error, "Error reading pdta chunk\n"); - - if(!ensureFontSanity(&sfont)) - goto error; - - presets = calloc(1, (soundfont->NumPresets+sfont.phdr_size-1)*sizeof(presets[0])); - if(!presets) - ERROR_GOTO(error, "Error allocating presets\n"); - memcpy(presets, soundfont->Presets, soundfont->NumPresets*sizeof(presets[0])); - presets_size = soundfont->NumPresets; - - for(i = 0;i < sfont.phdr_size-1;i++) - { - const Generator *gen, *gen_end; - const Modulator *mod, *mod_end; - const Zone *zone, *zone_end; - ALfontsound **sounds = NULL; - ALsizei sounds_size = 0; - GenModList gzone; - - if(sfont.phdr[i+1].mZoneIdx == sfont.phdr[i].mZoneIdx) - continue; - - GenModList_Construct(&gzone); - zone = sfont.pbag + sfont.phdr[i].mZoneIdx; - zone_end = sfont.pbag + sfont.phdr[i+1].mZoneIdx; - if(zone_end-zone > 1) - { - gen = sfont.pgen + zone->mGenIdx; - gen_end = sfont.pgen + (zone+1)->mGenIdx; - - // If no generators, or last generator is not an instrument, this is a global zone - for(;gen != gen_end;gen++) - { - if(gen->mGenerator == 41) - break; - } - - if(gen == gen_end) - { - gen = sfont.pgen + zone->mGenIdx; - gen_end = sfont.pgen + (zone+1)->mGenIdx; - for(;gen != gen_end;gen++) - GenModList_insertGen(&gzone, gen, AL_TRUE); - - mod = sfont.pmod + zone->mModIdx; - mod_end = sfont.pmod + (zone+1)->mModIdx; - for(;mod != mod_end;mod++) - GenModList_insertMod(&gzone, mod); - - zone++; - } - } - - for(;zone != zone_end;zone++) - { - GenModList lzone = GenModList_clone(&gzone); - - mod = sfont.pmod + zone->mModIdx; - mod_end = sfont.pmod + (zone+1)->mModIdx; - for(;mod != mod_end;mod++) - GenModList_insertMod(&lzone, mod); - - gen = sfont.pgen + zone->mGenIdx; - gen_end = sfont.pgen + (zone+1)->mGenIdx; - for(;gen != gen_end;gen++) - { - if(gen->mGenerator == 41) - { - if(gen->mAmount >= sfont.inst_size-1) - ERR("Generator %ld has invalid instrument ID (%d of %d)\n", - (long)(gen-sfont.pgen), gen->mAmount, sfont.inst_size-1); - else - processInstrument( - &sounds, &sounds_size, context, buffer, &sfont.inst[gen->mAmount], - &sfont.phdr[i], &sfont, &lzone - ); - break; - } - GenModList_insertGen(&lzone, gen, AL_TRUE); - } - GenModList_Destruct(&lzone); - } - - if(sounds_size > 0) - { - ALsizei j; - - presets[presets_size] = NewPreset(context); - presets[presets_size]->Preset = sfont.phdr[i].mPreset; - presets[presets_size]->Bank = sfont.phdr[i].mBank; - - for(j = 0;j < sounds_size;j++) - IncrementRef(&sounds[j]->ref); - sounds = ExchangePtr((XchgPtr*)&presets[presets_size]->Sounds, sounds); - presets[presets_size]->NumSounds = sounds_size; - presets_size++; - } - free(sounds); - - GenModList_Destruct(&gzone); - } - - for(i = soundfont->NumPresets;i < presets_size;i++) - IncrementRef(&presets[i]->ref); - presets = ExchangePtr((XchgPtr*)&soundfont->Presets, presets); - soundfont->NumPresets = presets_size; - - free(presets); - - Soundfont_Destruct(&sfont); - /* If the buffer ends up unused, delete it. */ - if(ReadRef(&buffer->ref) == 0) - { - TRACE("Deleting unused buffer...\n"); - DeleteBuffer(context->Device, buffer); - } - - return AL_TRUE; - -error: - if(presets) - { - ALCdevice *device = context->Device; - for(i = soundfont->NumPresets;i < presets_size;i++) - DeletePreset(device, presets[i]); - free(presets); - } - - Soundfont_Destruct(&sfont); - if(buffer) - DeleteBuffer(context->Device, buffer); - - return AL_FALSE; -} diff --git a/Alc/midi/soft.c b/Alc/midi/soft.c deleted file mode 100644 index a000266b..00000000 --- a/Alc/midi/soft.c +++ /dev/null @@ -1,139 +0,0 @@ - -#include "config.h" - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <limits.h> - -#include "alMain.h" -#include "alError.h" -#include "evtqueue.h" -#include "alu.h" - -#include "midi/base.h" - - -typedef struct SSynth { - DERIVE_FROM_TYPE(MidiSynth); -} SSynth; - -static void SSynth_mixSamples(SSynth *self, ALuint SamplesToDo, ALfloat (*restrict DryBuffer)[BUFFERSIZE], ALuint NumChannels); - -static void SSynth_Construct(SSynth *self, ALCdevice *device); -static void SSynth_Destruct(SSynth *self); -static DECLARE_FORWARD3(SSynth, MidiSynth, ALenum, selectSoundfonts, ALCcontext*, ALsizei, const ALuint*) -static DECLARE_FORWARD1(SSynth, MidiSynth, void, setGain, ALfloat) -static DECLARE_FORWARD(SSynth, MidiSynth, void, stop) -static DECLARE_FORWARD(SSynth, MidiSynth, void, reset) -static void SSynth_update(SSynth *self, ALCdevice *device); -static void SSynth_process(SSynth *self, ALuint SamplesToDo, ALfloat (*restrict DryBuffer)[BUFFERSIZE], ALuint NumChannels); -DECLARE_DEFAULT_ALLOCATORS(SSynth) -DEFINE_MIDISYNTH_VTABLE(SSynth); - - -static void SSynth_Construct(SSynth *self, ALCdevice *device) -{ - MidiSynth_Construct(STATIC_CAST(MidiSynth, self), device); - SET_VTABLE2(SSynth, MidiSynth, self); -} - -static void SSynth_Destruct(SSynth* UNUSED(self)) -{ -} - - -static void SSynth_update(SSynth* UNUSED(self), ALCdevice* UNUSED(device)) -{ -} - - -static void SSynth_mixSamples(SSynth* UNUSED(self), ALuint UNUSED(SamplesToDo), ALfloatBUFFERSIZE *restrict UNUSED(DryBuffer), ALuint UNUSED(NumChannels)) -{ -} - - -static void SSynth_processQueue(SSynth *self, ALuint64 time) -{ - EvtQueue *queue = &STATIC_CAST(MidiSynth, self)->EventQueue; - - while(queue->pos < queue->size && queue->events[queue->pos].time <= time) - queue->pos++; -} - -static void SSynth_process(SSynth *self, ALuint SamplesToDo, ALfloat (*restrict DryBuffer)[BUFFERSIZE], ALuint NumChannels) -{ - MidiSynth *synth = STATIC_CAST(MidiSynth, self); - ALenum state = synth->State; - ALuint64 curtime; - ALuint total = 0; - - if(state == AL_INITIAL) - return; - if(state != AL_PLAYING) - { - SSynth_mixSamples(self, SamplesToDo, DryBuffer, NumChannels); - return; - } - - curtime = MidiSynth_getTime(synth); - while(total < SamplesToDo) - { - ALuint64 time, diff; - ALint tonext; - - time = MidiSynth_getNextEvtTime(synth); - diff = maxu64(time, curtime) - curtime; - if(diff >= MIDI_CLOCK_RES || time == UINT64_MAX) - { - /* If there's no pending event, or if it's more than 1 second - * away, do as many samples as we can. */ - tonext = INT_MAX; - } - else - { - /* Figure out how many samples until the next event. */ - tonext = (ALint)((diff*synth->SampleRate + (MIDI_CLOCK_RES-1)) / MIDI_CLOCK_RES); - tonext -= total; - /* For efficiency reasons, try to mix a multiple of 64 samples - * (~1ms @ 44.1khz) before processing the next event. */ - tonext = (tonext+63) & ~63; - } - - if(tonext > 0) - { - ALuint todo = mini(tonext, SamplesToDo-total); - SSynth_mixSamples(self, todo, DryBuffer, NumChannels); - total += todo; - tonext -= todo; - } - if(total < SamplesToDo && tonext <= 0) - SSynth_processQueue(self, time); - } - - synth->SamplesDone += SamplesToDo; - synth->ClockBase += (synth->SamplesDone/synth->SampleRate) * MIDI_CLOCK_RES; - synth->SamplesDone %= synth->SampleRate; -} - - -MidiSynth *SSynth_create(ALCdevice *device) -{ - SSynth *synth; - - /* This option is temporary. Once this synth is in a more usable state, a - * more generic selector should be used. */ - if(!GetConfigValueBool(NULL, "midi", "internal-synth", 0)) - { - TRACE("Not using internal MIDI synth\n"); - return NULL; - } - - NEW_OBJ(synth, SSynth)(device); - if(!synth) - { - ERR("Failed to allocate SSynth\n"); - return NULL; - } - return STATIC_CAST(MidiSynth, synth); -} |