Add a method to update device-dependant effect parameters.

The effect state's update method will be called afterwards
This commit is contained in:
Chris Robinson 2009-10-20 08:31:44 -07:00
parent 790aa68621
commit f14cf8289e
4 changed files with 104 additions and 114 deletions

View File

@ -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; ALechoState *state = (ALechoState*)effect;
ALfloat lrpan, cw, a, g;
ALuint maxlen; ALuint maxlen;
maxlen = (ALuint)(AL_ECHO_MAX_DELAY * Context->Frequency); // Use the next power of 2 for the buffer length, so the tap offsets can be
maxlen += (ALuint)(AL_ECHO_MAX_LRDELAY * Context->Frequency); // 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); maxlen = NextPowerOf2(maxlen+1);
if(maxlen > state->BufferLength) if(maxlen != state->BufferLength)
{ {
void *temp; void *temp;
ALuint i; ALuint i;
state->BufferLength = maxlen; temp = realloc(state->SampleBuffer, maxlen * sizeof(ALfloat));
temp = realloc(state->SampleBuffer, state->BufferLength * sizeof(ALfloat));
if(!temp) if(!temp)
{ {
AL_PRINT("Failed reallocation!"); alSetError(AL_OUT_OF_MEMORY);
abort(); return AL_FALSE;
} }
state->BufferLength = maxlen;
for(i = 0;i < state->BufferLength;i++) for(i = 0;i < state->BufferLength;i++)
state->SampleBuffer[i] = 0.0f; 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[0].delay = (ALuint)(Effect->Echo.Delay * Context->Frequency);
state->Tap[1].delay = (ALuint)(Effect->Echo.LRDelay * Context->Frequency); state->Tap[1].delay = (ALuint)(Effect->Echo.LRDelay * Context->Frequency);
state->Tap[1].delay += state->Tap[0].delay; state->Tap[1].delay += state->Tap[0].delay;
@ -173,7 +182,6 @@ ALvoid EchoProcess(ALeffectState *effect, const ALeffectslot *Slot, ALuint Sampl
ALeffectState *EchoCreate(void) ALeffectState *EchoCreate(void)
{ {
ALechoState *state; ALechoState *state;
ALuint i, maxlen;
state = malloc(sizeof(*state)); state = malloc(sizeof(*state));
if(!state) if(!state)
@ -183,25 +191,12 @@ ALeffectState *EchoCreate(void)
} }
state->state.Destroy = EchoDestroy; state->state.Destroy = EchoDestroy;
state->state.DeviceUpdate = EchoDeviceUpdate;
state->state.Update = EchoUpdate; state->state.Update = EchoUpdate;
state->state.Process = EchoProcess; state->state.Process = EchoProcess;
maxlen = (ALuint)(AL_ECHO_MAX_DELAY * MAX_ECHO_FREQ); state->BufferLength = 0;
maxlen += (ALuint)(AL_ECHO_MAX_LRDELAY * MAX_ECHO_FREQ); state->SampleBuffer = NULL;
// 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->Tap[0].delay = 0; state->Tap[0].delay = 0;
state->Tap[1].delay = 0; state->Tap[1].delay = 0;
@ -209,9 +204,9 @@ ALeffectState *EchoCreate(void)
state->GainL = 0.0f; state->GainL = 0.0f;
state->GainR = 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.coeff = 0.0f;
state->iirFilter.history[0] = 0.0f;
state->iirFilter.history[1] = 0.0f;
return &state->state; return &state->state;
} }

View File

@ -31,10 +31,6 @@
#include "alError.h" #include "alError.h"
#include "alu.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 typedef struct DelayLine
{ {
// The delay lines use sample lengths that are powers of 2 to allow // 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; 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 // This updates the reverb state. This is called any time the reverb effect
// is loaded into a slot. // is loaded into a slot.
ALvoid VerbUpdate(ALeffectState *effect, ALCcontext *Context, const ALeffect *Effect) ALvoid VerbUpdate(ALeffectState *effect, ALCcontext *Context, const ALeffect *Effect)
@ -420,56 +477,6 @@ ALvoid VerbUpdate(ALeffectState *effect, ALCcontext *Context, const ALeffect *Ef
ALuint index; ALuint index;
ALfloat length, mixCoeff, cw, g, coeff; ALfloat length, mixCoeff, cw, g, coeff;
ALfloat hfRatio = Effect->Reverb.DecayHFRatio; 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). // Calculate the master low-pass filter (from the master effect HF gain).
cw = cos(2.0 * M_PI * Effect->Reverb.HFReference / Context->Frequency); 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) ALeffectState *VerbCreate(void)
{ {
ALverbState *State = NULL; ALverbState *State = NULL;
ALuint length[13], totalLength, index; ALuint index;
State = malloc(sizeof(ALverbState)); State = malloc(sizeof(ALverbState));
if(!State) if(!State)
@ -767,28 +774,18 @@ ALeffectState *VerbCreate(void)
} }
State->state.Destroy = VerbDestroy; State->state.Destroy = VerbDestroy;
State->state.DeviceUpdate = VerbDeviceUpdate;
State->state.Update = VerbUpdate; State->state.Update = VerbUpdate;
State->state.Process = VerbProcess; State->state.Process = VerbProcess;
totalLength = CalcLengths(length, MAX_REVERB_FREQ); State->TotalLength = 0;
State->SampleBuffer = NULL;
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->LpFilter.coeff = 0.0f; State->LpFilter.coeff = 0.0f;
State->LpFilter.history[0] = 0.0f; State->LpFilter.history[0] = 0.0f;
State->LpFilter.history[1] = 0.0f; State->LpFilter.history[1] = 0.0f;
State->Delay.Mask = length[0] - 1; State->Delay.Mask = 0;
State->Delay.Line = &State->SampleBuffer[0]; State->Delay.Line = NULL;
totalLength = length[0];
State->Tap[0] = 0; State->Tap[0] = 0;
State->Tap[1] = 0; State->Tap[1] = 0;
@ -800,10 +797,8 @@ ALeffectState *VerbCreate(void)
for(index = 0;index < 4;index++) for(index = 0;index < 4;index++)
{ {
State->Early.Coeff[index] = 0.0f; State->Early.Coeff[index] = 0.0f;
State->Early.Delay[index].Mask = length[1 + index] - 1; State->Early.Delay[index].Mask = 0;
State->Early.Delay[index].Line = &State->SampleBuffer[totalLength]; State->Early.Delay[index].Line = NULL;
totalLength += length[1 + index];
State->Early.Offset[index] = 0; State->Early.Offset[index] = 0;
} }
@ -815,20 +810,13 @@ ALeffectState *VerbCreate(void)
for(index = 0;index < 4;index++) for(index = 0;index < 4;index++)
{ {
State->Late.ApCoeff[index] = 0.0f; State->Late.ApCoeff[index] = 0.0f;
State->Late.ApDelay[index].Mask = length[5 + index] - 1; State->Late.ApDelay[index].Mask = 0;
State->Late.ApDelay[index].Line = &State->SampleBuffer[totalLength]; State->Late.ApDelay[index].Line = NULL;
totalLength += length[5 + index];
State->Late.ApOffset[index] = 0; State->Late.ApOffset[index] = 0;
}
for(index = 0;index < 4;index++)
{
State->Late.Coeff[index] = 0.0f; State->Late.Coeff[index] = 0.0f;
State->Late.Delay[index].Mask = length[9 + index] - 1; State->Late.Delay[index].Mask = 0;
State->Late.Delay[index].Line = &State->SampleBuffer[totalLength]; State->Late.Delay[index].Line = NULL;
totalLength += length[9 + index];
State->Late.Offset[index] = 0; State->Late.Offset[index] = 0;
State->Late.LpCoeff[index] = 0.0f; State->Late.LpCoeff[index] = 0.0f;

View File

@ -55,6 +55,7 @@ ALvoid ReleaseALAuxiliaryEffectSlots(ALCcontext *Context);
struct ALeffectState { struct ALeffectState {
ALvoid (*Destroy)(ALeffectState *State); ALvoid (*Destroy)(ALeffectState *State);
ALboolean (*DeviceUpdate)(ALeffectState *State, ALCdevice *Device);
ALvoid (*Update)(ALeffectState *State, ALCcontext *Context, const ALeffect *Effect); ALvoid (*Update)(ALeffectState *State, ALCcontext *Context, const ALeffect *Effect);
ALvoid (*Process)(ALeffectState *State, const ALeffectslot *Slot, ALuint SamplesToDo, const ALfloat *SamplesIn, ALfloat (*SamplesOut)[OUTPUTCHANNELS]); 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); ALeffectState *EchoCreate(void);
#define ALEffect_Destroy(a) ((a)->Destroy((a))) #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_Update(a,b,c) ((a)->Update((a),(b),(c)))
#define ALEffect_Process(a,b,c,d,e) ((a)->Process((a),(b),(c),(d),(e))) #define ALEffect_Process(a,b,c,d,e) ((a)->Process((a),(b),(c),(d),(e)))

View File

@ -428,8 +428,13 @@ static ALvoid InitializeEffect(ALCcontext *Context, ALeffectslot *ALEffectSlot,
else if(effect->type == AL_EFFECT_ECHO) else if(effect->type == AL_EFFECT_ECHO)
NewState = EchoCreate(); NewState = EchoCreate();
/* No new state? An error occured.. */ /* No new state? An error occured.. */
if(!NewState) if(NewState == NULL ||
ALEffect_DeviceUpdate(NewState, Context->Device) == AL_FALSE)
{
if(NewState)
ALEffect_Destroy(NewState);
return; return;
}
} }
if(ALEffectSlot->EffectState) if(ALEffectSlot->EffectState)
ALEffect_Destroy(ALEffectSlot->EffectState); ALEffect_Destroy(ALEffectSlot->EffectState);