Add gain stepping to the send mixers

This commit is contained in:
Chris Robinson 2014-03-23 16:11:21 -07:00
parent 83038c0dab
commit 52deb557d5
7 changed files with 184 additions and 65 deletions

View File

@ -1931,6 +1931,13 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList)
{
ALactivesource *src = context->ActiveSources[pos];
ALsource *source = src->Source;
ALuint s = device->NumAuxSends;
while(s < MAX_SENDS)
{
src->Send[s].Moving = AL_FALSE;
src->Send[s].Counter = 0;
s++;
}
src->Update(src, context);
source->NeedsUpdate = AL_FALSE;

View File

@ -565,7 +565,27 @@ ALvoid CalcNonAttnSourceParams(ALactivesource *src, const ALCcontext *ALContext)
src->DryMix = SelectDirectMixer();
}
for(i = 0;i < NumSends;i++)
src->Send[i].Gain = WetGain[i];
{
if(src->Send[i].Moving)
{
ALfloat cur = maxf(src->Send[i].Gain.Current, GAIN_SILENCE_THRESHOLD);
ALfloat trg = maxf(src->Send[i].Gain.Target, GAIN_SILENCE_THRESHOLD);
if(fabs(trg - cur) >= GAIN_SILENCE_THRESHOLD)
src->Send[i].Gain.Step = powf(trg/cur, 1.0f/64.0f);
else
src->Send[i].Gain.Step = 1.0f;
src->Send[i].Gain.Current = cur;
src->Send[i].Counter = 64;
}
else
{
src->Send[i].Gain.Current = WetGain[i];
src->Send[i].Gain.Target = WetGain[i];
src->Send[i].Gain.Step = 1.0f;
src->Send[i].Counter = 0;
src->Send[i].Moving = AL_TRUE;
}
}
src->WetMix = SelectSendMixer();
{
@ -1050,7 +1070,27 @@ ALvoid CalcSourceParams(ALactivesource *src, const ALCcontext *ALContext)
src->DryMix = SelectDirectMixer();
}
for(i = 0;i < NumSends;i++)
src->Send[i].Gain = WetGain[i];
{
if(src->Send[i].Moving)
{
ALfloat cur = maxf(src->Send[i].Gain.Current, GAIN_SILENCE_THRESHOLD);
ALfloat trg = maxf(src->Send[i].Gain.Target, GAIN_SILENCE_THRESHOLD);
if(fabs(trg - cur) >= GAIN_SILENCE_THRESHOLD)
src->Send[i].Gain.Step = powf(trg/cur, 1.0f/64.0f);
else
src->Send[i].Gain.Step = 1.0f;
src->Send[i].Gain.Current = cur;
src->Send[i].Counter = 64;
}
else
{
src->Send[i].Gain.Current = WetGain[i];
src->Send[i].Gain.Target = WetGain[i];
src->Send[i].Gain.Step = 1.0f;
src->Send[i].Counter = 0;
src->Send[i].Moving = AL_TRUE;
}
}
src->WetMix = SelectSendMixer();
{

View File

@ -115,22 +115,30 @@ void MixDirect_C(DirectParams *params, const ALfloat *restrict data, ALuint srcc
void MixSend_C(SendParams *params, const ALfloat *restrict data,
ALuint OutPos, ALuint SamplesToDo, ALuint BufferSize)
ALuint OutPos, ALuint UNUSED(SamplesToDo), ALuint BufferSize)
{
ALfloat (*restrict OutBuffer)[BUFFERSIZE] = params->OutBuffer;
ALfloat *restrict ClickRemoval = params->ClickRemoval;
ALfloat *restrict PendingClicks = params->PendingClicks;
ALfloat WetSend;
ALuint pos;
ALuint Counter = maxu(params->Counter, OutPos) - OutPos;
ALfloat WetSend, Step;
WetSend = params->Gain;
if(!(WetSend > GAIN_SILENCE_THRESHOLD))
return;
{
ALuint pos = 0;
Step = params->Gain.Step;
if(Step != 1.0f && Counter > 0)
{
WetSend = params->Gain.Current;
for(;pos < BufferSize && pos < Counter;pos++)
{
OutBuffer[0][OutPos+pos] += data[pos]*WetSend;
WetSend *= Step;
}
params->Gain.Current = WetSend;
}
if(OutPos == 0)
ClickRemoval[0] -= data[0] * WetSend;
for(pos = 0;pos < BufferSize;pos++)
OutBuffer[0][OutPos+pos] += data[pos] * WetSend;
if(OutPos+pos == SamplesToDo)
PendingClicks[0] += data[pos] * WetSend;
WetSend = params->Gain.Target;
if(!(WetSend > GAIN_SILENCE_THRESHOLD))
return;
for(;pos < BufferSize;pos++)
OutBuffer[0][OutPos+pos] += data[pos] * WetSend;
}
}

View File

@ -133,33 +133,53 @@ void MixDirect_Neon(DirectParams *params, const ALfloat *restrict data, ALuint s
void MixSend_Neon(SendParams *params, const ALfloat *restrict data,
ALuint OutPos, ALuint SamplesToDo, ALuint BufferSize)
ALuint OutPos, ALuint UNUSED(SamplesToDo), ALuint BufferSize)
{
ALfloat (*restrict OutBuffer)[BUFFERSIZE] = params->OutBuffer;
ALfloat *restrict ClickRemoval = params->ClickRemoval;
ALfloat *restrict PendingClicks = params->PendingClicks;
ALfloat WetGain;
ALuint Counter = maxu(params->Counter, OutPos) - OutPos;
ALfloat WetGain, Step;
float32x4_t gain;
ALuint pos;
WetGain = params->Gain;
if(!(WetGain > GAIN_SILENCE_THRESHOLD))
return;
if(OutPos == 0)
ClickRemoval[0] -= data[0] * WetGain;
gain = vdupq_n_f32(WetGain);
for(pos = 0;BufferSize-pos > 3;pos += 4)
{
const float32x4_t val4 = vld1q_f32(&data[pos]);
float32x4_t wet4 = vld1q_f32(&OutBuffer[0][OutPos+pos]);
wet4 = vaddq_f32(wet4, vmulq_f32(val4, gain));
vst1q_f32(&OutBuffer[0][OutPos+pos], wet4);
}
for(;pos < BufferSize;pos++)
OutBuffer[0][OutPos+pos] += data[pos] * WetGain;
ALuint pos = 0;
Step = params->Gain.Step;
if(Step != 1.0f && Counter > 0)
{
WetGain = params->Gain.Current;
if(BufferSize-pos > 3 && Counter-pos > 3)
{
OutBuffer[0][OutPos+pos ] += data[pos ]*WetGain;
WetGain *= Step;
OutBuffer[0][OutPos+pos+1] += data[pos+1]*WetGain;
WetGain *= Step;
OutBuffer[0][OutPos+pos+2] += data[pos+2]*WetGain;
WetGain *= Step;
OutBuffer[0][OutPos+pos+4] += data[pos+3]*WetGain;
WetGain *= Step;
}
if(!(BufferSize-pos > 3))
{
for(;pos < BufferSize && pos < Counter;pos++)
{
OutBuffer[0][OutPos+pos] += data[pos]*WetGain;
WetGain *= Step;
}
}
params->Gain.Current = WetGain;
}
if(OutPos+pos == SamplesToDo)
PendingClicks[0] += data[pos] * WetGain;
WetGain = params->Gain.Target;
if(!(WetGain > GAIN_SILENCE_THRESHOLD))
return;
gain = vdupq_n_f32(WetGain);
for(;BufferSize-pos > 3;pos += 4)
{
const float32x4_t val4 = vld1q_f32(&data[pos]);
float32x4_t wet4 = vld1q_f32(&OutBuffer[0][OutPos+pos]);
wet4 = vaddq_f32(wet4, vmulq_f32(val4, gain));
vst1q_f32(&OutBuffer[0][OutPos+pos], wet4);
}
for(;pos < BufferSize;pos++)
OutBuffer[0][OutPos+pos] += data[pos] * WetGain;
}
}

