#include "config.h" #include "alMain.h" #include "alSource.h" #include "hrtf.h" #include "alu.h" #include "defs.h" 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); void MixHrtf(ALfloat *RESTRICT LeftOut, ALfloat *RESTRICT RightOut, const ALfloat *data, ALsizei Offset, const ALsizei OutPos, const ALsizei IrSize, MixHrtfParams *hrtfparams, HrtfState *hrtfstate, const ALsizei BufferSize) { 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(ALsizei i{0};i < BufferSize;) { /* 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); for(;i < todo;++i) { hrtfstate->Values[HeadOffset][0] = 0.0f; hrtfstate->Values[HeadOffset][1] = 0.0f; ++HeadOffset; hrtfstate->History[HistOffset++] = *(data++); 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); *(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, const ALsizei OutPos, const ALsizei IrSize, const HrtfParams *oldparams, MixHrtfParams *newparams, HrtfState *hrtfstate, const ALsizei BufferSize) { const ALfloat (&OldCoeffs)[HRIR_LENGTH][2] = oldparams->Coeffs; const ALfloat oldGain{oldparams->Gain}; const ALfloat oldGainStep{-oldGain / (ALfloat)BufferSize}; const ALfloat (&NewCoeffs)[HRIR_LENGTH][2] = *newparams->Coeffs; 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(ALsizei i{0};i < BufferSize;) { 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); for(;i < todo;++i) { hrtfstate->Values[HeadOffset][0] = 0.0f; hrtfstate->Values[HeadOffset][1] = 0.0f; ++HeadOffset; hrtfstate->History[HistOffset++] = *(data++); 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); g = newGainStep*stepcount; left = hrtfstate->History[NewDelay[0]++] * g; right = hrtfstate->History[NewDelay[1]++] * g; ApplyCoeffs(Offset, hrtfstate->Values, IrSize, NewCoeffs, left, right); *(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 = newGainStep*stepcount; } void MixDirectHrtf(ALfloat *RESTRICT LeftOut, ALfloat *RESTRICT RightOut, const ALfloat *data, DirectHrtfState *State, const ALsizei Chan, const ALsizei BufferSize) { ASSUME(Chan >= 0); ASSUME(BufferSize > 0); 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}; 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; } }