commit 53d8f31000d0c9e12c3733d6a2c65b3a0e1569c2
parent 45308431307da401441b97341eafcf17f4175df4
Author: Matt Demanett <matt@demanett.net>
Date: Sat, 18 Apr 2020 23:29:43 -0400
Speed up filters somewhat with rack::simd.
Diffstat:
6 files changed, 304 insertions(+), 70 deletions(-)
diff --git a/Makefile b/Makefile
@@ -7,6 +7,10 @@ ifdef TEST
FLAGS += -DTEST=1
endif
+ifndef NO_RACK_SIMD
+FLAGS += -DRACK_SIMD=1
+endif
+
DSP_SOURCES = $(wildcard src/dsp/*cpp src/dsp/filters/*cpp)
SOURCES = $(wildcard src/*.cpp) $(DSP_SOURCES)
@@ -31,7 +35,8 @@ TESTMAIN_OBJECTS = $(patsubst %, build/%.o, $(TESTMAIN_SOURCES))
TESTMAIN_DEPS = $(patsubst %, build/%.d, $(TESTMAIN_SOURCES))
-include $(TESTMAIN_DEPS)
testmain: $(TESTMAIN_OBJECTS)
- $(CXX) -o $@ $^ ../../build/src/util.cpp.o
+ # $(CXX) -o $@ $^ ../../build/src/util.cpp.o
+ $(CXX) -o $@ $^
testmain_clean:
rm -f testmain $(TESTMAIN_OBJECTS)
diff --git a/benchmarks/filter_benchmark.cpp b/benchmarks/filter_benchmark.cpp
@@ -2,6 +2,7 @@
#include <benchmark/benchmark.h>
#include "dsp/noise.hpp"
+#include "dsp/filters/multimode.hpp"
#include "dsp/filters/resample.hpp"
// #include "dsp/decimator.hpp" // rack
@@ -82,3 +83,112 @@ static void BM_AnalogFrequency(benchmark::State& state) {
}
}
BENCHMARK(BM_AnalogFrequency);
+
+#ifdef RACK_SIMD
+static void BM_Biquad4(benchmark::State& state) {
+ WhiteNoiseGenerator r;
+ const int n = 128;
+ float buf[n];
+ for (int i = 0; i < n; ++i) {
+ buf[i] = std::abs(r.next()) * 0.5f * M_PI;
+ }
+
+ Biquad4 biquads;
+ for (int i = 0; i < 4; ++i) {
+ biquads.setParams(i, 0.012672, 0.025345, 0.012672, 1.102730, -1.974655, 0.922615);
+ }
+ int i = 0;
+ for (auto _ : state) {
+ benchmark::DoNotOptimize(biquads.next(buf[i]));
+ i = (i + 1) % n;
+ }
+}
+BENCHMARK(BM_Biquad4);
+#endif
+
+static void BM_BiquadBank4(benchmark::State& state) {
+ WhiteNoiseGenerator r;
+ const int n = 128;
+ float buf[n];
+ for (int i = 0; i < n; ++i) {
+ buf[i] = std::abs(r.next()) * 0.5f * M_PI;
+ }
+
+ MultimodeDesigner<4> designer;
+ BiquadBank<float, 4> biquads;
+ float outGain;
+ designer.setParams(
+ biquads,
+ outGain,
+ 44100.0f,
+ MultimodeTypes::BUTTERWORTH_TYPE,
+ 4,
+ MultimodeTypes::BANDPASS_MODE,
+ 2000.0f,
+ 1.0f
+ );
+ int i = 0;
+ for (auto _ : state) {
+ benchmark::DoNotOptimize(biquads.next(buf[i]));
+ i = (i + 1) % n;
+ }
+}
+BENCHMARK(BM_BiquadBank4);
+
+static void BM_BiquadBank16(benchmark::State& state) {
+ WhiteNoiseGenerator r;
+ const int n = 128;
+ float buf[n];
+ for (int i = 0; i < n; ++i) {
+ buf[i] = std::abs(r.next()) * 0.5f * M_PI;
+ }
+
+ MultimodeDesigner<16> designer;
+ BiquadBank<float, 16> biquads;
+ float outGain;
+ designer.setParams(
+ biquads,
+ outGain,
+ 44100.0f,
+ MultimodeTypes::BUTTERWORTH_TYPE,
+ 16,
+ MultimodeTypes::BANDPASS_MODE,
+ 2000.0f,
+ 1.0f
+ );
+ int i = 0;
+ for (auto _ : state) {
+ benchmark::DoNotOptimize(biquads.next(buf[i]));
+ i = (i + 1) % n;
+ }
+}
+BENCHMARK(BM_BiquadBank16);
+
+static void BM_BiquadBank16_2Pole(benchmark::State& state) {
+ WhiteNoiseGenerator r;
+ const int n = 128;
+ float buf[n];
+ for (int i = 0; i < n; ++i) {
+ buf[i] = std::abs(r.next()) * 0.5f * M_PI;
+ }
+
+ MultimodeDesigner<16> designer;
+ BiquadBank<float, 16> biquads;
+ float outGain;
+ designer.setParams(
+ biquads,
+ outGain,
+ 44100.0f,
+ MultimodeTypes::BUTTERWORTH_TYPE,
+ 2,
+ MultimodeTypes::BANDPASS_MODE,
+ 2000.0f,
+ 1.0f
+ );
+ int i = 0;
+ for (auto _ : state) {
+ benchmark::DoNotOptimize(biquads.next(buf[i]));
+ i = (i + 1) % n;
+ }
+}
+BENCHMARK(BM_BiquadBank16_2Pole);
diff --git a/src/dsp/filters/equalizer.hpp b/src/dsp/filters/equalizer.hpp
@@ -13,7 +13,7 @@ struct Equalizer : Filter {
Amplifier _midAmp;
Amplifier _highAmp;
FourPoleButtworthLowpassFilter _lowFilter;
- TowPoleButtworthBandpassFilter _midFilter;
+ TwoPoleButtworthBandpassFilter _midFilter;
FourPoleButtworthHighpassFilter _highFilter;
void setParams(
diff --git a/src/dsp/filters/multimode.cpp b/src/dsp/filters/multimode.cpp
@@ -7,40 +7,129 @@
using namespace bogaudio::dsp;
+#ifdef RACK_SIMD
+
+void Biquad4::setParams(int i, float a0, float a1, float a2, float b0, float b1, float b2) {
+ assert(i >= 0 && i < 4);
+ float ib0 = 1.0 / b0;
+ _a0[i] = a0 * ib0;
+ _a1[i] = a1 * ib0;
+ _a2[i] = a2 * ib0;
+ _b1[i] = b1 * ib0;
+ _b2[i] = b2 * ib0;
+}
+
+void Biquad4::reset() {
+ _x[0] = _x[1] = _x[2] = 0.0;
+ _y[0] = _y[1] = _y[2] = 0.0;
+}
+
+void Biquad4::setN(int n) {
+ assert(n <= 4);
+ for (; n < 4; ++n) {
+ setParams(n, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0);
+ }
+}
+
+float Biquad4::next(float sample) {
+ if (_disable) {
+ return sample;
+ }
+
+ _x[2] = _x[1];
+ _x[1] = _x[0];
+
+ // slower: _x[0] = _mm_shuffle_ps(_y[0].v, _y[0].v, _MM_SHUFFLE(2, 1, 0, 0)); _x[0][0] = sample;
+ _x[0] = float_4(sample, _y[0][0], _y[0][1], _y[0][2]);
+
+ _y[2] = _y[1];
+ _y[1] = _y[0];
+ _y[0] = ((_a0 * _x[0]) + (_a1 * _x[1]) + (_a2 * _x[2])) - ((_b1 * _y[1]) + (_b2 * _y[2]));
+ return _y[0][3];
+}
+
+template<> void BiquadBank<MultimodeTypes::T, 4>::setParams(int i, MultimodeTypes::T a0, MultimodeTypes::T a1, MultimodeTypes::T a2, MultimodeTypes::T b0, MultimodeTypes::T b1, MultimodeTypes::T b2) {
+ assert(i >= 0 && i < 4);
+ _biquads->setParams(i, a0, a1, a2, b0, b1, b2);
+}
+
+template<> void BiquadBank<MultimodeTypes::T, 4>::reset() {
+ _biquads->reset();
+}
+
+template<> void BiquadBank<MultimodeTypes::T, 4>::setN(int n) {
+ for (; n < 4; ++n) {
+ _biquads->setParams(n, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0);
+ }
+}
+
+template<> float BiquadBank<MultimodeTypes::T, 4>::next(float sample) {
+ return _biquads->next(sample);
+}
+
+template<> void BiquadBank<MultimodeTypes::T, 16>::setParams(int i, MultimodeTypes::T a0, MultimodeTypes::T a1, MultimodeTypes::T a2, MultimodeTypes::T b0, MultimodeTypes::T b1, MultimodeTypes::T b2) {
+ assert(i >= 0 && i < 16);
+ _biquads[i / 4].setParams(i % 4, a0, a1, a2, b0, b1, b2);
+}
+
+template<> void BiquadBank<MultimodeTypes::T, 16>::reset() {
+ _biquads[0].reset();
+ _biquads[1].reset();
+ _biquads[2].reset();
+ _biquads[3].reset();
+}
+
+template<> void BiquadBank<MultimodeTypes::T, 16>::setN(int n) {
+ for (int i = n, nn = n + (4 - n % 4); i < nn; ++i) {
+ _biquads[i / 4].setParams(i % 4, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0);
+ }
+ for (int i = 0; i < 4; ++i) {
+ _biquads[i].disable(4 * i > n);
+ }
+}
+
+template<> float BiquadBank<MultimodeTypes::T, 16>::next(float sample) {
+ sample = _biquads[0].next(sample);
+ sample = _biquads[1].next(sample);
+ sample = _biquads[2].next(sample);
+ return _biquads[3].next(sample);
+}
+
+#else
+
template<typename T, int N> void BiquadBank<T, N>::setParams(int i, T a0, T a1, T a2, T b0, T b1, T b2) {
assert(i >= 0 && i < N);
_biquads[i].setParams(a0, a1, a2, b0, b1, b2);
}
-template<typename T, int N> void BiquadBank<T, N>::reset(int from) {
- assert(from >= 0);
- for (; from < N; ++from) {
- _biquads[from].reset();
+template<typename T, int N> void BiquadBank<T, N>::reset() {
+ for (int i = 0; i < N; ++i) {
+ _biquads[i].reset();
}
}
-template<> float BiquadBank<MultimodeTypes::T, 4>::next(float sample) {
- assert(_n <= 4);
- for (int i = 0; i < _n; ++i) {
- sample = _biquads[i].next(sample);
+template<typename T, int N> void BiquadBank<T, N>::setN(int n) {
+ assert(n <= N);
+ _n = n;
+ for (; n < N; ++n) {
+ _biquads[n].reset();
}
- return sample;
}
-template<> float BiquadBank<MultimodeTypes::T, 16>::next(float sample) {
- assert(_n <= 16);
+template<typename T, int N> float BiquadBank<T, N>::next(float sample) {
for (int i = 0; i < _n; ++i) {
sample = _biquads[i].next(sample);
}
return sample;
}
+#endif
+
template struct bogaudio::dsp::BiquadBank<MultimodeTypes::T, 4>;
template struct bogaudio::dsp::BiquadBank<MultimodeTypes::T, 16>;
template<int N> void MultimodeDesigner<N>::setParams(
- bool& changed,
BiquadBank<T, N>& biquads,
float& outGain,
float sampleRate,
@@ -59,7 +148,6 @@ template<int N> void MultimodeDesigner<N>::setParams(
bool repole = _type != type || _mode != mode || _nPoles != poles || (type == CHEBYSHEV_TYPE && (mode == LOWPASS_MODE || mode == HIGHPASS_MODE) && _qbw != qbw);
bool redesign = repole || _frequency != frequency || _qbw != qbw || _sampleRate != sampleRate || _bandwidthMode != bwm;
- changed = redesign;
_sampleRate = sampleRate;
_half2PiST = M_PI * (1.0f / sampleRate);
_type = type;
@@ -120,9 +208,8 @@ template<int N> void MultimodeDesigner<N>::setParams(
switch (_mode) {
case LOWPASS_MODE:
case HIGHPASS_MODE: {
- biquads.reset(_nBiquads);
_nBiquads = _nPoles / 2 + _nPoles % 2;
- biquads.setSectionsInUse(_nBiquads);
+ biquads.setN(_nBiquads);
// T iq = (1.0 / std::sqrt(2.0)) - 0.65 * _qbw;
T iq = (T)0.8 - (T)0.6 * _qbw;
@@ -181,9 +268,8 @@ template<int N> void MultimodeDesigner<N>::setParams(
case BANDPASS_MODE:
case BANDREJECT_MODE: {
- biquads.reset(_nBiquads);
_nBiquads = ((_nPoles / 2) * 2) + (_nPoles % 2);
- biquads.setSectionsInUse(_nBiquads);
+ biquads.setN(_nBiquads);
T wdl = 0.0;
T wdh = 0.0;
@@ -346,9 +432,7 @@ template<int N> void MultimodeBase<N>::design(
float qbw,
BandwidthMode bwm
) {
- bool changed = false;
_designer.setParams(
- changed,
_biquads,
_outGain,
sampleRate,
diff --git a/src/dsp/filters/multimode.hpp b/src/dsp/filters/multimode.hpp
@@ -4,17 +4,45 @@
#include "filters/filter.hpp"
+#ifdef RACK_SIMD
+#include "simd/vector.hpp"
+using rack::simd::float_4;
+#endif
+
namespace bogaudio {
namespace dsp {
+#ifdef RACK_SIMD
+ struct Biquad4 {
+ float_4 _a0;
+ float_4 _a1;
+ float_4 _a2;
+ float_4 _b1;
+ float_4 _b2;
+ float_4 _x[3] {};
+ float_4 _y[3] {};
+ bool _disable = false;
+
+ void setParams(int i, float a0, float a1, float a2, float b0, float b1, float b2);
+ void reset();
+ void setN(int n);
+ inline void disable(bool disable) { _disable = disable; }
+ float next(float sample);
+ };
+#endif
+
template<typename T, int N>
struct BiquadBank : Filter {
+#ifdef RACK_SIMD
+ Biquad4 _biquads[N / 4];
+#else
BiquadFilter<T> _biquads[N];
int _n = N;
+#endif
void setParams(int i, T a0, T a1, T a2, T b0, T b1, T b2);
- void reset(int from = 0);
- inline void setSectionsInUse(int n) { _n = n; }
+ void reset();
+ void setN(int n);
float next(float sample) override;
};
@@ -99,7 +127,6 @@ struct MultimodeDesigner : MultimodeTypes {
int _nBiquads = 0;
void setParams(
- bool& changed,
BiquadBank<T, N>& biquads,
float& outGain,
float sampleRate,
@@ -187,7 +214,7 @@ struct FourPoleButtworthHighpassFilter : MultimodeBase<4> {
}
};
-struct TowPoleButtworthBandpassFilter : MultimodeBase<4> {
+struct TwoPoleButtworthBandpassFilter : MultimodeBase<4> {
inline void setParams(
float sampleRate,
float frequency,
diff --git a/test/testmain.cpp b/test/testmain.cpp
@@ -6,54 +6,62 @@
#include <math.h>
#include <algorithm>
-#include "util/math.hpp" // Rack
+// #include "util/math.hpp" // Rack
+#include "simd/vector.hpp" // Rack
+using rack::simd::float_4;
-#include "dsp/fixed.hpp"
-
-using namespace bogaudio::dsp;
+// #include "dsp/fixed.hpp"
+// using namespace bogaudio::dsp;
int main() {
- {
- fixed_16_16 x = 5;
- fixed_16_16 y = 1;
- x = 3;
- printf("X=%d\n", (int)(x + y));
- y = 2;
- printf("X=%d\n", (int)(x - y));
- x = y + 5;
- printf("X=%d\n", (int)x);
- x = y - 3;
- printf("X=%d\n", (int)x);
-
- x += 2.5;
- printf("X=%d\n", (int)x);
- printf("X=%f\n", (float)x);
+ // {
+ // fixed_16_16 x = 5;
+ // fixed_16_16 y = 1;
+ // x = 3;
+ // printf("X=%d\n", (int)(x + y));
+ // y = 2;
+ // printf("X=%d\n", (int)(x - y));
+ // x = y + 5;
+ // printf("X=%d\n", (int)x);
+ // x = y - 3;
+ // printf("X=%d\n", (int)x);
+ //
+ // x += 2.5;
+ // printf("X=%d\n", (int)x);
+ // printf("X=%f\n", (float)x);
+ //
+ // x = y - 0.3;
+ // printf("X=%d\n", (int)x);
+ // printf("X=%f\n", (float)x);
+ // }
+ //
+ // {
+ // fixed_32_32 x = 5;
+ // fixed_32_32 y = 1;
+ // x = 3;
+ // printf("X=%d\n", (int)(x + y));
+ // y = 2;
+ // printf("X=%d\n", (int)(x - y));
+ // x = y + 5;
+ // printf("X=%d\n", (int)x);
+ // x = y - 3;
+ // printf("X=%d\n", (int)x);
+ //
+ // x += 2.5;
+ // printf("X=%d\n", (int)x);
+ // printf("X=%f\n", (float)x);
+ //
+ // x = y - 0.3;
+ // printf("X=%d\n", (int)x);
+ // printf("X=%f\n", (float)x);
+ // }
+ //
+ // return 0;
- x = y - 0.3;
- printf("X=%d\n", (int)x);
- printf("X=%f\n", (float)x);
+ float_4 a(1.0, 2.0, 3.0, 4.0);
+ float_4 b = _mm_shuffle_ps(a.v, a.v, _MM_SHUFFLE(2, 1, 0, 0));
+ b[0] = 0.0;
+ for (int i = 0; i < 4; ++i) {
+ printf("a=%f b=%f\n", a[i], b[i]);
}
-
- {
- fixed_32_32 x = 5;
- fixed_32_32 y = 1;
- x = 3;
- printf("X=%d\n", (int)(x + y));
- y = 2;
- printf("X=%d\n", (int)(x - y));
- x = y + 5;
- printf("X=%d\n", (int)x);
- x = y - 3;
- printf("X=%d\n", (int)x);
-
- x += 2.5;
- printf("X=%d\n", (int)x);
- printf("X=%f\n", (float)x);
-
- x = y - 0.3;
- printf("X=%d\n", (int)x);
- printf("X=%f\n", (float)x);
- }
-
- return 0;
}