Limit convolution processing to the output ambisonic order
[openal-soft.git] / alc / mixer / hrtfbase.h
blob4ec6c95d5fa1ca397ad0b050a452aff25ef08893
1 #ifndef MIXER_HRTFBASE_H
2 #define MIXER_HRTFBASE_H
4 #include <algorithm>
6 #include "alu.h"
7 #include "../hrtf.h"
8 #include "opthelpers.h"
9 #include "voice.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);
35 stepcount += 1.0f;
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);
63 stepcount -= 1.0f;
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);
79 stepcount += 1.0f;
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);
144 ++chan_iter;
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,
156 AccumSamples);
157 std::fill_n(accum_iter, BufferSize, float2{});
160 #endif /* MIXER_HRTFBASE_H */