Don't expose effect-specific structures

This commit is contained in:
Chris Robinson 2009-05-29 13:30:50 -07:00
parent e12ac95d69
commit 74dc7090fd
7 changed files with 236 additions and 277 deletions

View File

@ -36,7 +36,6 @@
#include "alAuxEffectSlot.h"
#include "alu.h"
#include "bs2b.h"
#include "alReverb.h"
#if defined(HAVE_STDINT_H)
#include <stdint.h>
@ -1310,18 +1309,8 @@ ALvoid aluMixData(ALCcontext *ALContext,ALvoid *buffer,ALsizei size,ALenum forma
// effect slot processing
while(ALEffectSlot)
{
switch(ALEffectSlot->effect.type)
{
case AL_EFFECT_REVERB:
VerbProcess(ALEffectSlot->ReverbState, SamplesToDo, ALEffectSlot->WetBuffer, DryBuffer);
break;
case AL_EFFECT_ECHO:
EchoProcess(ALEffectSlot->EchoState, SamplesToDo, ALEffectSlot->WetBuffer, DryBuffer);
break;
case AL_EFFECT_EAXREVERB:
EAXVerbProcess(ALEffectSlot->ReverbState, SamplesToDo, ALEffectSlot->WetBuffer, DryBuffer);
break;
}
if(ALEffectSlot->EffectState)
ALEffect_Process(ALEffectSlot->EffectState, SamplesToDo, ALEffectSlot->WetBuffer, DryBuffer);
for(i = 0;i < SamplesToDo;i++)
ALEffectSlot->WetBuffer[i] = 0.0f;

View File

@ -23,13 +23,15 @@
#include <math.h>
#include <stdlib.h>
#include "AL/al.h"
#include "alMain.h"
#include "alFilter.h"
#include "alAuxEffectSlot.h"
#include "alEcho.h"
#include "alu.h"
struct ALechoState {
typedef struct ALechoState {
// Must be first in all effects!
ALeffectState state;
ALfloat *SampleBuffer;
ALuint BufferLength;
@ -46,7 +48,7 @@ struct ALechoState {
FILTER iirFilter;
ALfloat history[2];
};
} ALechoState;
// Find the next power of 2. Actually, this will return the input value if
// it is already a power of 2.
@ -66,46 +68,9 @@ static ALuint NextPowerOf2(ALuint value)
return powerOf2;
}
ALechoState *EchoCreate(ALCcontext *Context)
{
ALechoState *state;
ALuint i, maxlen;
state = malloc(sizeof(*state));
if(!state)
return NULL;
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
state->BufferLength = NextPowerOf2(maxlen+1);
state->SampleBuffer = malloc(state->BufferLength * sizeof(ALfloat));
if(!state->SampleBuffer)
{
free(state);
return NULL;
}
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->GainL = 0.0f;
state->GainR = 0.0f;
for(i = 0;i < 2;i++)
state->iirFilter.history[i] = 0.0f;
state->iirFilter.coeff = 0.0f;
return state;
}
ALvoid EchoDestroy(ALechoState *state)
ALvoid EchoDestroy(ALeffectState *effect)
{
ALechoState *state = (ALechoState*)effect;
if(state)
{
free(state->SampleBuffer);
@ -114,9 +79,9 @@ ALvoid EchoDestroy(ALechoState *state)
}
}
ALvoid EchoUpdate(ALCcontext *Context, struct ALeffectslot *Slot, ALeffect *Effect)
ALvoid EchoUpdate(ALeffectState *effect, ALCcontext *Context, struct ALeffectslot *Slot, ALeffect *Effect)
{
ALechoState *state = Slot->EchoState;
ALechoState *state = (ALechoState*)effect;
ALuint newdelay1, newdelay2;
ALfloat lrpan, cw, a, g;
@ -142,8 +107,9 @@ ALvoid EchoUpdate(ALCcontext *Context, struct ALeffectslot *Slot, ALeffect *Effe
state->iirFilter.coeff = a;
}
ALvoid EchoProcess(ALechoState *state, ALuint SamplesToDo, const ALfloat *SamplesIn, ALfloat (*SamplesOut)[OUTPUTCHANNELS])
ALvoid EchoProcess(ALeffectState *effect, 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;
@ -182,3 +148,45 @@ ALvoid EchoProcess(ALechoState *state, ALuint SamplesToDo, const ALfloat *Sample
state->Tap[1].offset = tap2off;
state->Tap[2].offset = fboff;
}
ALeffectState *EchoCreate(ALCcontext *Context)
{
ALechoState *state;
ALuint i, maxlen;
state = malloc(sizeof(*state));
if(!state)
return NULL;
state->state.Destroy = EchoDestroy;
state->state.Update = EchoUpdate;
state->state.Process = EchoProcess;
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
state->BufferLength = NextPowerOf2(maxlen+1);
state->SampleBuffer = malloc(state->BufferLength * sizeof(ALfloat));
if(!state->SampleBuffer)
{
free(state);
return NULL;
}
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->GainL = 0.0f;
state->GainR = 0.0f;
for(i = 0;i < 2;i++)
state->iirFilter.history[i] = 0.0f;
state->iirFilter.coeff = 0.0f;
return &state->state;
}

View File

@ -28,7 +28,6 @@
#include "alMain.h"
#include "alAuxEffectSlot.h"
#include "alEffect.h"
#include "alReverb.h"
#include "alu.h"
typedef struct DelayLine
@ -39,8 +38,10 @@ typedef struct DelayLine
ALfloat *Line;
} DelayLine;
struct ALverbState
{
typedef struct ALverbState {
// Must be first in all effects!
ALeffectState state;
// All delay lines are allocated as a single buffer to reduce memory
// fragmentation and management code.
ALfloat *SampleBuffer;
@ -87,7 +88,7 @@ struct ALverbState
} Late;
// The current read offset for all delay lines.
ALuint Offset;
};
} ALverbState;
// All delay line lengths are specified in seconds.
@ -340,138 +341,11 @@ static __inline ALvoid ReverbInOut(ALverbState *State, ALfloat in, ALfloat *earl
State->Offset++;
}
// 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.
ALverbState *VerbCreate(ALCcontext *Context)
{
ALverbState *State = NULL;
ALuint samples, length[13], totalLength, index;
State = malloc(sizeof(ALverbState));
if(!State)
return NULL;
// 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];
}
// All lines share a single sample buffer and have their masks and start
// addresses calculated once.
State->SampleBuffer = malloc(totalLength * sizeof(ALfloat));
if(!State->SampleBuffer)
{
free(State);
return NULL;
}
for(index = 0; index < totalLength;index++)
State->SampleBuffer[index] = 0.0f;
State->LpCoeff = 0.0f;
State->LpSamples[0] = 0.0f;
State->LpSamples[1] = 0.0f;
State->Delay.Mask = length[0] - 1;
State->Delay.Line = &State->SampleBuffer[0];
totalLength = length[0];
State->Tap[0] = 0;
State->Tap[1] = 0;
State->Tap[2] = 0;
State->Tap[3] = 0;
State->Tap[4] = 0;
State->Early.Gain = 0.0f;
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];
// The early delay lines have their read offsets calculated once.
State->Early.Offset[index] = (ALuint)(EARLY_LINE_LENGTH[index] *
Context->Frequency);
}
State->Late.Gain = 0.0f;
State->Late.DensityGain = 0.0f;
State->Late.ApFeedCoeff = 0.0f;
State->Late.MixCoeff = 0.0f;
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];
// The late all-pass lines have their read offsets calculated once.
State->Late.ApOffset[index] = (ALuint)(ALLPASS_LINE_LENGTH[index] *
Context->Frequency);
}
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.Offset[index] = 0;
State->Late.LpCoeff[index] = 0.0f;
State->Late.LpSample[index] = 0.0f;
}
// Panning is applied as an independent gain for each output channel.
for(index = 0;index < OUTPUTCHANNELS;index++)
{
State->Early.PanGain[index] = 0.0f;
State->Late.PanGain[index] = 0.0f;
}
State->Offset = 0;
return State;
}
ALverbState *EAXVerbCreate(ALCcontext *Context)
{
ALverbState *State = VerbCreate(Context);
return State;
}
// This destroys the reverb state. It should be called only when the effect
// slot has a different (or no) effect loaded over the reverb effect.
ALvoid VerbDestroy(ALverbState *State)
ALvoid VerbDestroy(ALeffectState *effect)
{
ALverbState *State = (ALverbState*)effect;
if(State)
{
free(State->SampleBuffer);
@ -497,9 +371,9 @@ 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(ALCcontext *Context, ALeffectslot *Slot, ALeffect *Effect)
ALvoid VerbUpdate(ALeffectState *effect, ALCcontext *Context, ALeffectslot *Slot, ALeffect *Effect)
{
ALverbState *State = Slot->ReverbState;
ALverbState *State = (ALverbState*)effect;
ALuint index;
ALfloat length, mixCoeff, cw, g, coeff;
ALfloat hfRatio = Effect->Reverb.DecayHFRatio;
@ -695,8 +569,9 @@ ALvoid VerbUpdate(ALCcontext *Context, ALeffectslot *Slot, ALeffect *Effect)
// This processes the reverb state, given the input samples and an output
// buffer.
ALvoid VerbProcess(ALverbState *State, ALuint SamplesToDo, const ALfloat *SamplesIn, ALfloat (*SamplesOut)[OUTPUTCHANNELS])
ALvoid VerbProcess(ALeffectState *effect, ALuint SamplesToDo, const ALfloat *SamplesIn, ALfloat (*SamplesOut)[OUTPUTCHANNELS])
{
ALverbState *State = (ALverbState*)effect;
ALuint index;
ALfloat early[4], late[4], out[4];
@ -725,8 +600,9 @@ ALvoid VerbProcess(ALverbState *State, ALuint SamplesToDo, const ALfloat *Sample
// This processes the EAX reverb state, given the input samples and an output
// buffer.
ALvoid EAXVerbProcess(ALverbState *State, ALuint SamplesToDo, const ALfloat *SamplesIn, ALfloat (*SamplesOut)[OUTPUTCHANNELS])
ALvoid EAXVerbProcess(ALeffectState *effect, ALuint SamplesToDo, const ALfloat *SamplesIn, ALfloat (*SamplesOut)[OUTPUTCHANNELS])
{
ALverbState *State = (ALverbState*)effect;
ALuint index;
ALfloat early[4], late[4];
@ -765,3 +641,135 @@ ALvoid EAXVerbProcess(ALverbState *State, ALuint SamplesToDo, const ALfloat *Sam
}
}
// 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)
{
ALverbState *State = NULL;
ALuint samples, length[13], totalLength, index;
State = malloc(sizeof(ALverbState));
if(!State)
return NULL;
State->state.Destroy = VerbDestroy;
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];
}
// All lines share a single sample buffer and have their masks and start
// addresses calculated once.
State->SampleBuffer = malloc(totalLength * sizeof(ALfloat));
if(!State->SampleBuffer)
{
free(State);
return NULL;
}
for(index = 0; index < totalLength;index++)
State->SampleBuffer[index] = 0.0f;
State->LpCoeff = 0.0f;
State->LpSamples[0] = 0.0f;
State->LpSamples[1] = 0.0f;
State->Delay.Mask = length[0] - 1;
State->Delay.Line = &State->SampleBuffer[0];
totalLength = length[0];
State->Tap[0] = 0;
State->Tap[1] = 0;
State->Tap[2] = 0;
State->Tap[3] = 0;
State->Tap[4] = 0;
State->Early.Gain = 0.0f;
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];
// The early delay lines have their read offsets calculated once.
State->Early.Offset[index] = (ALuint)(EARLY_LINE_LENGTH[index] *
Context->Frequency);
}
State->Late.Gain = 0.0f;
State->Late.DensityGain = 0.0f;
State->Late.ApFeedCoeff = 0.0f;
State->Late.MixCoeff = 0.0f;
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];
// The late all-pass lines have their read offsets calculated once.
State->Late.ApOffset[index] = (ALuint)(ALLPASS_LINE_LENGTH[index] *
Context->Frequency);
}
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.Offset[index] = 0;
State->Late.LpCoeff[index] = 0.0f;
State->Late.LpSample[index] = 0.0f;
}
// Panning is applied as an independent gain for each output channel.
for(index = 0;index < OUTPUTCHANNELS;index++)
{
State->Early.PanGain[index] = 0.0f;
State->Late.PanGain[index] = 0.0f;
}
State->Offset = 0;
return &State->state;
}
ALeffectState *EAXVerbCreate(ALCcontext *Context)
{
ALeffectState *State = VerbCreate(Context);
if(State) State->Process = EAXVerbProcess;
return State;
}

