Skip to content

Commit

Permalink
Pass spans to the HRTF mixer functions instead of pointers
Browse files Browse the repository at this point in the history
  • Loading branch information
kcat committed Mar 30, 2024
1 parent 361ed79 commit 739670e
Show file tree
Hide file tree
Showing 7 changed files with 136 additions and 122 deletions.
10 changes: 5 additions & 5 deletions alc/alu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -135,9 +135,9 @@ float NfcScale{1.0f};


using HrtfDirectMixerFunc = void(*)(const FloatBufferSpan LeftOut, const FloatBufferSpan RightOut,
const al::span<const FloatBufferLine> InSamples, float2 *AccumSamples,
const al::span<float,BufferLineSize> TempBuf, HrtfChannelState *ChanState, const size_t IrSize,
const size_t BufferSize);
const al::span<const FloatBufferLine> InSamples, const al::span<float2> AccumSamples,
const al::span<float,BufferLineSize> TempBuf, const al::span<HrtfChannelState> ChanState,
const size_t IrSize, const size_t SamplesToDo);

HrtfDirectMixerFunc MixDirectHrtf{MixDirectHrtf_<CTag>};

Expand Down Expand Up @@ -290,8 +290,8 @@ void DeviceBase::ProcessHrtf(const size_t SamplesToDo)
const size_t lidx{RealOut.ChannelIndex[FrontLeft]};
const size_t ridx{RealOut.ChannelIndex[FrontRight]};

MixDirectHrtf(RealOut.Buffer[lidx], RealOut.Buffer[ridx], Dry.Buffer, HrtfAccumData.data(),
mHrtfState->mTemp, mHrtfState->mChannels.data(), mHrtfState->mIrSize, SamplesToDo);
MixDirectHrtf(RealOut.Buffer[lidx], RealOut.Buffer[ridx], Dry.Buffer, HrtfAccumData,
mHrtfState->mTemp, mHrtfState->mChannels, mHrtfState->mIrSize, SamplesToDo);
}

void DeviceBase::ProcessAmbiDec(const size_t SamplesToDo)
Expand Down
15 changes: 8 additions & 7 deletions core/mixer/defs.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,16 +83,17 @@ void Mix_(const al::span<const float> InSamples, const al::span<float> OutBuffer
float &CurrentGain, const float TargetGain, const size_t Counter);

template<typename InstTag>
void MixHrtf_(const float *InSamples, float2 *AccumSamples, const uint IrSize,
const MixHrtfFilter *hrtfparams, const size_t BufferSize);
void MixHrtf_(const al::span<const float> InSamples, const al::span<float2> AccumSamples,
const uint IrSize, const MixHrtfFilter *hrtfparams, const size_t SamplesToDo);
template<typename InstTag>
void MixHrtfBlend_(const float *InSamples, float2 *AccumSamples, const uint IrSize,
const HrtfFilter *oldparams, const MixHrtfFilter *newparams, const size_t BufferSize);
void MixHrtfBlend_(const al::span<const float> InSamples, const al::span<float2> AccumSamples,
const uint IrSize, const HrtfFilter *oldparams, const MixHrtfFilter *newparams,
const size_t SamplesToDo);
template<typename InstTag>
void MixDirectHrtf_(const FloatBufferSpan LeftOut, const FloatBufferSpan RightOut,
const al::span<const FloatBufferLine> InSamples, float2 *AccumSamples,
const al::span<float,BufferLineSize> TempBuf, HrtfChannelState *ChanState, const size_t IrSize,
const size_t BufferSize);
const al::span<const FloatBufferLine> InSamples, const al::span<float2> AccumSamples,
const al::span<float,BufferLineSize> TempBuf, const al::span<HrtfChannelState> ChanState,
const size_t IrSize, const size_t SamplesToDo);

/* Vectorized resampler helpers */
template<size_t N>
Expand Down
74 changes: 41 additions & 33 deletions core/mixer/hrtfbase.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,16 @@

using uint = unsigned int;