View File

@ -204,33 +204,62 @@ void MixDirect_SSE(DirectParams *params, const ALfloat *restrict data, ALuint sr
void MixSend_SSE(SendParams *params, const ALfloat *restrict data,
ALuint OutPos, ALuint SamplesToDo, ALuint BufferSize)
ALuint OutPos, ALuint UNUSED(SamplesToDo), ALuint BufferSize)
{
ALfloat (*restrict OutBuffer)[BUFFERSIZE] = params->OutBuffer;
ALfloat *restrict ClickRemoval = params->ClickRemoval;
ALfloat *restrict PendingClicks = params->PendingClicks;
ALfloat WetGain;
__m128 gain;
ALuint pos;
ALuint Counter = maxu(params->Counter, OutPos) - OutPos;
ALfloat WetGain, Step;
__m128 gain, step;
WetGain = params->Gain;
if(!(WetGain > GAIN_SILENCE_THRESHOLD))
return;
if(OutPos == 0)
ClickRemoval[0] -= data[0] * WetGain;
gain = _mm_set1_ps(WetGain);
for(pos = 0;BufferSize-pos > 3;pos += 4)
{
const __m128 val4 = _mm_load_ps(&data[pos]);
__m128 wet4 = _mm_load_ps(&OutBuffer[0][OutPos+pos]);
wet4 = _mm_add_ps(wet4, _mm_mul_ps(val4, gain));
_mm_store_ps(&OutBuffer[0][OutPos+pos], wet4);
}
for(;pos < BufferSize;pos++)
OutBuffer[0][OutPos+pos] += data[pos] * WetGain;
ALuint pos = 0;
if(OutPos+pos == SamplesToDo)
PendingClicks[0] += data[pos] * WetGain;
Step = params->Gain.Step;
if(Step != 1.0f && Counter > 0)
{
WetGain = params->Gain.Current;
if(BufferSize-pos > 3 && Counter-pos > 3)
{
gain = _mm_set_ps(
WetGain,
WetGain * Step,
WetGain * Step * Step,
WetGain * Step * Step * Step
);
step = _mm_set1_ps(Step * Step * Step * Step);
do {
const __m128 val4 = _mm_load_ps(&data[pos]);
__m128 dry4 = _mm_load_ps(&OutBuffer[0][OutPos+pos]);
dry4 = _mm_add_ps(dry4, _mm_mul_ps(val4, gain));
gain = _mm_mul_ps(gain, step);
_mm_store_ps(&OutBuffer[0][OutPos+pos], dry4);
pos += 4;
} while(BufferSize-pos > 3 && Counter-pos > 3);
WetGain = _mm_cvtss_f32(_mm_shuffle_ps(gain, gain, _MM_SHUFFLE(3, 3, 3, 3)));
}
if(!(BufferSize-pos > 3))
{
for(;pos < BufferSize && pos < Counter;pos++)
{
OutBuffer[0][OutPos+pos] += data[pos]*WetGain;
WetGain *= Step;
}
}
params->Gain.Current = WetGain;
}
WetGain = params->Gain.Target;
if(!(WetGain > GAIN_SILENCE_THRESHOLD))
return;
gain = _mm_set1_ps(WetGain);
for(;BufferSize-pos > 3;pos += 4)
{
const __m128 val4 = _mm_load_ps(&data[pos]);
__m128 wet4 = _mm_load_ps(&OutBuffer[0][OutPos+pos]);
wet4 = _mm_add_ps(wet4, _mm_mul_ps(val4, gain));
_mm_store_ps(&OutBuffer[0][OutPos+pos], wet4);
}
for(;pos < BufferSize;pos++)
OutBuffer[0][OutPos+pos] += data[pos] * WetGain;
}
}

