From d2608e4bde41b3005a06346bea99bbe06404ef22 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 3 Nov 2019 00:30:33 -0700 Subject: Avoid holding HRTF accumulation samples per-source It notably simplifies things to mix HRTF sources into an accumulation buffer together, which the Dry buffer's Ambisonic-to-HRTF decode is then added to, before being mixed to the Real output. --- alc/alc.cpp | 2 ++ alc/alcmain.h | 2 ++ alc/hrtf.h | 2 -- alc/mixer/defs.h | 10 ++++------ alc/mixer/hrtfbase.h | 27 ++++++++------------------- alc/mixer/mixer_c.cpp | 15 +++++---------- alc/mixer/mixer_neon.cpp | 15 +++++---------- alc/mixer/mixer_sse.cpp | 15 +++++---------- alc/voice.cpp | 39 +++++++++++++-------------------------- 9 files changed, 44 insertions(+), 83 deletions(-) diff --git a/alc/alc.cpp b/alc/alc.cpp index cd2911f5..bee42fc5 100644 --- a/alc/alc.cpp +++ b/alc/alc.cpp @@ -1853,6 +1853,8 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) device->Limiter = nullptr; device->ChannelDelay.clear(); + std::fill(std::begin(device->HrtfAccumData), std::end(device->HrtfAccumData), float2{}); + device->Dry.AmbiMap.fill(BFChannelConfig{}); device->Dry.Buffer = {}; std::fill(std::begin(device->NumChannelsPerOrder), std::end(device->NumChannelsPerOrder), 0u); diff --git a/alc/alcmain.h b/alc/alcmain.h index c26b3a28..30c5b835 100644 --- a/alc/alcmain.h +++ b/alc/alcmain.h @@ -277,6 +277,8 @@ struct ALCdevice : public al::intrusive_ref { alignas(16) ALfloat HrtfSourceData[BUFFERSIZE + HRTF_HISTORY_LENGTH]; alignas(16) ALfloat NfcSampleData[BUFFERSIZE]; }; + + /* Persistent storage for HRTF mixing. */ alignas(16) float2 HrtfAccumData[BUFFERSIZE + HRIR_LENGTH]; /* Mixing buffer used by the Dry mix and Real output. */ diff --git a/alc/hrtf.h b/alc/hrtf.h index d133133a..a81ebfed 100644 --- a/alc/hrtf.h +++ b/alc/hrtf.h @@ -68,7 +68,6 @@ using HrirArray = std::array; struct HrtfState { alignas(16) std::array History; - alignas(16) HrirArray Values; }; struct HrtfFilter { @@ -80,7 +79,6 @@ struct HrtfFilter { struct DirectHrtfState { /* HRTF filter state for dry buffer content */ ALuint IrSize{0}; - alignas(16) HrirArray Values{}; al::FlexArray Coeffs; DirectHrtfState(size_t numchans) : Coeffs{numchans} { } diff --git a/alc/mixer/defs.h b/alc/mixer/defs.h index b2535265..1e5b40d8 100644 --- a/alc/mixer/defs.h +++ b/alc/mixer/defs.h @@ -41,13 +41,11 @@ void MixRow_(const al::span OutBuffer, const al::span Gains, const float *InSamples, const size_t InStride); template -void MixHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, const float *InSamples, - float2 *AccumSamples, const size_t OutPos, const ALuint IrSize, MixHrtfFilter *hrtfparams, - const size_t BufferSize); +void MixHrtf_(const float *InSamples, float2 *AccumSamples, const ALuint IrSize, + MixHrtfFilter *hrtfparams, const size_t BufferSize); template -void MixHrtfBlend_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, const float *InSamples, - float2 *AccumSamples, const size_t OutPos, const ALuint IrSize, const HrtfFilter *oldparams, - MixHrtfFilter *newparams, const size_t BufferSize); +void MixHrtfBlend_(const float *InSamples, float2 *AccumSamples, const ALuint IrSize, + const HrtfFilter *oldparams, MixHrtfFilter *newparams, const size_t BufferSize); template void MixDirectHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, const al::span InSamples, float2 *AccumSamples, DirectHrtfState *State, diff --git a/alc/mixer/hrtfbase.h b/alc/mixer/hrtfbase.h index cbc885c5..4a6eab50 100644 --- a/alc/mixer/hrtfbase.h +++ b/alc/mixer/hrtfbase.h @@ -13,9 +13,8 @@ using ApplyCoeffsT = void(&)(float2 *RESTRICT Values, const ALuint irSize, const const float left, const float right); template -inline void MixHrtfBase(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, - const float *InSamples, float2 *RESTRICT AccumSamples, const size_t OutPos, - const ALuint IrSize, MixHrtfFilter *hrtfparams, const size_t BufferSize) +inline void MixHrtfBase(const float *InSamples, float2 *RESTRICT AccumSamples, const ALuint IrSize, + MixHrtfFilter *hrtfparams, const size_t BufferSize) { ASSUME(BufferSize > 0); @@ -38,17 +37,11 @@ inline void MixHrtfBase(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, stepcount += 1.0f; } - for(size_t i{0u};i < BufferSize;++i) - LeftOut[OutPos+i] += AccumSamples[i][0]; - for(size_t i{0u};i < BufferSize;++i) - RightOut[OutPos+i] += AccumSamples[i][1]; - hrtfparams->Gain = gain + gainstep*stepcount; } template -inline void MixHrtfBlendBase(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, - const float *InSamples, float2 *RESTRICT AccumSamples, const size_t OutPos, +inline void MixHrtfBlendBase(const float *InSamples, float2 *RESTRICT AccumSamples, const ALuint IrSize, const HrtfFilter *oldparams, MixHrtfFilter *newparams, const size_t BufferSize) { @@ -89,11 +82,6 @@ inline void MixHrtfBlendBase(FloatBufferLine &LeftOut, FloatBufferLine &RightOut stepcount += 1.0f; } - for(size_t i{0u};i < BufferSize;++i) - LeftOut[OutPos+i] += AccumSamples[i][0]; - for(size_t i{0u};i < BufferSize;++i) - RightOut[OutPos+i] += AccumSamples[i][1]; - newparams->Gain = newGainStep*stepcount; } @@ -106,9 +94,6 @@ inline void MixDirectHrtfBase(FloatBufferLine &LeftOut, FloatBufferLine &RightOu const ALuint IrSize{State->IrSize}; - auto accum_iter = std::copy_n(State->Values.begin(), State->Values.size(), AccumSamples); - std::fill_n(accum_iter, BufferSize, float2{}); - auto coeff_iter = State->Coeffs.begin(); for(const FloatBufferLine &input : InSamples) { @@ -124,7 +109,11 @@ inline void MixDirectHrtfBase(FloatBufferLine &LeftOut, FloatBufferLine &RightOu for(size_t i{0u};i < BufferSize;++i) RightOut[i] += AccumSamples[i][1]; - std::copy_n(AccumSamples + BufferSize, State->Values.size(), State->Values.begin()); + /* Copy the new in-progress accumulation values to the front and clear the + * following samples for the next mix. + */ + auto accum_iter = std::copy_n(AccumSamples+BufferSize, HRIR_LENGTH, AccumSamples); + std::fill_n(accum_iter, BufferSize, float2{}); } #endif /* MIXER_HRTFBASE_H */ diff --git a/alc/mixer/mixer_c.cpp b/alc/mixer/mixer_c.cpp index 8d375de7..fad33746 100644 --- a/alc/mixer/mixer_c.cpp +++ b/alc/mixer/mixer_c.cpp @@ -136,21 +136,16 @@ const ALfloat *Resample_(const InterpState *state, const ALfl template<> -void MixHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, - const float *InSamples, float2 *AccumSamples, const size_t OutPos, const ALuint IrSize, +void MixHrtf_(const float *InSamples, float2 *AccumSamples, const ALuint IrSize, MixHrtfFilter *hrtfparams, const size_t BufferSize) -{ - MixHrtfBase(LeftOut, RightOut, InSamples, AccumSamples, OutPos, IrSize, - hrtfparams, BufferSize); -} +{ MixHrtfBase(InSamples, AccumSamples, IrSize, hrtfparams, BufferSize); } template<> -void MixHrtfBlend_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, - const float *InSamples, float2 *AccumSamples, const size_t OutPos, const ALuint IrSize, +void MixHrtfBlend_(const float *InSamples, float2 *AccumSamples, const ALuint IrSize, const HrtfFilter *oldparams, MixHrtfFilter *newparams, const size_t BufferSize) { - MixHrtfBlendBase(LeftOut, RightOut, InSamples, AccumSamples, OutPos, IrSize, - oldparams, newparams, BufferSize); + MixHrtfBlendBase(InSamples, AccumSamples, IrSize, oldparams, newparams, + BufferSize); } template<> diff --git a/alc/mixer/mixer_neon.cpp b/alc/mixer/mixer_neon.cpp index ae782897..67bf9c71 100644 --- a/alc/mixer/mixer_neon.cpp +++ b/alc/mixer/mixer_neon.cpp @@ -190,21 +190,16 @@ const ALfloat *Resample_(const InterpState *state, template<> -void MixHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, - const float *InSamples, float2 *AccumSamples, const size_t OutPos, const ALuint IrSize, +void MixHrtf_(const float *InSamples, float2 *AccumSamples, const ALuint IrSize, MixHrtfFilter *hrtfparams, const size_t BufferSize) -{ - MixHrtfBase(LeftOut, RightOut, InSamples, AccumSamples, OutPos, IrSize, - hrtfparams, BufferSize); -} +{ MixHrtfBase(InSamples, AccumSamples, IrSize, hrtfparams, BufferSize); } template<> -void MixHrtfBlend_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, - const float *InSamples, float2 *AccumSamples, const size_t OutPos, const ALuint IrSize, +void MixHrtfBlend_(const float *InSamples, float2 *AccumSamples, const ALuint IrSize, const HrtfFilter *oldparams, MixHrtfFilter *newparams, const size_t BufferSize) { - MixHrtfBlendBase(LeftOut, RightOut, InSamples, AccumSamples, OutPos, IrSize, - oldparams, newparams, BufferSize); + MixHrtfBlendBase(InSamples, AccumSamples, IrSize, oldparams, newparams, + BufferSize); } template<> diff --git a/alc/mixer/mixer_sse.cpp b/alc/mixer/mixer_sse.cpp index 62ce5eab..aaf37df6 100644 --- a/alc/mixer/mixer_sse.cpp +++ b/alc/mixer/mixer_sse.cpp @@ -165,21 +165,16 @@ const ALfloat *Resample_(const InterpState *state, template<> -void MixHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, - const float *InSamples, float2 *AccumSamples, const size_t OutPos, const ALuint IrSize, +void MixHrtf_(const float *InSamples, float2 *AccumSamples, const ALuint IrSize, MixHrtfFilter *hrtfparams, const size_t BufferSize) -{ - MixHrtfBase(LeftOut, RightOut, InSamples, AccumSamples, OutPos, IrSize, - hrtfparams, BufferSize); -} +{ MixHrtfBase(InSamples, AccumSamples, IrSize, hrtfparams, BufferSize); } template<> -void MixHrtfBlend_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, - const float *InSamples, float2 *AccumSamples, const size_t OutPos, const ALuint IrSize, +void MixHrtfBlend_(const float *InSamples, float2 *AccumSamples, const ALuint IrSize, const HrtfFilter *oldparams, MixHrtfFilter *newparams, const size_t BufferSize) { - MixHrtfBlendBase(LeftOut, RightOut, InSamples, AccumSamples, OutPos, IrSize, - oldparams, newparams, BufferSize); + MixHrtfBlendBase(InSamples, AccumSamples, IrSize, oldparams, newparams, + BufferSize); } template<> diff --git a/alc/voice.cpp b/alc/voice.cpp index 0aac0258..1c38f36f 100644 --- a/alc/voice.cpp +++ b/alc/voice.cpp @@ -72,12 +72,11 @@ Resampler ResamplerDefault{Resampler::Linear}; namespace { -using HrtfMixerFunc = void(*)(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, - const ALfloat *InSamples, float2 *AccumSamples, const size_t OutPos, const ALuint IrSize, +using HrtfMixerFunc = void(*)(const ALfloat *InSamples, float2 *AccumSamples, const ALuint IrSize, MixHrtfFilter *hrtfparams, const size_t BufferSize); -using HrtfMixerBlendFunc = void(*)(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, - const ALfloat *InSamples, float2 *AccumSamples, const size_t OutPos, const ALuint IrSize, - const HrtfFilter *oldparams, MixHrtfFilter *newparams, const size_t BufferSize); +using HrtfMixerBlendFunc = void(*)(const ALfloat *InSamples, float2 *AccumSamples, + const ALuint IrSize, const HrtfFilter *oldparams, MixHrtfFilter *newparams, + const size_t BufferSize); HrtfMixerFunc MixHrtfSamples = MixHrtf_; HrtfMixerBlendFunc MixHrtfBlendSamples = MixHrtfBlend_; @@ -423,12 +422,10 @@ ALfloat *LoadBufferQueue(ALbufferlistitem *BufferListItem, ALbufferlistitem *Buf } -void DoHrtfMix(ALvoice::TargetData &Direct, const float TargetGain, DirectParams &parms, - const float *samples, const ALuint DstBufferSize, const ALuint Counter, const ALuint OutPos, - const ALuint IrSize, ALCdevice *Device) +void DoHrtfMix(const float TargetGain, DirectParams &parms, const float *samples, + const ALuint DstBufferSize, const ALuint Counter, ALuint OutPos, const ALuint IrSize, + ALCdevice *Device) { - const ALuint OutLIdx{GetChannelIdxByName(Device->RealOut, FrontLeft)}; - const ALuint OutRIdx{GetChannelIdxByName(Device->RealOut, FrontRight)}; auto &HrtfSamples = Device->HrtfSourceData; auto &AccumSamples = Device->HrtfAccumData; @@ -440,12 +437,6 @@ void DoHrtfMix(ALvoice::TargetData &Direct, const float TargetGain, DirectParams std::copy_n(std::begin(HrtfSamples) + DstBufferSize, parms.Hrtf.State.History.size(), parms.Hrtf.State.History.begin()); - /* Copy the current filtered values being accumulated into the temp buffer. */ - auto accum_iter = std::copy_n(parms.Hrtf.State.Values.begin(), parms.Hrtf.State.Values.size(), - std::begin(AccumSamples)); - /* Clear the accumulation buffer that will start getting filled in. */ - std::fill_n(accum_iter, DstBufferSize, float2{}); - /* If fading, the old gain is not silence, and this is the first mixing * pass, fade between the IRs. */ @@ -473,14 +464,15 @@ void DoHrtfMix(ALvoice::TargetData &Direct, const float TargetGain, DirectParams hrtfparams.Gain = 0.0f; hrtfparams.GainStep = gain / static_cast(fademix); - MixHrtfBlendSamples(Direct.Buffer[OutLIdx], Direct.Buffer[OutRIdx], HrtfSamples, - AccumSamples, OutPos, IrSize, &parms.Hrtf.Old, &hrtfparams, fademix); + MixHrtfBlendSamples(HrtfSamples, AccumSamples+OutPos, IrSize, &parms.Hrtf.Old, &hrtfparams, + fademix); /* Update the old parameters with the result. */ parms.Hrtf.Old = parms.Hrtf.Target; if(fademix < Counter) parms.Hrtf.Old.Gain = hrtfparams.Gain; else parms.Hrtf.Old.Gain = TargetGain; + OutPos += fademix; } if LIKELY(fademix < DstBufferSize) @@ -503,8 +495,7 @@ void DoHrtfMix(ALvoice::TargetData &Direct, const float TargetGain, DirectParams hrtfparams.Delay[1] = parms.Hrtf.Target.Delay[1]; hrtfparams.Gain = parms.Hrtf.Old.Gain; hrtfparams.GainStep = (gain - parms.Hrtf.Old.Gain) / static_cast(todo); - MixHrtfSamples(Direct.Buffer[OutLIdx], Direct.Buffer[OutRIdx], HrtfSamples+fademix, - AccumSamples+fademix, OutPos+fademix, IrSize, &hrtfparams, todo); + MixHrtfSamples(HrtfSamples+fademix, AccumSamples+OutPos, IrSize, &hrtfparams, todo); /* Store the interpolated gain or the final target gain depending if * the fade is done. */ @@ -513,10 +504,6 @@ void DoHrtfMix(ALvoice::TargetData &Direct, const float TargetGain, DirectParams else parms.Hrtf.Old.Gain = TargetGain; } - - /* Copy the new in-progress accumulation values back for the next mix. */ - std::copy_n(std::begin(AccumSamples) + DstBufferSize, parms.Hrtf.State.Values.size(), - parms.Hrtf.State.Values.begin()); } void DoNfcMix(ALvoice::TargetData &Direct, const float *TargetGains, DirectParams &parms, @@ -713,8 +700,8 @@ void ALvoice::mix(const State vstate, ALCcontext *Context, const ALuint SamplesT { const ALfloat TargetGain{UNLIKELY(vstate == ALvoice::Stopping) ? 0.0f : parms.Hrtf.Target.Gain}; - DoHrtfMix(mDirect, TargetGain, parms, samples, DstBufferSize, Counter, OutPos, - IrSize, Device); + DoHrtfMix(TargetGain, parms, samples, DstBufferSize, Counter, OutPos, IrSize, + Device); } else if((mFlags&VOICE_HAS_NFC)) { -- cgit v1.2.3