diff options
author | Chris Robinson <[email protected]> | 2009-10-19 07:46:53 -0700 |
---|---|---|
committer | Chris Robinson <[email protected]> | 2009-10-19 07:46:53 -0700 |
commit | 6d1d61026d5c5ba75986c2cd8c499bcf72549197 (patch) | |
tree | bc23ed399f8694bdbf483eb7221f1a2b7b3982a9 /Alc/alcReverb.c | |
parent | a4e3ca933b036102b1aed623015d007869416c7b (diff) |
Be context-agnostic in the effect Create functions
This allows the effect Update functions to handle the playback frequency being
changed. By default the effects assume a maximum frequency of 192khz, however,
it can go higher at the cost of the sample buffers being cleared and the risk
of an abort() if reallocation fails
Diffstat (limited to 'Alc/alcReverb.c')
-rw-r--r-- | Alc/alcReverb.c | 151 |
1 files changed, 105 insertions, 46 deletions
diff --git a/Alc/alcReverb.c b/Alc/alcReverb.c index 42c823ce..f0d9e0be 100644 --- a/Alc/alcReverb.c +++ b/Alc/alcReverb.c @@ -31,6 +31,10 @@ #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 @@ -46,6 +50,7 @@ typedef struct ALverbState { // All delay lines are allocated as a single buffer to reduce memory // fragmentation and management code. ALfloat *SampleBuffer; + ALuint TotalLength; // Master effect low-pass filter (2 chained 1-pole filters). FILTER LpFilter; ALfloat LpHistory[2]; @@ -143,6 +148,46 @@ static ALuint NextPowerOf2(ALuint value) return powerOf2; } +static ALuint CalcLengths(ALuint length[13], ALuint frequency) +{ + ALuint samples, totalLength, index; + + // All line lengths are powers of 2, calculated from their lengths, with + // an additional sample in case of rounding errors. + + // See VerbUpdate() for an explanation of the additional calculation + // added to the master line length. + samples = (ALuint) + ((MASTER_LINE_LENGTH + + (LATE_LINE_LENGTH[0] * (1.0f + LATE_LINE_MULTIPLIER) * + (DECO_FRACTION * ((DECO_MULTIPLIER * DECO_MULTIPLIER * + DECO_MULTIPLIER) - 1.0f)))) * + frequency) + 1; + length[0] = NextPowerOf2(samples); + totalLength = length[0]; + for(index = 0;index < 4;index++) + { + samples = (ALuint)(EARLY_LINE_LENGTH[index] * frequency) + 1; + length[1 + index] = NextPowerOf2(samples); + totalLength += length[1 + index]; + } + for(index = 0;index < 4;index++) + { + samples = (ALuint)(ALLPASS_LINE_LENGTH[index] * frequency) + 1; + length[5 + index] = NextPowerOf2(samples); + totalLength += length[5 + index]; + } + for(index = 0;index < 4;index++) + { + samples = (ALuint)(LATE_LINE_LENGTH[index] * + (1.0f + LATE_LINE_MULTIPLIER) * frequency) + 1; + length[9 + index] = NextPowerOf2(samples); + totalLength += length[9 + index]; + } + + return totalLength; +} + // Basic delay line input/output routines. static __inline ALfloat DelayLineOut(DelayLine *Delay, ALuint offset) { @@ -369,12 +414,62 @@ static __inline ALint aluCart2LUTpos(ALfloat re, ALfloat im) // This updates the reverb state. This is called any time the reverb effect // is loaded into a slot. -ALvoid VerbUpdate(ALeffectState *effect, ALCcontext *Context, ALeffect *Effect) +ALvoid VerbUpdate(ALeffectState *effect, ALCcontext *Context, const ALeffect *Effect) { ALverbState *State = (ALverbState*)effect; 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); @@ -659,10 +754,10 @@ ALvoid EAXVerbProcess(ALeffectState *effect, const ALeffectslot *Slot, ALuint Sa // This creates the reverb state. It should be called only when the reverb // effect is loaded into a slot that doesn't already have a reverb effect. -ALeffectState *VerbCreate(ALCcontext *Context) +ALeffectState *VerbCreate(void) { ALverbState *State = NULL; - ALuint samples, length[13], totalLength, index; + ALuint length[13], totalLength, index; State = malloc(sizeof(ALverbState)); if(!State) @@ -675,42 +770,10 @@ ALeffectState *VerbCreate(ALCcontext *Context) State->state.Update = VerbUpdate; State->state.Process = VerbProcess; - // All line lengths are powers of 2, calculated from their lengths, with - // an additional sample in case of rounding errors. - - // See VerbUpdate() for an explanation of the additional calculation - // added to the master line length. - samples = (ALuint) - ((MASTER_LINE_LENGTH + - (LATE_LINE_LENGTH[0] * (1.0f + LATE_LINE_MULTIPLIER) * - (DECO_FRACTION * ((DECO_MULTIPLIER * DECO_MULTIPLIER * - DECO_MULTIPLIER) - 1.0f)))) * - Context->Frequency) + 1; - length[0] = NextPowerOf2(samples); - totalLength = length[0]; - for(index = 0;index < 4;index++) - { - samples = (ALuint)(EARLY_LINE_LENGTH[index] * Context->Frequency) + 1; - length[1 + index] = NextPowerOf2(samples); - totalLength += length[1 + index]; - } - for(index = 0;index < 4;index++) - { - samples = (ALuint)(ALLPASS_LINE_LENGTH[index] * Context->Frequency) + 1; - length[5 + index] = NextPowerOf2(samples); - totalLength += length[5 + index]; - } - for(index = 0;index < 4;index++) - { - samples = (ALuint)(LATE_LINE_LENGTH[index] * - (1.0f + LATE_LINE_MULTIPLIER) * Context->Frequency) + 1; - length[9 + index] = NextPowerOf2(samples); - totalLength += length[9 + index]; - } + totalLength = CalcLengths(length, MAX_REVERB_FREQ); - // All lines share a single sample buffer and have their masks and start - // addresses calculated once. - State->SampleBuffer = malloc(totalLength * sizeof(ALfloat)); + State->TotalLength = totalLength; + State->SampleBuffer = malloc(State->TotalLength * sizeof(ALfloat)); if(!State->SampleBuffer) { free(State); @@ -741,9 +804,7 @@ ALeffectState *VerbCreate(ALCcontext *Context) State->Early.Delay[index].Line = &State->SampleBuffer[totalLength]; totalLength += length[1 + index]; - // The early delay lines have their read offsets calculated once. - State->Early.Offset[index] = (ALuint)(EARLY_LINE_LENGTH[index] * - Context->Frequency); + State->Early.Offset[index] = 0; } State->Late.Gain = 0.0f; @@ -758,9 +819,7 @@ ALeffectState *VerbCreate(ALCcontext *Context) State->Late.ApDelay[index].Line = &State->SampleBuffer[totalLength]; totalLength += length[5 + index]; - // The late all-pass lines have their read offsets calculated once. - State->Late.ApOffset[index] = (ALuint)(ALLPASS_LINE_LENGTH[index] * - Context->Frequency); + State->Late.ApOffset[index] = 0; } for(index = 0;index < 4;index++) @@ -787,9 +846,9 @@ ALeffectState *VerbCreate(ALCcontext *Context) return &State->state; } -ALeffectState *EAXVerbCreate(ALCcontext *Context) +ALeffectState *EAXVerbCreate(void) { - ALeffectState *State = VerbCreate(Context); + ALeffectState *State = VerbCreate(); if(State) State->Process = EAXVerbProcess; return State; } |