aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--alc/effects/reverb.cpp5
-rw-r--r--alc/filters/biquad.cpp39
-rw-r--r--alc/filters/biquad.h12
-rw-r--r--alc/voice.cpp21
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()