Improve HRTF delay handling
Ensures source-level HRTF, the dry mix, and direct output all align properly, and simplifies adding the delay in the direct mix output.
This commit is contained in:
parent
f38b813ba8
commit
200c164d78
@ -269,7 +269,7 @@ struct ALCdevice : public al::intrusive_ref<ALCdevice> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/* Persistent storage for HRTF mixing. */
|
/* Persistent storage for HRTF mixing. */
|
||||||
alignas(16) float2 HrtfAccumData[BUFFERSIZE + HRIR_LENGTH];
|
alignas(16) float2 HrtfAccumData[BUFFERSIZE + HRIR_LENGTH + HRTF_DIRECT_DELAY];
|
||||||
|
|
||||||
/* Mixing buffer used by the Dry mix and Real output. */
|
/* Mixing buffer used by the Dry mix and Real output. */
|
||||||
al::vector<FloatBufferLine, 16> MixBuffer;
|
al::vector<FloatBufferLine, 16> MixBuffer;
|
||||||
|
@ -88,8 +88,6 @@ struct DirectHrtfState {
|
|||||||
alignas(16) HrirArray mCoeffs{};
|
alignas(16) HrirArray mCoeffs{};
|
||||||
};
|
};
|
||||||
|
|
||||||
std::array<float,HRTF_DIRECT_DELAY> mLeftDelay{};
|
|
||||||
std::array<float,HRTF_DIRECT_DELAY> mRightDelay{};
|
|
||||||
std::array<float,HRTF_DIRECT_DELAY+BUFFERSIZE> mTemp;
|
std::array<float,HRTF_DIRECT_DELAY+BUFFERSIZE> mTemp;
|
||||||
|
|
||||||
/* HRTF filter state for dry buffer content */
|
/* HRTF filter state for dry buffer content */
|
||||||
|
@ -85,8 +85,16 @@ inline void MixDirectHrtfBase(FloatBufferLine &LeftOut, FloatBufferLine &RightOu
|
|||||||
{
|
{
|
||||||
ASSUME(BufferSize > 0);
|
ASSUME(BufferSize > 0);
|
||||||
|
|
||||||
const uint_fast32_t IrSize{State->mIrSize};
|
/* Add the existing signal directly to the accumulation buffer, unfiltered,
|
||||||
|
* and with a delay to align with the input delay.
|
||||||
|
*/
|
||||||
|
for(size_t i{0};i < BufferSize;++i)
|
||||||
|
{
|
||||||
|
AccumSamples[HRTF_DIRECT_DELAY+i][0] += LeftOut[i];
|
||||||
|
AccumSamples[HRTF_DIRECT_DELAY+i][1] += RightOut[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint_fast32_t IrSize{State->mIrSize};
|
||||||
auto chan_iter = State->mChannels.begin();
|
auto chan_iter = State->mChannels.begin();
|
||||||
for(const FloatBufferLine &input : InSamples)
|
for(const FloatBufferLine &input : InSamples)
|
||||||
{
|
{
|
||||||
@ -123,47 +131,25 @@ inline void MixDirectHrtfBase(FloatBufferLine &LeftOut, FloatBufferLine &RightOu
|
|||||||
|
|
||||||
/* Now apply the HRIR coefficients to this channel. */
|
/* Now apply the HRIR coefficients to this channel. */
|
||||||
const auto &Coeffs = chan_iter->mCoeffs;
|
const auto &Coeffs = chan_iter->mCoeffs;
|
||||||
++chan_iter;
|
|
||||||
|
|
||||||
for(size_t i{0u};i < BufferSize;++i)
|
for(size_t i{0u};i < BufferSize;++i)
|
||||||
{
|
{
|
||||||
const float insample{tempbuf[i]};
|
const float insample{tempbuf[i]};
|
||||||
ApplyCoeffs(AccumSamples+i, IrSize, Coeffs, insample, insample);
|
ApplyCoeffs(AccumSamples+i, IrSize, Coeffs, insample, insample);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
++chan_iter;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Apply a delay to the existing signal to align with the input delay. */
|
|
||||||
auto &ldelay = State->mLeftDelay;
|
|
||||||
auto &rdelay = State->mRightDelay;
|
|
||||||
if LIKELY(BufferSize >= HRTF_DIRECT_DELAY)
|
|
||||||
{
|
|
||||||
auto buffer_end = LeftOut.begin() + BufferSize;
|
|
||||||
auto delay_end = std::rotate(LeftOut.begin(), buffer_end - HRTF_DIRECT_DELAY, buffer_end);
|
|
||||||
std::swap_ranges(LeftOut.begin(), delay_end, ldelay.begin());
|
|
||||||
|
|
||||||
buffer_end = RightOut.begin() + BufferSize;
|
|
||||||
delay_end = std::rotate(RightOut.begin(), buffer_end - HRTF_DIRECT_DELAY, buffer_end);
|
|
||||||
std::swap_ranges(RightOut.begin(), delay_end, rdelay.begin());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
auto buffer_end = LeftOut.begin() + BufferSize;
|
|
||||||
auto delay_start = std::swap_ranges(LeftOut.begin(), buffer_end, ldelay.begin());
|
|
||||||
std::rotate(ldelay.begin(), delay_start, ldelay.end());
|
|
||||||
|
|
||||||
buffer_end = RightOut.begin() + BufferSize;
|
|
||||||
delay_start = std::swap_ranges(RightOut.begin(), buffer_end, rdelay.begin());
|
|
||||||
std::rotate(rdelay.begin(), delay_start, rdelay.end());
|
|
||||||
}
|
|
||||||
for(size_t i{0u};i < BufferSize;++i)
|
for(size_t i{0u};i < BufferSize;++i)
|
||||||
LeftOut[i] += AccumSamples[i][0];
|
LeftOut[i] = AccumSamples[i][0];
|
||||||
for(size_t i{0u};i < BufferSize;++i)
|
for(size_t i{0u};i < BufferSize;++i)
|
||||||
RightOut[i] += AccumSamples[i][1];
|
RightOut[i] = AccumSamples[i][1];
|
||||||
|
|
||||||
/* Copy the new in-progress accumulation values to the front and clear the
|
/* Copy the new in-progress accumulation values to the front and clear the
|
||||||
* following samples for the next mix.
|
* following samples for the next mix.
|
||||||
*/
|
*/
|
||||||
auto accum_iter = std::copy_n(AccumSamples+BufferSize, HRIR_LENGTH, AccumSamples);
|
auto accum_iter = std::copy_n(AccumSamples+BufferSize, HRIR_LENGTH+HRTF_DIRECT_DELAY,
|
||||||
|
AccumSamples);
|
||||||
std::fill_n(accum_iter, BufferSize, float2{});
|
std::fill_n(accum_iter, BufferSize, float2{});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -468,7 +468,10 @@ void DoHrtfMix(const float *samples, const ALuint DstBufferSize, DirectParams &p
|
|||||||
ALCdevice *Device)
|
ALCdevice *Device)
|
||||||
{
|
{
|
||||||
auto &HrtfSamples = Device->HrtfSourceData;
|
auto &HrtfSamples = Device->HrtfSourceData;
|
||||||
auto &AccumSamples = Device->HrtfAccumData;
|
/* Source HRTF mixing needs to include the direct delay so it remains
|
||||||
|
* aligned with the direct mix's HRTF filtering.
|
||||||
|
*/
|
||||||
|
float2 *AccumSamples{Device->HrtfAccumData + HRTF_DIRECT_DELAY};
|
||||||
|
|
||||||
/* Copy the HRTF history and new input samples into a temp buffer. */
|
/* Copy the HRTF history and new input samples into a temp buffer. */
|
||||||
auto src_iter = std::copy(parms.Hrtf.History.begin(), parms.Hrtf.History.end(),
|
auto src_iter = std::copy(parms.Hrtf.History.begin(), parms.Hrtf.History.end(),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user