diff options
-rw-r--r-- | alc/effects/reverb.cpp | 5 | ||||
-rw-r--r-- | alc/filters/biquad.cpp | 39 | ||||
-rw-r--r-- | alc/filters/biquad.h | 12 | ||||
-rw-r--r-- | alc/voice.cpp | 21 |
4 files changed, 61 insertions, 16 deletions
diff --git a/alc/effects/reverb.cpp b/alc/effects/reverb.cpp index 0e92daee..6b7aad44 100644 --- a/alc/effects/reverb.cpp +++ b/alc/effects/reverb.cpp @@ -301,10 +301,7 @@ struct T60Filter { /* Applies the two T60 damping filter sections. */ void process(const al::span<float> samples) - { - HFFilter.process(samples, samples.begin()); - LFFilter.process(samples, samples.begin()); - } + { DualBiquad{HFFilter, LFFilter}.process(samples, samples.data()); } }; struct EarlyReflections { diff --git a/alc/filters/biquad.cpp b/alc/filters/biquad.cpp index 271ca696..fefdc8e1 100644 --- a/alc/filters/biquad.cpp +++ b/alc/filters/biquad.cpp @@ -120,5 +120,44 @@ void BiquadFilterR<Real>::process(const al::span<const Real> src, Real *dst) mZ2 = z2; } +template<typename Real> +void BiquadFilterR<Real>::dualProcess(BiquadFilterR &other, const al::span<const Real> src, + Real *dst) +{ + const Real b00{mB0}; + const Real b01{mB1}; + const Real b02{mB2}; + const Real a01{mA1}; + const Real a02{mA2}; + const Real b10{other.mB0}; + const Real b11{other.mB1}; + const Real b12{other.mB2}; + const Real a11{other.mA1}; + const Real a12{other.mA2}; + Real z01{mZ1}; + Real z02{mZ2}; + Real z11{other.mZ1}; + Real z12{other.mZ2}; + + auto proc_sample = [b00,b01,b02,a01,a02,b10,b11,b12,a11,a12,&z01,&z02,&z11,&z12](Real input) noexcept -> Real + { + const Real tmpout{input*b00 + z01}; + z01 = input*b01 - tmpout*a01 + z02; + z02 = input*b02 - tmpout*a02; + input = tmpout; + + const Real output{input*b10 + z11}; + z11 = input*b11 - output*a11 + z12; + z12 = input*b12 - output*a12; + return output; + }; + std::transform(src.cbegin(), src.cend(), dst, proc_sample); + + mZ1 = z01; + mZ2 = z02; + other.mZ1 = z11; + other.mZ2 = z12; +} + template class BiquadFilterR<float>; template class BiquadFilterR<double>; diff --git a/alc/filters/biquad.h b/alc/filters/biquad.h index 30eed57d..3ce70cb3 100644 --- a/alc/filters/biquad.h +++ b/alc/filters/biquad.h @@ -114,8 +114,9 @@ public: mA2 = other.mA2; } - void process(const al::span<const Real> src, Real *dst); + /** Processes this filter and the other at the same time. */ + void dualProcess(BiquadFilterR &other, const al::span<const Real> src, Real *dst); /* Rather hacky. It's just here to support "manual" processing. */ std::pair<Real,Real> getComponents() const noexcept { return {mZ1, mZ2}; } @@ -129,6 +130,15 @@ public: } }; +template<typename Real> +struct DualBiquadR { + BiquadFilterR<Real> &f0, &f1; + + void process(const al::span<const Real> src, Real *dst) + { f0.dualProcess(f1, src, dst); } +}; + using BiquadFilter = BiquadFilterR<float>; +using DualBiquad = DualBiquadR<float>; #endif /* FILTERS_BIQUAD_H */ diff --git a/alc/voice.cpp b/alc/voice.cpp index 47e8f145..5dce9541 100644 --- a/alc/voice.cpp +++ b/alc/voice.cpp @@ -309,28 +309,27 @@ void SendSourceStoppedEvent(ALCcontext *context, ALuint id) } -const float *DoFilters(BiquadFilter *lpfilter, BiquadFilter *hpfilter, float *dst, +const float *DoFilters(BiquadFilter &lpfilter, BiquadFilter &hpfilter, float *dst, const al::span<const float> src, int type) { switch(type) { case AF_None: - lpfilter->clear(); - hpfilter->clear(); + lpfilter.clear(); + hpfilter.clear(); break; case AF_LowPass: - lpfilter->process(src, dst); - hpfilter->clear(); + lpfilter.process(src, dst); + hpfilter.clear(); return dst; case AF_HighPass: - lpfilter->clear(); - hpfilter->process(src, dst); + lpfilter.clear(); + hpfilter.process(src, dst); return dst; case AF_BandPass: - lpfilter->process(src, dst); - hpfilter->process({dst, src.size()}, dst); + DualBiquad{lpfilter, hpfilter}.process(src, dst); return dst; } return src.data(); @@ -765,7 +764,7 @@ void Voice::mix(const State vstate, ALCcontext *Context, const ALuint SamplesToD float (&FilterBuf)[BUFFERSIZE] = Device->FilteredData; { DirectParams &parms = chandata.mDryParams; - const float *samples{DoFilters(&parms.LowPass, &parms.HighPass, FilterBuf, + const float *samples{DoFilters(parms.LowPass, parms.HighPass, FilterBuf, {ResampledData, DstBufferSize}, mDirect.FilterType)}; if((mFlags&VOICE_HAS_HRTF)) @@ -797,7 +796,7 @@ void Voice::mix(const State vstate, ALCcontext *Context, const ALuint SamplesToD continue; SendParams &parms = chandata.mWetParams[send]; - const float *samples{DoFilters(&parms.LowPass, &parms.HighPass, FilterBuf, + const float *samples{DoFilters(parms.LowPass, parms.HighPass, FilterBuf, {ResampledData, DstBufferSize}, mSend[send].FilterType)}; const float *TargetGains{UNLIKELY(vstate == Stopping) ? SilentTarget.data() |