using ApplyCoeffsT = void(&)(float2 *Values, const size_t irSize, const ConstHrirSpan Coeffs,
const float left, const float right);
using ApplyCoeffsT = void(&)(const al::span<float2> Values, const size_t irSize,
const ConstHrirSpan Coeffs, const float left, const float right);

template<ApplyCoeffsT ApplyCoeffs>
inline void MixHrtfBase(const float *InSamples, float2 *AccumSamples, const size_t IrSize,
const MixHrtfFilter *hrtfparams, const size_t BufferSize)
inline void MixHrtfBase(const al::span<const float> InSamples, const al::span<float2> AccumSamples,
const size_t IrSize, const MixHrtfFilter *hrtfparams, const size_t SamplesToDo)
{
ASSUME(BufferSize > 0);
ASSUME(SamplesToDo > 0);
ASSUME(SamplesToDo <= BufferLineSize);
ASSUME(IrSize <= HrirLength);

const ConstHrirSpan Coeffs{hrtfparams->Coeffs};
const float gainstep{hrtfparams->GainStep};
Expand All @@ -27,55 +29,58 @@ inline void MixHrtfBase(const float *InSamples, float2 *AccumSamples, const size
size_t ldelay{HrtfHistoryLength - hrtfparams->Delay[0]};
size_t rdelay{HrtfHistoryLength - hrtfparams->Delay[1]};
float stepcount{0.0f};
for(size_t i{0u};i < BufferSize;++i)
for(size_t i{0u};i < SamplesToDo;++i)
{
const float g{gain + gainstep*stepcount};
const float left{InSamples[ldelay++] * g};
const float right{InSamples[rdelay++] * g};
ApplyCoeffs(AccumSamples+i, IrSize, Coeffs, left, right);
ApplyCoeffs(AccumSamples.subspan(i), IrSize, Coeffs, left, right);

stepcount += 1.0f;
}
}

template<ApplyCoeffsT ApplyCoeffs>
inline void MixHrtfBlendBase(const float *InSamples, float2 *AccumSamples, const size_t IrSize,
const HrtfFilter *oldparams, const MixHrtfFilter *newparams, const size_t BufferSize)
inline void MixHrtfBlendBase(const al::span<const float> InSamples,
const al::span<float2> AccumSamples, const size_t IrSize, const HrtfFilter *oldparams,
const MixHrtfFilter *newparams, const size_t SamplesToDo)
{
ASSUME(BufferSize > 0);
ASSUME(SamplesToDo > 0);
ASSUME(SamplesToDo <= BufferLineSize);
ASSUME(IrSize <= HrirLength);

const ConstHrirSpan OldCoeffs{oldparams->Coeffs};
const float oldGainStep{oldparams->Gain / static_cast<float>(BufferSize)};
const float oldGainStep{oldparams->Gain / static_cast<float>(SamplesToDo)};
const ConstHrirSpan NewCoeffs{newparams->Coeffs};
const float newGainStep{newparams->GainStep};

if(oldparams->Gain > GainSilenceThreshold) LIKELY
{
size_t ldelay{HrtfHistoryLength - oldparams->Delay[0]};
size_t rdelay{HrtfHistoryLength - oldparams->Delay[1]};
auto stepcount = static_cast<float>(BufferSize);
for(size_t i{0u};i < BufferSize;++i)
auto stepcount = static_cast<float>(SamplesToDo);
for(size_t i{0u};i < SamplesToDo;++i)
{
const float g{oldGainStep*stepcount};
const float left{InSamples[ldelay++] * g};
const float right{InSamples[rdelay++] * g};
ApplyCoeffs(AccumSamples+i, IrSize, OldCoeffs, left, right);
ApplyCoeffs(AccumSamples.subspan(i), IrSize, OldCoeffs, left, right);

stepcount -= 1.0f;
}
}

if(newGainStep*static_cast<float>(BufferSize) > GainSilenceThreshold) LIKELY
if(newGainStep*static_cast<float>(SamplesToDo) > GainSilenceThreshold) LIKELY
{
size_t ldelay{HrtfHistoryLength+1 - newparams->Delay[0]};
size_t rdelay{HrtfHistoryLength+1 - newparams->Delay[1]};
float stepcount{1.0f};
for(size_t i{1u};i < BufferSize;++i)
for(size_t i{1u};i < SamplesToDo;++i)
{
const float g{newGainStep*stepcount};
const float left{InSamples[ldelay++] * g};
const float right{InSamples[rdelay++] * g};
ApplyCoeffs(AccumSamples+i, IrSize, NewCoeffs, left, right);
ApplyCoeffs(AccumSamples.subspan(i), IrSize, NewCoeffs, left, right);

stepcount += 1.0f;
}
Expand All @@ -84,49 +89,52 @@ inline void MixHrtfBlendBase(const float *InSamples, float2 *AccumSamples, const

template<ApplyCoeffsT ApplyCoeffs>
inline void MixDirectHrtfBase(const FloatBufferSpan LeftOut, const FloatBufferSpan RightOut,
const al::span<const FloatBufferLine> InSamples, float2 *AccumSamples,
const al::span<float,BufferLineSize> TempBuf, HrtfChannelState *ChanState, const size_t IrSize,
const size_t BufferSize)
const al::span<const FloatBufferLine> InSamples, const al::span<float2> AccumSamples,
const al::span<float,BufferLineSize> TempBuf, const al::span<HrtfChannelState> ChannelState,
const size_t IrSize, const size_t SamplesToDo)
{
ASSUME(BufferSize > 0);
ASSUME(SamplesToDo > 0);
ASSUME(SamplesToDo <= BufferLineSize);
ASSUME(IrSize <= HrirLength);
assert(ChannelState.size() == InSamples.size());

auto ChanState = ChannelState.begin();
for(const FloatBufferLine &input : InSamples)
{
/* For dual-band processing, the signal needs extra scaling applied to
* the high frequency response. The band-splitter applies this scaling
* with a consistent phase shift regardless of the scale amount.
*/
ChanState->mSplitter.processHfScale({input.data(), BufferSize}, TempBuf,
ChanState->mSplitter.processHfScale(al::span{input}.first(SamplesToDo), TempBuf,
ChanState->mHfScale);

/* Now apply the HRIR coefficients to this channel. */
const float *RESTRICT tempbuf{al::assume_aligned<16>(TempBuf.data())};
const ConstHrirSpan Coeffs{ChanState->mCoeffs};
for(size_t i{0u};i < BufferSize;++i)
for(size_t i{0u};i < SamplesToDo;++i)
{
const float insample{tempbuf[i]};
ApplyCoeffs(AccumSamples+i, IrSize, Coeffs, insample, insample);
const float insample{TempBuf[i]};
ApplyCoeffs(AccumSamples.subspan(i), IrSize, Coeffs, insample, insample);
}

++ChanState;
}

/* Add the HRTF signal to the existing "direct" signal. */
const auto left = al::assume_aligned<16>(LeftOut.data());
std::transform(left, left+BufferSize, AccumSamples, left,
const auto left = al::span{al::assume_aligned<16>(LeftOut.data()), SamplesToDo};
std::transform(left.cbegin(), left.cend(), AccumSamples.cbegin(), left.begin(),
[](const float sample, const float2 &accum) noexcept -> float
{ return sample + accum[0]; });
const auto right = al::assume_aligned<16>(RightOut.data());
std::transform(right, right+BufferSize, AccumSamples, right,
const auto right = al::span{al::assume_aligned<16>(RightOut.data()), SamplesToDo};
std::transform(right.cbegin(), right.cend(), AccumSamples.cbegin(), right.begin(),
[](const float sample, const float2 &accum) noexcept -> float
{ return sample + accum[1]; });

/* Copy the new in-progress accumulation values to the front and clear the
* following samples for the next mix.
*/
const auto accum_inprog = AccumSamples + BufferSize;
auto accum_iter = std::copy(accum_inprog, accum_inprog+HrirLength, AccumSamples);
std::fill_n(accum_iter, BufferSize, float2{});
const auto accum_inprog = AccumSamples.subspan(SamplesToDo, HrirLength);
auto accum_iter = std::copy(accum_inprog.cbegin(), accum_inprog.cend(), AccumSamples.begin());
std::fill_n(accum_iter, SamplesToDo, float2{});
}

#endif /* CORE_MIXER_HRTFBASE_H */
34 changes: 19 additions & 15 deletions core/mixer/mixer_c.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -123,13 +123,16 @@ void DoResample(const U istate, const float *src, uint frac, const uint incremen
});
}

inline void ApplyCoeffs(float2 *Values, const size_t IrSize, const ConstHrirSpan Coeffs,
const float left, const float right) noexcept
inline void ApplyCoeffs(const al::span<float2> Values, const size_t IrSize,
const ConstHrirSpan Coeffs, const float left, const float right) noexcept
{
ASSUME(IrSize >= MinIrLength);
std::transform(Values, Values+IrSize, Coeffs.cbegin(), Values,
[left,right](const float2 &value, const float2 &coeff) noexcept -> float2
{ return float2{{value[0] + coeff[0]*left, value[1] + coeff[1]*right}}; });
ASSUME(IrSize <= HrirLength);

auto mix_impulse = [left,right](const float2 &value, const float2 &coeff) noexcept -> float2
{ return float2{{value[0] + coeff[0]*left, value[1] + coeff[1]*right}}; };
std::transform(Values.cbegin(), Values.cbegin()+ptrdiff_t(IrSize), Coeffs.cbegin(),
Values.begin(), mix_impulse);
}

force_inline void MixLine(const al::span<const float> InSamples, const al::span<float> dst,
Expand Down Expand Up @@ -204,26 +207,27 @@ void Resample_<FastBSincTag,CTag>(const InterpState *state, const float *src, ui


template<>
void MixHrtf_<CTag>(const float *InSamples, float2 *AccumSamples, const uint IrSize,
const MixHrtfFilter *hrtfparams, const size_t BufferSize)
{ MixHrtfBase<ApplyCoeffs>(InSamples, AccumSamples, IrSize, hrtfparams, BufferSize); }
void MixHrtf_<CTag>(const al::span<const float> InSamples, const al::span<float2> AccumSamples,
const uint IrSize, const MixHrtfFilter *hrtfparams, const size_t SamplesToDo)
{ MixHrtfBase<ApplyCoeffs>(InSamples, AccumSamples, IrSize, hrtfparams, SamplesToDo); }

template<>
void MixHrtfBlend_<CTag>(const float *InSamples, float2 *AccumSamples, const uint IrSize,
const HrtfFilter *oldparams, const MixHrtfFilter *newparams, const size_t BufferSize)
void MixHrtfBlend_<CTag>(const al::span<const float> InSamples,const al::span<float2> AccumSamples,
const uint IrSize, const HrtfFilter *oldparams, const MixHrtfFilter *newparams,
const size_t SamplesToDo)
{
MixHrtfBlendBase<ApplyCoeffs>(InSamples, AccumSamples, IrSize, oldparams, newparams,
BufferSize);
SamplesToDo);
}

template<>
void MixDirectHrtf_<CTag>(const FloatBufferSpan LeftOut, const FloatBufferSpan RightOut,
const al::span<const FloatBufferLine> InSamples, float2 *AccumSamples,
const al::span<float,BufferLineSize> TempBuf, HrtfChannelState *ChanState, const size_t IrSize,
const size_t BufferSize)
const al::span<const FloatBufferLine> InSamples, const al::span<float2> AccumSamples,
const al::span<float,BufferLineSize> TempBuf, const al::span<HrtfChannelState> ChanState,
const size_t IrSize, const size_t SamplesToDo)
{
MixDirectHrtfBase<ApplyCoeffs>(LeftOut, RightOut, InSamples, AccumSamples, TempBuf, ChanState,
IrSize, BufferSize);
IrSize, SamplesToDo);
}


Expand Down
47 changes: 23 additions & 24 deletions core/mixer/mixer_neon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,26 +63,24 @@ inline float32x4_t set_f4(float l0, float l1, float l2, float l3)
return ret;
}

inline void ApplyCoeffs(float2 *Values, const size_t IrSize, const ConstHrirSpan Coeffs,
const float left, const float right)
inline void ApplyCoeffs(const al::span<float2> Values, const size_t IrSize,
const ConstHrirSpan Coeffs, const float left, const float right)
{
auto dup_samples = [left,right]
ASSUME(IrSize >= MinIrLength);
ASSUME(IrSize <= HrirLength);

auto dup_samples = [left,right]() -> float32x4_t
{
float32x2_t leftright2{vset_lane_f32(right, vmov_n_f32(left), 1)};
return vcombine_f32(leftright2, leftright2);
};
const float32x4_t leftright4{dup_samples()};
const auto leftright4 = dup_samples();

ASSUME(IrSize >= MinIrLength);
for(size_t c{0};c < IrSize;c += 2)
{
float32x4_t vals = vld1q_f32(&Values[c][0]);
float32x4_t coefs = vld1q_f32(&Coeffs[c][0]);

vals = vmlaq_f32(vals, coefs, leftright4);

vst1q_f32(&Values[c][0], vals);
}
const auto vals4 = al::span{reinterpret_cast<float32x4_t*>(Values[0].data()), IrSize/2};
const auto coeffs4=al::span{reinterpret_cast<const float32x4_t*>(Coeffs[0].data()), IrSize/2};
std::transform(vals4.cbegin(), vals4.cend(), coeffs4.cbegin(), vals4.begin(),
[leftright4](const float32x4_t &val, const float32x4_t &coeff) -> float32x4_t
{ return vmlaq_f32(val, coeff, leftright4); });
}

force_inline void MixLine(const al::span<const float> InSamples, const al::span<float> dst,
Expand Down Expand Up @@ -395,26 +393,27 @@ void Resample_<FastBSincTag,NEONTag>(const InterpState *state, const float *src,


template<>
void MixHrtf_<NEONTag>(const float *InSamples, float2 *AccumSamples, const uint IrSize,
const MixHrtfFilter *hrtfparams, const size_t BufferSize)
{ MixHrtfBase<ApplyCoeffs>(InSamples, AccumSamples, IrSize, hrtfparams, BufferSize); }
void MixHrtf_<NEONTag>(const al::span<const float> InSamples, const al::span<float2> AccumSamples,
const uint IrSize, const MixHrtfFilter *hrtfparams, const size_t SamplesToDo)
{ MixHrtfBase<ApplyCoeffs>(InSamples, AccumSamples, IrSize, hrtfparams, SamplesToDo); }

template<>
void MixHrtfBlend_<NEONTag>(const float *InSamples, float2 *AccumSamples, const uint IrSize,
const HrtfFilter *oldparams, const MixHrtfFilter *newparams, const size_t BufferSize)
void MixHrtfBlend_<NEONTag>(const al::span<const float> InSamples,
const al::span<float2> AccumSamples, const uint IrSize, const HrtfFilter *oldparams,
const MixHrtfFilter *newparams, const size_t SamplesToDo)
{
MixHrtfBlendBase<ApplyCoeffs>(InSamples, AccumSamples, IrSize, oldparams, newparams,
BufferSize);
SamplesToDo);
}

template<>
void MixDirectHrtf_<NEONTag>(const FloatBufferSpan LeftOut, const FloatBufferSpan RightOut,
const al::span<const FloatBufferLine> InSamples, float2 *AccumSamples,
const al::span<float,BufferLineSize> TempBuf, HrtfChannelState *ChanState, const size_t IrSize,
const size_t BufferSize)
const al::span<const FloatBufferLine> InSamples, const al::span<float2> AccumSamples,
const al::span<float,BufferLineSize> TempBuf, const al::span<HrtfChannelState> ChanState,
const size_t IrSize, const size_t SamplesToDo)
{
MixDirectHrtfBase<ApplyCoeffs>(LeftOut, RightOut, InSamples, AccumSamples, TempBuf, ChanState,
IrSize, BufferSize);
IrSize, SamplesToDo);
}


Expand Down

0 comments on commit 739670e

Please sign in to comment.