1 #ifndef MIXER_HRTFBASE_H
2 #define MIXER_HRTFBASE_H
8 #include "opthelpers.h"
12 using ApplyCoeffsT
= void(&)(float2
*RESTRICT Values
, const uint_fast32_t irSize
,
13 const HrirArray
&Coeffs
, const float left
, const float right
);
15 template<ApplyCoeffsT ApplyCoeffs
>
16 inline void MixHrtfBase(const float *InSamples
, float2
*RESTRICT AccumSamples
, const ALuint IrSize
,
17 const MixHrtfFilter
*hrtfparams
, const size_t BufferSize
)
19 ASSUME(BufferSize
> 0);
21 const HrirArray
&Coeffs
= *hrtfparams
->Coeffs
;
22 const float gainstep
{hrtfparams
->GainStep
};
23 const float gain
{hrtfparams
->Gain
};
25 size_t ldelay
{HRTF_HISTORY_LENGTH
- hrtfparams
->Delay
[0]};
26 size_t rdelay
{HRTF_HISTORY_LENGTH
- hrtfparams
->Delay
[1]};
27 float stepcount
{0.0f
};
28 for(size_t i
{0u};i
< BufferSize
;++i
)
30 const float g
{gain
+ gainstep
*stepcount
};
31 const float left
{InSamples
[ldelay
++] * g
};
32 const float right
{InSamples
[rdelay
++] * g
};
33 ApplyCoeffs(AccumSamples
+i
, IrSize
, Coeffs
, left
, right
);
39 template<ApplyCoeffsT ApplyCoeffs
>
40 inline void MixHrtfBlendBase(const float *InSamples
, float2
*RESTRICT AccumSamples
,
41 const ALuint IrSize
, const HrtfFilter
*oldparams
, const MixHrtfFilter
*newparams
,
42 const size_t BufferSize
)
44 ASSUME(BufferSize
> 0);
46 const auto &OldCoeffs
= oldparams
->Coeffs
;
47 const float oldGainStep
{oldparams
->Gain
/ static_cast<float>(BufferSize
)};
48 const auto &NewCoeffs
= *newparams
->Coeffs
;
49 const float newGainStep
{newparams
->GainStep
};
51 if LIKELY(oldparams
->Gain
> GAIN_SILENCE_THRESHOLD
)
53 size_t ldelay
{HRTF_HISTORY_LENGTH
- oldparams
->Delay
[0]};
54 size_t rdelay
{HRTF_HISTORY_LENGTH
- oldparams
->Delay
[1]};
55 auto stepcount
= static_cast<float>(BufferSize
);
56 for(size_t i
{0u};i
< BufferSize
;++i
)
58 const float g
{oldGainStep
*stepcount
};
59 const float left
{InSamples
[ldelay
++] * g
};
60 const float right
{InSamples
[rdelay
++] * g
};
61 ApplyCoeffs(AccumSamples
+i
, IrSize
, OldCoeffs
, left
, right
);
67 if LIKELY(newGainStep
*static_cast<float>(BufferSize
) > GAIN_SILENCE_THRESHOLD
)
69 size_t ldelay
{HRTF_HISTORY_LENGTH
+1 - newparams
->Delay
[0]};
70 size_t rdelay
{HRTF_HISTORY_LENGTH
+1 - newparams
->Delay
[1]};
71 float stepcount
{1.0f
};
72 for(size_t i
{1u};i
< BufferSize
;++i
)
74 const float g
{newGainStep
*stepcount
};
75 const float left
{InSamples
[ldelay
++] * g
};
76 const float right
{InSamples
[rdelay
++] * g
};
77 ApplyCoeffs(AccumSamples
+i
, IrSize
, NewCoeffs
, left
, right
);
84 template<ApplyCoeffsT ApplyCoeffs
>
85 inline void MixDirectHrtfBase(FloatBufferLine
&LeftOut
, FloatBufferLine
&RightOut
,
86 const al::span
<const FloatBufferLine
> InSamples
, float2
*RESTRICT AccumSamples
,
87 DirectHrtfState
*State
, const size_t BufferSize
)
89 ASSUME(BufferSize
> 0);
91 /* Add the existing signal directly to the accumulation buffer, unfiltered,
92 * and with a delay to align with the input delay.
94 for(size_t i
{0};i
< BufferSize
;++i
)
96 AccumSamples
[HRTF_DIRECT_DELAY
+i
][0] += LeftOut
[i
];
97 AccumSamples
[HRTF_DIRECT_DELAY
+i
][1] += RightOut
[i
];
100 const uint_fast32_t IrSize
{State
->mIrSize
};
101 auto chan_iter
= State
->mChannels
.begin();
102 for(const FloatBufferLine
&input
: InSamples
)
104 /* For dual-band processing, the signal needs extra scaling applied to
105 * the high frequency response. The band-splitter alone creates a
106 * frequency-dependent phase shift, which is not ideal. To counteract
107 * it, combine it with a backwards phase shift.
110 /* Load the input signal backwards, into a temp buffer with delay
111 * padding. The delay serves to reduce the error caused by the IIR
112 * filter's phase shift on a partial input.
114 al::span
<float> tempbuf
{al::assume_aligned
<16>(State
->mTemp
.data()),
115 HRTF_DIRECT_DELAY
+BufferSize
};
116 auto tmpiter
= std::reverse_copy(input
.begin(), input
.begin()+BufferSize
, tempbuf
.begin());
117 std::copy(chan_iter
->mDelay
.cbegin(), chan_iter
->mDelay
.cend(), tmpiter
);
119 /* Save the unfiltered newest input samples for next time. */
120 std::copy_n(tempbuf
.begin(), chan_iter
->mDelay
.size(), chan_iter
->mDelay
.begin());
122 /* Apply the all-pass on the reversed signal and reverse the resulting
123 * sample array. This produces the forward response with a backwards
124 * phase shift (+n degrees becomes -n degrees).
126 chan_iter
->mSplitter
.applyAllpass(tempbuf
);
127 tempbuf
= tempbuf
.subspan
<HRTF_DIRECT_DELAY
>();
128 std::reverse(tempbuf
.begin(), tempbuf
.end());
130 /* Now apply the HF scale with the band-splitter. This applies the
131 * forward phase shift, which cancels out with the backwards phase
132 * shift to get the original phase on the scaled signal.
134 chan_iter
->mSplitter
.processHfScale(tempbuf
, chan_iter
->mHfScale
);
136 /* Now apply the HRIR coefficients to this channel. */
137 const auto &Coeffs
= chan_iter
->mCoeffs
;
138 for(size_t i
{0u};i
< BufferSize
;++i
)
140 const float insample
{tempbuf
[i
]};
141 ApplyCoeffs(AccumSamples
+i
, IrSize
, Coeffs
, insample
, insample
);
147 for(size_t i
{0u};i
< BufferSize
;++i
)
148 LeftOut
[i
] = AccumSamples
[i
][0];
149 for(size_t i
{0u};i
< BufferSize
;++i
)
150 RightOut
[i
] = AccumSamples
[i
][1];
152 /* Copy the new in-progress accumulation values to the front and clear the
153 * following samples for the next mix.
155 auto accum_iter
= std::copy_n(AccumSamples
+BufferSize
, HRIR_LENGTH
+HRTF_DIRECT_DELAY
,
157 std::fill_n(accum_iter
, BufferSize
, float2
{});
160 #endif /* MIXER_HRTFBASE_H */