aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Robinson <[email protected]>2014-03-23 06:57:00 -0700
committerChris Robinson <[email protected]>2014-03-23 06:57:00 -0700
commit81e049bd47cc2423dc6983c47d9f99e70c3135ac (patch)
tree74424462f69b97dffaebdc04dc263bf5eeb6183c
parent0ce0a88fd67ddcf7cb5248ac08d36cfa1c0013eb (diff)
Step mixing gains per-sample for non-HRTF mixing
This fades the dry mixing gains using a logarithmic curve, which should produce a smoother transition than a linear one. It functions similarly to a linear fade except that step = (target - current) / numsteps; ... gain += step; becomes step = powf(target / current, 1.0f / numsteps); ... gain *= step; where 'target' and 'current' are clamped to a lower bound that is greater than 0 (which makes no sense on a logarithmic scale). Consequently, the non-HRTF direct mixers do not do not feed into the click removal and pending click buffers, as this per-sample fading would do an adequate job of stopping clicks and pops caused by extreme gain changes. These buffers should be removed shortly.
-rw-r--r--Alc/ALu.c127
-rw-r--r--Alc/mixer.c2
-rw-r--r--Alc/mixer_c.c30
-rw-r--r--Alc/mixer_inc.c2
-rw-r--r--Alc/mixer_neon.c46
-rw-r--r--Alc/mixer_sse.c56
-rw-r--r--OpenAL32/Include/alu.h9
7 files changed, 212 insertions, 60 deletions
diff --git a/Alc/ALu.c b/Alc/ALu.c
index ca0c0be4..9c563023 100644
--- a/Alc/ALu.c
+++ b/Alc/ALu.c
@@ -291,7 +291,7 @@ ALvoid CalcNonAttnSourceParams(ALactivesource *src, const ALCcontext *ALContext)
ALboolean DirectChannels;
ALfloat hwidth = 0.0f;
ALfloat Pitch;
- ALint i, c;
+ ALint i, j, c;
/* Get device properties */
NumSends = Device->NumAuxSends;
@@ -420,11 +420,11 @@ ALvoid CalcNonAttnSourceParams(ALactivesource *src, const ALCcontext *ALContext)
if(DirectChannels != AL_FALSE)
{
- ALfloat (*SrcMatrix)[MaxChannels] = src->Direct.Mix.Gains;
+ ALfloat (*Matrix)[MaxChannels] = src->Direct.Mix.Gains.Target;
for(i = 0;i < MAX_INPUT_CHANNELS;i++)
{
for(c = 0;c < MaxChannels;c++)
- SrcMatrix[i][c] = 0.0f;
+ Matrix[i][c] = 0.0f;
}
for(c = 0;c < num_channels;c++)
{
@@ -433,13 +433,47 @@ ALvoid CalcNonAttnSourceParams(ALactivesource *src, const ALCcontext *ALContext)
enum Channel chan = Device->Speaker2Chan[i];
if(chan == chans[c].channel)
{
- SrcMatrix[c][chan] = DryGain;
+ Matrix[c][chan] = DryGain;
break;
}
}
}
- src->Direct.Counter = 0;
- src->Direct.Moving = AL_TRUE;
+
+ if(src->Direct.Moving)
+ {
+ ALfloat (*restrict Current)[MaxChannels] = src->Direct.Mix.Gains.Current;
+ ALfloat (*restrict Step)[MaxChannels] = src->Direct.Mix.Gains.Step;
+ for(i = 0;i < MAX_INPUT_CHANNELS;i++)
+ {
+ for(j = 0;j < MaxChannels;j++)
+ {
+ ALfloat cur = maxf(Current[i][j], GAIN_SILENCE_THRESHOLD);
+ ALfloat trg = maxf(Matrix[i][j], GAIN_SILENCE_THRESHOLD);
+ if(fabs(trg - cur) >= GAIN_SILENCE_THRESHOLD)
+ Step[i][j] = powf(trg/cur, 1.0f/64.0f);
+ else
+ Step[i][j] = 1.0f;
+ Current[i][j] = cur;
+ }
+ }
+ src->Direct.Counter = 64;
+ }
+ else
+ {
+ ALfloat (*restrict Current)[MaxChannels] = src->Direct.Mix.Gains.Current;
+ ALfloat (*restrict Step)[MaxChannels] = src->Direct.Mix.Gains.Step;
+ for(i = 0;i < MAX_INPUT_CHANNELS;i++)
+ {
+ for(j = 0;j < MaxChannels;j++)
+ {
+ Current[i][j] = Matrix[i][j];
+ Step[i][j] = 1.0f;
+ }
+ }
+ src->Direct.Counter = 0;
+ src->Direct.Moving = AL_TRUE;
+ }
+
src->DryMix = SelectDirectMixer();
}
else if(Device->Hrtf)
@@ -475,11 +509,11 @@ ALvoid CalcNonAttnSourceParams(ALactivesource *src, const ALCcontext *ALContext)
}
else
{
- ALfloat (*SrcMatrix)[MaxChannels] = src->Direct.Mix.Gains;
+ ALfloat (*Matrix)[MaxChannels] = src->Direct.Mix.Gains.Target;
for(i = 0;i < MAX_INPUT_CHANNELS;i++)
{
for(c = 0;c < MaxChannels;c++)
- SrcMatrix[i][c] = 0.0f;
+ Matrix[i][c] = 0.0f;
}
DryGain *= lerp(1.0f, 1.0f/sqrtf((float)Device->NumChan), hwidth/F_PI);
@@ -488,14 +522,48 @@ ALvoid CalcNonAttnSourceParams(ALactivesource *src, const ALCcontext *ALContext)
/* Special-case LFE */
if(chans[c].channel == LFE)
{
- SrcMatrix[c][chans[c].channel] = DryGain;
+ Matrix[c][chans[c].channel] = DryGain;
continue;
}
ComputeAngleGains(Device, chans[c].angle, hwidth, DryGain,
- SrcMatrix[c]);
+ Matrix[c]);
}
- src->Direct.Counter = 0;
- src->Direct.Moving = AL_TRUE;
+
+ if(src->Direct.Moving)
+ {
+ ALfloat (*restrict Current)[MaxChannels] = src->Direct.Mix.Gains.Current;
+ ALfloat (*restrict Step)[MaxChannels] = src->Direct.Mix.Gains.Step;
+ for(i = 0;i < MAX_INPUT_CHANNELS;i++)
+ {
+ for(j = 0;j < MaxChannels;j++)
+ {
+ ALfloat trg = maxf(Matrix[i][j], GAIN_SILENCE_THRESHOLD);
+ ALfloat cur = maxf(Current[i][j], GAIN_SILENCE_THRESHOLD);
+ if(fabs(trg - cur) >= GAIN_SILENCE_THRESHOLD)
+ Step[i][j] = powf(trg/cur, 1.0f/64.0f);
+ else
+ Step[i][j] = 1.0f;
+ Current[i][j] = cur;
+ }
+ }
+ src->Direct.Counter = 64;
+ }
+ else
+ {
+ ALfloat (*restrict Current)[MaxChannels] = src->Direct.Mix.Gains.Current;
+ ALfloat (*restrict Step)[MaxChannels] = src->Direct.Mix.Gains.Step;
+ for(i = 0;i < MAX_INPUT_CHANNELS;i++)
+ {
+ for(j = 0;j < MaxChannels;j++)
+ {
+ Current[i][j] = Matrix[i][j];
+ Step[i][j] = 1.0f;
+ }
+ }
+ src->Direct.Counter = 0;
+ src->Direct.Moving = AL_TRUE;
+ }
+
src->DryMix = SelectDirectMixer();
}
for(i = 0;i < NumSends;i++)
@@ -919,7 +987,7 @@ ALvoid CalcSourceParams(ALactivesource *src, const ALCcontext *ALContext)
}
else
{
- ALfloat (*Matrix)[MaxChannels] = src->Direct.Mix.Gains;
+ ALfloat (*Matrix)[MaxChannels] = src->Direct.Mix.Gains.Target;
ALfloat DirGain = 0.0f;
ALfloat AmbientGain;
@@ -951,8 +1019,37 @@ ALvoid CalcSourceParams(ALactivesource *src, const ALCcontext *ALContext)
Matrix[0][chan] = maxf(Matrix[0][chan], AmbientGain);
}
- src->Direct.Counter = 0;
- src->Direct.Moving = AL_TRUE;
+ if(src->Direct.Moving)
+ {
+ ALfloat (*restrict Current)[MaxChannels] = src->Direct.Mix.Gains.Current;
+ ALfloat (*restrict Step)[MaxChannels] = src->Direct.Mix.Gains.Step;
+ for(j = 0;j < MaxChannels;j++)
+ {
+ ALfloat cur = maxf(Current[0][j], GAIN_SILENCE_THRESHOLD);
+ ALfloat trg = maxf(Matrix[0][j], GAIN_SILENCE_THRESHOLD);
+ if(fabs(trg - cur) >= GAIN_SILENCE_THRESHOLD)
+ Step[0][j] = powf(trg/cur, 1.0f/64.0f);
+ else
+ Step[0][j] = 1.0f;
+ Current[0][j] = cur;
+ }
+ src->Direct.Counter = 64;
+ }
+ else
+ {
+ ALfloat (*restrict Current)[MaxChannels] = src->Direct.Mix.Gains.Current;
+ ALfloat (*restrict Step)[MaxChannels] = src->Direct.Mix.Gains.Step;
+ for(i = 0;i < MAX_INPUT_CHANNELS;i++)
+ {
+ for(j = 0;j < MaxChannels;j++)
+ {
+ Current[i][j] = Matrix[i][j];
+ Step[i][j] = 1.0f;
+ }
+ }
+ src->Direct.Counter = 0;
+ src->Direct.Moving = AL_TRUE;
+ }
src->DryMix = SelectDirectMixer();
}
diff --git a/Alc/mixer.c b/Alc/mixer.c
index 8ce7d845..96acb3e8 100644
--- a/Alc/mixer.c
+++ b/Alc/mixer.c
@@ -411,7 +411,7 @@ ALvoid MixSource(ALactivesource *src, ALCdevice *Device, ALuint SamplesToDo)
Source->BuffersPlayed = BuffersPlayed;
Source->position = DataPosInt;
Source->position_fraction = DataPosFrac;
- src->Direct.Mix.Hrtf.State.Offset += OutPos;
+ src->Direct.Offset += OutPos;
if(State == AL_PLAYING)
src->Direct.Counter = maxu(src->Direct.Counter, OutPos) - OutPos;
else
diff --git a/Alc/mixer_c.c b/Alc/mixer_c.c
index 6b21e67a..e83655e6 100644
--- a/Alc/mixer_c.c
+++ b/Alc/mixer_c.c
@@ -83,27 +83,33 @@ static inline void ApplyCoeffs(ALuint Offset, ALfloat (*restrict Values)[2],
void MixDirect_C(DirectParams *params, const ALfloat *restrict data, ALuint srcchan,
- 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 DrySend;
- ALuint pos;
+ ALuint Counter = maxu(params->Counter, OutPos) - OutPos;
+ ALfloat DrySend, Step;
ALuint c;
for(c = 0;c < MaxChannels;c++)
{
- DrySend = params->Mix.Gains[srcchan][c];
+ ALuint pos = 0;
+ Step = params->Mix.Gains.Step[srcchan][c];
+ if(Step != 0.0f && Counter > 0)
+ {
+ DrySend = params->Mix.Gains.Current[srcchan][c];
+ for(;pos < BufferSize && pos < Counter;pos++)
+ {
+ OutBuffer[c][OutPos+pos] += data[pos]*DrySend;
+ DrySend *= Step;
+ }
+ params->Mix.Gains.Current[srcchan][c] = DrySend;
+ }
+
+ DrySend = params->Mix.Gains.Target[srcchan][c];
if(!(DrySend > GAIN_SILENCE_THRESHOLD))
continue;
-
- if(OutPos == 0)
- ClickRemoval[c] -= data[0]*DrySend;
- for(pos = 0;pos < BufferSize;pos++)
+ for(;pos < BufferSize;pos++)
OutBuffer[c][OutPos+pos] += data[pos]*DrySend;
- if(OutPos+pos == SamplesToDo)
- PendingClicks[c] += data[pos]*DrySend;
}
}
diff --git a/Alc/mixer_inc.c b/Alc/mixer_inc.c
index 1cb1967d..d27cb979 100644
--- a/Alc/mixer_inc.c
+++ b/Alc/mixer_inc.c
@@ -43,8 +43,8 @@ void MixDirect_Hrtf(DirectParams *params, const ALfloat *restrict data, ALuint s
const ALuint *restrict TargetDelay = params->Mix.Hrtf.Params.Delay[srcchan];
ALfloat *restrict History = params->Mix.Hrtf.State.History[srcchan];
ALfloat (*restrict Values)[2] = params->Mix.Hrtf.State.Values[srcchan];
- ALuint Offset = params->Mix.Hrtf.State.Offset + OutPos;
ALint Counter = maxu(params->Counter, OutPos) - OutPos;
+ ALuint Offset = params->Offset + OutPos;
ALIGN(16) ALfloat Coeffs[HRIR_LENGTH][2];
ALuint Delay[2];
ALfloat left, right;
diff --git a/Alc/mixer_neon.c b/Alc/mixer_neon.c
index 448eadd3..15703226 100644
--- a/Alc/mixer_neon.c
+++ b/Alc/mixer_neon.c
@@ -78,27 +78,48 @@ static inline void ApplyCoeffs(ALuint Offset, ALfloat (*restrict Values)[2],
void MixDirect_Neon(DirectParams *params, const ALfloat *restrict data, ALuint srcchan,
- 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 DrySend;
+ ALuint Counter = maxu(params->Counter, OutPos) - OutPos;
+ ALfloat DrySend, Step;
float32x4_t gain;
- ALuint pos;
ALuint c;
for(c = 0;c < MaxChannels;c++)
{
- DrySend = params->Mix.Gains[srcchan][c];
+ ALuint pos = 0;
+ Step = params->Mix.Gains.Step[srcchan][c];
+ if(Step != 1.0f && Counter > 0)
+ {
+ DrySend = params->Mix.Gains.Current[srcchan][c];
+ if(BufferSize-pos > 3 && Counter-pos > 3)
+ {
+ OutBuffer[c][OutPos+pos ] += data[pos ]*DrySend;
+ DrySend *= Step;
+ OutBuffer[c][OutPos+pos+1] += data[pos+1]*DrySend;
+ DrySend *= Step;
+ OutBuffer[c][OutPos+pos+2] += data[pos+2]*DrySend;
+ DrySend *= Step;
+ OutBuffer[c][OutPos+pos+4] += data[pos+3]*DrySend;
+ DrySend *= Step;
+ }
+ if(!(BufferSize-pos > 3))
+ {
+ for(;pos < BufferSize && pos < Counter;pos++)
+ {
+ OutBuffer[c][OutPos+pos] += data[pos]*DrySend;
+ DrySend *= Step;
+ }
+ }
+ params->Mix.Gains.Current[srcchan][c] = DrySend;
+ }
+
+ DrySend = params->Mix.Gains.Target[srcchan][c];
if(!(DrySend > GAIN_SILENCE_THRESHOLD))
continue;
-
- if(OutPos == 0)
- ClickRemoval[c] -= data[0]*DrySend;
-
gain = vdupq_n_f32(DrySend);
- for(pos = 0;BufferSize-pos > 3;pos += 4)
+ for(;BufferSize-pos > 3;pos += 4)
{
const float32x4_t val4 = vld1q_f32(&data[pos]);
float32x4_t dry4 = vld1q_f32(&OutBuffer[c][OutPos+pos]);
@@ -107,9 +128,6 @@ void MixDirect_Neon(DirectParams *params, const ALfloat *restrict data, ALuint s
}
for(;pos < BufferSize;pos++)
OutBuffer[c][OutPos+pos] += data[pos]*DrySend;
-
- if(OutPos+pos == SamplesToDo)
- PendingClicks[c] += data[pos]*DrySend;
}
}
diff --git a/Alc/mixer_sse.c b/Alc/mixer_sse.c
index c9296d3d..52785086 100644
--- a/Alc/mixer_sse.c
+++ b/Alc/mixer_sse.c
@@ -141,27 +141,56 @@ static inline void ApplyCoeffs(ALuint Offset, ALfloat (*restrict Values)[2],
void MixDirect_SSE(DirectParams *params, const ALfloat *restrict data, ALuint srcchan,
- 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 DrySend;
- __m128 gain;
- ALuint pos;
+ ALuint Counter = maxu(params->Counter, OutPos) - OutPos;
+ ALfloat DrySend, Step;
+ __m128 gain, step;
ALuint c;
for(c = 0;c < MaxChannels;c++)
{
- DrySend = params->Mix.Gains[srcchan][c];
+ ALuint pos = 0;
+ Step = params->Mix.Gains.Step[srcchan][c];
+ if(Step != 1.0f && Counter > 0)
+ {
+ DrySend = params->Mix.Gains.Current[srcchan][c];
+ if(BufferSize-pos > 3 && Counter-pos > 3)
+ {
+ gain = _mm_set_ps(
+ DrySend,
+ DrySend * Step,
+ DrySend * Step * Step,
+ DrySend * 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[c][OutPos+pos]);
+ dry4 = _mm_add_ps(dry4, _mm_mul_ps(val4, gain));
+ gain = _mm_mul_ps(gain, step);
+ _mm_store_ps(&OutBuffer[c][OutPos+pos], dry4);
+ pos += 4;
+ } while(BufferSize-pos > 3 && Counter-pos > 3);
+ DrySend = _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[c][OutPos+pos] += data[pos]*DrySend;
+ DrySend *= Step;
+ }
+ }
+ params->Mix.Gains.Current[srcchan][c] = DrySend;
+ }
+
+ DrySend = params->Mix.Gains.Target[srcchan][c];
if(!(DrySend > GAIN_SILENCE_THRESHOLD))
continue;
-
- if(OutPos == 0)
- ClickRemoval[c] -= data[0]*DrySend;
-
gain = _mm_set1_ps(DrySend);
- for(pos = 0;BufferSize-pos > 3;pos += 4)
+ for(;BufferSize-pos > 3;pos += 4)
{
const __m128 val4 = _mm_load_ps(&data[pos]);
__m128 dry4 = _mm_load_ps(&OutBuffer[c][OutPos+pos]);
@@ -170,9 +199,6 @@ void MixDirect_SSE(DirectParams *params, const ALfloat *restrict data, ALuint sr
}
for(;pos < BufferSize;pos++)
OutBuffer[c][OutPos+pos] += data[pos]*DrySend;
-
- if(OutPos+pos == SamplesToDo)
- PendingClicks[c] += data[pos]*DrySend;
}
}
diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h
index 3ec16565..6202c28a 100644
--- a/OpenAL32/Include/alu.h
+++ b/OpenAL32/Include/alu.h
@@ -40,7 +40,6 @@ extern "C" {
typedef struct HrtfState {
ALIGN(16) ALfloat History[MAX_INPUT_CHANNELS][SRC_HISTORY_LENGTH];
ALIGN(16) ALfloat Values[MAX_INPUT_CHANNELS][HRIR_LENGTH][2];
- ALuint Offset;
} HrtfState;
typedef struct HrtfParams {
@@ -67,12 +66,18 @@ typedef struct DirectParams {
/* A mixing matrix. First subscript is the channel number of the input
* data (regardless of channel configuration) and the second is the
* channel target (eg. FrontLeft). Not used with HRTF. */
- ALfloat Gains[MAX_INPUT_CHANNELS][MaxChannels];
+ struct {
+ ALfloat Current[MAX_INPUT_CHANNELS][MaxChannels];
+ ALfloat Step[MAX_INPUT_CHANNELS][MaxChannels];
+ ALfloat Target[MAX_INPUT_CHANNELS][MaxChannels];
+ } Gains;
} Mix;
/* If not 'moving', gain/coefficients are set directly without fading. */
ALboolean Moving;
/* Stepping counter for gain/coefficient fading. */
ALuint Counter;
+ /* History/coefficient offset. */
+ ALuint Offset;
ALfilterState LpFilter[MAX_INPUT_CHANNELS];
} DirectParams;