aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--common/phase_shifter.h100
-rw-r--r--core/uhjfilter.cpp172
-rw-r--r--core/uhjfilter.h33
-rw-r--r--utils/uhjencoder.cpp63
4 files changed, 143 insertions, 225 deletions
diff --git a/common/phase_shifter.h b/common/phase_shifter.h
index ace92c9a..83e07c7a 100644
--- a/common/phase_shifter.h
+++ b/common/phase_shifter.h
@@ -69,7 +69,6 @@ struct PhaseShifterT {
}
void process(al::span<float> dst, const float *RESTRICT src) const;
- void processAccum(al::span<float> dst, const float *RESTRICT src) const;
private:
#if defined(HAVE_NEON)
@@ -212,103 +211,4 @@ inline void PhaseShifterT<S>::process(al::span<float> dst, const float *RESTRICT
#endif
}
-template<size_t S>
-inline void PhaseShifterT<S>::processAccum(al::span<float> dst, const float *RESTRICT src) const
-{
-#ifdef HAVE_SSE_INTRINSICS
- if(size_t todo{dst.size()>>1})
- {
- auto *out = reinterpret_cast<__m64*>(dst.data());
- do {
- __m128 r04{_mm_setzero_ps()};
- __m128 r14{_mm_setzero_ps()};
- for(size_t j{0};j < mCoeffs.size();j+=4)
- {
- const __m128 coeffs{_mm_load_ps(&mCoeffs[j])};
- const __m128 s0{_mm_loadu_ps(&src[j*2])};
- const __m128 s1{_mm_loadu_ps(&src[j*2 + 4])};
-
- __m128 s{_mm_shuffle_ps(s0, s1, _MM_SHUFFLE(2, 0, 2, 0))};
- r04 = _mm_add_ps(r04, _mm_mul_ps(s, coeffs));
-
- s = _mm_shuffle_ps(s0, s1, _MM_SHUFFLE(3, 1, 3, 1));
- r14 = _mm_add_ps(r14, _mm_mul_ps(s, coeffs));
- }
- src += 2;
-
- __m128 r4{_mm_add_ps(_mm_unpackhi_ps(r04, r14), _mm_unpacklo_ps(r04, r14))};
- r4 = _mm_add_ps(r4, _mm_movehl_ps(r4, r4));
-
- _mm_storel_pi(out, _mm_add_ps(_mm_loadl_pi(_mm_undefined_ps(), out), r4));
- ++out;
- } while(--todo);
- }
- if((dst.size()&1))
- {
- __m128 r4{_mm_setzero_ps()};
- for(size_t j{0};j < mCoeffs.size();j+=4)
- {
- const __m128 coeffs{_mm_load_ps(&mCoeffs[j])};
- const __m128 s{_mm_setr_ps(src[j*2], src[j*2 + 2], src[j*2 + 4], src[j*2 + 6])};
- r4 = _mm_add_ps(r4, _mm_mul_ps(s, coeffs));
- }
- r4 = _mm_add_ps(r4, _mm_shuffle_ps(r4, r4, _MM_SHUFFLE(0, 1, 2, 3)));
- r4 = _mm_add_ps(r4, _mm_movehl_ps(r4, r4));
-
- dst.back() += _mm_cvtss_f32(r4);
- }
-
-#elif defined(HAVE_NEON)
-
- size_t pos{0};
- if(size_t todo{dst.size()>>1})
- {
- do {
- float32x4_t r04{vdupq_n_f32(0.0f)};
- float32x4_t r14{vdupq_n_f32(0.0f)};
- for(size_t j{0};j < mCoeffs.size();j+=4)
- {
- const float32x4_t coeffs{vld1q_f32(&mCoeffs[j])};
- const float32x4_t s0{vld1q_f32(&src[j*2])};
- const float32x4_t s1{vld1q_f32(&src[j*2 + 4])};
-
- r04 = vmlaq_f32(r04, shuffle_2020(s0, s1), coeffs);
- r14 = vmlaq_f32(r14, shuffle_3131(s0, s1), coeffs);
- }
- src += 2;
-
- float32x4_t r4{vaddq_f32(unpackhi(r04, r14), unpacklo(r04, r14))};
- float32x2_t r2{vadd_f32(vget_low_f32(r4), vget_high_f32(r4))};
-
- vst1_f32(&dst[pos], vadd_f32(vld1_f32(&dst[pos]), r2));
- pos += 2;
- } while(--todo);
- }
- if((dst.size()&1))
- {
- float32x4_t r4{vdupq_n_f32(0.0f)};
- for(size_t j{0};j < mCoeffs.size();j+=4)
- {
- const float32x4_t coeffs{vld1q_f32(&mCoeffs[j])};
- const float32x4_t s{load4(src[j*2], src[j*2 + 2], src[j*2 + 4], src[j*2 + 6])};
- r4 = vmlaq_f32(r4, s, coeffs);
- }
- r4 = vaddq_f32(r4, vrev64q_f32(r4));
- dst[pos] += vget_lane_f32(vadd_f32(vget_low_f32(r4), vget_high_f32(r4)), 0);
- }
-
-#else
-
- for(float &output : dst)
- {
- float ret{0.0f};
- for(size_t j{0};j < mCoeffs.size();++j)
- ret += src[j*2] * mCoeffs[j];
-
- output += ret;
- ++src;
- }
-#endif
-}
-
#endif /* PHASE_SHIFTER_H */
diff --git a/core/uhjfilter.cpp b/core/uhjfilter.cpp
index 2b2cbee7..82e23da4 100644
--- a/core/uhjfilter.cpp
+++ b/core/uhjfilter.cpp
@@ -101,35 +101,6 @@ void allpass2_process(const al::span<UhjAllPassState,4> state, const al::span<co
std::transform(src.begin()+forwardSamples, src.end(), dstiter, proc_sample);
}
-/* This applies the shifted all-pass filter to the output of the base filter,
- * adding to the output buffer.
- */
-void allpass2_process_add(const al::span<UhjAllPassState,4> state, const al::span<const float> src,
- float *RESTRICT dst)
-{
- float z[4][2]{{state[0].z[0], state[0].z[1]}, {state[1].z[0], state[1].z[1]},
- {state[2].z[0], state[2].z[1]}, {state[3].z[0], state[3].z[1]}};
-
- auto proc_sample = [&z](float x, const float dst) noexcept -> float
- {
- for(size_t i{0};i < 4;++i)
- {
- const float y{x*Filter2Coeff[i] + z[i][0]};
- z[i][0] = z[i][1];
- z[i][1] = y*Filter2Coeff[i] - x;
- x = y;
- }
- return x + dst;
- };
- std::transform(src.begin(), src.end(), dst, dst, proc_sample);
-
- for(size_t i{0};i < 4;++i)
- {
- state[i].z[0] = z[i][0];
- state[i].z[1] = z[i][1];
- }
-}
-
} // namespace
@@ -158,50 +129,65 @@ void UhjEncoder<N>::encode(float *LeftOut, float *RightOut,
ASSUME(SamplesToDo > 0);
- float *RESTRICT left{al::assume_aligned<16>(LeftOut)};
- float *RESTRICT right{al::assume_aligned<16>(RightOut)};
-
const float *RESTRICT winput{al::assume_aligned<16>(InSamples[0])};
const float *RESTRICT xinput{al::assume_aligned<16>(InSamples[1])};
const float *RESTRICT yinput{al::assume_aligned<16>(InSamples[2])};
- /* Combine the previously delayed S/D signal with the input. Include any
- * existing direct signal with it.
- */
+ std::copy_n(winput, SamplesToDo, mW.begin()+sFilterDelay);
+ std::copy_n(xinput, SamplesToDo, mX.begin()+sFilterDelay);
+ std::copy_n(yinput, SamplesToDo, mY.begin()+sFilterDelay);
/* S = 0.9396926*W + 0.1855740*X */
- auto miditer = mS.begin() + sFilterDelay;
- std::transform(winput, winput+SamplesToDo, xinput, miditer,
- [](const float w, const float x) noexcept -> float
- { return 0.9396926f*w + 0.1855740f*x; });
- for(size_t i{0};i < SamplesToDo;++i,++miditer)
- *miditer += left[i] + right[i];
-
- /* D = 0.6554516*Y */
- auto sideiter = mD.begin() + sFilterDelay;
- std::transform(yinput, yinput+SamplesToDo, sideiter,
- [](const float y) noexcept -> float { return 0.6554516f*y; });
- for(size_t i{0};i < SamplesToDo;++i,++sideiter)
- *sideiter += left[i] - right[i];
-
- /* D += j(-0.3420201*W + 0.5098604*X) */
- auto tmpiter = std::copy(mWXHistory.cbegin(), mWXHistory.cend(), mTemp.begin());
- std::transform(winput, winput+SamplesToDo, xinput, tmpiter,
+ for(size_t i{0};i < SamplesToDo;++i)
+ mS[i] = 0.9396926f*mW[i] + 0.1855740f*mX[i];
+
+ /* Precompute j(-0.3420201*W + 0.5098604*X) and store in mD. */
+ std::transform(winput, winput+SamplesToDo, xinput, mWX.begin() + sWXInOffset,
[](const float w, const float x) noexcept -> float
{ return -0.3420201f*w + 0.5098604f*x; });
- std::copy_n(mTemp.cbegin()+SamplesToDo, mWXHistory.size(), mWXHistory.begin());
- PShift.processAccum({mD.data(), SamplesToDo}, mTemp.data());
+ PShift.process({mD.data(), SamplesToDo}, mWX.data());
+
+ /* D = 0.6554516*Y + j(-0.3420201*W + 0.5098604*X) */
+ for(size_t i{0};i < SamplesToDo;++i)
+ mD[i] = 0.6554516f*mY[i] + mD[i];
+
+ /* Copy the future samples to the front for next time. */
+ std::copy(mW.cbegin()+SamplesToDo, mW.cbegin()+SamplesToDo+sFilterDelay, mW.begin());
+ std::copy(mX.cbegin()+SamplesToDo, mX.cbegin()+SamplesToDo+sFilterDelay, mX.begin());
+ std::copy(mY.cbegin()+SamplesToDo, mY.cbegin()+SamplesToDo+sFilterDelay, mY.begin());
+ std::copy(mWX.cbegin()+SamplesToDo, mWX.cbegin()+SamplesToDo+sWXInOffset, mWX.begin());
+
+ /* Apply a delay to the existing output to align with the input delay. */
+ auto *delayBuffer = mDirectDelay.data();
+ for(float *buffer : {LeftOut, RightOut})
+ {
+ float *distbuf{al::assume_aligned<16>(delayBuffer->data())};
+ ++delayBuffer;
+
+ float *inout{al::assume_aligned<16>(buffer)};
+ auto inout_end = inout + SamplesToDo;
+ if(likely(SamplesToDo >= sFilterDelay))
+ {
+ auto delay_end = std::rotate(inout, inout_end - sFilterDelay, inout_end);
+ std::swap_ranges(inout, delay_end, distbuf);
+ }
+ else
+ {
+ auto delay_start = std::swap_ranges(inout, inout_end, distbuf);
+ std::rotate(distbuf, delay_start, distbuf + sFilterDelay);
+ }
+ }
+
+ /* Combine the direct signal with the produced output. */
/* Left = (S + D)/2.0 */
+ float *RESTRICT left{al::assume_aligned<16>(LeftOut)};
for(size_t i{0};i < SamplesToDo;i++)
- left[i] = (mS[i] + mD[i]) * 0.5f;
+ left[i] += (mS[i] + mD[i]) * 0.5f;
/* Right = (S - D)/2.0 */
+ float *RESTRICT right{al::assume_aligned<16>(RightOut)};
for(size_t i{0};i < SamplesToDo;i++)
- right[i] = (mS[i] - mD[i]) * 0.5f;
-
- /* Copy the future samples to the front for next time. */
- std::copy(mS.cbegin()+SamplesToDo, mS.cbegin()+SamplesToDo+sFilterDelay, mS.begin());
- std::copy(mD.cbegin()+SamplesToDo, mD.cbegin()+SamplesToDo+sFilterDelay, mD.begin());
+ right[i] += (mS[i] - mD[i]) * 0.5f;
}
void UhjEncoderIIR::encode(float *LeftOut, float *RightOut,
@@ -209,43 +195,65 @@ void UhjEncoderIIR::encode(float *LeftOut, float *RightOut,
{
ASSUME(SamplesToDo > 0);
- float *RESTRICT left{al::assume_aligned<16>(LeftOut)};
- float *RESTRICT right{al::assume_aligned<16>(RightOut)};
-
const float *RESTRICT winput{al::assume_aligned<16>(InSamples[0])};
const float *RESTRICT xinput{al::assume_aligned<16>(InSamples[1])};
const float *RESTRICT yinput{al::assume_aligned<16>(InSamples[2])};
- /* Combine the previously delayed S/D signal with the input. Include any
- * existing direct signal with it.
- */
+ std::copy_n(winput, SamplesToDo, mW.begin()+sFilterDelay);
+ std::copy_n(xinput, SamplesToDo, mX.begin()+sFilterDelay);
+ std::copy_n(yinput, SamplesToDo, mY.begin()+sFilterDelay);
/* S = 0.9396926*W + 0.1855740*X */
for(size_t i{0};i < SamplesToDo;++i)
- mS[sFilterDelay+i] = 0.9396926f*winput[i] + 0.1855740f*xinput[i] + (left[i] + right[i]);
+ mS[i] = 0.9396926f*mW[i] + 0.1855740f*mX[i];
- /* D = 0.6554516*Y */
+ /* Precompute j(-0.3420201*W + 0.5098604*X) and store in mD. */
+ std::transform(winput, winput+SamplesToDo, mX.cbegin(), mWX.begin()+sFilterDelay,
+ [](const float w, const float x) noexcept { return -0.3420201f*w + 0.5098604f*x; });
+ allpass1_process_rev({mWX.data()+1, SamplesToDo+sFilterDelay-1}, mRevTemp.data());
+ allpass2_process(mFilterWX, {mRevTemp.data(), SamplesToDo}, SamplesToDo, mD.data());
+
+ /* D = 0.6554516*Y + j(-0.3420201*W + 0.5098604*X) */
for(size_t i{0};i < SamplesToDo;++i)
- mD[sFilterDelay+i] = 0.6554516f*yinput[i] + (left[i] - right[i]);
+ mD[i] = 0.6554516f*mY[i] + mD[i];
- /* D += j(-0.3420201*W + 0.5098604*X) */
- std::transform(winput, winput+SamplesToDo, xinput, mWXTemp.begin()+sFilterDelay,
- [](const float w, const float x) noexcept { return -0.3420201f*w + 0.5098604f*x; });
- allpass1_process_rev({mWXTemp.data()+1, SamplesToDo+sFilterDelay-1}, mRevTemp.data());
- allpass2_process_add(mFilterWX, {mRevTemp.data(), SamplesToDo}, mD.data());
+ /* Copy the future samples to the front for next time. */
+ std::copy(mW.cbegin()+SamplesToDo, mW.cbegin()+SamplesToDo+sFilterDelay, mW.begin());
+ std::copy(mX.cbegin()+SamplesToDo, mX.cbegin()+SamplesToDo+sFilterDelay, mX.begin());
+ std::copy(mY.cbegin()+SamplesToDo, mY.cbegin()+SamplesToDo+sFilterDelay, mY.begin());
+ std::copy(mWX.cbegin()+SamplesToDo, mWX.cbegin()+SamplesToDo+sFilterDelay, mWX.begin());
+
+ /* Apply a delay to the existing output to align with the input delay. */
+ auto *delayBuffer = mDirectDelay.data();
+ for(float *buffer : {LeftOut, RightOut})
+ {
+ float *RESTRICT distbuf{al::assume_aligned<16>(delayBuffer->data())};
+ ++delayBuffer;
+
+ float *inout{al::assume_aligned<16>(buffer)};
+ auto inout_end = inout + SamplesToDo;
+ if(likely(SamplesToDo >= sFilterDelay))
+ {
+ auto delay_end = std::rotate(inout, inout_end - sFilterDelay, inout_end);
+ std::swap_ranges(inout, delay_end, distbuf);
+ }
+ else
+ {
+ auto delay_start = std::swap_ranges(inout, inout_end, distbuf);
+ std::rotate(distbuf, delay_start, distbuf + sFilterDelay);
+ }
+ }
+
+ /* Combine the direct signal with the produced output. */
/* Left = (S + D)/2.0 */
+ float *RESTRICT left{al::assume_aligned<16>(LeftOut)};
for(size_t i{0};i < SamplesToDo;i++)
- left[i] = (mS[i] + mD[i]) * 0.5f;
+ left[i] += (mS[i] + mD[i]) * 0.5f;
/* Right = (S - D)/2.0 */
+ float *RESTRICT right{al::assume_aligned<16>(RightOut)};
for(size_t i{0};i < SamplesToDo;i++)
- right[i] = (mS[i] - mD[i]) * 0.5f;
-
- /* Copy the future samples to the front for next time. */
- std::copy(mS.cbegin()+SamplesToDo, mS.cbegin()+SamplesToDo+sFilterDelay, mS.begin());
- std::copy(mD.cbegin()+SamplesToDo, mD.cbegin()+SamplesToDo+sFilterDelay, mD.begin());
- std::copy(mWXTemp.cbegin()+SamplesToDo, mWXTemp.cbegin()+SamplesToDo+sFilterDelay,
- mWXTemp.begin());
+ right[i] += (mS[i] - mD[i]) * 0.5f;
}
diff --git a/core/uhjfilter.h b/core/uhjfilter.h
index 29778605..e0aa73d2 100644
--- a/core/uhjfilter.h
+++ b/core/uhjfilter.h
@@ -47,14 +47,21 @@ template<size_t N>
struct UhjEncoder final : public UhjEncoderBase {
static constexpr size_t sFilterDelay{N/2};
- /* Delays and processing storage for the unfiltered signal. */
- alignas(16) std::array<float,BufferLineSize+sFilterDelay> mS{};
- alignas(16) std::array<float,BufferLineSize+sFilterDelay> mD{};
+ /* Delays and processing storage for the input signal. */
+ alignas(16) std::array<float,BufferLineSize+sFilterDelay> mW{};
+ alignas(16) std::array<float,BufferLineSize+sFilterDelay> mX{};
+ alignas(16) std::array<float,BufferLineSize+sFilterDelay> mY{};
- /* History for the FIR filter. */
- alignas(16) std::array<float,sFilterDelay*2 - 1> mWXHistory{};
+ alignas(16) std::array<float,BufferLineSize> mS{};
+ alignas(16) std::array<float,BufferLineSize> mD{};
- alignas(16) std::array<float,BufferLineSize + sFilterDelay*2> mTemp{};
+ /* History and temp storage for the FIR filter. New samples should be
+ * written to index sFilterDelay*2 - 1.
+ */
+ static constexpr size_t sWXInOffset{sFilterDelay*2 - 1};
+ alignas(16) std::array<float,BufferLineSize + sFilterDelay*2> mWX{};
+
+ alignas(16) std::array<std::array<float,sFilterDelay>,2> mDirectDelay{};
size_t getDelay() noexcept override { return sFilterDelay; }
@@ -72,15 +79,21 @@ struct UhjEncoder final : public UhjEncoderBase {
struct UhjEncoderIIR final : public UhjEncoderBase {
static constexpr size_t sFilterDelay{256};
- /* Delays and processing storage for the unfiltered signal. */
- alignas(16) std::array<float,BufferLineSize+sFilterDelay> mS{};
- alignas(16) std::array<float,BufferLineSize+sFilterDelay> mD{};
+ /* Delays and processing storage for the input signal. */
+ alignas(16) std::array<float,BufferLineSize+sFilterDelay> mW{};
+ alignas(16) std::array<float,BufferLineSize+sFilterDelay> mX{};
+ alignas(16) std::array<float,BufferLineSize+sFilterDelay> mY{};
- alignas(16) std::array<float,BufferLineSize+sFilterDelay> mWXTemp{};
+ alignas(16) std::array<float,BufferLineSize> mS{};
+ alignas(16) std::array<float,BufferLineSize> mD{};
+
+ alignas(16) std::array<float,BufferLineSize+sFilterDelay> mWX{};
alignas(16) std::array<float,BufferLineSize+sFilterDelay> mRevTemp{};
UhjAllPassState mFilterWX[4];
+ alignas(16) std::array<std::array<float,sFilterDelay>,2> mDirectDelay{};
+
size_t getDelay() noexcept override { return sFilterDelay; }
/**
diff --git a/utils/uhjencoder.cpp b/utils/uhjencoder.cpp
index b380ed86..5dc3b949 100644
--- a/utils/uhjencoder.cpp
+++ b/utils/uhjencoder.cpp
@@ -65,10 +65,14 @@ struct UhjEncoder {
constexpr static size_t sFilterDelay{1024};
/* Delays and processing storage for the unfiltered signal. */
- alignas(16) std::array<float,BufferLineSize+sFilterDelay> mS{};
- alignas(16) std::array<float,BufferLineSize+sFilterDelay> mD{};
- alignas(16) std::array<float,BufferLineSize+sFilterDelay> mT{};
- alignas(16) std::array<float,BufferLineSize+sFilterDelay> mQ{};
+ alignas(16) std::array<float,BufferLineSize+sFilterDelay> mW{};
+ alignas(16) std::array<float,BufferLineSize+sFilterDelay> mX{};
+ alignas(16) std::array<float,BufferLineSize+sFilterDelay> mY{};
+ alignas(16) std::array<float,BufferLineSize+sFilterDelay> mZ{};
+
+ alignas(16) std::array<float,BufferLineSize> mS{};
+ alignas(16) std::array<float,BufferLineSize> mD{};
+ alignas(16) std::array<float,BufferLineSize> mT{};
/* History for the FIR filter. */
alignas(16) std::array<float,sFilterDelay*2 - 1> mWXHistory1{};
@@ -106,26 +110,27 @@ void UhjEncoder::encode(const al::span<FloatBufferLine> OutSamples,
const float *RESTRICT yinput{al::assume_aligned<16>(InSamples[2].data())};
const float *RESTRICT zinput{al::assume_aligned<16>(InSamples[3].data())};
- /* Combine the previously delayed S/D signal with the input. */
+ /* Combine the previously delayed input signal with the new input. */
+ std::copy_n(winput, SamplesToDo, mW.begin()+sFilterDelay);
+ std::copy_n(xinput, SamplesToDo, mX.begin()+sFilterDelay);
+ std::copy_n(yinput, SamplesToDo, mY.begin()+sFilterDelay);
+ std::copy_n(zinput, SamplesToDo, mZ.begin()+sFilterDelay);
/* S = 0.9396926*W + 0.1855740*X */
- auto miditer = mS.begin() + sFilterDelay;
- std::transform(winput, winput+SamplesToDo, xinput, miditer,
- [](const float w, const float x) noexcept -> float
- { return 0.9396926f*w + 0.1855740f*x; });
-
- /* D = 0.6554516*Y */
- auto sideiter = mD.begin() + sFilterDelay;
- std::transform(yinput, yinput+SamplesToDo, sideiter,
- [](const float y) noexcept -> float { return 0.6554516f*y; });
+ for(size_t i{0};i < SamplesToDo;++i)
+ mS[i] = 0.9396926f*mW[i] + 0.1855740f*mX[i];
- /* D += j(-0.3420201*W + 0.5098604*X) */
+ /* Precompute j(-0.3420201*W + 0.5098604*X) and store in mD. */
auto tmpiter = std::copy(mWXHistory1.cbegin(), mWXHistory1.cend(), mTemp.begin());
std::transform(winput, winput+SamplesToDo, xinput, tmpiter,
[](const float w, const float x) noexcept -> float
{ return -0.3420201f*w + 0.5098604f*x; });
std::copy_n(mTemp.cbegin()+SamplesToDo, mWXHistory1.size(), mWXHistory1.begin());
- PShift.processAccum({mD.data(), SamplesToDo}, mTemp.data());
+ PShift.process({mD.data(), SamplesToDo}, mTemp.data());
+
+ /* D = 0.6554516*Y + j(-0.3420201*W + 0.5098604*X) */
+ for(size_t i{0};i < SamplesToDo;++i)
+ mD[i] = 0.6554516f*mY[i] + mD[i];
/* Left = (S + D)/2.0 */
float *RESTRICT left{al::assume_aligned<16>(OutSamples[0].data())};
@@ -138,40 +143,32 @@ void UhjEncoder::encode(const al::span<FloatBufferLine> OutSamples,
if(OutSamples.size() > 2)
{
- /* T = -0.7071068*Y */
- sideiter = mT.begin() + sFilterDelay;
- std::transform(yinput, yinput+SamplesToDo, sideiter,
- [](const float y) noexcept -> float { return -0.7071068f*y; });
-
- /* T += j(-0.1432*W + 0.6512*X) */
+ /* Precompute j(-0.1432*W + 0.6512*X) and store in mT. */
tmpiter = std::copy(mWXHistory2.cbegin(), mWXHistory2.cend(), mTemp.begin());
std::transform(winput, winput+SamplesToDo, xinput, tmpiter,
[](const float w, const float x) noexcept -> float
{ return -0.1432f*w + 0.6512f*x; });
std::copy_n(mTemp.cbegin()+SamplesToDo, mWXHistory2.size(), mWXHistory2.begin());
- PShift.processAccum({mT.data(), SamplesToDo}, mTemp.data());
+ PShift.process({mT.data(), SamplesToDo}, mTemp.data());
+ /* T = j(-0.1432*W + 0.6512*X) - 0.7071068*Y */
float *RESTRICT t{al::assume_aligned<16>(OutSamples[2].data())};
for(size_t i{0};i < SamplesToDo;i++)
- t[i] = mT[i];
+ t[i] = mT[i] - 0.7071068f*mY[i];
}
if(OutSamples.size() > 3)
{
/* Q = 0.9772*Z */
- sideiter = mQ.begin() + sFilterDelay;
- std::transform(zinput, zinput+SamplesToDo, sideiter,
- [](const float z) noexcept -> float { return 0.9772f*z; });
-
float *RESTRICT q{al::assume_aligned<16>(OutSamples[3].data())};
for(size_t i{0};i < SamplesToDo;i++)
- q[i] = mQ[i];
+ q[i] = 0.9772f*mZ[i];
}
/* Copy the future samples to the front for next time. */
- std::copy(mS.cbegin()+SamplesToDo, mS.cbegin()+SamplesToDo+sFilterDelay, mS.begin());
- std::copy(mD.cbegin()+SamplesToDo, mD.cbegin()+SamplesToDo+sFilterDelay, mD.begin());
- std::copy(mT.cbegin()+SamplesToDo, mT.cbegin()+SamplesToDo+sFilterDelay, mT.begin());
- std::copy(mQ.cbegin()+SamplesToDo, mQ.cbegin()+SamplesToDo+sFilterDelay, mQ.begin());
+ std::copy(mW.cbegin()+SamplesToDo, mW.cbegin()+SamplesToDo+sFilterDelay, mW.begin());
+ std::copy(mX.cbegin()+SamplesToDo, mX.cbegin()+SamplesToDo+sFilterDelay, mX.begin());
+ std::copy(mY.cbegin()+SamplesToDo, mY.cbegin()+SamplesToDo+sFilterDelay, mY.begin());
+ std::copy(mZ.cbegin()+SamplesToDo, mZ.cbegin()+SamplesToDo+sFilterDelay, mZ.begin());
}