diff options
author | Chris Robinson <[email protected]> | 2013-12-18 22:51:53 -0800 |
---|---|---|
committer | Chris Robinson <[email protected]> | 2013-12-18 22:51:53 -0800 |
commit | 8083fb5be7943e6c5ade6c062ae78559c0826472 (patch) | |
tree | 5e39ff595fcead4d272ad8896aef43b94c8adcec | |
parent | b9468dc9176861f6ab6f6e358fda71c0d6fecc90 (diff) |
Add a new ALsoundfont object type
Includes a basic hierarchy for presets, instruments, samples, zones,
generators, and modulators.
-rw-r--r-- | Alc/ALc.c | 2 | ||||
-rw-r--r-- | Alc/midi/base.c | 344 | ||||
-rw-r--r-- | OpenAL32/Include/alMain.h | 7 | ||||
-rw-r--r-- | OpenAL32/Include/alMidi.h | 105 | ||||
-rw-r--r-- | OpenAL32/alMidi.c | 93 |
5 files changed, 485 insertions, 66 deletions
@@ -280,6 +280,8 @@ static const ALCfunction alcFunctions[] = { DECL(alGetSource3i64SOFT), DECL(alGetSourcei64vSOFT), + DECL(alGenSoundfontsSOFT), + DECL(alDeleteSoundfontsSOFT), DECL(alIsSoundfontSOFT), DECL(alMidiSoundfontSOFT), DECL(alMidiEventSOFT), diff --git a/Alc/midi/base.c b/Alc/midi/base.c index 46c9b3d2..20d7a27c 100644 --- a/Alc/midi/base.c +++ b/Alc/midi/base.c @@ -8,6 +8,7 @@ #include "midi/base.h" +#include "alMidi.h" #include "alMain.h" #include "alError.h" #include "evtqueue.h" @@ -22,6 +23,100 @@ #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); @@ -147,95 +242,212 @@ ALenum MidiSynth_insertSysExEvent(MidiSynth *self, ALuint64 time, const ALbyte * } -void InitEvtQueue(EvtQueue *queue) +void ALsfzone_Construct(ALsfzone *self) { - queue->events = NULL; - queue->maxsize = 0; - queue->size = 0; - queue->pos = 0; + self->Generators = NULL; + self->NumGenerators = 0; + self->GeneratorsMax = 0; + + self->Modulators = NULL; + self->NumModulators = 0; + self->ModulatorsMax = 0; + + self->Object = NULL; } -void ResetEvtQueue(EvtQueue *queue) +void ALsfzone_Destruct(ALsfzone *self) +{ + self->Object = NULL; + + free(self->Modulators); + self->Modulators = NULL; + self->NumModulators = 0; + self->ModulatorsMax = 0; + + free(self->Generators); + self->Generators = NULL; + self->NumGenerators = 0; + self->GeneratorsMax = 0; +} + +ALenum ALsfzone_addGenerator(ALsfzone *self, ALenum generator, ALint value) { ALsizei i; - for(i = 0;i < queue->size;i++) + for(i = 0;i < self->NumGenerators;i++) { - if(queue->events[i].event == SYSEX_EVENT) + if(self->Generators[i].Generator == generator) { - free(queue->events[i].param.sysex.data); - queue->events[i].param.sysex.data = NULL; + self->Generators[i].Value = value; + return AL_NO_ERROR; } } - free(queue->events); - queue->events = NULL; - queue->maxsize = 0; - queue->size = 0; - queue->pos = 0; + if(self->NumGenerators == self->GeneratorsMax) + { + ALsizei newmax = 0; + ALvoid *temp = NULL; + + newmax = (self->GeneratorsMax ? self->GeneratorsMax<<1 : 1); + if(newmax > self->GeneratorsMax) + temp = realloc(self->Generators, newmax * sizeof(ALsfgenerator)); + if(!temp) return AL_OUT_OF_MEMORY; + + self->Generators = temp; + self->GeneratorsMax = newmax; + } + + self->Generators[self->NumGenerators].Generator = generator; + self->Generators[self->NumGenerators].Value = value; + self->NumGenerators++; + + return AL_NO_ERROR; } -ALenum InsertEvtQueue(EvtQueue *queue, const MidiEvent *evt) +ALenum ALsfzone_addModulator(ALsfzone *self, ALenum sourceop, ALenum destop, ALint amount, ALenum amtsourceop, ALenum transop) { - ALsizei pos; - - if(queue->maxsize == queue->size) + ALsizei i; + for(i = 0;i < self->NumModulators;i++) { - if(queue->pos > 0) + if(self->Modulators[i].SourceOp == sourceop && self->Modulators[i].DestOp == destop && + self->Modulators[i].AmountSourceOp == amtsourceop && + self->Modulators[i].TransformOp == transop) { - /* 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; + self->Modulators[i].Amount = amount; + return AL_NO_ERROR; } - 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; + if(self->NumModulators == self->ModulatorsMax) + { + ALsizei newmax = 0; + ALvoid *temp = NULL; - queue->events = temp; - queue->maxsize = newsize; - } + newmax = (self->ModulatorsMax ? self->ModulatorsMax<<1 : 1); + if(newmax > self->ModulatorsMax) + temp = realloc(self->Modulators, newmax * sizeof(ALsfmodulator)); + if(!temp) return AL_OUT_OF_MEMORY; + + self->Modulators = temp; + self->ModulatorsMax = newmax; } - pos = queue->pos; - if(queue->size > 0) + self->Modulators[self->NumModulators].SourceOp = sourceop; + self->Modulators[self->NumModulators].DestOp = destop; + self->Modulators[self->NumModulators].Amount = amount; + self->Modulators[self->NumModulators].AmountSourceOp = amtsourceop; + self->Modulators[self->NumModulators].TransformOp = transop; + self->NumModulators++; + + return AL_NO_ERROR; +} + +/* Stores a new object pointer in the zone. Returns the old object pointer. */ +ALvoid *ALsfzone_setRefObject(ALsfzone *self, ALvoid *object) +{ + ALvoid *oldobj = self->Object; + self->Object = object; + return oldobj; +} + + +void ALsfsample_Construct(ALsfsample *self) +{ + self->ref = 0; + + self->id = 0; +} + +void ALsfsample_Destruct(ALsfsample *self) +{ + self->id = 0; +} + + +void ALsfinstrument_Construct(ALsfinstrument *self) +{ + self->ref = 0; + + self->Zones = NULL; + self->NumZones = 0; + + self->id = 0; +} + +void ALsfinstrument_Destruct(ALsfinstrument *self) +{ + ALsizei i; + + self->id = 0; + + for(i = 0;i < self->NumZones;i++) { - 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(self->Zones[i].Object) + DecrementRef(&((ALsfsample*)self->Zones[i].Object)->ref); + ALsfzone_Destruct(&self->Zones[i]); + } + free(self->Zones); + self->Zones = NULL; + self->NumZones = 0; +} - if(pos < queue->size) - memmove(&queue->events[pos+1], &queue->events[pos], - (queue->size-pos)*sizeof(queue->events[0])); + +void ALsfpreset_Construct(ALsfpreset *self) +{ + self->ref = 0; + + self->Zones = NULL; + self->NumZones = 0; + + self->id = 0; +} + +void ALsfpreset_Destruct(ALsfpreset *self) +{ + ALsizei i; + + self->id = 0; + + for(i = 0;i < self->NumZones;i++) + { + if(self->Zones[i].Object) + DecrementRef(&((ALsfinstrument*)self->Zones[i].Object)->ref); + ALsfzone_Destruct(&self->Zones[i]); } + free(self->Zones); + self->Zones = NULL; + self->NumZones = 0; +} - queue->events[pos] = *evt; - queue->size++; - return AL_NO_ERROR; +void ALsoundfont_Construct(ALsoundfont *self) +{ + self->ref = 0; + + self->Presets = NULL; + self->NumPresets = 0; + + self->SampleData = NULL; + self->SampleDataLen = 0; + + self->id = 0; +} + +void ALsoundfont_Destruct(ALsoundfont *self) +{ + ALsizei i; + + self->id = 0; + + for(i = 0;i < self->NumPresets;i++) + { + DecrementRef(&self->Presets[i]->ref); + self->Presets[i] = NULL; + } + free(self->Presets); + self->Presets = NULL; + self->NumPresets = 0; + + free(self->SampleData); + self->SampleData = NULL; + self->SampleDataLen = 0; } diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 64ab1174..37cab1c4 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -38,6 +38,8 @@ #define AL_PROGRAMCHANGE_SOFT 0x00C0 #define AL_CHANNELPRESSURE_SOFT 0x00D0 #define AL_PITCHBEND_SOFT 0x00E0 +typedef void (AL_APIENTRY*LPALGENSOUNDFONTSSOFT)(ALsizei n, ALuint *ids); +typedef void (AL_APIENTRY*LPALDELETESOUNDFONTSSOFT)(ALsizei n, const ALuint *ids); typedef ALboolean (AL_APIENTRY*LPALISSOUNDFONTSOFT)(const char *filename); typedef void (AL_APIENTRY*LPALMIDISOUNDFONTSOFT)(const char *filename); typedef void (AL_APIENTRY*LPALMIDIEVENTSOFT)(ALuint64SOFT time, ALenum event, ALsizei channel, ALsizei param1, ALsizei param2); @@ -50,6 +52,8 @@ typedef void (AL_APIENTRY*LPALMIDIGAINSOFT)(ALfloat value); typedef ALint64SOFT (AL_APIENTRY*LPALGETINTEGER64SOFT)(ALenum pname); typedef void (AL_APIENTRY*LPALGETINTEGER64VSOFT)(ALenum pname, ALint64SOFT *values); #ifdef AL_ALEXT_PROTOTYPES +AL_API void AL_APIENTRY alGenSoundfontsSOFT(ALsizei n, ALuint *ids); +AL_API void AL_APIENTRY alDeleteSoundfontsSOFT(ALsizei n, const ALuint *ids); AL_API ALboolean AL_APIENTRY alIsSoundfontSOFT(const char *filename); AL_API void AL_APIENTRY alMidiSoundfontSOFT(const char *filename); AL_API void AL_APIENTRY alMidiEventSOFT(ALuint64SOFT time, ALenum event, ALsizei channel, ALsizei param1, ALsizei param2); @@ -424,6 +428,9 @@ struct ALCdevice_struct // Map of Filters for this device UIntMap FilterMap; + // Map of Soundfonts for this device + UIntMap SfontMap; + /* MIDI synth engine */ struct MidiSynth *Synth; diff --git a/OpenAL32/Include/alMidi.h b/OpenAL32/Include/alMidi.h index e03cad13..46dcaad5 100644 --- a/OpenAL32/Include/alMidi.h +++ b/OpenAL32/Include/alMidi.h @@ -8,6 +8,111 @@ extern "C" { #endif +typedef struct ALsfgenerator { + ALenum Generator; + ALint Value; +} ALsfgenerator; + +typedef struct ALsfmodulator { + ALenum SourceOp; + ALenum DestOp; + ALint Amount; + ALenum AmountSourceOp; + ALenum TransformOp; +} ALsfmodulator; + +typedef struct ALsfzone { + ALsfgenerator *Generators; + ALsizei NumGenerators; + ALsizei GeneratorsMax; + + ALsfmodulator *Modulators; + ALsizei NumModulators; + ALsizei ModulatorsMax; + + /* NOTE: Preset zones may have a reference to an ALsfinstrument. Instrument + * zones may have a reference to an ALsfsample. */ + ALvoid *Object; +} ALsfzone; + +void ALsfzone_Construct(ALsfzone *self); +void ALsfzone_Destruct(ALsfzone *self); +ALenum ALsfzone_addGenerator(ALsfzone *self, ALenum generator, ALint value); +ALenum ALsfzone_addModulator(ALsfzone *self, ALenum sourceop, ALenum destop, ALint amount, ALenum amtsourceop, ALenum transop); +/* Stores a new object pointer in the zone. Returns the old object pointer. */ +ALvoid *ALsfzone_setRefObject(ALsfzone *self, ALvoid *object); + + +typedef struct ALsfsample { + volatile RefCount ref; + + ALuint Start; + ALuint End; + ALuint LoopStart; + ALuint LoopEnd; + ALuint SampleRate; + ALubyte PitchKey; + ALbyte PitchCorrection; + ALushort SampleLink; + ALenum SampleType; + + ALuint id; +} ALsfsample; + +void ALsfsample_Construct(ALsfsample *self); +void ALsfsample_Destruct(ALsfsample *self); + + +typedef struct ALsfinstrument { + volatile RefCount ref; + + ALsfzone *Zones; + ALsizei NumZones; + + ALuint id; +} ALsfinstrument; + +void ALsfinstrument_Construct(ALsfinstrument *self); +void ALsfinstrument_Destruct(ALsfinstrument *self); + + +typedef struct ALsfpreset { + volatile RefCount ref; + + ALint Program; + ALint Bank; + + ALsfzone *Zones; + ALsizei NumZones; + + ALuint id; +} ALsfpreset; + +void ALsfpreset_Construct(ALsfpreset *self); +void ALsfpreset_Destruct(ALsfpreset *self); + + +typedef struct ALsoundfont { + volatile RefCount ref; + + ALsfpreset **Presets; + ALsizei NumPresets; + + ALshort *SampleData; + ALint SampleDataLen; + + ALuint id; +} ALsoundfont; + +void ALsoundfont_Construct(ALsoundfont *self); +void ALsoundfont_Destruct(ALsoundfont *self); + +inline struct ALsoundfont *LookupSfont(ALCdevice *device, ALuint id) +{ return (struct ALsoundfont*)LookupUIntMapKey(&device->SfontMap, id); } +inline struct ALsoundfont *RemoveSfont(ALCdevice *device, ALuint id) +{ return (struct ALsoundfont*)RemoveUIntMapKey(&device->SfontMap, id); } + + #ifdef __cplusplus } #endif diff --git a/OpenAL32/alMidi.c b/OpenAL32/alMidi.c index d1231fa7..74e37267 100644 --- a/OpenAL32/alMidi.c +++ b/OpenAL32/alMidi.c @@ -7,7 +7,9 @@ #include <limits.h> #include "alMain.h" +#include "alMidi.h" #include "alError.h" +#include "alThunk.h" #include "evtqueue.h" #include "rwlock.h" #include "alu.h" @@ -23,6 +25,97 @@ MidiSynth *SynthCreate(ALCdevice *device) } +extern inline struct ALsoundfont *LookupSfont(ALCdevice *device, ALuint id); +extern inline struct ALsoundfont *RemoveSfont(ALCdevice *device, ALuint id); + + +AL_API void AL_APIENTRY alGenSoundfontsSOFT(ALsizei n, ALuint *ids) +{ + ALCdevice *device; + ALCcontext *context; + ALsizei cur = 0; + ALenum err; + + context = GetContextRef(); + if(!context) return; + + if(!(n >= 0)) + SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); + + device = context->Device; + for(cur = 0;cur < n;cur++) + { + ALsoundfont *sfont = calloc(1, sizeof(ALsoundfont)); + if(!sfont) + { + alDeleteSoundfontsSOFT(cur, ids); + SET_ERROR_AND_GOTO(context, AL_OUT_OF_MEMORY, done); + } + ALsoundfont_Construct(sfont); + + err = NewThunkEntry(&sfont->id); + if(err == AL_NO_ERROR) + err = InsertUIntMapEntry(&device->SfontMap, sfont->id, sfont); + if(err != AL_NO_ERROR) + { + FreeThunkEntry(sfont->id); + memset(sfont, 0, sizeof(ALsoundfont)); + free(sfont); + + alDeleteSoundfontsSOFT(cur, ids); + SET_ERROR_AND_GOTO(context, err, done); + } + + ids[cur] = sfont->id; + } + +done: + ALCcontext_DecRef(context); +} + +AL_API ALvoid AL_APIENTRY alDeleteSoundfontsSOFT(ALsizei n, const ALuint *ids) +{ + ALCdevice *device; + ALCcontext *context; + ALsoundfont *sfont; + ALsizei i; + + context = GetContextRef(); + if(!context) return; + + if(!(n >= 0)) + SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); + + device = context->Device; + for(i = 0;i < n;i++) + { + if(!ids[i]) + continue; + + /* Check for valid soundfont ID */ + if((sfont=LookupSfont(device, ids[i])) == NULL) + SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); + if(sfont->ref != 0) + SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done); + } + + for(i = 0;i < n;i++) + { + if((sfont=RemoveSfont(device, ids[i])) == NULL) + continue; + FreeThunkEntry(sfont->id); + + ALsoundfont_Destruct(sfont); + + memset(sfont, 0, sizeof(*sfont)); + free(sfont); + } + +done: + ALCcontext_DecRef(context); +} + + AL_API ALboolean AL_APIENTRY alIsSoundfontSOFT(const char *filename) { ALCdevice *device; |