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.
This commit is contained in:
parent
2741a94e58
commit
d2608e4bde
@ -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);
|
||||
|
@ -277,6 +277,8 @@ struct ALCdevice : public al::intrusive_ref<ALCdevice> {
|
||||
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. */
|
||||
|
@ -68,7 +68,6 @@ using HrirArray = std::array<float2,HRIR_LENGTH>;
|
||||
|
||||
struct HrtfState {
|
||||
alignas(16) std::array<ALfloat,HRTF_HISTORY_LENGTH> 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<HrirArray,16> Coeffs;
|
||||
|
||||
DirectHrtfState(size_t numchans) : Coeffs{numchans} { }
|
||||
|
@ -41,13 +41,11 @@ void MixRow_(const al::span<float> OutBuffer, const al::span<const float> Gains,
|
||||
const float *InSamples, const size_t InStride);
|
||||
|
||||
template<InstSetType InstTag>
|
||||
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<InstSetType InstTag>
|
||||
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<InstSetType InstTag>
|
||||
void MixDirectHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut,
|
||||
const al::span<const FloatBufferLine> InSamples, float2 *AccumSamples, DirectHrtfState *State,
|
||||
|
@ -13,9 +13,8 @@ using ApplyCoeffsT = void(&)(float2 *RESTRICT Values, const ALuint irSize, const
|
||||
const float left, const float right);
|
||||
|
||||
template<ApplyCoeffsT ApplyCoeffs>
|
||||
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<ApplyCoeffsT ApplyCoeffs>
|
||||
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 */
|
||||
|
@ -136,21 +136,16 @@ const ALfloat *Resample_<FastBSincTag,CTag>(const InterpState *state, const ALfl
|
||||
|
||||
|
||||
template<>
|
||||
void MixHrtf_<CTag>(FloatBufferLine &LeftOut, FloatBufferLine &RightOut,
|
||||
const float *InSamples, float2 *AccumSamples, const size_t OutPos, const ALuint IrSize,
|
||||
void MixHrtf_<CTag>(const float *InSamples, float2 *AccumSamples, const ALuint IrSize,
|
||||
MixHrtfFilter *hrtfparams, const size_t BufferSize)
|
||||
{
|
||||
MixHrtfBase<ApplyCoeffs>(LeftOut, RightOut, InSamples, AccumSamples, OutPos, IrSize,
|
||||
hrtfparams, BufferSize);
|
||||
}
|
||||
{ MixHrtfBase<ApplyCoeffs>(InSamples, AccumSamples, IrSize, hrtfparams, BufferSize); }
|
||||
|
||||
template<>
|
||||
void MixHrtfBlend_<CTag>(FloatBufferLine &LeftOut, FloatBufferLine &RightOut,
|
||||
const float *InSamples, float2 *AccumSamples, const size_t OutPos, const ALuint IrSize,
|
||||
void MixHrtfBlend_<CTag>(const float *InSamples, float2 *AccumSamples, const ALuint IrSize,
|
||||
const HrtfFilter *oldparams, MixHrtfFilter *newparams, const size_t BufferSize)
|
||||
{
|
||||
MixHrtfBlendBase<ApplyCoeffs>(LeftOut, RightOut, InSamples, AccumSamples, OutPos, IrSize,
|
||||
oldparams, newparams, BufferSize);
|
||||
MixHrtfBlendBase<ApplyCoeffs>(InSamples, AccumSamples, IrSize, oldparams, newparams,
|
||||
BufferSize);
|
||||
}
|
||||
|
||||
template<>
|
||||
|
@ -190,21 +190,16 @@ const ALfloat *Resample_<FastBSincTag,NEONTag>(const InterpState *state,
|
||||
|
||||
|
||||
template<>
|
||||
void MixHrtf_<NEONTag>(FloatBufferLine &LeftOut, FloatBufferLine &RightOut,
|
||||
const float *InSamples, float2 *AccumSamples, const size_t OutPos, const ALuint IrSize,
|
||||
void MixHrtf_<NEONTag>(const float *InSamples, float2 *AccumSamples, const ALuint IrSize,
|
||||
MixHrtfFilter *hrtfparams, const size_t BufferSize)
|
||||
{
|
||||
MixHrtfBase<ApplyCoeffs>(LeftOut, RightOut, InSamples, AccumSamples, OutPos, IrSize,
|
||||
hrtfparams, BufferSize);
|
||||
}
|
||||
{ MixHrtfBase<ApplyCoeffs>(InSamples, AccumSamples, IrSize, hrtfparams, BufferSize); }
|
||||
|
||||
template<>
|
||||
void MixHrtfBlend_<NEONTag>(FloatBufferLine &LeftOut, FloatBufferLine &RightOut,
|
||||
const float *InSamples, float2 *AccumSamples, const size_t OutPos, const ALuint IrSize,
|
||||
void MixHrtfBlend_<NEONTag>(const float *InSamples, float2 *AccumSamples, const ALuint IrSize,
|
||||
const HrtfFilter *oldparams, MixHrtfFilter *newparams, const size_t BufferSize)
|
||||
{
|
||||
MixHrtfBlendBase<ApplyCoeffs>(LeftOut, RightOut, InSamples, AccumSamples, OutPos, IrSize,
|
||||
oldparams, newparams, BufferSize);
|
||||
MixHrtfBlendBase<ApplyCoeffs>(InSamples, AccumSamples, IrSize, oldparams, newparams,
|
||||
BufferSize);
|
||||
}
|
||||
|
||||
template<>
|
||||
|
@ -165,21 +165,16 @@ const ALfloat *Resample_<FastBSincTag,SSETag>(const InterpState *state,
|
||||
|
||||
|
||||
template<>
|
||||
void MixHrtf_<SSETag>(FloatBufferLine &LeftOut, FloatBufferLine &RightOut,
|
||||
const float *InSamples, float2 *AccumSamples, const size_t OutPos, const ALuint IrSize,
|
||||
void MixHrtf_<SSETag>(const float *InSamples, float2 *AccumSamples, const ALuint IrSize,
|
||||
MixHrtfFilter *hrtfparams, const size_t BufferSize)
|
||||
{
|
||||
MixHrtfBase<ApplyCoeffs>(LeftOut, RightOut, InSamples, AccumSamples, OutPos, IrSize,
|
||||
hrtfparams, BufferSize);
|
||||
}
|
||||
{ MixHrtfBase<ApplyCoeffs>(InSamples, AccumSamples, IrSize, hrtfparams, BufferSize); }
|
||||
|
||||
template<>
|
||||
void MixHrtfBlend_<SSETag>(FloatBufferLine &LeftOut, FloatBufferLine &RightOut,
|
||||
const float *InSamples, float2 *AccumSamples, const size_t OutPos, const ALuint IrSize,
|
||||
void MixHrtfBlend_<SSETag>(const float *InSamples, float2 *AccumSamples, const ALuint IrSize,
|
||||
const HrtfFilter *oldparams, MixHrtfFilter *newparams, const size_t BufferSize)
|
||||
{
|
||||
MixHrtfBlendBase<ApplyCoeffs>(LeftOut, RightOut, InSamples, AccumSamples, OutPos, IrSize,
|
||||
oldparams, newparams, BufferSize);
|
||||
MixHrtfBlendBase<ApplyCoeffs>(InSamples, AccumSamples, IrSize, oldparams, newparams,
|
||||
BufferSize);
|
||||
}
|
||||
|
||||
template<>
|
||||
|
@ -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_<CTag>;
|
||||
HrtfMixerBlendFunc MixHrtfBlendSamples = MixHrtfBlend_<CTag>;
|
||||
@ -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<float>(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<float>(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))
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user