Further improve HRTF methods to avoid masking in the inner loops

This commit is contained in:
Chris Robinson
2018-12-31 04:12:20 -08:00
parent 5e03941701
commit 5a9a1c8d7d
4 changed files with 156 additions and 93 deletions
+129 -65
View File
@@ -14,114 +14,178 @@ static inline void ApplyCoeffs(ALsizei Offset, ALfloat (&Values)[HRIR_LENGTH][2]
void MixHrtf(ALfloat *RESTRICT LeftOut, ALfloat *RESTRICT RightOut,
const ALfloat *data, ALsizei Offset, ALsizei OutPos,
const ALfloat *data, ALsizei Offset, const ALsizei OutPos,
const ALsizei IrSize, MixHrtfParams *hrtfparams, HrtfState *hrtfstate,
ALsizei BufferSize)
const ALsizei BufferSize)
{
const ALfloat (&Coeffs)[HRIR_LENGTH][2] = *hrtfparams->Coeffs;
const ALsizei Delay[2] = { hrtfparams->Delay[0], hrtfparams->Delay[1] };
const ALfloat gainstep = hrtfparams->GainStep;
const ALfloat gain = hrtfparams->Gain;
ALfloat g, stepcount = 0.0f;
ALfloat left, right;
ALsizei i;
ASSUME(OutPos >= 0);
ASSUME(IrSize >= 4);
ASSUME(BufferSize > 0);
const ALfloat (&Coeffs)[HRIR_LENGTH][2] = *hrtfparams->Coeffs;
const ALfloat gainstep{hrtfparams->GainStep};
const ALfloat gain{hrtfparams->Gain};
ALfloat stepcount{0.0f};
ALsizei HistOffset{Offset&HRTF_HISTORY_MASK};
ALsizei Delay[2]{
(HistOffset-hrtfparams->Delay[0])&HRTF_HISTORY_MASK,
(HistOffset-hrtfparams->Delay[1])&HRTF_HISTORY_MASK };
Offset &= HRIR_MASK;
ALsizei HeadOffset{(Offset+IrSize-1)&HRIR_MASK};
LeftOut += OutPos;
RightOut += OutPos;
for(i = 0;i < BufferSize;i++)
for(ALsizei i{0};i < BufferSize;)
{
hrtfstate->History[Offset&HRTF_HISTORY_MASK] = *(data++);
/* Calculate the number of samples we can do until one of the indices
* wraps on its buffer, or we reach the end.
*/
const ALsizei todo_hist{HRTF_HISTORY_LENGTH - maxi(maxi(HistOffset, Delay[0]), Delay[1])};
const ALsizei todo_hrir{HRIR_LENGTH - maxi(HeadOffset, Offset)};
const ALsizei todo{mini(BufferSize-i, mini(todo_hist, todo_hrir)) + i};
ASSUME(todo > i);
g = gain + gainstep*stepcount;
left = hrtfstate->History[(Offset-Delay[0])&HRTF_HISTORY_MASK]*g;
right = hrtfstate->History[(Offset-Delay[1])&HRTF_HISTORY_MASK]*g;
for(;i < todo;++i)
{
hrtfstate->Values[HeadOffset][0] = 0.0f;
hrtfstate->Values[HeadOffset][1] = 0.0f;
++HeadOffset;
hrtfstate->Values[(Offset+IrSize-1)&HRIR_MASK][0] = 0.0f;
hrtfstate->Values[(Offset+IrSize-1)&HRIR_MASK][1] = 0.0f;
hrtfstate->History[HistOffset++] = *(data++);
ApplyCoeffs(Offset, hrtfstate->Values, IrSize, Coeffs, left, right);
*(LeftOut++) += hrtfstate->Values[Offset&HRIR_MASK][0];
*(RightOut++) += hrtfstate->Values[Offset&HRIR_MASK][1];
const ALfloat g{gain + gainstep*stepcount};
const ALfloat left{hrtfstate->History[Delay[0]++] * g};
const ALfloat right{hrtfstate->History[Delay[1]++] * g};
ApplyCoeffs(Offset, hrtfstate->Values, IrSize, Coeffs, left, right);
stepcount += 1.0f;
Offset++;
*(LeftOut++) += hrtfstate->Values[Offset][0];
*(RightOut++) += hrtfstate->Values[Offset][1];
++Offset;
stepcount += 1.0f;
}
HeadOffset &= HRIR_MASK;
HistOffset &= HRTF_HISTORY_MASK;
Delay[0] &= HRTF_HISTORY_MASK;
Delay[1] &= HRTF_HISTORY_MASK;
Offset &= HRIR_MASK;
}
hrtfparams->Gain = gain + gainstep*stepcount;
}
void MixHrtfBlend(ALfloat *RESTRICT LeftOut, ALfloat *RESTRICT RightOut,
const ALfloat *data, ALsizei Offset, ALsizei OutPos,
const ALfloat *data, ALsizei Offset, const ALsizei OutPos,
const ALsizei IrSize, const HrtfParams *oldparams,
MixHrtfParams *newparams, HrtfState *hrtfstate,
ALsizei BufferSize)
const ALsizei BufferSize)
{
const ALfloat (&OldCoeffs)[HRIR_LENGTH][2] = oldparams->Coeffs;
const ALsizei OldDelay[2] = { oldparams->Delay[0], oldparams->Delay[1] };
const ALfloat oldGain = oldparams->Gain;
const ALfloat oldGainStep = -oldGain / (ALfloat)BufferSize;
const ALfloat oldGain{oldparams->Gain};
const ALfloat oldGainStep{-oldGain / (ALfloat)BufferSize};
const ALfloat (&NewCoeffs)[HRIR_LENGTH][2] = *newparams->Coeffs;
const ALsizei NewDelay[2] = { newparams->Delay[0], newparams->Delay[1] };
const ALfloat newGain = newparams->Gain;
const ALfloat newGainStep = newparams->GainStep;
ALfloat g, stepcount = 0.0f;
ALfloat left, right;
ALsizei i;
const ALfloat newGainStep{newparams->GainStep};
ALfloat stepcount{0.0f};
ASSUME(OutPos >= 0);
ASSUME(IrSize >= 4);
ASSUME(BufferSize > 0);
ALsizei HistOffset{Offset&HRTF_HISTORY_MASK};
ALsizei OldDelay[2]{
(HistOffset-oldparams->Delay[0])&HRTF_HISTORY_MASK,
(HistOffset-oldparams->Delay[1])&HRTF_HISTORY_MASK };
ALsizei NewDelay[2]{
(HistOffset-newparams->Delay[0])&HRTF_HISTORY_MASK,
(HistOffset-newparams->Delay[1])&HRTF_HISTORY_MASK };
Offset &= HRIR_MASK;
ALsizei HeadOffset{(Offset+IrSize-1)&HRIR_MASK};
LeftOut += OutPos;
RightOut += OutPos;
for(i = 0;i < BufferSize;i++)
for(ALsizei i{0};i < BufferSize;)
{
hrtfstate->Values[(Offset+IrSize-1)&HRIR_MASK][0] = 0.0f;
hrtfstate->Values[(Offset+IrSize-1)&HRIR_MASK][1] = 0.0f;
const ALsizei todo_hist{HRTF_HISTORY_LENGTH -
maxi(maxi(maxi(maxi(HistOffset, OldDelay[0]), OldDelay[1]), NewDelay[0]), NewDelay[1])
};
const ALsizei todo_hrir{HRIR_LENGTH - maxi(HeadOffset, Offset)};
const ALsizei todo{mini(BufferSize-i, mini(todo_hist, todo_hrir)) + i};
ASSUME(todo > i);
hrtfstate->History[Offset&HRTF_HISTORY_MASK] = *(data++);
for(;i < todo;++i)
{
hrtfstate->Values[HeadOffset][0] = 0.0f;
hrtfstate->Values[HeadOffset][1] = 0.0f;
++HeadOffset;
g = oldGain + oldGainStep*stepcount;
left = hrtfstate->History[(Offset-OldDelay[0])&HRTF_HISTORY_MASK]*g;
right = hrtfstate->History[(Offset-OldDelay[1])&HRTF_HISTORY_MASK]*g;
ApplyCoeffs(Offset, hrtfstate->Values, IrSize, OldCoeffs, left, right);
hrtfstate->History[HistOffset++] = *(data++);
g = newGain + newGainStep*stepcount;
left = hrtfstate->History[(Offset-NewDelay[0])&HRTF_HISTORY_MASK]*g;
right = hrtfstate->History[(Offset-NewDelay[1])&HRTF_HISTORY_MASK]*g;
ApplyCoeffs(Offset, hrtfstate->Values, IrSize, NewCoeffs, left, right);
ALfloat g{oldGain + oldGainStep*stepcount};
ALfloat left{hrtfstate->History[OldDelay[0]++] * g};
ALfloat right{hrtfstate->History[OldDelay[1]++] * g};
ApplyCoeffs(Offset, hrtfstate->Values, IrSize, OldCoeffs, left, right);
*(LeftOut++) += hrtfstate->Values[Offset&HRIR_MASK][0];
*(RightOut++) += hrtfstate->Values[Offset&HRIR_MASK][1];
g = newGainStep*stepcount;
left = hrtfstate->History[NewDelay[0]++] * g;
right = hrtfstate->History[NewDelay[1]++] * g;
ApplyCoeffs(Offset, hrtfstate->Values, IrSize, NewCoeffs, left, right);
stepcount += 1.0f;
Offset++;
*(LeftOut++) += hrtfstate->Values[Offset][0];
*(RightOut++) += hrtfstate->Values[Offset][1];
++Offset;
stepcount += 1.0f;
}
HeadOffset &= HRIR_MASK;
HistOffset &= HRTF_HISTORY_MASK;
OldDelay[0] &= HRTF_HISTORY_MASK;
OldDelay[1] &= HRTF_HISTORY_MASK;
NewDelay[0] &= HRTF_HISTORY_MASK;
NewDelay[1] &= HRTF_HISTORY_MASK;
Offset &= HRIR_MASK;
}
newparams->Gain = newGain + newGainStep*stepcount;
newparams->Gain = newGainStep*stepcount;
}
void MixDirectHrtf(ALfloat *RESTRICT LeftOut, ALfloat *RESTRICT RightOut,
const ALfloat *data, DirectHrtfState *State, const ALsizei Chan,
const ALsizei BufferSize)
{
const ALsizei IrSize{State->IrSize};
ALsizei Offset{State->Offset};
ALfloat (&Values)[HRIR_LENGTH][2] = State->Chan[Chan].Values;
const ALfloat (&Coeffs)[HRIR_LENGTH][2] = State->Chan[Chan].Coeffs;
ASSUME(IrSize >= 4);
ASSUME(Chan >= 0);
ASSUME(BufferSize > 0);
for(ALsizei i{0};i < BufferSize;i++)
{
Values[(Offset+IrSize)&HRIR_MASK][0] = 0.0f;
Values[(Offset+IrSize)&HRIR_MASK][1] = 0.0f;
Offset++;
const ALfloat (&Coeffs)[HRIR_LENGTH][2] = State->Chan[Chan].Coeffs;
ALfloat (&Values)[HRIR_LENGTH][2] = State->Chan[Chan].Values;
ALsizei Offset{State->Offset&HRIR_MASK};
const ALsizei IrSize{State->IrSize};
const ALfloat insample{*(data++)};
ApplyCoeffs(Offset, Values, IrSize, Coeffs, insample, insample);
*(LeftOut++) += Values[Offset&HRIR_MASK][0];
*(RightOut++) += Values[Offset&HRIR_MASK][1];
ASSUME(IrSize >= 4);
ALsizei HeadOffset{(Offset+IrSize-1)&HRIR_MASK};
for(ALsizei i{0};i < BufferSize;)
{
const ALsizei todo_hrir{HRIR_LENGTH - maxi(HeadOffset, Offset)};
const ALsizei todo{mini(BufferSize-i, todo_hrir) + i};
ASSUME(todo > i);
for(;i < todo;++i)
{
Values[HeadOffset][0] = 0.0f;
Values[HeadOffset][1] = 0.0f;
++HeadOffset;
const ALfloat insample{*(data++)};
ApplyCoeffs(Offset, Values, IrSize, Coeffs, insample, insample);
*(LeftOut++) += Values[Offset][0];
*(RightOut++) += Values[Offset][1];
++Offset;
}
HeadOffset &= HRIR_MASK;
Offset &= HRIR_MASK;
}
}
+7 -8
View File
@@ -107,24 +107,23 @@ static inline void ApplyCoeffs(ALsizei Offset, ALfloat (&Values)[HRIR_LENGTH][2]
const ALsizei IrSize, const ALfloat (&Coeffs)[HRIR_LENGTH][2],
const ALfloat left, const ALfloat right)
{
ALsizei off{Offset&HRIR_MASK};
ALsizei count{mini(IrSize, HRIR_LENGTH - off)};
ASSUME(Offset >= 0 && Offset < HRIR_LENGTH);
ASSUME(IrSize >= 2);
ASSUME(&Values != &Coeffs);
ASSUME(count > 0);
ALsizei count{mini(IrSize, HRIR_LENGTH - Offset)};
ASSUME(count > 0);
for(ALsizei c{0};;)
{
for(;c < count;++c)
{
Values[off][0] += Coeffs[c][0] * left;
Values[off][1] += Coeffs[c][1] * right;
++off;
Values[Offset][0] += Coeffs[c][0] * left;
Values[Offset][1] += Coeffs[c][1] * right;
++Offset;
}
if(c >= IrSize)
break;
off = 0;
Offset = 0;
count = IrSize;
}
}
+16 -16
View File
@@ -90,45 +90,45 @@ static inline void ApplyCoeffs(ALsizei Offset, ALfloat (&Values)[HRIR_LENGTH][2]
ASSUME(IrSize >= 2);
ASSUME(&Values != &Coeffs);
ALsizei off{Offset&HRIR_MASK};
ASSUME(Offset >= 0 && Offset < HRIR_LENGTH);
if((Offset&1))
{
ALsizei count{mini(IrSize-1, HRIR_LENGTH - off)};
ALsizei count{mini(IrSize-1, HRIR_LENGTH - Offset)};
ASSUME(count >= 1);
__m128 imp0, imp1;
coeffs = _mm_load_ps(&Coeffs[0][0]);
vals = _mm_loadl_pi(vals, (__m64*)&Values[off][0]);
vals = _mm_loadl_pi(vals, (__m64*)&Values[Offset][0]);
imp0 = _mm_mul_ps(lrlr, coeffs);
vals = _mm_add_ps(imp0, vals);
_mm_storel_pi((__m64*)&Values[off][0], vals);
++off;
_mm_storel_pi((__m64*)&Values[Offset][0], vals);
++Offset;
for(ALsizei i{1};;)
{
for(;i < count;i += 2)
{
coeffs = _mm_load_ps(&Coeffs[i+1][0]);
vals = _mm_load_ps(&Values[off][0]);
vals = _mm_load_ps(&Values[Offset][0]);
imp1 = _mm_mul_ps(lrlr, coeffs);
imp0 = _mm_shuffle_ps(imp0, imp1, _MM_SHUFFLE(1, 0, 3, 2));
vals = _mm_add_ps(imp0, vals);
_mm_store_ps(&Values[off][0], vals);
_mm_store_ps(&Values[Offset][0], vals);
imp0 = imp1;
off += 2;
Offset += 2;
}
off &= HRIR_MASK;
Offset &= HRIR_MASK;
if(i >= IrSize-1)
break;
count = IrSize-1;
}
vals = _mm_loadl_pi(vals, (__m64*)&Values[off][0]);
vals = _mm_loadl_pi(vals, (__m64*)&Values[Offset][0]);
imp0 = _mm_movehl_ps(imp0, imp0);
vals = _mm_add_ps(imp0, vals);
_mm_storel_pi((__m64*)&Values[off][0], vals);
_mm_storel_pi((__m64*)&Values[Offset][0], vals);
}
else
{
ALsizei count{mini(IrSize, HRIR_LENGTH - off)};
ALsizei count{mini(IrSize, HRIR_LENGTH - Offset)};
ASSUME(count >= 2);
for(ALsizei i{0};;)
@@ -136,14 +136,14 @@ static inline void ApplyCoeffs(ALsizei Offset, ALfloat (&Values)[HRIR_LENGTH][2]
for(;i < count;i += 2)
{
coeffs = _mm_load_ps(&Coeffs[i][0]);
vals = _mm_load_ps(&Values[off][0]);
vals = _mm_load_ps(&Values[Offset][0]);
vals = _mm_add_ps(vals, _mm_mul_ps(lrlr, coeffs));
_mm_store_ps(&Values[off][0], vals);
off += 2;
_mm_store_ps(&Values[Offset][0], vals);
Offset += 2;
}
if(i >= IrSize)
break;
off = 0;
Offset = 0;
count = IrSize;
}
}
+4 -4
View File
@@ -280,12 +280,12 @@ using RowMixerFunc = void(*)(ALfloat *OutBuffer, const ALfloat *gains,
const ALfloat (*RESTRICT data)[BUFFERSIZE], ALsizei InChans, ALsizei InPos,
ALsizei BufferSize);
using HrtfMixerFunc = void(*)(ALfloat *RESTRICT LeftOut, ALfloat *RESTRICT RightOut,
const ALfloat *data, ALsizei Offset, ALsizei OutPos, const ALsizei IrSize,
MixHrtfParams *hrtfparams, HrtfState *hrtfstate, ALsizei BufferSize);
const ALfloat *data, ALsizei Offset, const ALsizei OutPos, const ALsizei IrSize,
MixHrtfParams *hrtfparams, HrtfState *hrtfstate, const ALsizei BufferSize);
using HrtfMixerBlendFunc = void(*)(ALfloat *RESTRICT LeftOut, ALfloat *RESTRICT RightOut,
const ALfloat *data, ALsizei Offset, ALsizei OutPos, const ALsizei IrSize,
const ALfloat *data, ALsizei Offset, const ALsizei OutPos, const ALsizei IrSize,
const HrtfParams *oldparams, MixHrtfParams *newparams, HrtfState *hrtfstate,
ALsizei BufferSize);
const ALsizei BufferSize);
using HrtfDirectMixerFunc = void(*)(ALfloat *RESTRICT LeftOut, ALfloat *RESTRICT RightOut,
const ALfloat *data, DirectHrtfState *State, const ALsizei Chan, const ALsizei BufferSize);