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/alcEcho.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/alcEcho.c')
-rw-r--r-- | Alc/alcEcho.c | 102 |
1 files changed, 59 insertions, 43 deletions
diff --git a/Alc/alcEcho.c b/Alc/alcEcho.c index deaae622..8aa4d2ce 100644 --- a/Alc/alcEcho.c +++ b/Alc/alcEcho.c @@ -29,6 +29,10 @@ #include "alError.h" #include "alu.h" +// Just a soft maximum. Being higher will cause EchoUpdate to reallocate the +// sample buffer which may cause an abort if realloc fails +#define MAX_ECHO_FREQ 192000 + typedef struct ALechoState { // Must be first in all effects! ALeffectState state; @@ -36,11 +40,12 @@ typedef struct ALechoState { ALfloat *SampleBuffer; ALuint BufferLength; - // The echo is two tap. The third tap is the offset to write the feedback - // and input sample to + // The echo is two tap. The delay is the number of samples from before the + // current offset struct { - ALuint offset; - } Tap[3]; + ALuint delay; + } Tap[2]; + ALuint Offset; // The LR gains for the first tap. The second tap uses the reverse ALfloat GainL; ALfloat GainR; @@ -80,19 +85,35 @@ ALvoid EchoDestroy(ALeffectState *effect) } } -ALvoid EchoUpdate(ALeffectState *effect, ALCcontext *Context, ALeffect *Effect) +ALvoid EchoUpdate(ALeffectState *effect, ALCcontext *Context, const ALeffect *Effect) { ALechoState *state = (ALechoState*)effect; - ALuint newdelay1, newdelay2; ALfloat lrpan, cw, a, g; + ALuint maxlen; - newdelay1 = (ALuint)(Effect->Echo.Delay * Context->Frequency); - newdelay2 = (ALuint)(Effect->Echo.LRDelay * Context->Frequency); + maxlen = (ALuint)(AL_ECHO_MAX_DELAY * Context->Frequency); + maxlen += (ALuint)(AL_ECHO_MAX_LRDELAY * Context->Frequency); + maxlen = NextPowerOf2(maxlen+1); + + if(maxlen > state->BufferLength) + { + void *temp; + ALuint i; + + state->BufferLength = maxlen; + temp = realloc(state->SampleBuffer, state->BufferLength * sizeof(ALfloat)); + if(!temp) + { + AL_PRINT("Failed reallocation!"); + abort(); + } + for(i = 0;i < state->BufferLength;i++) + state->SampleBuffer[i] = 0.0f; + } - state->Tap[0].offset = (state->BufferLength - newdelay1 - 1 + - state->Tap[2].offset)%state->BufferLength; - state->Tap[1].offset = (state->BufferLength - newdelay1 - newdelay2 - 1 + - state->Tap[2].offset)%state->BufferLength; + 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; lrpan = Effect->Echo.Spread*0.5f + 0.5f; state->GainL = aluSqrt( lrpan); @@ -111,32 +132,30 @@ ALvoid EchoUpdate(ALeffectState *effect, ALCcontext *Context, ALeffect *Effect) ALvoid EchoProcess(ALeffectState *effect, const ALeffectslot *Slot, ALuint SamplesToDo, const ALfloat *SamplesIn, ALfloat (*SamplesOut)[OUTPUTCHANNELS]) { ALechoState *state = (ALechoState*)effect; - const ALuint delay = state->BufferLength-1; - ALuint tap1off = state->Tap[0].offset; - ALuint tap2off = state->Tap[1].offset; - ALuint fboff = state->Tap[2].offset; - ALfloat gain = Slot->Gain; - ALfloat samp[2]; + const ALuint mask = state->BufferLength-1; + const ALuint tap1 = state->Tap[0].delay; + const ALuint tap2 = state->Tap[1].delay; + ALuint offset = state->Offset; + const ALfloat gain = Slot->Gain; + ALfloat samp[2], smp; ALuint i; - for(i = 0;i < SamplesToDo;i++) + for(i = 0;i < SamplesToDo;i++,offset++) { - // Apply damping - samp[0] = lpFilter2P(&state->iirFilter, 0, state->SampleBuffer[tap2off]+SamplesIn[i]); - - // Apply feedback gain and mix in the new sample - state->SampleBuffer[fboff] = samp[0] * state->FeedGain; - - tap1off = (tap1off+1) & delay; - tap2off = (tap2off+1) & delay; - fboff = (fboff+1) & delay; - // Sample first tap - samp[0] = state->SampleBuffer[tap1off]*state->GainL; - samp[1] = state->SampleBuffer[tap1off]*state->GainR; + smp = state->SampleBuffer[(offset-tap1) & mask]; + samp[0] = smp * state->GainL; + samp[1] = smp * state->GainR; // Sample second tap. Reverse LR panning - samp[0] += state->SampleBuffer[tap2off]*state->GainR; - samp[1] += state->SampleBuffer[tap2off]*state->GainL; + smp = state->SampleBuffer[(offset-tap2) & mask]; + samp[0] += smp * state->GainR; + samp[1] += smp * state->GainL; + + // Apply damping and feedback gain to the second tap, and mix in the + // new sample + smp = lpFilter2P(&state->iirFilter, 0, smp+SamplesIn[i]); + state->SampleBuffer[offset&mask] = smp * state->FeedGain; + // Apply slot gain samp[0] *= gain; samp[1] *= gain; @@ -148,13 +167,10 @@ ALvoid EchoProcess(ALeffectState *effect, const ALeffectslot *Slot, ALuint Sampl SamplesOut[i][BACK_LEFT] += samp[0]; SamplesOut[i][BACK_RIGHT] += samp[1]; } - - state->Tap[0].offset = tap1off; - state->Tap[1].offset = tap2off; - state->Tap[2].offset = fboff; + state->Offset = offset; } -ALeffectState *EchoCreate(ALCcontext *Context) +ALeffectState *EchoCreate(void) { ALechoState *state; ALuint i, maxlen; @@ -170,8 +186,8 @@ ALeffectState *EchoCreate(ALCcontext *Context) state->state.Update = EchoUpdate; state->state.Process = EchoProcess; - maxlen = (ALuint)(AL_ECHO_MAX_DELAY * Context->Frequency); - maxlen += (ALuint)(AL_ECHO_MAX_LRDELAY * Context->Frequency); + 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 @@ -187,9 +203,9 @@ ALeffectState *EchoCreate(ALCcontext *Context) for(i = 0;i < state->BufferLength;i++) state->SampleBuffer[i] = 0.0f; - state->Tap[0].offset = 0; - state->Tap[1].offset = 0; - state->Tap[2].offset = 0; + state->Tap[0].delay = 0; + state->Tap[1].delay = 0; + state->Offset = 0; state->GainL = 0.0f; state->GainR = 0.0f; |