marvin 0.0.1
Pure C++ audio helper library
 
Loading...
Searching...
No Matches
marvin_SIMDBiquad.h
Go to the documentation of this file.
1//
2// Created by Syl Morrison on 03/05/2025.
3//
4
5#ifndef MARVIN_SIMDBIQUAD_H
6#define MARVIN_SIMDBIQUAD_H
8#include <xsimd/xsimd.hpp>
11namespace marvin::dsp::filters {
21 template <marvin::FloatType SampleType, size_t N>
22 requires(N > 0)
23 class SIMDBiquad final {
24 public:
29 m_working.resize(N, 0.0);
30 m_a0.resize(N, 0.0);
31 m_a1.resize(N, 0.0);
32 m_a2.resize(N, 0.0);
33 m_b1.resize(N, 0.0);
34 m_b2.resize(N, 0.0);
35 m_x1.resize(N, 0.0);
36 m_x2.resize(N, 0.0);
37 m_y1.resize(N, 0.0);
38 m_y2.resize(N, 0.0);
39 }
40
46 auto setCoeffs(BiquadCoefficients<SampleType> coeffs) noexcept -> void {
47 m_equalCoeffs = true;
48 const auto a0 = coeffs.a0 / coeffs.b0;
49 const auto a1 = coeffs.a1 / coeffs.b0;
50 const auto a2 = coeffs.a2 / coeffs.b0;
51 const auto b1 = coeffs.b1 / coeffs.b0;
52 const auto b2 = coeffs.b2 / coeffs.b0;
53
54 const auto a0Batch = xsimd::broadcast(a0);
55 const auto a1Batch = xsimd::broadcast(a1);
56 const auto a2Batch = xsimd::broadcast(a2);
57 const auto b1Batch = xsimd::broadcast(b1);
58 const auto b2Batch = xsimd::broadcast(b2);
59 for (size_t i = 0; i < m_vecSize; i += m_simdSize) {
60 a0Batch.store_aligned(&m_a0[i]);
61 a1Batch.store_aligned(&m_a1[i]);
62 a2Batch.store_aligned(&m_a2[i]);
63 b1Batch.store_aligned(&m_b1[i]);
64 b2Batch.store_aligned(&m_b2[i]);
65 }
66 for (size_t i = m_vecSize; i < N; ++i) {
67 m_a0[i] = a0;
68 m_a1[i] = a1;
69 m_a2[i] = a2;
70 m_b1[i] = b1;
71 m_b2[i] = b2;
72 }
73 }
74
80 auto setCoeffs(size_t index, BiquadCoefficients<SampleType> coeffs) noexcept -> void {
81 m_equalCoeffs = false;
82 const auto [a0, a1, a2, b0, b1, b2] = coeffs;
83 m_a0[index] = a0 / b0;
84 m_a1[index] = a1 / b0;
85 m_a2[index] = a2 / b0;
86 m_b1[index] = b1 / b0;
87 m_b2[index] = b2 / b0;
88 }
89
94 auto operator()(std::span<SampleType, N> x) noexcept -> void {
95 constexpr static auto sizeBytes = sizeof(SampleType) * N;
96 std::memcpy(m_working.data(), x.data(), sizeBytes);
97 for (size_t i = 0; i < m_vecSize; i += m_simdSize) {
98 const auto& a0 = xsimd::load_aligned(&m_a0[i]);
99 const auto& x0 = xsimd::load_aligned(&m_working[i]);
100 const auto a0x0 = a0 * x0;
101 const auto& a1 = xsimd::load_aligned(&m_a1[i]);
102 const auto& x1 = xsimd::load_aligned(&m_x1[i]);
103 const auto a1x1 = a1 * x1;
104 const auto& a2 = xsimd::load_aligned(&m_a2[i]);
105 const auto& x2 = xsimd::load_aligned(&m_x2[i]);
106 const auto a2x2 = a2 * x2;
107 const auto& b1 = xsimd::load_aligned(&m_b1[i]);
108 const auto& y1 = xsimd::load_aligned(&m_y1[i]);
109 const auto b1y1 = b1 * y1;
110 const auto& b2 = xsimd::load_aligned(&m_b2[i]);
111 const auto& y2 = xsimd::load_aligned(&m_y2[i]);
112 const auto b2y2 = b2 * y2;
113 const auto res = a0x0 + a1x1 + a2x2 - b1y1 - b2y2;
114 x1.store_aligned(&m_x2[i]);
115 x0.store_aligned(&m_x1[i]);
116 y1.store_aligned(&m_y2[i]);
117 res.store_aligned(&m_y1[i]);
118 }
119
120 for (size_t i = m_vecSize; i < N; ++i) {
121 const auto res = (m_a0[i] * m_working[i]) + (m_a1[i] * m_x1[i]) + (m_a2[i] * m_x2[i]) - (m_b1[i] * m_y1[i]) - (m_b2[i] * m_y2[i]);
122 m_x2[i] = m_x1[i];
123 m_x1[i] = m_working[i];
124 m_y2[i] = m_y1[i];
125 m_y1[i] = res;
126 }
127 std::memcpy(x.data(), m_y1.data(), sizeBytes);
128 }
129
133 auto reset() noexcept -> void {
134 auto batch = xsimd::broadcast(0.0);
135 for (size_t i = 0; i < m_vecSize; i += m_simdSize) {
136 batch.store_aligned(&m_working[i]);
137 batch.store_aligned(&m_x1[i]);
138 batch.store_aligned(&m_x2[i]);
139 batch.store_aligned(&m_y1[i]);
140 batch.store_aligned(&m_y2[i]);
141 }
142 for (size_t i = m_vecSize; i < N; ++i) {
143 m_working[i] = 0.0;
144 m_x1[i] = 0.0;
145 m_x2[i] = 0.0;
146 m_y1[i] = 0.0;
147 m_y2[i] = 0.0;
148 }
149 }
150
151 private:
152 constexpr static auto m_simdSize = xsimd::simd_type<SampleType>::size;
153 constexpr static auto m_vecSize = N - N % m_simdSize;
154 bool m_equalCoeffs{ false };
155 std::vector<SampleType, xsimd::aligned_allocator<SampleType>> m_working;
156 std::vector<SampleType, xsimd::aligned_allocator<SampleType>> m_a0, m_a1, m_a2, m_b1, m_b2;
157 std::vector<SampleType, xsimd::aligned_allocator<SampleType>> m_x1, m_x2, m_y1, m_y2;
158 };
159
160
161} // namespace marvin::dsp::filters
162#endif // MARVIN_SIMDBIQUAD_H
auto setCoeffs(size_t index, BiquadCoefficients< SampleType > coeffs) noexcept -> void
Definition marvin_SIMDBiquad.h:80
auto setCoeffs(BiquadCoefficients< SampleType > coeffs) noexcept -> void
Definition marvin_SIMDBiquad.h:46
SIMDBiquad()
Definition marvin_SIMDBiquad.h:28
auto reset() noexcept -> void
Definition marvin_SIMDBiquad.h:133
auto operator()(std::span< SampleType, N > x) noexcept -> void
Definition marvin_SIMDBiquad.h:94
Digital filter functions and classes.
Definition marvin_SVF.h:15
A POD type for use with the Biquad class, and the SmoothedBiquadCoefficients class.
Definition marvin_BiquadCoefficients.h:22