aboutsummaryrefslogtreecommitdiffstats
path: root/Alc/alcEcho.c
diff options
context:
space:
mode:
authorChris Robinson <[email protected]>2009-10-19 07:46:53 -0700
committerChris Robinson <[email protected]>2009-10-19 07:46:53 -0700
commit6d1d61026d5c5ba75986c2cd8c499bcf72549197 (patch)
treebc23ed399f8694bdbf483eb7221f1a2b7b3982a9 /Alc/alcEcho.c
parenta4e3ca933b036102b1aed623015d007869416c7b (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.c102
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;