Provide (mostly) lockless updates for effect slots

Similar to the listener, separate containers are provided atomically for the
mixer thread to apply updates without needing to block, and a free-list is used
to reuse container objects.

A couple things to note. First, the lock is still used when the effect state's
deviceUpdate method is called to prevent asynchronous calls to reset the device
from interfering. This can be fixed by using the list lock in ALc.c instead.

Secondly, old effect states aren't immediately deleted when the effect type
changes (the actual type, not just its properties). This is because the mixer
thread is intended to be real-time safe, and so can't be freeing anything. They
are cleared away when updates reuse the container they were kept in, and they
don't incur any extra processing cost, but there may be cases where the memory
is kept around until the effect slot is deleted.
This commit is contained in:
Chris Robinson 2016-05-12 18:26:33 -07:00
parent 186b54aa3d
commit ef0d4f8210
15 changed files with 332 additions and 187 deletions

View File

@ -1570,12 +1570,6 @@ void ALCcontext_DeferUpdates(ALCcontext *context)
/* Make sure all pending updates are performed */
UpdateContextSources(context);
#define UPDATE_SLOT(iter) do { \
if(ATOMIC_EXCHANGE(ALenum, &(*iter)->NeedsUpdate, AL_FALSE)) \
V((*iter)->EffectState,update)(device, *iter); \
} while(0)
VECTOR_FOR_EACH(ALeffectslot*, context->ActiveAuxSlots, UPDATE_SLOT);
#undef UPDATE_SLOT
}
V0(device->Backend,unlock)();
@ -2059,6 +2053,22 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList)
SetMixerFPUMode(&oldMode);
V0(device->Backend,lock)();
if(device->DefaultSlot)
{
ALeffectslot *slot = device->DefaultSlot;
ALeffectState *state = slot->Params.EffectState;
state->OutBuffer = device->Dry.Buffer;
state->OutChannels = device->Dry.NumChannels;
if(V(state,deviceUpdate)(device) == AL_FALSE)
{
V0(device->Backend,unlock)();
RestoreFPUMode(&oldMode);
return ALC_INVALID_DEVICE;
}
UpdateEffectSlotProps(slot);
}
context = ATOMIC_LOAD(&device->ContextList);
while(context)
{
@ -2069,17 +2079,16 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList)
{
ALeffectslot *slot = context->EffectSlotMap.array[pos].value;
slot->EffectState->OutBuffer = device->Dry.Buffer;
slot->EffectState->OutChannels = device->Dry.NumChannels;
if(V(slot->EffectState,deviceUpdate)(device) == AL_FALSE)
slot->Params.EffectState->OutBuffer = device->Dry.Buffer;
slot->Params.EffectState->OutChannels = device->Dry.NumChannels;
if(V(slot->Params.EffectState,deviceUpdate)(device) == AL_FALSE)
{
UnlockUIntMapRead(&context->EffectSlotMap);
V0(device->Backend,unlock)();
RestoreFPUMode(&oldMode);
return ALC_INVALID_DEVICE;
}
ATOMIC_STORE(&slot->NeedsUpdate, AL_FALSE);
V(slot->EffectState,update)(device, slot);
UpdateEffectSlotProps(slot);
}
UnlockUIntMapRead(&context->EffectSlotMap);
@ -2126,22 +2135,6 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList)
context = context->next;
}
if(device->DefaultSlot)
{
ALeffectslot *slot = device->DefaultSlot;
ALeffectState *state = slot->EffectState;
state->OutBuffer = device->Dry.Buffer;
state->OutChannels = device->Dry.NumChannels;
if(V(state,deviceUpdate)(device) == AL_FALSE)
{
V0(device->Backend,unlock)();
RestoreFPUMode(&oldMode);
return ALC_INVALID_DEVICE;
}
ATOMIC_STORE(&slot->NeedsUpdate, AL_FALSE);
V(slot->EffectState,update)(device, slot);
}
V0(device->Backend,unlock)();
RestoreFPUMode(&oldMode);
@ -2170,9 +2163,8 @@ static ALCvoid FreeDevice(ALCdevice *device)
if(device->DefaultSlot)
{
ALeffectState *state = device->DefaultSlot->EffectState;
DeinitEffectSlot(device->DefaultSlot);
device->DefaultSlot = NULL;
DELETE_OBJ(state);
}
if(device->BufferMap.size > 0)
@ -3497,13 +3489,15 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName)
}
else if(InitializeEffect(device, device->DefaultSlot, &DefaultEffect) != AL_NO_ERROR)
{
ALeffectState *state = device->DefaultSlot->EffectState;
DeinitEffectSlot(device->DefaultSlot);
device->DefaultSlot = NULL;
DELETE_OBJ(state);
ERR("Failed to initialize the default effect\n");
}
else
{
aluInitEffectPanning(device->DefaultSlot);
UpdateEffectSlotProps(device->DefaultSlot);
}
}
{

103
Alc/ALu.c
View File

@ -330,6 +330,55 @@ static ALboolean CalcListenerParams(ALCcontext *Context)
return AL_TRUE;
}
static ALboolean CalcEffectSlotParams(ALeffectslot *slot, ALCdevice *device)
{
struct ALeffectslotProps *first;
struct ALeffectslotProps *props;
props = ATOMIC_EXCHANGE(struct ALeffectslotProps*, &slot->Update, NULL, almemory_order_acq_rel);
if(!props) return AL_FALSE;
slot->Params.Gain = ATOMIC_LOAD(&props->Gain, almemory_order_relaxed);
slot->Params.AuxSendAuto = ATOMIC_LOAD(&props->AuxSendAuto, almemory_order_relaxed);
slot->Params.EffectType = ATOMIC_LOAD(&props->Type, almemory_order_relaxed);
memcpy(&slot->Params.EffectProps, &props->Props, sizeof(props->Props));
/* If the existing state object is different from the one being set,
* exchange it so it remains in the freelist and isn't leaked.
*/
if(slot->Params.EffectState == ATOMIC_LOAD(&props->State, almemory_order_relaxed))
slot->Params.EffectState = NULL;
slot->Params.EffectState = ATOMIC_EXCHANGE(ALeffectState*,
&props->State, slot->Params.EffectState, almemory_order_relaxed
);
if(IsReverbEffect(slot->Params.EffectType))
{
slot->Params.RoomRolloff = slot->Params.EffectProps.Reverb.RoomRolloffFactor;
slot->Params.DecayTime = slot->Params.EffectProps.Reverb.DecayTime;
slot->Params.AirAbsorptionGainHF = slot->Params.EffectProps.Reverb.AirAbsorptionGainHF;
}
else
{
slot->Params.RoomRolloff = 0.0f;
slot->Params.DecayTime = 0.0f;
slot->Params.AirAbsorptionGainHF = 1.0f;
}
V(slot->Params.EffectState,update)(device, slot);
/* WARNING: A livelock is theoretically possible if another thread keeps
* changing the freelist head without giving this a chance to actually swap
* in the old container (practically impossible with this little code,
* but...).
*/
first = ATOMIC_LOAD(&slot->FreeList);
do {
ATOMIC_STORE(&props->next, first, almemory_order_relaxed);
} while(ATOMIC_COMPARE_EXCHANGE_WEAK(struct ALeffectslotProps*,
&slot->FreeList, &first, props) == 0);
return AL_TRUE;
}
ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const ALbuffer *ALBuffer, const ALCcontext *ALContext)
{
static const struct ChanMap MonoMap[1] = {
@ -415,7 +464,7 @@ ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const A
SendSlots[i] = ALSource->Send[i].Slot;
if(!SendSlots[i] && i == 0)
SendSlots[i] = Device->DefaultSlot;
if(!SendSlots[i] || SendSlots[i]->EffectType == AL_EFFECT_NULL)
if(!SendSlots[i] || SendSlots[i]->Params.EffectType == AL_EFFECT_NULL)
{
SendSlots[i] = NULL;
voice->Send[i].OutBuffer = NULL;
@ -847,7 +896,7 @@ ALvoid CalcSourceParams(ALvoice *voice, const ALsource *ALSource, const ALbuffer
if(!SendSlots[i] && i == 0)
SendSlots[i] = Device->DefaultSlot;
if(!SendSlots[i] || SendSlots[i]->EffectType == AL_EFFECT_NULL)
if(!SendSlots[i] || SendSlots[i]->Params.EffectType == AL_EFFECT_NULL)
{
SendSlots[i] = NULL;
RoomRolloff[i] = 0.0f;
@ -856,19 +905,10 @@ ALvoid CalcSourceParams(ALvoice *voice, const ALsource *ALSource, const ALbuffer
}
else if(SendSlots[i]->AuxSendAuto)
{
RoomRolloff[i] = RoomRolloffBase;
if(IsReverbEffect(SendSlots[i]->EffectType))
{
RoomRolloff[i] += SendSlots[i]->EffectProps.Reverb.RoomRolloffFactor;
DecayDistance[i] = SendSlots[i]->EffectProps.Reverb.DecayTime *
SPEEDOFSOUNDMETRESPERSEC;
RoomAirAbsorption[i] = SendSlots[i]->EffectProps.Reverb.AirAbsorptionGainHF;
}
else
{
DecayDistance[i] = 0.0f;
RoomAirAbsorption[i] = 1.0f;
}
RoomRolloff[i] = SendSlots[i]->Params.RoomRolloff + RoomRolloffBase;
DecayDistance[i] = SendSlots[i]->Params.DecayTime *
SPEEDOFSOUNDMETRESPERSEC;
RoomAirAbsorption[i] = SendSlots[i]->Params.AirAbsorptionGainHF;
}
else
{
@ -1245,9 +1285,18 @@ ALvoid CalcSourceParams(ALvoice *voice, const ALsource *ALSource, const ALbuffer
void UpdateContextSources(ALCcontext *ctx)
{
ALvoice *voice, *voice_end;
ALboolean fullupdate;
ALsource *source;
if(CalcListenerParams(ctx))
fullupdate = CalcListenerParams(ctx);
#define UPDATE_SLOT(iter) do { \
if(CalcEffectSlotParams(*iter, ctx->Device)) \
fullupdate = AL_TRUE; \
} while(0)
VECTOR_FOR_EACH(ALeffectslot*, ctx->ActiveAuxSlots, UPDATE_SLOT);
#undef UPDATE_SLOT
if(fullupdate)
{
voice = ctx->Voices;
voice_end = voice + ctx->VoiceCount;
@ -1388,8 +1437,7 @@ ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size)
if((slot=device->DefaultSlot) != NULL)
{
if(ATOMIC_EXCHANGE(ALenum, &slot->NeedsUpdate, AL_FALSE))
V(slot->EffectState,update)(device, slot);
CalcEffectSlotParams(device->DefaultSlot, device);
for(i = 0;i < slot->NumChannels;i++)
memset(slot->WetBuffer[i], 0, SamplesToDo*sizeof(ALfloat));
}
@ -1398,26 +1446,13 @@ ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size)
while(ctx)
{
if(!ctx->DeferUpdates)
{
UpdateContextSources(ctx);
#define UPDATE_SLOT(iter) do { \
if(ATOMIC_EXCHANGE(ALenum, &(*iter)->NeedsUpdate, AL_FALSE)) \
V((*iter)->EffectState,update)(device, *iter); \
for(i = 0;i < (*iter)->NumChannels;i++) \
memset((*iter)->WetBuffer[i], 0, SamplesToDo*sizeof(ALfloat)); \
} while(0)
VECTOR_FOR_EACH(ALeffectslot*, ctx->ActiveAuxSlots, UPDATE_SLOT);
#undef UPDATE_SLOT
}
else
{
#define CLEAR_WET_BUFFER(iter) do { \
for(i = 0;i < (*iter)->NumChannels;i++) \
memset((*iter)->WetBuffer[i], 0, SamplesToDo*sizeof(ALfloat)); \
} while(0)
VECTOR_FOR_EACH(ALeffectslot*, ctx->ActiveAuxSlots, CLEAR_WET_BUFFER);
VECTOR_FOR_EACH(ALeffectslot*, ctx->ActiveAuxSlots, CLEAR_WET_BUFFER);
#undef CLEAR_WET_BUFFER
}
/* source processing */
voice = ctx->Voices;
@ -1434,7 +1469,7 @@ ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size)
for(i = 0;i < c;i++)
{
const ALeffectslot *slot = VECTOR_ELEM(ctx->ActiveAuxSlots, i);
ALeffectState *state = slot->EffectState;
ALeffectState *state = slot->Params.EffectState;
V(state,process)(SamplesToDo, slot->WetBuffer, state->OutBuffer,
state->OutChannels);
}
@ -1445,7 +1480,7 @@ ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size)
if(device->DefaultSlot != NULL)
{
const ALeffectslot *slot = device->DefaultSlot;
ALeffectState *state = slot->EffectState;
ALeffectState *state = slot->Params.EffectState;
V(state,process)(SamplesToDo, slot->WetBuffer, state->OutBuffer,
state->OutChannels);
}

View File

@ -53,8 +53,9 @@ typedef struct ALautowahState {
ALfilterState LowPass;
} ALautowahState;
static ALvoid ALautowahState_Destruct(ALautowahState *UNUSED(state))
static ALvoid ALautowahState_Destruct(ALautowahState *state)
{
ALeffectState_Destruct(STATIC_CAST(ALeffectState,state));
}
static ALboolean ALautowahState_deviceUpdate(ALautowahState *state, ALCdevice *device)
@ -67,15 +68,15 @@ static ALvoid ALautowahState_update(ALautowahState *state, const ALCdevice *devi
{
ALfloat attackTime, releaseTime;
attackTime = slot->EffectProps.Autowah.AttackTime * state->Frequency;
releaseTime = slot->EffectProps.Autowah.ReleaseTime * state->Frequency;
attackTime = slot->Params.EffectProps.Autowah.AttackTime * state->Frequency;
releaseTime = slot->Params.EffectProps.Autowah.ReleaseTime * state->Frequency;
state->AttackRate = powf(1.0f/GAIN_SILENCE_THRESHOLD, 1.0f/attackTime);
state->ReleaseRate = powf(GAIN_SILENCE_THRESHOLD/1.0f, 1.0f/releaseTime);
state->PeakGain = slot->EffectProps.Autowah.PeakGain;
state->Resonance = slot->EffectProps.Autowah.Resonance;
state->PeakGain = slot->Params.EffectProps.Autowah.PeakGain;
state->Resonance = slot->Params.EffectProps.Autowah.Resonance;
ComputeAmbientGains(device->Dry, slot->Gain, state->Gain);
ComputeAmbientGains(device->Dry, slot->Params.Gain, state->Gain);
}
static ALvoid ALautowahState_process(ALautowahState *state, ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels)

View File

@ -60,6 +60,7 @@ static ALvoid ALchorusState_Destruct(ALchorusState *state)
free(state->SampleBuffer[0]);
state->SampleBuffer[0] = NULL;
state->SampleBuffer[1] = NULL;
ALeffectState_Destruct(STATIC_CAST(ALeffectState,state));
}
static ALboolean ALchorusState_deviceUpdate(ALchorusState *state, ALCdevice *Device)
@ -98,7 +99,7 @@ static ALvoid ALchorusState_update(ALchorusState *state, const ALCdevice *Device
ALfloat rate;
ALint phase;
switch(Slot->EffectProps.Chorus.Waveform)
switch(Slot->Params.EffectProps.Chorus.Waveform)
{
case AL_CHORUS_WAVEFORM_TRIANGLE:
state->waveform = CWF_Triangle;
@ -107,18 +108,18 @@ static ALvoid ALchorusState_update(ALchorusState *state, const ALCdevice *Device
state->waveform = CWF_Sinusoid;
break;
}
state->depth = Slot->EffectProps.Chorus.Depth;
state->feedback = Slot->EffectProps.Chorus.Feedback;
state->delay = fastf2i(Slot->EffectProps.Chorus.Delay * frequency);
state->depth = Slot->Params.EffectProps.Chorus.Depth;
state->feedback = Slot->Params.EffectProps.Chorus.Feedback;
state->delay = fastf2i(Slot->Params.EffectProps.Chorus.Delay * frequency);
/* Gains for left and right sides */
CalcXYZCoeffs(-1.0f, 0.0f, 0.0f, 0.0f, coeffs);
ComputePanningGains(Device->Dry, coeffs, Slot->Gain, state->Gain[0]);
ComputePanningGains(Device->Dry, coeffs, Slot->Params.Gain, state->Gain[0]);
CalcXYZCoeffs( 1.0f, 0.0f, 0.0f, 0.0f, coeffs);
ComputePanningGains(Device->Dry, coeffs, Slot->Gain, state->Gain[1]);
ComputePanningGains(Device->Dry, coeffs, Slot->Params.Gain, state->Gain[1]);
phase = Slot->EffectProps.Chorus.Phase;
rate = Slot->EffectProps.Chorus.Rate;
phase = Slot->Params.EffectProps.Chorus.Phase;
rate = Slot->Params.EffectProps.Chorus.Rate;
if(!(rate > 0.0f))
{
state->lfo_scale = 0.0f;

View File

@ -40,8 +40,9 @@ typedef struct ALcompressorState {
ALfloat GainCtrl;
} ALcompressorState;
static ALvoid ALcompressorState_Destruct(ALcompressorState *UNUSED(state))
static ALvoid ALcompressorState_Destruct(ALcompressorState *state)
{
ALeffectState_Destruct(STATIC_CAST(ALeffectState,state));
}
static ALboolean ALcompressorState_deviceUpdate(ALcompressorState *state, ALCdevice *device)
@ -60,7 +61,7 @@ static ALvoid ALcompressorState_update(ALcompressorState *state, const ALCdevice
aluMatrixf matrix;
ALuint i;
state->Enabled = slot->EffectProps.Compressor.OnOff;
state->Enabled = slot->Params.EffectProps.Compressor.OnOff;
aluMatrixfSet(&matrix,
1.0f, 0.0f, 0.0f, 0.0f,
@ -72,7 +73,7 @@ static ALvoid ALcompressorState_update(ALcompressorState *state, const ALCdevice
STATIC_CAST(ALeffectState,state)->OutBuffer = device->FOAOut.Buffer;
STATIC_CAST(ALeffectState,state)->OutChannels = device->FOAOut.NumChannels;
for(i = 0;i < 4;i++)
ComputeFirstOrderGains(device->FOAOut, matrix.m[i], slot->Gain,
ComputeFirstOrderGains(device->FOAOut, matrix.m[i], slot->Params.Gain,
state->Gain[i]);
}

View File

@ -36,8 +36,9 @@ typedef struct ALdedicatedState {
} ALdedicatedState;
static ALvoid ALdedicatedState_Destruct(ALdedicatedState *UNUSED(state))
static ALvoid ALdedicatedState_Destruct(ALdedicatedState *state)
{
ALeffectState_Destruct(STATIC_CAST(ALeffectState,state));
}
static ALboolean ALdedicatedState_deviceUpdate(ALdedicatedState *UNUSED(state), ALCdevice *UNUSED(device))
@ -53,8 +54,8 @@ static ALvoid ALdedicatedState_update(ALdedicatedState *state, const ALCdevice *
for(i = 0;i < MAX_OUTPUT_CHANNELS;i++)
state->gains[i] = 0.0f;
Gain = Slot->Gain * Slot->EffectProps.Dedicated.Gain;
if(Slot->EffectType == AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT)
Gain = Slot->Params.Gain * Slot->Params.EffectProps.Dedicated.Gain;
if(Slot->Params.EffectType == AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT)
{
int idx;
if((idx=GetChannelIdxByName(device->RealOut, LFE)) != -1)
@ -64,7 +65,7 @@ static ALvoid ALdedicatedState_update(ALdedicatedState *state, const ALCdevice *
state->gains[idx] = Gain;
}
}
else if(Slot->EffectType == AL_EFFECT_DEDICATED_DIALOGUE)
else if(Slot->Params.EffectType == AL_EFFECT_DEDICATED_DIALOGUE)
{
int idx;
/* Dialog goes to the front-center speaker if it exists, otherwise it

View File

@ -43,8 +43,9 @@ typedef struct ALdistortionState {
ALfloat edge_coeff;
} ALdistortionState;
static ALvoid ALdistortionState_Destruct(ALdistortionState *UNUSED(state))
static ALvoid ALdistortionState_Destruct(ALdistortionState *state)
{
ALeffectState_Destruct(STATIC_CAST(ALeffectState,state));
}
static ALboolean ALdistortionState_deviceUpdate(ALdistortionState *UNUSED(state), ALCdevice *UNUSED(device))
@ -60,15 +61,15 @@ static ALvoid ALdistortionState_update(ALdistortionState *state, const ALCdevice
ALfloat edge;
/* Store distorted signal attenuation settings */
state->attenuation = Slot->EffectProps.Distortion.Gain;
state->attenuation = Slot->Params.EffectProps.Distortion.Gain;
/* Store waveshaper edge settings */
edge = sinf(Slot->EffectProps.Distortion.Edge * (F_PI_2));
edge = sinf(Slot->Params.EffectProps.Distortion.Edge * (F_PI_2));
edge = minf(edge, 0.99f);
state->edge_coeff = 2.0f * edge / (1.0f-edge);
/* Lowpass filter */
cutoff = Slot->EffectProps.Distortion.LowpassCutoff;
cutoff = Slot->Params.EffectProps.Distortion.LowpassCutoff;
/* Bandwidth value is constant in octaves */
bandwidth = (cutoff / 2.0f) / (cutoff * 0.67f);
ALfilterState_setParams(&state->lowpass, ALfilterType_LowPass, 1.0f,
@ -76,14 +77,14 @@ static ALvoid ALdistortionState_update(ALdistortionState *state, const ALCdevice
);
/* Bandpass filter */
cutoff = Slot->EffectProps.Distortion.EQCenter;
cutoff = Slot->Params.EffectProps.Distortion.EQCenter;
/* Convert bandwidth in Hz to octaves */
bandwidth = Slot->EffectProps.Distortion.EQBandwidth / (cutoff * 0.67f);
bandwidth = Slot->Params.EffectProps.Distortion.EQBandwidth / (cutoff * 0.67f);
ALfilterState_setParams(&state->bandpass, ALfilterType_BandPass, 1.0f,
cutoff / (frequency*4.0f), calc_rcpQ_from_bandwidth(cutoff / (frequency*4.0f), bandwidth)
);
ComputeAmbientGains(Device->Dry, Slot->Gain, state->Gain);
ComputeAmbientGains(Device->Dry, Slot->Params.Gain, state->Gain);
}
static ALvoid ALdistortionState_process(ALdistortionState *state, ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels)

View File

@ -54,6 +54,7 @@ static ALvoid ALechoState_Destruct(ALechoState *state)
{
free(state->SampleBuffer);
state->SampleBuffer = NULL;
ALeffectState_Destruct(STATIC_CAST(ALeffectState,state));
}
static ALboolean ALechoState_deviceUpdate(ALechoState *state, ALCdevice *Device)
@ -87,11 +88,11 @@ static ALvoid ALechoState_update(ALechoState *state, const ALCdevice *Device, co
ALfloat coeffs[MAX_AMBI_COEFFS];
ALfloat gain, lrpan, spread;
state->Tap[0].delay = fastf2u(Slot->EffectProps.Echo.Delay * frequency) + 1;
state->Tap[1].delay = fastf2u(Slot->EffectProps.Echo.LRDelay * frequency);
state->Tap[0].delay = fastf2u(Slot->Params.EffectProps.Echo.Delay * frequency) + 1;
state->Tap[1].delay = fastf2u(Slot->Params.EffectProps.Echo.LRDelay * frequency);
state->Tap[1].delay += state->Tap[0].delay;
spread = Slot->EffectProps.Echo.Spread;
spread = Slot->Params.EffectProps.Echo.Spread;
if(spread < 0.0f) lrpan = -1.0f;
else lrpan = 1.0f;
/* Convert echo spread (where 0 = omni, +/-1 = directional) to coverage
@ -99,14 +100,14 @@ static ALvoid ALechoState_update(ALechoState *state, const ALCdevice *Device, co
*/
spread = asinf(1.0f - fabsf(spread))*4.0f;
state->FeedGain = Slot->EffectProps.Echo.Feedback;
state->FeedGain = Slot->Params.EffectProps.Echo.Feedback;
gain = minf(1.0f - Slot->EffectProps.Echo.Damping, 0.01f);
gain = minf(1.0f - Slot->Params.EffectProps.Echo.Damping, 0.01f);
ALfilterState_setParams(&state->Filter, ALfilterType_HighShelf,
gain, LOWPASSFREQREF/frequency,
calc_rcpQ_from_slope(gain, 0.75f));
gain = Slot->Gain;
gain = Slot->Params.Gain;
/* First tap panning */
CalcXYZCoeffs(-lrpan, 0.0f, 0.0f, spread, coeffs);

View File

@ -87,8 +87,9 @@ typedef struct ALequalizerState {
ALfloat SampleBuffer[4][MAX_EFFECT_CHANNELS][MAX_UPDATE_SAMPLES];
} ALequalizerState;
static ALvoid ALequalizerState_Destruct(ALequalizerState *UNUSED(state))
static ALvoid ALequalizerState_Destruct(ALequalizerState *state)
{
ALeffectState_Destruct(STATIC_CAST(ALeffectState,state));
}
static ALboolean ALequalizerState_deviceUpdate(ALequalizerState *UNUSED(state), ALCdevice *UNUSED(device))
@ -113,15 +114,15 @@ static ALvoid ALequalizerState_update(ALequalizerState *state, const ALCdevice *
STATIC_CAST(ALeffectState,state)->OutBuffer = device->FOAOut.Buffer;
STATIC_CAST(ALeffectState,state)->OutChannels = device->FOAOut.NumChannels;
for(i = 0;i < MAX_EFFECT_CHANNELS;i++)
ComputeFirstOrderGains(device->FOAOut, matrix.m[i], slot->Gain,
ComputeFirstOrderGains(device->FOAOut, matrix.m[i], slot->Params.Gain,
state->Gain[i]);
/* Calculate coefficients for the each type of filter. Note that the shelf
* filters' gain is for the reference frequency, which is the centerpoint
* of the transition band.
*/
gain = sqrtf(slot->EffectProps.Equalizer.LowGain);
freq_mult = slot->EffectProps.Equalizer.LowCutoff/frequency;
gain = sqrtf(slot->Params.EffectProps.Equalizer.LowGain);
freq_mult = slot->Params.EffectProps.Equalizer.LowCutoff/frequency;
ALfilterState_setParams(&state->filter[0][0], ALfilterType_LowShelf,
gain, freq_mult, calc_rcpQ_from_slope(gain, 0.75f)
);
@ -136,10 +137,12 @@ static ALvoid ALequalizerState_update(ALequalizerState *state, const ALCdevice *
state->filter[0][i].process = state->filter[0][0].process;
}
gain = slot->EffectProps.Equalizer.Mid1Gain;
freq_mult = slot->EffectProps.Equalizer.Mid1Center/frequency;
gain = slot->Params.EffectProps.Equalizer.Mid1Gain;
freq_mult = slot->Params.EffectProps.Equalizer.Mid1Center/frequency;
ALfilterState_setParams(&state->filter[1][0], ALfilterType_Peaking,
gain, freq_mult, calc_rcpQ_from_bandwidth(freq_mult, slot->EffectProps.Equalizer.Mid1Width)
gain, freq_mult, calc_rcpQ_from_bandwidth(
freq_mult, slot->Params.EffectProps.Equalizer.Mid1Width
)
);
for(i = 1;i < MAX_EFFECT_CHANNELS;i++)
{
@ -151,10 +154,12 @@ static ALvoid ALequalizerState_update(ALequalizerState *state, const ALCdevice *
state->filter[1][i].process = state->filter[1][0].process;
}
gain = slot->EffectProps.Equalizer.Mid2Gain;
freq_mult = slot->EffectProps.Equalizer.Mid2Center/frequency;
gain = slot->Params.EffectProps.Equalizer.Mid2Gain;
freq_mult = slot->Params.EffectProps.Equalizer.Mid2Center/frequency;
ALfilterState_setParams(&state->filter[2][0], ALfilterType_Peaking,
gain, freq_mult, calc_rcpQ_from_bandwidth(freq_mult, slot->EffectProps.Equalizer.Mid2Width)
gain, freq_mult, calc_rcpQ_from_bandwidth(
freq_mult, slot->Params.EffectProps.Equalizer.Mid2Width
)
);
for(i = 1;i < MAX_EFFECT_CHANNELS;i++)
{
@ -166,8 +171,8 @@ static ALvoid ALequalizerState_update(ALequalizerState *state, const ALCdevice *
state->filter[2][i].process = state->filter[2][0].process;
}
gain = sqrtf(slot->EffectProps.Equalizer.HighGain);
freq_mult = slot->EffectProps.Equalizer.HighCutoff/frequency;
gain = sqrtf(slot->Params.EffectProps.Equalizer.HighGain);
freq_mult = slot->Params.EffectProps.Equalizer.HighCutoff/frequency;
ALfilterState_setParams(&state->filter[3][0], ALfilterType_HighShelf,
gain, freq_mult, calc_rcpQ_from_slope(gain, 0.75f)
);

View File

@ -60,6 +60,7 @@ static ALvoid ALflangerState_Destruct(ALflangerState *state)
free(state->SampleBuffer[0]);
state->SampleBuffer[0] = NULL;
state->SampleBuffer[1] = NULL;
ALeffectState_Destruct(STATIC_CAST(ALeffectState,state));
}
static ALboolean ALflangerState_deviceUpdate(ALflangerState *state, ALCdevice *Device)
@ -98,7 +99,7 @@ static ALvoid ALflangerState_update(ALflangerState *state, const ALCdevice *Devi
ALfloat rate;
ALint phase;
switch(Slot->EffectProps.Flanger.Waveform)
switch(Slot->Params.EffectProps.Flanger.Waveform)
{
case AL_FLANGER_WAVEFORM_TRIANGLE:
state->waveform = FWF_Triangle;
@ -107,18 +108,18 @@ static ALvoid ALflangerState_update(ALflangerState *state, const ALCdevice *Devi
state->waveform = FWF_Sinusoid;
break;
}
state->depth = Slot->EffectProps.Flanger.Depth;
state->feedback = Slot->EffectProps.Flanger.Feedback;
state->delay = fastf2i(Slot->EffectProps.Flanger.Delay * frequency);
state->depth = Slot->Params.EffectProps.Flanger.Depth;
state->feedback = Slot->Params.EffectProps.Flanger.Feedback;
state->delay = fastf2i(Slot->Params.EffectProps.Flanger.Delay * frequency);
/* Gains for left and right sides */
CalcXYZCoeffs(-1.0f, 0.0f, 0.0f, 0.0f, coeffs);
ComputePanningGains(Device->Dry, coeffs, Slot->Gain, state->Gain[0]);
ComputePanningGains(Device->Dry, coeffs, Slot->Params.Gain, state->Gain[0]);
CalcXYZCoeffs( 1.0f, 0.0f, 0.0f, 0.0f, coeffs);
ComputePanningGains(Device->Dry, coeffs, Slot->Gain, state->Gain[1]);
ComputePanningGains(Device->Dry, coeffs, Slot->Params.Gain, state->Gain[1]);
phase = Slot->EffectProps.Flanger.Phase;
rate = Slot->EffectProps.Flanger.Rate;
phase = Slot->Params.EffectProps.Flanger.Phase;
rate = Slot->Params.EffectProps.Flanger.Rate;
if(!(rate > 0.0f))
{
state->lfo_scale = 0.0f;

View File

@ -82,8 +82,9 @@ DECL_TEMPLATE(Square)
#undef DECL_TEMPLATE
static ALvoid ALmodulatorState_Destruct(ALmodulatorState *UNUSED(state))
static ALvoid ALmodulatorState_Destruct(ALmodulatorState *state)
{
ALeffectState_Destruct(STATIC_CAST(ALeffectState,state));
}
static ALboolean ALmodulatorState_deviceUpdate(ALmodulatorState *UNUSED(state), ALCdevice *UNUSED(device))
@ -97,19 +98,19 @@ static ALvoid ALmodulatorState_update(ALmodulatorState *state, const ALCdevice *
ALfloat cw, a;
ALuint i;
if(Slot->EffectProps.Modulator.Waveform == AL_RING_MODULATOR_SINUSOID)
if(Slot->Params.EffectProps.Modulator.Waveform == AL_RING_MODULATOR_SINUSOID)
state->Process = ModulateSin;
else if(Slot->EffectProps.Modulator.Waveform == AL_RING_MODULATOR_SAWTOOTH)
else if(Slot->Params.EffectProps.Modulator.Waveform == AL_RING_MODULATOR_SAWTOOTH)
state->Process = ModulateSaw;
else /*if(Slot->EffectProps.Modulator.Waveform == AL_RING_MODULATOR_SQUARE)*/
else /*if(Slot->Params.EffectProps.Modulator.Waveform == AL_RING_MODULATOR_SQUARE)*/
state->Process = ModulateSquare;
state->step = fastf2u(Slot->EffectProps.Modulator.Frequency*WAVEFORM_FRACONE /
state->step = fastf2u(Slot->Params.EffectProps.Modulator.Frequency*WAVEFORM_FRACONE /
Device->Frequency);
if(state->step == 0) state->step = 1;
/* Custom filter coeffs, which match the old version instead of a low-shelf. */
cw = cosf(F_TAU * Slot->EffectProps.Modulator.HighPassCutoff / Device->Frequency);
cw = cosf(F_TAU * Slot->Params.EffectProps.Modulator.HighPassCutoff / Device->Frequency);
a = (2.0f-cw) - sqrtf(powf(2.0f-cw, 2.0f) - 1.0f);
for(i = 0;i < MAX_EFFECT_CHANNELS;i++)
@ -132,7 +133,7 @@ static ALvoid ALmodulatorState_update(ALmodulatorState *state, const ALCdevice *
STATIC_CAST(ALeffectState,state)->OutBuffer = Device->FOAOut.Buffer;
STATIC_CAST(ALeffectState,state)->OutChannels = Device->FOAOut.NumChannels;
for(i = 0;i < MAX_EFFECT_CHANNELS;i++)
ComputeFirstOrderGains(Device->FOAOut, matrix.m[i], Slot->Gain,
ComputeFirstOrderGains(Device->FOAOut, matrix.m[i], Slot->Params.Gain,
state->Gain[i]);
}

View File

@ -15,10 +15,12 @@ typedef struct ALnullState {
/* This destructs (not free!) the effect state. It's called only when the
* effect slot is no longer used.
* effect slot is no longer used. Make sure to call the parent Destruct
* function before returning!
*/
static ALvoid ALnullState_Destruct(ALnullState* UNUSED(state))
static ALvoid ALnullState_Destruct(ALnullState *state)
{
ALeffectState_Destruct(STATIC_CAST(ALeffectState,state));
}
/* This updates the device-dependant effect state. This is called on

View File

@ -169,6 +169,7 @@ static ALvoid ALreverbState_Destruct(ALreverbState *State)
{
free(State->SampleBuffer);
State->SampleBuffer = NULL;
ALeffectState_Destruct(STATIC_CAST(ALeffectState,State));
}
static ALboolean ALreverbState_deviceUpdate(ALreverbState *State, ALCdevice *Device);
@ -894,15 +895,15 @@ static ALvoid Update3DPanning(const ALCdevice *Device, const ALfloat *Reflection
static ALvoid ALreverbState_update(ALreverbState *State, const ALCdevice *Device, const ALeffectslot *Slot)
{
const ALeffectProps *props = &Slot->EffectProps;
const ALeffectProps *props = &Slot->Params.EffectProps;
ALuint frequency = Device->Frequency;
ALfloat lfscale, hfscale, hfRatio;
ALfloat gain, gainlf, gainhf;
ALfloat cw, x, y;
if(Slot->EffectType == AL_EFFECT_EAXREVERB && !EmulateEAXReverb)
if(Slot->Params.EffectType == AL_EFFECT_EAXREVERB && !EmulateEAXReverb)
State->IsEax = AL_TRUE;
else if(Slot->EffectType == AL_EFFECT_REVERB || EmulateEAXReverb)
else if(Slot->Params.EffectType == AL_EFFECT_REVERB || EmulateEAXReverb)
State->IsEax = AL_FALSE;
// Calculate the master filters
@ -952,7 +953,7 @@ static ALvoid ALreverbState_update(ALreverbState *State, const ALCdevice *Device
props->Reverb.Diffusion, props->Reverb.EchoDepth,
hfRatio, cw, frequency, State);
gain = props->Reverb.Gain * Slot->Gain * ReverbBoost;
gain = props->Reverb.Gain * Slot->Params.Gain * ReverbBoost;
// Update early and late 3D panning.
if(Device->Hrtf || Device->Uhj_Encoder)
UpdateMixedPanning(Device, props->Reverb.ReflectionsPan,

View File

@ -20,6 +20,8 @@ typedef struct ALeffectState {
ALuint OutChannels;
} ALeffectState;
void ALeffectState_Destruct(ALeffectState *state);
struct ALeffectStateVtable {
void (*const Destruct)(ALeffectState *state);
@ -70,18 +72,48 @@ static const struct ALeffectStateFactoryVtable T##_ALeffectStateFactory_vtable =
#define MAX_EFFECT_CHANNELS (4)
typedef struct ALeffectslot {
ALenum EffectType;
ALeffectProps EffectProps;
struct ALeffectslotProps {
ATOMIC(ALfloat) Gain;
ATOMIC(ALboolean) AuxSendAuto;
ATOMIC(ALenum) Type;
ALeffectProps Props;
ATOMIC(ALeffectState*) State;
ATOMIC(struct ALeffectslotProps*) next;
};
typedef struct ALeffectslot {
volatile ALfloat Gain;
volatile ALboolean AuxSendAuto;
ATOMIC(ALenum) NeedsUpdate;
ALeffectState *EffectState;
struct {
ALenum Type;
ALeffectProps Props;
ALeffectState *State;
} Effect;
RefCount ref;
ATOMIC(struct ALeffectslotProps*) Update;
ATOMIC(struct ALeffectslotProps*) FreeList;
struct {
ALfloat Gain;
ALboolean AuxSendAuto;
ALenum EffectType;
ALeffectProps EffectProps;
ALeffectState *EffectState;
ALfloat RoomRolloff; /* Added to the source's room rolloff, not multiplied. */
ALfloat DecayTime;
ALfloat AirAbsorptionGainHF;
} Params;
/* Self ID */
ALuint id;
@ -106,6 +138,8 @@ inline struct ALeffectslot *RemoveEffectSlot(ALCcontext *context, ALuint id)
{ return (struct ALeffectslot*)RemoveUIntMapKey(&context->EffectSlotMap, id); }
ALenum InitEffectSlot(ALeffectslot *slot);
void DeinitEffectSlot(ALeffectslot *slot);
void UpdateEffectSlotProps(ALeffectslot *slot);
ALvoid ReleaseALAuxiliaryEffectSlots(ALCcontext *Context);

View File

@ -86,7 +86,7 @@ AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslo
if(err != AL_NO_ERROR)
{
FreeThunkEntry(slot->id);
DELETE_OBJ(slot->EffectState);
DELETE_OBJ(slot->Params.EffectState);
al_free(slot);
alDeleteAuxiliaryEffectSlots(cur, effectslots);
@ -139,7 +139,7 @@ AL_API ALvoid AL_APIENTRY alDeleteAuxiliaryEffectSlots(ALsizei n, const ALuint *
FreeThunkEntry(slot->id);
RemoveEffectSlotArray(context, slot);
DELETE_OBJ(slot->EffectState);
DeinitEffectSlot(slot);
memset(slot, 0, sizeof(*slot));
al_free(slot);
@ -175,12 +175,13 @@ AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSloti(ALuint effectslot, ALenum param
context = GetContextRef();
if(!context) return;
device = context->Device;
WriteLock(&context->PropLock);
if((slot=LookupEffectSlot(context, effectslot)) == NULL)
SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
switch(param)
{
case AL_EFFECTSLOT_EFFECT:
device = context->Device;
effect = (value ? LookupEffect(device, value) : NULL);
if(!(value == 0 || effect != NULL))
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
@ -193,19 +194,16 @@ AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSloti(ALuint effectslot, ALenum param
case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO:
if(!(value == AL_TRUE || value == AL_FALSE))
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
slot->AuxSendAuto = value;
break;
default:
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
/* HACK: Force sources to update by doing a listener update */
ReadLock(&context->PropLock);
UpdateListenerProps(context);
ReadUnlock(&context->PropLock);
UpdateEffectSlotProps(slot);
done:
WriteUnlock(&context->PropLock);
ALCcontext_DecRef(context);
}
@ -244,6 +242,7 @@ AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotf(ALuint effectslot, ALenum param
context = GetContextRef();
if(!context) return;
WriteLock(&context->PropLock);
if((slot=LookupEffectSlot(context, effectslot)) == NULL)
SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
switch(param)
@ -251,16 +250,16 @@ AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotf(ALuint effectslot, ALenum param
case AL_EFFECTSLOT_GAIN:
if(!(value >= 0.0f && value <= 1.0f))
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
slot->Gain = value;
ATOMIC_STORE(&slot->NeedsUpdate, AL_TRUE);
break;
default:
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
UpdateEffectSlotProps(slot);
done:
WriteUnlock(&context->PropLock);
ALCcontext_DecRef(context);
}
@ -451,7 +450,7 @@ ALenum InitializeEffect(ALCdevice *Device, ALeffectslot *EffectSlot, ALeffect *e
ALenum newtype = (effect ? effect->type : AL_EFFECT_NULL);
ALeffectStateFactory *factory;
if(newtype != EffectSlot->EffectType)
if(newtype != EffectSlot->Effect.Type)
{
ALeffectState *State;
FPUCtl oldMode;
@ -467,7 +466,9 @@ ALenum InitializeEffect(ALCdevice *Device, ALeffectslot *EffectSlot, ALeffect *e
return AL_OUT_OF_MEMORY;
SetMixerFPUMode(&oldMode);
/* FIXME: This just needs to prevent the device from being reset during
* the state's device update, so the list lock in ALc.c should do here.
*/
ALCdevice_Lock(Device);
State->OutBuffer = Device->Dry.Buffer;
State->OutChannels = Device->Dry.NumChannels;
@ -478,70 +479,135 @@ ALenum InitializeEffect(ALCdevice *Device, ALeffectslot *EffectSlot, ALeffect *e
DELETE_OBJ(State);
return AL_OUT_OF_MEMORY;
}
State = ExchangePtr((XchgPtr*)&EffectSlot->EffectState, State);
if(!effect)
{
memset(&EffectSlot->EffectProps, 0, sizeof(EffectSlot->EffectProps));
EffectSlot->EffectType = AL_EFFECT_NULL;
}
else
{
memcpy(&EffectSlot->EffectProps, &effect->Props, sizeof(effect->Props));
EffectSlot->EffectType = effect->type;
}
/* FIXME: This should be done asynchronously, but since the EffectState
* object was changed, it needs an update before its Process method can
* be called. */
ATOMIC_STORE(&EffectSlot->NeedsUpdate, AL_FALSE);
V(EffectSlot->EffectState,update)(Device, EffectSlot);
ALCdevice_Unlock(Device);
RestoreFPUMode(&oldMode);
DELETE_OBJ(State);
State = NULL;
EffectSlot->Effect.State = State;
}
if(!effect)
{
EffectSlot->Effect.Type = AL_EFFECT_NULL;
memset(&EffectSlot->Effect.Props, 0, sizeof(EffectSlot->Effect.Props));
}
else
{
if(effect)
{
ALCdevice_Lock(Device);
memcpy(&EffectSlot->EffectProps, &effect->Props, sizeof(effect->Props));
ALCdevice_Unlock(Device);
ATOMIC_STORE(&EffectSlot->NeedsUpdate, AL_TRUE);
}
EffectSlot->Effect.Type = effect->type;
memcpy(&EffectSlot->Effect.Props, &effect->Props, sizeof(EffectSlot->Effect.Props));
}
return AL_NO_ERROR;
}
void ALeffectState_Destruct(ALeffectState *UNUSED(state))
{
}
ALenum InitEffectSlot(ALeffectslot *slot)
{
ALeffectStateFactory *factory;
ALuint i, c;
slot->EffectType = AL_EFFECT_NULL;
slot->Effect.Type = AL_EFFECT_NULL;
factory = getFactoryByType(AL_EFFECT_NULL);
if(!(slot->EffectState=V0(factory,create)()))
if(!(slot->Effect.State=V0(factory,create)()))
return AL_OUT_OF_MEMORY;
slot->Gain = 1.0;
slot->AuxSendAuto = AL_TRUE;
ATOMIC_INIT(&slot->NeedsUpdate, AL_FALSE);
for(c = 0;c < 1;c++)
{
for(i = 0;i < BUFFERSIZE;i++)
slot->WetBuffer[c][i] = 0.0f;
}
InitRef(&slot->ref, 0);
ATOMIC_INIT(&slot->Update, NULL);
ATOMIC_INIT(&slot->FreeList, NULL);
slot->Params.Gain = 1.0f;
slot->Params.AuxSendAuto = AL_TRUE;
slot->Params.EffectState = slot->Effect.State;
slot->Params.RoomRolloff = 0.0f;
slot->Params.DecayTime = 0.0f;
slot->Params.AirAbsorptionGainHF = 1.0f;
return AL_NO_ERROR;
}
void DeinitEffectSlot(ALeffectslot *slot)
{
struct ALeffectslotProps *props;
size_t count = 0;
props = ATOMIC_LOAD(&slot->Update);
if(props)
{
DELETE_OBJ(props->State);
TRACE("Freed unapplied AuxiliaryEffectSlot update %p\n", props);
al_free(props);
}
props = ATOMIC_LOAD(&slot->FreeList, almemory_order_relaxed);
while(props)
{
struct ALeffectslotProps *next;
next = ATOMIC_LOAD(&props->next, almemory_order_relaxed);
DELETE_OBJ(props->State);
al_free(props);
props = next;
++count;
}
TRACE("Freed "SZFMT" AuxiliaryEffectSlot property object%s\n", count, (count==1)?"":"s");
DELETE_OBJ(slot->Params.EffectState);
}
void UpdateEffectSlotProps(ALeffectslot *slot)
{
struct ALeffectslotProps *props;
ALeffectState *oldstate;
/* Get an unused property container, or allocate a new one as needed. */
props = ATOMIC_LOAD(&slot->FreeList, almemory_order_acquire);
if(!props)
props = al_calloc(16, sizeof(*props));
else
{
struct ALeffectslotProps *next;
do {
next = ATOMIC_LOAD(&props->next, almemory_order_relaxed);
} while(ATOMIC_COMPARE_EXCHANGE_WEAK(struct ALeffectslotProps*,
&slot->FreeList, &props, next, almemory_order_seq_cst,
almemory_order_consume) == 0);
}
/* Copy in current property values. */
ATOMIC_STORE(&props->Gain, slot->Gain, almemory_order_relaxed);
ATOMIC_STORE(&props->AuxSendAuto, slot->AuxSendAuto, almemory_order_relaxed);
ATOMIC_STORE(&props->Type, slot->Effect.Type, almemory_order_relaxed);
memcpy(&props->Props, &slot->Effect.Props, sizeof(props->Props));
/* Swap out any stale effect state object there may be in the container, to
* delete it.
*/
oldstate = ATOMIC_EXCHANGE(ALeffectState*, &props->State, slot->Effect.State,
almemory_order_relaxed);
/* Set the new container for updating internal parameters. */
props = ATOMIC_EXCHANGE(struct ALeffectslotProps*, &slot->Update, props,
almemory_order_acq_rel);
if(props)
{
/* If there was an unused update container, put it back in the
* freelist.
*/
struct ALeffectslotProps *first = ATOMIC_LOAD(&slot->FreeList);
do {
ATOMIC_STORE(&props->next, first, almemory_order_relaxed);
} while(ATOMIC_COMPARE_EXCHANGE_WEAK(struct ALeffectslotProps*,
&slot->FreeList, &first, props) == 0);
}
DELETE_OBJ(oldstate);
}
ALvoid ReleaseALAuxiliaryEffectSlots(ALCcontext *Context)
{
ALsizei pos;
@ -550,7 +616,7 @@ ALvoid ReleaseALAuxiliaryEffectSlots(ALCcontext *Context)
ALeffectslot *temp = Context->EffectSlotMap.array[pos].value;
Context->EffectSlotMap.array[pos].value = NULL;
DELETE_OBJ(temp->EffectState);
DeinitEffectSlot(temp);
FreeThunkEntry(temp->id);
memset(temp, 0, sizeof(ALeffectslot));