From f14cf8289eae832b090c4067ae66a19be08b7029 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 20 Oct 2009 08:31:44 -0700 Subject: [PATCH] Add a method to update device-dependant effect parameters. The effect state's update method will be called afterwards --- Alc/alcEcho.c | 51 +++++----- Alc/alcReverb.c | 158 +++++++++++++---------------- OpenAL32/Include/alAuxEffectSlot.h | 2 + OpenAL32/alAuxEffectSlot.c | 7 +- 4 files changed, 104 insertions(+), 114 deletions(-) diff --git a/Alc/alcEcho.c b/Alc/alcEcho.c index 8aa4d2c..6601051 100644 --- a/Alc/alcEcho.c +++ b/Alc/alcEcho.c @@ -85,32 +85,41 @@ ALvoid EchoDestroy(ALeffectState *effect) } } -ALvoid EchoUpdate(ALeffectState *effect, ALCcontext *Context, const ALeffect *Effect) +ALboolean EchoDeviceUpdate(ALeffectState *effect, ALCdevice *Device) { ALechoState *state = (ALechoState*)effect; - ALfloat lrpan, cw, a, g; ALuint maxlen; - maxlen = (ALuint)(AL_ECHO_MAX_DELAY * Context->Frequency); - maxlen += (ALuint)(AL_ECHO_MAX_LRDELAY * Context->Frequency); + // Use the next power of 2 for the buffer length, so the tap offsets can be + // wrapped using a mask instead of a modulo + maxlen = (ALuint)(AL_ECHO_MAX_DELAY * Device->Frequency); + maxlen += (ALuint)(AL_ECHO_MAX_LRDELAY * Device->Frequency); maxlen = NextPowerOf2(maxlen+1); - if(maxlen > state->BufferLength) + if(maxlen != state->BufferLength) { void *temp; ALuint i; - state->BufferLength = maxlen; - temp = realloc(state->SampleBuffer, state->BufferLength * sizeof(ALfloat)); + temp = realloc(state->SampleBuffer, maxlen * sizeof(ALfloat)); if(!temp) { - AL_PRINT("Failed reallocation!"); - abort(); + alSetError(AL_OUT_OF_MEMORY); + return AL_FALSE; } + state->BufferLength = maxlen; for(i = 0;i < state->BufferLength;i++) state->SampleBuffer[i] = 0.0f; } + return AL_TRUE; +} + +ALvoid EchoUpdate(ALeffectState *effect, ALCcontext *Context, const ALeffect *Effect) +{ + ALechoState *state = (ALechoState*)effect; + ALfloat lrpan, cw, a, g; + state->Tap[0].delay = (ALuint)(Effect->Echo.Delay * Context->Frequency); state->Tap[1].delay = (ALuint)(Effect->Echo.LRDelay * Context->Frequency); state->Tap[1].delay += state->Tap[0].delay; @@ -173,7 +182,6 @@ ALvoid EchoProcess(ALeffectState *effect, const ALeffectslot *Slot, ALuint Sampl ALeffectState *EchoCreate(void) { ALechoState *state; - ALuint i, maxlen; state = malloc(sizeof(*state)); if(!state) @@ -183,25 +191,12 @@ ALeffectState *EchoCreate(void) } state->state.Destroy = EchoDestroy; + state->state.DeviceUpdate = EchoDeviceUpdate; state->state.Update = EchoUpdate; state->state.Process = EchoProcess; - maxlen = (ALuint)(AL_ECHO_MAX_DELAY * MAX_ECHO_FREQ); - maxlen += (ALuint)(AL_ECHO_MAX_LRDELAY * MAX_ECHO_FREQ); - - // Use the next power of 2 for the buffer length, so the tap offsets can be - // wrapped using a mask instead of a modulo - state->BufferLength = NextPowerOf2(maxlen+1); - state->SampleBuffer = malloc(state->BufferLength * sizeof(ALfloat)); - if(!state->SampleBuffer) - { - free(state); - alSetError(AL_OUT_OF_MEMORY); - return NULL; - } - - for(i = 0;i < state->BufferLength;i++) - state->SampleBuffer[i] = 0.0f; + state->BufferLength = 0; + state->SampleBuffer = NULL; state->Tap[0].delay = 0; state->Tap[1].delay = 0; @@ -209,9 +204,9 @@ ALeffectState *EchoCreate(void) state->GainL = 0.0f; state->GainR = 0.0f; - for(i = 0;i < 2;i++) - state->iirFilter.history[i] = 0.0f; state->iirFilter.coeff = 0.0f; + state->iirFilter.history[0] = 0.0f; + state->iirFilter.history[1] = 0.0f; return &state->state; } diff --git a/Alc/alcReverb.c b/Alc/alcReverb.c index f0d9e0b..4126b3e 100644 --- a/Alc/alcReverb.c +++ b/Alc/alcReverb.c @@ -31,10 +31,6 @@ #include "alError.h" #include "alu.h" -// Just a soft maximum. Being higher will cause VerbUpdate to reallocate the -// sample buffer which may cause an abort if realloc fails -#define MAX_REVERB_FREQ 192000 - typedef struct DelayLine { // The delay lines use sample lengths that are powers of 2 to allow @@ -412,6 +408,67 @@ static __inline ALint aluCart2LUTpos(ALfloat re, ALfloat im) return pos%LUT_NUM; } +// This updates the device-dependant reverb state. This is called on +// initialization and any time the device parameters (eg. playback frequency, +// format) have been changed. +ALboolean VerbDeviceUpdate(ALeffectState *effect, ALCdevice *Device) +{ + ALverbState *State = (ALverbState*)effect; + ALuint length[13], totalLength; + ALuint index; + + totalLength = CalcLengths(length, Device->Frequency); + if(totalLength != State->TotalLength) + { + void *temp; + + temp = realloc(State->SampleBuffer, totalLength * sizeof(ALfloat)); + if(!temp) + { + alSetError(AL_OUT_OF_MEMORY); + return AL_FALSE; + } + State->TotalLength = totalLength; + State->SampleBuffer = temp; + + for(index = 0; index < totalLength;index++) + State->SampleBuffer[index] = 0.0f; + + // All lines share a single sample buffer + State->Delay.Mask = length[0] - 1; + State->Delay.Line = &State->SampleBuffer[0]; + totalLength = length[0]; + for(index = 0;index < 4;index++) + { + State->Early.Delay[index].Mask = length[1 + index] - 1; + State->Early.Delay[index].Line = &State->SampleBuffer[totalLength]; + totalLength += length[1 + index]; + } + for(index = 0;index < 4;index++) + { + State->Late.ApDelay[index].Mask = length[5 + index] - 1; + State->Late.ApDelay[index].Line = &State->SampleBuffer[totalLength]; + totalLength += length[5 + index]; + } + for(index = 0;index < 4;index++) + { + State->Late.Delay[index].Mask = length[9 + index] - 1; + State->Late.Delay[index].Line = &State->SampleBuffer[totalLength]; + totalLength += length[9 + index]; + } + } + + for(index = 0;index < 4;index++) + { + State->Early.Offset[index] = (ALuint)(EARLY_LINE_LENGTH[index] * + Device->Frequency); + State->Late.ApOffset[index] = (ALuint)(ALLPASS_LINE_LENGTH[index] * + Device->Frequency); + } + + return AL_TRUE; +} + // This updates the reverb state. This is called any time the reverb effect // is loaded into a slot. ALvoid VerbUpdate(ALeffectState *effect, ALCcontext *Context, const ALeffect *Effect) @@ -420,56 +477,6 @@ ALvoid VerbUpdate(ALeffectState *effect, ALCcontext *Context, const ALeffect *Ef ALuint index; ALfloat length, mixCoeff, cw, g, coeff; ALfloat hfRatio = Effect->Reverb.DecayHFRatio; - ALuint lengths[13], totalLength; - - totalLength = CalcLengths(lengths, Context->Frequency); - if(totalLength > State->TotalLength) - { - void *temp; - - State->TotalLength = totalLength; - temp = realloc(State->SampleBuffer, State->TotalLength * sizeof(ALfloat)); - if(!temp) - { - AL_PRINT("Failed reallocation!"); - abort(); - } - State->SampleBuffer = temp; - - for(index = 0; index < totalLength;index++) - State->SampleBuffer[index] = 0.0f; - - // All lines share a single sample buffer - State->Delay.Mask = lengths[0] - 1; - State->Delay.Line = &State->SampleBuffer[0]; - totalLength = lengths[0]; - for(index = 0;index < 4;index++) - { - State->Early.Delay[index].Mask = lengths[1 + index] - 1; - State->Early.Delay[index].Line = &State->SampleBuffer[totalLength]; - totalLength += lengths[1 + index]; - } - for(index = 0;index < 4;index++) - { - State->Late.ApDelay[index].Mask = lengths[5 + index] - 1; - State->Late.ApDelay[index].Line = &State->SampleBuffer[totalLength]; - totalLength += lengths[5 + index]; - } - for(index = 0;index < 4;index++) - { - State->Late.Delay[index].Mask = lengths[9 + index] - 1; - State->Late.Delay[index].Line = &State->SampleBuffer[totalLength]; - totalLength += lengths[9 + index]; - } - } - - for(index = 0;index < 4;index++) - { - State->Early.Offset[index] = (ALuint)(EARLY_LINE_LENGTH[index] * - Context->Frequency); - State->Late.ApOffset[index] = (ALuint)(ALLPASS_LINE_LENGTH[index] * - Context->Frequency); - } // Calculate the master low-pass filter (from the master effect HF gain). cw = cos(2.0 * M_PI * Effect->Reverb.HFReference / Context->Frequency); @@ -757,7 +764,7 @@ ALvoid EAXVerbProcess(ALeffectState *effect, const ALeffectslot *Slot, ALuint Sa ALeffectState *VerbCreate(void) { ALverbState *State = NULL; - ALuint length[13], totalLength, index; + ALuint index; State = malloc(sizeof(ALverbState)); if(!State) @@ -767,28 +774,18 @@ ALeffectState *VerbCreate(void) } State->state.Destroy = VerbDestroy; + State->state.DeviceUpdate = VerbDeviceUpdate; State->state.Update = VerbUpdate; State->state.Process = VerbProcess; - totalLength = CalcLengths(length, MAX_REVERB_FREQ); - - State->TotalLength = totalLength; - State->SampleBuffer = malloc(State->TotalLength * sizeof(ALfloat)); - if(!State->SampleBuffer) - { - free(State); - alSetError(AL_OUT_OF_MEMORY); - return NULL; - } - for(index = 0; index < totalLength;index++) - State->SampleBuffer[index] = 0.0f; + State->TotalLength = 0; + State->SampleBuffer = NULL; State->LpFilter.coeff = 0.0f; State->LpFilter.history[0] = 0.0f; State->LpFilter.history[1] = 0.0f; - State->Delay.Mask = length[0] - 1; - State->Delay.Line = &State->SampleBuffer[0]; - totalLength = length[0]; + State->Delay.Mask = 0; + State->Delay.Line = NULL; State->Tap[0] = 0; State->Tap[1] = 0; @@ -800,10 +797,8 @@ ALeffectState *VerbCreate(void) for(index = 0;index < 4;index++) { State->Early.Coeff[index] = 0.0f; - State->Early.Delay[index].Mask = length[1 + index] - 1; - State->Early.Delay[index].Line = &State->SampleBuffer[totalLength]; - totalLength += length[1 + index]; - + State->Early.Delay[index].Mask = 0; + State->Early.Delay[index].Line = NULL; State->Early.Offset[index] = 0; } @@ -815,20 +810,13 @@ ALeffectState *VerbCreate(void) for(index = 0;index < 4;index++) { State->Late.ApCoeff[index] = 0.0f; - State->Late.ApDelay[index].Mask = length[5 + index] - 1; - State->Late.ApDelay[index].Line = &State->SampleBuffer[totalLength]; - totalLength += length[5 + index]; - + State->Late.ApDelay[index].Mask = 0; + State->Late.ApDelay[index].Line = NULL; State->Late.ApOffset[index] = 0; - } - for(index = 0;index < 4;index++) - { State->Late.Coeff[index] = 0.0f; - State->Late.Delay[index].Mask = length[9 + index] - 1; - State->Late.Delay[index].Line = &State->SampleBuffer[totalLength]; - totalLength += length[9 + index]; - + State->Late.Delay[index].Mask = 0; + State->Late.Delay[index].Line = NULL; State->Late.Offset[index] = 0; State->Late.LpCoeff[index] = 0.0f; diff --git a/OpenAL32/Include/alAuxEffectSlot.h b/OpenAL32/Include/alAuxEffectSlot.h index 667d74d..14e3b2f 100644 --- a/OpenAL32/Include/alAuxEffectSlot.h +++ b/OpenAL32/Include/alAuxEffectSlot.h @@ -55,6 +55,7 @@ ALvoid ReleaseALAuxiliaryEffectSlots(ALCcontext *Context); struct ALeffectState { ALvoid (*Destroy)(ALeffectState *State); + ALboolean (*DeviceUpdate)(ALeffectState *State, ALCdevice *Device); ALvoid (*Update)(ALeffectState *State, ALCcontext *Context, const ALeffect *Effect); ALvoid (*Process)(ALeffectState *State, const ALeffectslot *Slot, ALuint SamplesToDo, const ALfloat *SamplesIn, ALfloat (*SamplesOut)[OUTPUTCHANNELS]); }; @@ -64,6 +65,7 @@ ALeffectState *VerbCreate(void); ALeffectState *EchoCreate(void); #define ALEffect_Destroy(a) ((a)->Destroy((a))) +#define ALEffect_DeviceUpdate(a,b) ((a)->DeviceUpdate((a),(b))) #define ALEffect_Update(a,b,c) ((a)->Update((a),(b),(c))) #define ALEffect_Process(a,b,c,d,e) ((a)->Process((a),(b),(c),(d),(e))) diff --git a/OpenAL32/alAuxEffectSlot.c b/OpenAL32/alAuxEffectSlot.c index 1fd2f70..7a9c632 100644 --- a/OpenAL32/alAuxEffectSlot.c +++ b/OpenAL32/alAuxEffectSlot.c @@ -428,8 +428,13 @@ static ALvoid InitializeEffect(ALCcontext *Context, ALeffectslot *ALEffectSlot, else if(effect->type == AL_EFFECT_ECHO) NewState = EchoCreate(); /* No new state? An error occured.. */ - if(!NewState) + if(NewState == NULL || + ALEffect_DeviceUpdate(NewState, Context->Device) == AL_FALSE) + { + if(NewState) + ALEffect_Destroy(NewState); return; + } } if(ALEffectSlot->EffectState) ALEffect_Destroy(ALEffectSlot->EffectState);