View File

@ -4,8 +4,6 @@
#include "AL/al.h"
#include "alEffect.h"
#include "alFilter.h"
#include "alReverb.h"
#include "alEcho.h"
#ifdef __cplusplus
extern "C" {
@ -17,6 +15,8 @@ extern "C" {
#define AL_EFFECTSLOT_NULL 0x0000
typedef struct ALeffectState ALeffectState;
typedef struct ALeffectslot
{
ALeffect effect;
@ -24,8 +24,7 @@ typedef struct ALeffectslot
ALfloat Gain;
ALboolean AuxSendAuto;
ALverbState *ReverbState;
ALechoState *EchoState;
ALeffectState *EffectState;
ALfloat WetBuffer[BUFFERSIZE];
@ -53,6 +52,22 @@ ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, A
ALvoid ReleaseALAuxiliaryEffectSlots(ALCcontext *Context);
struct ALeffectState {
ALvoid (*Destroy)(ALeffectState *State);
ALvoid (*Update)(ALeffectState *State, ALCcontext *Context, ALeffectslot *Slot, ALeffect *Effect);
ALvoid (*Process)(ALeffectState *State, ALuint SamplesToDo, const ALfloat *SamplesIn, ALfloat (*SamplesOut)[OUTPUTCHANNELS]);
};
ALeffectState *EAXVerbCreate(ALCcontext *Context);
ALeffectState *VerbCreate(ALCcontext *Context);
ALeffectState *EchoCreate(ALCcontext *Context);
#define ALEffect_Destroy(a) ((a)->Destroy((a)))
#define ALEffect_Update(a,b,c,d) ((a)->Update((a),(b),(c),(d)))
#define ALEffect_Process(a,b,c,d) ((a)->Process((a),(b),(c),(d)))
#ifdef __cplusplus
}
#endif

View File

@ -1,24 +0,0 @@
#ifndef AL_ECHO_H
#define AL_ECHO_H
#include "AL/al.h"
#include "AL/alc.h"
#include "alMain.h"
#include "alEffect.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct ALechoState ALechoState;
ALechoState *EchoCreate(ALCcontext *Context);
ALvoid EchoDestroy(ALechoState *State);
ALvoid EchoUpdate(ALCcontext *Context, struct ALeffectslot *Slot, ALeffect *Effect);
ALvoid EchoProcess(ALechoState *State, ALuint SamplesToDo, const ALfloat *SamplesIn, ALfloat (*SamplesOut)[OUTPUTCHANNELS]);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,28 +0,0 @@
#ifndef _AL_REVERB_H_
#define _AL_REVERB_H_
#include "AL/al.h"
#include "AL/alc.h"
#include "alMain.h"
#include "alAuxEffectSlot.h"
#include "alEffect.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct ALverbState ALverbState;
ALverbState *VerbCreate(ALCcontext *Context);
ALverbState *EAXVerbCreate(ALCcontext *Context);
ALvoid VerbDestroy(ALverbState *State);
ALvoid VerbUpdate(ALCcontext *Context, struct ALeffectslot *Slot, ALeffect *Effect);
ALvoid VerbProcess(ALverbState *State, ALuint SamplesToDo, const ALfloat *SamplesIn, ALfloat (*SamplesOut)[OUTPUTCHANNELS]);
ALvoid EAXVerbProcess(ALverbState *State, ALuint SamplesToDo, const ALfloat *SamplesIn, ALfloat (*SamplesOut)[OUTPUTCHANNELS]);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -29,7 +29,6 @@
#include "alAuxEffectSlot.h"
#include "alThunk.h"
#include "alError.h"
#include "alReverb.h"
static ALvoid InitializeEffect(ALCcontext *Context, ALeffectslot *ALEffectSlot, ALeffect *effect);
@ -150,8 +149,8 @@ ALvoid AL_APIENTRY alDeleteAuxiliaryEffectSlots(ALsizei n, ALuint *effectslots)
*list = (*list)->next;
ALTHUNK_REMOVEENTRY(ALAuxiliaryEffectSlot->effectslot);
VerbDestroy(ALAuxiliaryEffectSlot->ReverbState);
EchoDestroy(ALAuxiliaryEffectSlot->EchoState);
if(ALAuxiliaryEffectSlot->EffectState)
ALEffect_Destroy(ALAuxiliaryEffectSlot->EffectState);
memset(ALAuxiliaryEffectSlot, 0, sizeof(ALeffectslot));
free(ALAuxiliaryEffectSlot);
@ -472,10 +471,9 @@ static ALvoid InitializeEffect(ALCcontext *Context, ALeffectslot *ALEffectSlot,
{
if((!effect) || (effect->type != ALEffectSlot->effect.type))
{
VerbDestroy(ALEffectSlot->ReverbState);
ALEffectSlot->ReverbState = NULL;
EchoDestroy(ALEffectSlot->EchoState);
ALEffectSlot->EchoState = NULL;
if(ALEffectSlot->EffectState)
ALEffect_Destroy(ALEffectSlot->EffectState);
ALEffectSlot->EffectState = NULL;
}
if(!effect)
{
@ -483,24 +481,17 @@ static ALvoid InitializeEffect(ALCcontext *Context, ALeffectslot *ALEffectSlot,
return;
}
memcpy(&ALEffectSlot->effect, effect, sizeof(*effect));
if(!ALEffectSlot->EffectState)
{
if(effect->type == AL_EFFECT_EAXREVERB)
{
if(!ALEffectSlot->ReverbState)
ALEffectSlot->ReverbState = EAXVerbCreate(Context);
VerbUpdate(Context, ALEffectSlot, effect);
}
ALEffectSlot->EffectState = EAXVerbCreate(Context);
else if(effect->type == AL_EFFECT_REVERB)
{
if(!ALEffectSlot->ReverbState)
ALEffectSlot->ReverbState = VerbCreate(Context);
VerbUpdate(Context, ALEffectSlot, effect);
}
ALEffectSlot->EffectState = VerbCreate(Context);
else if(effect->type == AL_EFFECT_ECHO)
{
if(!ALEffectSlot->EchoState)
ALEffectSlot->EchoState = EchoCreate(Context);
EchoUpdate(Context, ALEffectSlot, effect);
ALEffectSlot->EffectState = EchoCreate(Context);
}
ALEffect_Update(ALEffectSlot->EffectState, Context, ALEffectSlot, effect);
}
@ -517,8 +508,8 @@ ALvoid ReleaseALAuxiliaryEffectSlots(ALCcontext *Context)
Context->AuxiliaryEffectSlot = Context->AuxiliaryEffectSlot->next;
// Release effectslot structure
VerbDestroy(temp->ReverbState);
EchoDestroy(temp->EchoState);
if(temp->EffectState)
ALEffect_Destroy(temp->EffectState);
ALTHUNK_REMOVEENTRY(temp->effectslot);
memset(temp, 0, sizeof(ALeffectslot));