diff options
-rw-r--r-- | core/uhjfilter.cpp | 94 | ||||
-rw-r--r-- | core/uhjfilter.h | 12 | ||||
-rw-r--r-- | core/voice.cpp | 2 |
3 files changed, 57 insertions, 51 deletions
diff --git a/core/uhjfilter.cpp b/core/uhjfilter.cpp index da253300..22269e19 100644 --- a/core/uhjfilter.cpp +++ b/core/uhjfilter.cpp @@ -51,7 +51,7 @@ constexpr std::array<float,4> Filter2Coeff{{ } // namespace void UhjAllPassFilter::process(const al::span<const float,4> coeffs, - const al::span<const float> src, const size_t forwardSamples, float *RESTRICT dst) + const al::span<const float> src, const bool updateState, 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]}}; @@ -67,14 +67,15 @@ void UhjAllPassFilter::process(const al::span<const float,4> coeffs, } return x; }; - auto dstiter = std::transform(src.begin(), src.begin()+forwardSamples, dst, proc_sample); - for(size_t i{0};i < 4;++i) + std::transform(src.begin(), src.end(), dst, proc_sample); + if(updateState) [[likely]] { - state[i].z[0] = z[i][0]; - state[i].z[1] = z[i][1]; + for(size_t i{0};i < 4;++i) + { + state[i].z[0] = z[i][0]; + state[i].z[1] = z[i][1]; + } } - - std::transform(src.begin()+forwardSamples, src.end(), dstiter, proc_sample); } @@ -191,13 +192,13 @@ void UhjEncoderIIR::encode(float *LeftOut, float *RightOut, /* S = 0.9396926*W + 0.1855740*X */ std::transform(winput, winput+SamplesToDo, xinput, mTemp.begin(), [](const float w, const float x) noexcept { return 0.9396926f*w + 0.1855740f*x; }); - mFilter1WX.process(Filter1Coeff, {mTemp.data(), SamplesToDo}, SamplesToDo, mS.data()+1); + mFilter1WX.process(Filter1Coeff, {mTemp.data(), SamplesToDo}, true, mS.data()+1); mS[0] = mDelayWX; mDelayWX = mS[SamplesToDo]; /* Precompute j(-0.3420201*W + 0.5098604*X) and store in mWX. */ std::transform(winput, winput+SamplesToDo, xinput, mTemp.begin(), [](const float w, const float x) noexcept { return -0.3420201f*w + 0.5098604f*x; }); - mFilter2WX.process(Filter2Coeff, {mTemp.data(), SamplesToDo}, SamplesToDo, mWX.data()); + mFilter2WX.process(Filter2Coeff, {mTemp.data(), SamplesToDo}, true, mWX.data()); /* Apply filter1 to Y and store in mD. */ mFilter1Y.process(Filter1Coeff, {yinput, SamplesToDo}, SamplesToDo, mD.data()+1); @@ -210,7 +211,7 @@ void UhjEncoderIIR::encode(float *LeftOut, float *RightOut, /* Apply the base filter to the existing output to align with the processed * signal. */ - mFilter1Direct[0].process(Filter1Coeff, {LeftOut, SamplesToDo}, SamplesToDo, mTemp.data()+1); + mFilter1Direct[0].process(Filter1Coeff, {LeftOut, SamplesToDo}, true, mTemp.data()+1); mTemp[0] = mDirectDelay[0]; mDirectDelay[0] = mTemp[SamplesToDo]; /* Left = (S + D)/2.0 */ @@ -218,7 +219,7 @@ void UhjEncoderIIR::encode(float *LeftOut, float *RightOut, for(size_t i{0};i < SamplesToDo;i++) left[i] = (mS[i] + mD[i])*0.5f + mTemp[i]; - mFilter1Direct[1].process(Filter1Coeff, {RightOut, SamplesToDo}, SamplesToDo, mTemp.data()+1); + mFilter1Direct[1].process(Filter1Coeff, {RightOut, SamplesToDo}, true, mTemp.data()+1); mTemp[0] = mDirectDelay[1]; mDirectDelay[1] = mTemp[SamplesToDo]; /* Right = (S - D)/2.0 */ @@ -243,7 +244,7 @@ void UhjEncoderIIR::encode(float *LeftOut, float *RightOut, */ template<size_t N> void UhjDecoder<N>::decode(const al::span<float*> samples, const size_t samplesToDo, - const size_t forwardSamples) + const bool updateState) { static_assert(sInputPadding <= sMaxPadding, "Filter padding is too large"); @@ -277,7 +278,8 @@ void UhjDecoder<N>::decode(const al::span<float*> samples, const size_t samplesT auto tmpiter = std::copy(mDTHistory.cbegin(), mDTHistory.cend(), mTemp.begin()); std::transform(mD.cbegin(), mD.cbegin()+samplesToDo+sInputPadding, mT.cbegin(), tmpiter, [](const float d, const float t) noexcept { return 0.828331f*d + 0.767820f*t; }); - std::copy_n(mTemp.cbegin()+forwardSamples, mDTHistory.size(), mDTHistory.begin()); + if(updateState) [[likely]] + std::copy_n(mTemp.cbegin()+samplesToDo, mDTHistory.size(), mDTHistory.begin()); PShift.process({xoutput, samplesToDo}, mTemp.data()); /* W = 0.981532*S + 0.197484*j(0.828331*D + 0.767820*T) */ @@ -290,7 +292,8 @@ void UhjDecoder<N>::decode(const al::span<float*> samples, const size_t samplesT /* Precompute j*S and store in youtput. */ tmpiter = std::copy(mSHistory.cbegin(), mSHistory.cend(), mTemp.begin()); std::copy_n(mS.cbegin(), samplesToDo+sInputPadding, tmpiter); - std::copy_n(mTemp.cbegin()+forwardSamples, mSHistory.size(), mSHistory.begin()); + if(updateState) [[likely]] + std::copy_n(mTemp.cbegin()+samplesToDo, mSHistory.size(), mSHistory.begin()); PShift.process({youtput, samplesToDo}, mTemp.data()); /* Y = 0.795968*D - 0.676392*T + j(0.186633*S) */ @@ -307,7 +310,7 @@ void UhjDecoder<N>::decode(const al::span<float*> samples, const size_t samplesT } void UhjDecoderIIR::decode(const al::span<float*> samples, const size_t samplesToDo, - const size_t forwardSamples) + const bool updateState) { static_assert(sInputPadding <= sMaxPadding, "Filter padding is too large"); @@ -333,11 +336,12 @@ void UhjDecoderIIR::decode(const al::span<float*> samples, const size_t samplesT /* Precompute j(0.828331*D + 0.767820*T) and store in xoutput. */ std::transform(mD.cbegin(), mD.cbegin()+samplesToDo, youtput, mTemp.begin(), [](const float d, const float t) noexcept { return 0.828331f*d + 0.767820f*t; }); - mFilter2DT.process(Filter2Coeff, {mTemp.data(), samplesToDo}, forwardSamples, xoutput); + mFilter2DT.process(Filter2Coeff, {mTemp.data(), samplesToDo}, updateState, xoutput); /* Apply filter1 to S and store in mTemp. */ - mFilter1S.process(Filter1Coeff, {mS.data(), samplesToDo}, forwardSamples, mTemp.data()+1); - mTemp[0] = mDelayS; mDelayS = mTemp[forwardSamples]; + mTemp[0] = mDelayS; + mFilter1S.process(Filter1Coeff, {mS.data(), samplesToDo}, updateState, mTemp.data()+1); + if(updateState) [[likely]] mDelayS = mTemp[samplesToDo]; /* W = 0.981532*S + 0.197484*j(0.828331*D + 0.767820*T) */ for(size_t i{0};i < samplesToDo;++i) @@ -350,11 +354,12 @@ void UhjDecoderIIR::decode(const al::span<float*> samples, const size_t samplesT /* Apply filter1 to (0.795968*D - 0.676392*T) and store in mTemp. */ std::transform(mD.cbegin(), mD.cbegin()+samplesToDo, youtput, youtput, [](const float d, const float t) noexcept { return 0.795968f*d - 0.676392f*t; }); - mFilter1DT.process(Filter1Coeff, {youtput, samplesToDo}, forwardSamples, mTemp.data()+1); - mTemp[0] = mDelayDT; mDelayDT = mTemp[forwardSamples]; + mTemp[0] = mDelayDT; + mFilter1DT.process(Filter1Coeff, {youtput, samplesToDo}, updateState, mTemp.data()+1); + if(updateState) [[likely]] mDelayDT = mTemp[samplesToDo]; /* Precompute j*S and store in youtput. */ - mFilter2S.process(Filter2Coeff, {mS.data(), samplesToDo}, forwardSamples, youtput); + mFilter2S.process(Filter2Coeff, {mS.data(), samplesToDo}, updateState, youtput); /* Y = 0.795968*D - 0.676392*T + j(0.186633*S) */ for(size_t i{0};i < samplesToDo;++i) @@ -366,8 +371,9 @@ void UhjDecoderIIR::decode(const al::span<float*> samples, const size_t samplesT float *RESTRICT zoutput{al::assume_aligned<16>(samples[3])}; /* Apply filter1 to Q and store in mTemp. */ - mFilter1Q.process(Filter1Coeff, {zoutput, samplesToDo-1}, forwardSamples, mTemp.data()+1); - mTemp[0] = mDelayQ; mDelayQ = mTemp[forwardSamples]; + mTemp[0] = mDelayQ; + mFilter1Q.process(Filter1Coeff, {zoutput, samplesToDo}, updateState, mTemp.data()+1); + if(updateState) [[likely]] mDelayQ = mTemp[samplesToDo]; /* Z = 1.023332*Q */ for(size_t i{0};i < samplesToDo;++i) @@ -390,7 +396,7 @@ void UhjDecoderIIR::decode(const al::span<float*> samples, const size_t samplesT */ template<size_t N> void UhjStereoDecoder<N>::decode(const al::span<float*> samples, const size_t samplesToDo, - const size_t forwardSamples) + const bool updateState) { static_assert(sInputPadding <= sMaxPadding, "Filter padding is too large"); @@ -410,7 +416,7 @@ void UhjStereoDecoder<N>::decode(const al::span<float*> samples, const size_t sa */ const float wtarget{mWidthControl}; const float wcurrent{(mCurrentWidth < 0.0f) ? wtarget : mCurrentWidth}; - if(wtarget == wcurrent || forwardSamples == 0) + if(wtarget == wcurrent || !updateState) { for(size_t i{0};i < samplesToDo+sInputPadding;++i) mD[i] = (left[i] - right[i]) * wcurrent; @@ -418,15 +424,14 @@ void UhjStereoDecoder<N>::decode(const al::span<float*> samples, const size_t sa } else { - const float wstep{(wtarget - wcurrent) / static_cast<float>(forwardSamples)}; + const float wstep{(wtarget - wcurrent) / static_cast<float>(samplesToDo)}; float fi{0.0f}; - size_t i{0}; - for(;i < forwardSamples;++i) + for(size_t i{0};i < samplesToDo;++i) { mD[i] = (left[i] - right[i]) * (wcurrent + wstep*fi); fi += 1.0f; } - for(;i < samplesToDo+sInputPadding;++i) + for(size_t i{samplesToDo};i < samplesToDo+sInputPadding;++i) mD[i] = (left[i] - right[i]) * wtarget; mCurrentWidth = wtarget; } @@ -439,7 +444,8 @@ void UhjStereoDecoder<N>::decode(const al::span<float*> samples, const size_t sa /* Precompute j*D and store in xoutput. */ auto tmpiter = std::copy(mDTHistory.cbegin(), mDTHistory.cend(), mTemp.begin()); std::copy_n(mD.cbegin(), samplesToDo+sInputPadding, tmpiter); - std::copy_n(mTemp.cbegin()+forwardSamples, mDTHistory.size(), mDTHistory.begin()); + if(updateState) [[likely]] + std::copy_n(mTemp.cbegin()+samplesToDo, mDTHistory.size(), mDTHistory.begin()); PShift.process({xoutput, samplesToDo}, mTemp.data()); /* W = 0.6098637*S - 0.6896511*j*w*D */ @@ -452,7 +458,8 @@ void UhjStereoDecoder<N>::decode(const al::span<float*> samples, const size_t sa /* Precompute j*S and store in youtput. */ tmpiter = std::copy(mSHistory.cbegin(), mSHistory.cend(), mTemp.begin()); std::copy_n(mS.cbegin(), samplesToDo+sInputPadding, tmpiter); - std::copy_n(mTemp.cbegin()+forwardSamples, mSHistory.size(), mSHistory.begin()); + if(updateState) [[likely]] + std::copy_n(mTemp.cbegin()+samplesToDo, mSHistory.size(), mSHistory.begin()); PShift.process({youtput, samplesToDo}, mTemp.data()); /* Y = 1.6822415*w*D - 0.2156194*j*S */ @@ -461,7 +468,7 @@ void UhjStereoDecoder<N>::decode(const al::span<float*> samples, const size_t sa } void UhjStereoDecoderIIR::decode(const al::span<float*> samples, const size_t samplesToDo, - const size_t forwardSamples) + const bool updateState) { static_assert(sInputPadding <= sMaxPadding, "Filter padding is too large"); @@ -479,7 +486,7 @@ void UhjStereoDecoderIIR::decode(const al::span<float*> samples, const size_t sa */ const float wtarget{mWidthControl}; const float wcurrent{(mCurrentWidth < 0.0f) ? wtarget : mCurrentWidth}; - if(wtarget == wcurrent || forwardSamples == 0) + if(wtarget == wcurrent || !updateState) { for(size_t i{0};i < samplesToDo;++i) mD[i] = (left[i] - right[i]) * wcurrent; @@ -487,16 +494,13 @@ void UhjStereoDecoderIIR::decode(const al::span<float*> samples, const size_t sa } else { - const float wstep{(wtarget - wcurrent) / static_cast<float>(forwardSamples)}; + const float wstep{(wtarget - wcurrent) / static_cast<float>(samplesToDo)}; float fi{0.0f}; - size_t i{0}; - for(;i < forwardSamples;++i) + for(size_t i{0};i < samplesToDo;++i) { mD[i] = (left[i] - right[i]) * (wcurrent + wstep*fi); fi += 1.0f; } - for(;i < samplesToDo;++i) - mD[i] = (left[i] - right[i]) * wtarget; mCurrentWidth = wtarget; } } @@ -506,11 +510,12 @@ void UhjStereoDecoderIIR::decode(const al::span<float*> samples, const size_t sa float *RESTRICT youtput{al::assume_aligned<16>(samples[2])}; /* Apply filter1 to S and store in mTemp. */ - mFilter1S.process(Filter1Coeff, {mS.data(), samplesToDo}, forwardSamples, mTemp.data()+1); - mTemp[0] = mDelayS; mDelayS = mTemp[forwardSamples]; + mTemp[0] = mDelayS; + mFilter1S.process(Filter1Coeff, {mS.data(), samplesToDo}, updateState, mTemp.data()+1); + if(updateState) [[likely]] mDelayS = mTemp[samplesToDo]; /* Precompute j*D and store in xoutput. */ - mFilter2D.process(Filter2Coeff, {mD.data(), samplesToDo}, forwardSamples, xoutput); + mFilter2D.process(Filter2Coeff, {mD.data(), samplesToDo}, updateState, xoutput); /* W = 0.6098637*S - 0.6896511*j*w*D */ for(size_t i{0};i < samplesToDo;++i) @@ -520,11 +525,12 @@ void UhjStereoDecoderIIR::decode(const al::span<float*> samples, const size_t sa xoutput[i] = 0.8624776f*mTemp[i] + 0.7626955f*xoutput[i]; /* Precompute j*S and store in youtput. */ - mFilter2S.process(Filter2Coeff, {mS.data(), samplesToDo}, forwardSamples, youtput); + mFilter2S.process(Filter2Coeff, {mS.data(), samplesToDo}, updateState, youtput); /* Apply filter1 to D and store in mTemp. */ - mFilter1D.process(Filter1Coeff, {mD.data(), samplesToDo}, forwardSamples, mTemp.data()+1); - mTemp[0] = mDelayD; mDelayD = mTemp[forwardSamples]; + mTemp[0] = mDelayD; + mFilter1D.process(Filter1Coeff, {mD.data(), samplesToDo}, updateState, mTemp.data()+1); + if(updateState) [[likely]] mDelayD = mTemp[samplesToDo]; /* Y = 1.6822415*w*D - 0.2156194*j*S */ for(size_t i{0};i < samplesToDo;++i) diff --git a/core/uhjfilter.h b/core/uhjfilter.h index c92dd61b..ec2a9df9 100644 --- a/core/uhjfilter.h +++ b/core/uhjfilter.h @@ -30,7 +30,7 @@ struct UhjAllPassFilter { std::array<AllPassState,4> state; void process(const al::span<const float,4> coeffs, const al::span<const float> src, - const size_t forwardSamples, float *RESTRICT dst); + const bool update, float *RESTRICT dst); }; @@ -122,7 +122,7 @@ struct DecoderBase { virtual ~DecoderBase() = default; virtual void decode(const al::span<float*> samples, const size_t samplesToDo, - const size_t forwardSamples) = 0; + const bool updateState) = 0; /** * The width factor for Super Stereo processing. Can be changed in between @@ -154,7 +154,7 @@ struct UhjDecoder final : public DecoderBase { * B-Format decoder, as it needs different shelf filters. */ void decode(const al::span<float*> samples, const size_t samplesToDo, - const size_t forwardSamples) override; + const bool updateState) override; DEF_NEWDEL(UhjDecoder) }; @@ -179,7 +179,7 @@ struct UhjDecoderIIR final : public DecoderBase { UhjAllPassFilter mFilter1Q; void decode(const al::span<float*> samples, const size_t samplesToDo, - const size_t forwardSamples) override; + const bool updateState) override; DEF_NEWDEL(UhjDecoderIIR) }; @@ -205,7 +205,7 @@ struct UhjStereoDecoder final : public DecoderBase { * channels, and the third left empty. */ void decode(const al::span<float*> samples, const size_t samplesToDo, - const size_t forwardSamples) override; + const bool updateState) override; DEF_NEWDEL(UhjStereoDecoder) }; @@ -226,7 +226,7 @@ struct UhjStereoDecoderIIR final : public DecoderBase { UhjAllPassFilter mFilter2S; void decode(const al::span<float*> samples, const size_t samplesToDo, - const size_t forwardSamples) override; + const bool updateState) override; DEF_NEWDEL(UhjStereoDecoderIIR) }; diff --git a/core/voice.cpp b/core/voice.cpp index 31fe4088..4ca62a02 100644 --- a/core/voice.cpp +++ b/core/voice.cpp @@ -722,7 +722,7 @@ void Voice::mix(const State vstate, ContextBase *Context, const nanoseconds devi std::fill_n(samples, samplesToLoad, 0.0f); if(mDecoder) - mDecoder->decode(MixingSamples, samplesToMix, (vstate==Playing) ? samplesToMix : 0); + mDecoder->decode(MixingSamples, samplesToMix, (vstate==Playing)); if(mFlags.test(VoiceIsAmbisonic)) { |