54 static_assert(std::is_floating_point_v<SampleType>,
55 "BiquadT requires a floating-point sample type");
70 b0_ =
static_cast<SampleType
>(
c.b0);
71 b1_ =
static_cast<SampleType
>(
c.b1);
72 b2_ =
static_cast<SampleType
>(
c.b2);
73 a1_ =
static_cast<SampleType
>(
c.a1);
74 a2_ =
static_cast<SampleType
>(
c.a2);
87 SampleType sample_rate,
88 SampleType gain_db = SampleType{0}) {
98 if (!(std::isfinite(sample_rate) && sample_rate > SampleType{0}))
99 sample_rate = SampleType{44100};
100 if (!(std::isfinite(q) && q > SampleType{0}))
101 q = SampleType{1e-4f};
102 if (!std::isfinite(gain_db)) gain_db = SampleType{0};
103 if (!(std::isfinite(freq_hz) && freq_hz > SampleType{0}))
104 freq_hz = SampleType{1000};
105 freq_hz = std::min(freq_hz, sample_rate * SampleType{0.49});
107 SampleType w0 = SampleType{2} * pi * freq_hz / sample_rate;
108 SampleType cos_w0 = std::cos(w0);
109 SampleType sin_w0 = std::sin(w0);
110 SampleType
alpha = sin_w0 / (SampleType{2} *
q);
112 SampleType a0 = SampleType{1};
113 SampleType a1 = SampleType{0};
114 SampleType a2 = SampleType{0};
115 SampleType b0 = SampleType{1};
116 SampleType b1 = SampleType{0};
117 SampleType b2 = SampleType{0};
121 b0 = (SampleType{1} - cos_w0) / SampleType{2};
122 b1 = SampleType{1} - cos_w0;
123 b2 = (SampleType{1} - cos_w0) / SampleType{2};
124 a0 = SampleType{1} +
alpha;
125 a1 = -SampleType{2} * cos_w0;
126 a2 = SampleType{1} -
alpha;
130 b0 = (SampleType{1} + cos_w0) / SampleType{2};
131 b1 = -(SampleType{1} + cos_w0);
132 b2 = (SampleType{1} + cos_w0) / SampleType{2};
133 a0 = SampleType{1} +
alpha;
134 a1 = -SampleType{2} * cos_w0;
135 a2 = SampleType{1} -
alpha;
142 a0 = SampleType{1} +
alpha;
143 a1 = -SampleType{2} * cos_w0;
144 a2 = SampleType{1} -
alpha;
149 b1 = -SampleType{2} * cos_w0;
151 a0 = SampleType{1} +
alpha;
152 a1 = -SampleType{2} * cos_w0;
153 a2 = SampleType{1} -
alpha;
157 b0 = SampleType{1} -
alpha;
158 b1 = -SampleType{2} * cos_w0;
159 b2 = SampleType{1} +
alpha;
160 a0 = SampleType{1} +
alpha;
161 a1 = -SampleType{2} * cos_w0;
162 a2 = SampleType{1} -
alpha;
166 SampleType A = std::pow(SampleType{10}, gain_db / SampleType{40});
167 b0 = SampleType{1} +
alpha * A;
168 b1 = -SampleType{2} * cos_w0;
169 b2 = SampleType{1} -
alpha * A;
170 a0 = SampleType{1} +
alpha / A;
171 a1 = -SampleType{2} * cos_w0;
172 a2 = SampleType{1} -
alpha / A;
177 SampleType A = std::pow(SampleType{10}, gain_db / SampleType{40});
178 SampleType two_sqrt_a_alpha = SampleType{2} * std::sqrt(A) *
alpha;
179 b0 = A * ((A + SampleType{1}) - (A - SampleType{1}) * cos_w0 + two_sqrt_a_alpha);
180 b1 = SampleType{2} * A * ((A - SampleType{1}) - (A + SampleType{1}) * cos_w0);
181 b2 = A * ((A + SampleType{1}) - (A - SampleType{1}) * cos_w0 - two_sqrt_a_alpha);
182 a0 = (A + SampleType{1}) + (A - SampleType{1}) * cos_w0 + two_sqrt_a_alpha;
183 a1 = -SampleType{2} * ((A - SampleType{1}) + (A + SampleType{1}) * cos_w0);
184 a2 = (A + SampleType{1}) + (A - SampleType{1}) * cos_w0 - two_sqrt_a_alpha;
189 SampleType A = std::pow(SampleType{10}, gain_db / SampleType{40});
190 SampleType two_sqrt_a_alpha = SampleType{2} * std::sqrt(A) *
alpha;
191 b0 = A * ((A + SampleType{1}) + (A - SampleType{1}) * cos_w0 + two_sqrt_a_alpha);
192 b1 = -SampleType{2} * A * ((A - SampleType{1}) + (A + SampleType{1}) * cos_w0);
193 b2 = A * ((A + SampleType{1}) + (A - SampleType{1}) * cos_w0 - two_sqrt_a_alpha);
194 a0 = (A + SampleType{1}) - (A - SampleType{1}) * cos_w0 + two_sqrt_a_alpha;
195 a1 = SampleType{2} * ((A - SampleType{1}) - (A + SampleType{1}) * cos_w0);
196 a2 = (A + SampleType{1}) - (A - SampleType{1}) * cos_w0 - two_sqrt_a_alpha;
212 SampleType output = b0_ * input + s1_;
218 history_valid_ =
false;
266 if (num_samples <= 0)
268 dispatch_fixed<1>(
this,
nullptr,
buffer,
nullptr,
static_cast<std::size_t
>(num_samples));
279 SampleType* right_buffer, std::size_t num_samples) {
280 if (num_samples == 0)
283 dispatch_fixed<1>(&
left,
nullptr, left_buffer,
nullptr, num_samples);
284 dispatch_fixed<1>(&
left,
nullptr, right_buffer,
nullptr, num_samples);
291 dispatch_fixed<1>(&
left,
nullptr, left_buffer,
nullptr, num_samples);
292 dispatch_fixed<1>(&
right,
nullptr, right_buffer,
nullptr, num_samples);
295 dispatch_fixed<1>(&
left, &
right, left_buffer, right_buffer, num_samples);
321 std::size_t num_samples)
noexcept {
324 dispatch_pass(n, sections +
first,
nullptr,
buffer,
nullptr, num_samples);
335 SampleType* left_buffer, SampleType* right_buffer,
336 std::size_t num_samples)
noexcept {
350 dispatch_pass(n,
left +
first,
nullptr, left_buffer,
nullptr, num_samples);
351 dispatch_pass(n,
right +
first,
nullptr, right_buffer,
nullptr, num_samples);
380 hx1_ = hx2_ = hy1_ = hy2_ = 0.0;
381 history_valid_ =
true;
385 enum class BlockForm { sample_order, feedback_last, wide_df1 };
389 static BlockForm pass_form(
const BiquadT* sections, std::size_t count)
noexcept {
390 if constexpr (std::is_same_v<SampleType, float>) {
392 return BlockForm::wide_df1;
394 for (std::size_t k = 0; k < count; ++k)
395 if (sections[k].sample_path_order_in_block_)
396 return BlockForm::sample_order;
397 return BlockForm::feedback_last;
403 SampleType* left_buffer, SampleType* right_buffer,
404 std::size_t num_samples)
noexcept {
406 dispatch_fixed<decltype(sections)::value>(
left,
right, left_buffer, right_buffer,
411 template <std::
size_t Count>
413 SampleType* right_buffer, std::size_t num_samples)
noexcept {
414 BlockForm form = pass_form(
left, Count);
416 if (form == BlockForm::wide_df1) {
421 const bool left_ok = prepare_histories<Count>(
left);
422 const bool right_ok =
right ==
nullptr || prepare_histories<Count>(
right);
423 if (left_ok && right_ok) {
424 run_pass_lanes<Count, BlockForm::wide_df1>(
left,
right, left_buffer,
425 right_buffer, num_samples);
428 if (
right !=
nullptr) {
429 run_channel_df1_or_sample_order<Count>(
left, left_buffer, num_samples, left_ok);
430 run_channel_df1_or_sample_order<Count>(
right, right_buffer, num_samples,
434 form = BlockForm::sample_order;
437 if (form == BlockForm::feedback_last)
438 run_pass_lanes<Count, BlockForm::feedback_last>(
left,
right, left_buffer, right_buffer,
441 run_pass_lanes<Count, BlockForm::sample_order>(
left,
right, left_buffer, right_buffer,
445 template <std::
size_t Count>
static bool prepare_histories(
BiquadT* sections)
noexcept {
447 for (std::size_t k = 0;
k <
Count; ++
k)
448 ok = sections[k].prepare_history() &&
ok;
452 template <std::
size_t Count>
453 static void run_channel_df1_or_sample_order(
BiquadT* sections, SampleType*
buffer,
454 std::size_t num_samples,
bool df1)
noexcept {
456 run_pass_lanes<Count, BlockForm::wide_df1>(sections,
nullptr,
buffer,
nullptr,
459 run_pass_lanes<Count, BlockForm::sample_order>(sections,
nullptr,
buffer,
nullptr,
466 template <std::
size_t Count, BlockForm Form>
468 SampleType* right_buffer, std::size_t num_samples)
noexcept {
469 if (
right ==
nullptr) {
471 SampleType* buffers[1] = {left_buffer};
472 run_pass<Count, Form, 1>(filters, buffers, num_samples);
477 SampleType* buffers[2] = {left_buffer, right_buffer};
478 run_pass<Count, Form, 2>(filters, buffers, num_samples);
481 SampleType* buffers[2] = {left_buffer, right_buffer};
482 for (std::size_t lane = 0; lane < 2; ++lane)
483 run_pass<Count, Form, 1>(filters + lane, buffers + lane, num_samples);
489 template <BlockForm Form>
490 using PassElement = std::conditional_t<Form == BlockForm::wide_df1, double, SampleType>;
492 template <
typename E, std::
size_t W
idth>
struct PassLanes {
495#if PULP_SIMD_HAS_VECTOR_LANES
496 template <
typename E>
struct PassLanes<E, 2> {
497 using type = simd::Lanes<E, 2>;
510 template <BlockForm Form,
typename V>
511 static V step(V x, V b0, V b1, V b2, V a1, V a2, V& z0, V& z1, V& z2, V& z3)
noexcept {
512 if constexpr (Form == BlockForm::wide_df1) {
513 const V
feed = (b0 *
x + b1 * z0) + (b2 * z1 + a2 * z3);
514 const V
y = a1 * z2 +
feed;
520 }
else if constexpr (Form == BlockForm::feedback_last) {
523 const V
y = b0 *
x + z0;
524 const V t1 = b1 *
x + z1;
532 const V
y = b0 *
x + z0;
533 z0 = b1 *
x - a1 *
y + z1;
534 z1 = b2 *
x - a2 *
y;
540 template <
typename V>
static void snap_lanes(V& v)
noexcept {
541 for (std::size_t lane = 0; lane < simd::lane_count<V>; ++lane)
550 template <std::
size_t Count, BlockForm Form, std::
size_t W
idth>
551 static void run_pass(
BiquadT*
const* filters, SampleType*
const* buffers,
552 std::size_t num_samples)
noexcept {
553 using E = PassElement<Form>;
554 using V =
typename PassLanes<E, Width>::type;
555 constexpr bool df1 = Form == BlockForm::wide_df1;
558 for (std::size_t k = 0;
k <
Count; ++
k) {
559 for (std::size_t lane = 0; lane <
Width; ++lane) {
572 simd::set_lane(a1[k], lane, Form == BlockForm::feedback_last ? -
f.a1_ :
f.a1_);
580 for (
const auto [begin, end] :
snap_chunks(num_samples)) {
581 for (std::size_t
i = begin;
i <
end; ++
i) {
583 if constexpr (
Width == 1)
584 v =
static_cast<E
>(buffers[0][
i]);
586 v = V{
static_cast<E
>(buffers[0][
i]),
static_cast<E
>(buffers[1][
i])};
587 for (std::size_t k = 0;
k <
Count; ++
k)
588 v = step<Form>(v, b0[k], b1[k], b2[k], a1[k], a2[k], z0[k], z1[k], z2[k],
590 for (std::size_t lane = 0; lane <
Width; ++lane)
594 for (std::size_t k = 0;
k <
Count; ++
k) {
595 snap_lanes(df1 ? z2[k] : z0[k]);
596 snap_lanes(df1 ? z3[k] : z1[k]);
599 for (std::size_t k = 0;
k <
Count; ++
k) {
600 for (std::size_t lane = 0; lane <
Width; ++lane) {
608 f.history_valid_ =
false;
616 static constexpr double kMaxHistoryGain = 1.0e4;
630 bool prepare_history() noexcept {
633 const double b1 = b1_, b2 = b2_, a1 = a1_, a2 = a2_;
634 const double s1 = s1_, s2 = s2_;
635 const double m1 = std::max(std::abs(b2), std::abs(a2));
636 const double m2 = std::max({std::abs(b1), std::abs(b2), std::abs(a1), std::abs(a2)});
638 const std::array<double, 4>
q =
639 m2 > 0.0 ? std::array<double, 4>{b1 / m2, b2 / m2, -a1 / m2, -a2 / m2}
640 : std::array<double, 4>{};
641 const double t2 = m2 > 0.0 ? s1 / m2 : 0.0;
642 std::array<double, 4>
v{};
644 if (s1 != 0.0 || s2 != 0.0)
646 }
else if (m1 == 0.0) {
649 const double qq =
q[0] *
q[0] +
q[1] *
q[1] +
q[2] *
q[2] +
q[3] *
q[3];
650 for (std::size_t
i = 0;
i < 4; ++
i)
651 v[
i] = q[
i] * (t2 / qq);
653 const std::array<double, 4>
p{b2 / m1, 0.0, -a2 / m1, 0.0};
654 const double t1 = s2 / m1;
655 const double pp =
p[0] *
p[0] +
p[2] *
p[2];
656 const double qq =
q[0] *
q[0] +
q[1] *
q[1] +
q[2] *
q[2] +
q[3] *
q[3];
657 const double pq =
p[0] *
q[0] +
p[2] *
q[2];
658 const double det = pp * qq - pq * pq;
661 if (!(det > 1.0e-6 * pp * qq))
663 const double w1 = (qq * t1 - pq * t2) / det;
664 const double w2 = (pp * t2 - pq * t1) / det;
665 for (std::size_t
i = 0;
i < 4; ++
i)
666 v[
i] = p[
i] * w1 + q[
i] * w2;
673 const double state = std::max(std::abs(s1), std::abs(s2));
674 const double largest =
675 std::max({std::abs(v[0]), std::abs(v[1]), std::abs(v[2]), std::abs(v[3])});
676 if (!std::isfinite(largest) || largest > kMaxHistoryGain * state)
682 history_valid_ =
true;
688 void store_history(
double x1,
double x2,
double y1,
double y2)
noexcept {
693 const double b1 = b1_, b2 = b2_, a1 = a1_, a2 = a2_;
694 s2_ =
snap_to_zero(
static_cast<SampleType
>(b2 * x1 - a2 * y1));
695 s1_ =
snap_to_zero(
static_cast<SampleType
>(b1 * x1 - a1 * y1 + b2 * x2 - a2 * y2));
696 history_valid_ =
true;
701 void update_block_form() {
702 const double a1 =
static_cast<double>(a1_);
703 const double a2 =
static_cast<double>(a2_);
704 const double disc = a1 * a1 - 4.0 * a2;
707 radius = std::sqrt(a2);
709 const double root = std::sqrt(disc);
710 radius = std::max(std::abs(-a1 + root), std::abs(-a1 - root)) * 0.5;
716 history_valid_ =
false;
719 static constexpr SampleType pi =
720 std::is_same_v<SampleType, float>
721 ?
static_cast<SampleType
>(3.14159265358979323846f)
722 : static_cast<SampleType>(3.141592653589793238462643383279502884L);
724 SampleType b0_ = SampleType{1};
725 SampleType b1_ = SampleType{0};
726 SampleType b2_ = SampleType{0};
727 SampleType a1_ = SampleType{0};
728 SampleType a2_ = SampleType{0};
729 SampleType s1_ = SampleType{0};
730 SampleType s2_ = SampleType{0};
731 bool sample_path_order_in_block_ =
false;
734 double hx1_ = 0.0, hx2_ = 0.0, hy1_ = 0.0, hy2_ = 0.0;
735 bool history_valid_ =
true;