aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Robinson <[email protected]>2013-12-18 22:51:53 -0800
committerChris Robinson <[email protected]>2013-12-18 22:51:53 -0800
commit8083fb5be7943e6c5ade6c062ae78559c0826472 (patch)
tree5e39ff595fcead4d272ad8896aef43b94c8adcec
parentb9468dc9176861f6ab6f6e358fda71c0d6fecc90 (diff)
Add a new ALsoundfont object type
Includes a basic hierarchy for presets, instruments, samples, zones, generators, and modulators.
-rw-r--r--Alc/ALc.c2
-rw-r--r--Alc/midi/base.c344
-rw-r--r--OpenAL32/Include/alMain.h7
-rw-r--r--OpenAL32/Include/alMidi.h105
-rw-r--r--OpenAL32/alMidi.c93
5 files changed, 485 insertions, 66 deletions
diff --git a/Alc/ALc.c b/Alc/ALc.c
index c7206169..ced586d4 100644
--- a/Alc/ALc.c
+++ b/Alc/ALc.c
@@ -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;