Add a new ALsoundfont object type

Includes a basic hierarchy for presets, instruments, samples, zones,
generators, and modulators.
This commit is contained in:
Chris Robinson
2013-12-18 22:51:53 -08:00
parent b9468dc917
commit 8083fb5be7
5 changed files with 493 additions and 74 deletions
+2
View File
@@ -280,6 +280,8 @@ static const ALCfunction alcFunctions[] = {
DECL(alGetSource3i64SOFT),
DECL(alGetSourcei64vSOFT),
DECL(alGenSoundfontsSOFT),
DECL(alDeleteSoundfontsSOFT),
DECL(alIsSoundfontSOFT),
DECL(alMidiSoundfontSOFT),
DECL(alMidiEventSOFT),
+286 -74
View File
@@ -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;
}
ALenum InsertEvtQueue(EvtQueue *queue, const MidiEvent *evt)
{
ALsizei pos;
if(queue->maxsize == queue->size)
if(self->NumGenerators == self->GeneratorsMax)
{
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;
ALsizei newmax = 0;
ALvoid *temp = NULL;
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;
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;
queue->events = temp;
queue->maxsize = newsize;
}
self->Generators = temp;
self->GeneratorsMax = newmax;
}
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++;
self->Generators[self->NumGenerators].Generator = generator;
self->Generators[self->NumGenerators].Value = value;
self->NumGenerators++;
return AL_NO_ERROR;
}
ALenum ALsfzone_addModulator(ALsfzone *self, ALenum sourceop, ALenum destop, ALint amount, ALenum amtsourceop, ALenum transop)
{
ALsizei i;
for(i = 0;i < self->NumModulators;i++)
{
if(self->Modulators[i].SourceOp == sourceop && self->Modulators[i].DestOp == destop &&
self->Modulators[i].AmountSourceOp == amtsourceop &&
self->Modulators[i].TransformOp == transop)
{
self->Modulators[i].Amount = amount;
return AL_NO_ERROR;
}
}
if(self->NumModulators == self->ModulatorsMax)
{
ALsizei newmax = 0;
ALvoid *temp = NULL;
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;
}
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++)
{
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;
}
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;
}
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;
}
+7
View File
@@ -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;
+105
View File
@@ -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
+93
View File
@@ -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;