View File

@ -87,7 +87,14 @@ typedef struct SendParams {
/* Gain control, which applies to all input channels to a single (mono)
* output buffer. */
ALfloat Gain;
struct {
ALfloat Current;
ALfloat Step;
ALfloat Target;
} Gain;
ALboolean Moving;
ALuint Counter;
ALfilterState LpFilter[MAX_INPUT_CHANNELS];
} SendParams;

View File

@ -2276,6 +2276,7 @@ ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state)
{
if(state == AL_PLAYING)
{
ALCdevice *device = Context->Device;
ALbufferlistitem *BufferList;
ALactivesource *src = NULL;
ALsizei j, k;
@ -2306,7 +2307,7 @@ ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state)
/* If there's nothing to play, or device is disconnected, go right to
* stopped */
if(!BufferList || !Context->Device->Connected)
if(!BufferList || !device->Connected)
{
SetSourceState(Source, Context, AL_STOPPED);
return;
@ -2339,6 +2340,8 @@ ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state)
}
else
{
ALuint i;
src->Direct.Moving = AL_FALSE;
src->Direct.Counter = 0;
for(j = 0;j < MAX_INPUT_CHANNELS;j++)
@ -2351,6 +2354,11 @@ ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state)
src->Direct.Mix.Hrtf.State.Values[j][k][1] = 0.0f;
}
}
for(i = 0;i < device->NumAuxSends;i++)
{
src->Send[i].Counter = 0;
src->Send[i].Moving = AL_FALSE;
}
}
Source->NeedsUpdate = AL_TRUE;
}