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:
parent
186b54aa3d
commit
ef0d4f8210
56
Alc/ALc.c
56
Alc/ALc.c
@ -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
103
Alc/ALu.c
@ -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);
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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]);
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
);
|
||||
|
@ -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;
|
||||
|
@ -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]);
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
||||
|
||||
|
@ -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));
|
||||
|
Loading…
x
Reference in New Issue
Block a user