Pulp 1.88.0
Cross-platform audio plugin framework
Loading...
Searching...
No Matches
filter_design.hpp
Go to the documentation of this file.
1#pragma once
2
5
7#include <vector>
8#include <cmath>
9
10namespace pulp::signal {
11
31
38
39 // ── Standard biquad types (Audio EQ Cookbook) ────────────────────────
40
41 static Coefficients lowpass(float freq_hz, float Q, float sample_rate) {
42 auto [w0, alpha] = compute_w0_alpha(freq_hz, Q, sample_rate);
43 float cos_w0 = std::cos(w0);
44 float a0 = 1.0f + alpha;
45 return normalize(a0, {
46 (1.0f - cos_w0) / 2.0f,
47 1.0f - cos_w0,
48 (1.0f - cos_w0) / 2.0f,
49 -2.0f * cos_w0,
50 1.0f - alpha
51 });
52 }
53
54 static Coefficients highpass(float freq_hz, float Q, float sample_rate) {
55 auto [w0, alpha] = compute_w0_alpha(freq_hz, Q, sample_rate);
56 float cos_w0 = std::cos(w0);
57 float a0 = 1.0f + alpha;
58 return normalize(a0, {
59 (1.0f + cos_w0) / 2.0f,
60 -(1.0f + cos_w0),
61 (1.0f + cos_w0) / 2.0f,
62 -2.0f * cos_w0,
63 1.0f - alpha
64 });
65 }
66
67 static Coefficients bandpass(float freq_hz, float Q, float sample_rate) {
68 auto [w0, alpha] = compute_w0_alpha(freq_hz, Q, sample_rate);
69 float cos_w0 = std::cos(w0);
70 float a0 = 1.0f + alpha;
71 return normalize(a0, {
72 alpha,
73 0.0f,
74 -alpha,
75 -2.0f * cos_w0,
76 1.0f - alpha
77 });
78 }
79
80 static Coefficients notch(float freq_hz, float Q, float sample_rate) {
81 auto [w0, alpha] = compute_w0_alpha(freq_hz, Q, sample_rate);
82 float cos_w0 = std::cos(w0);
83 float a0 = 1.0f + alpha;
84 return normalize(a0, {
85 1.0f,
86 -2.0f * cos_w0,
87 1.0f,
88 -2.0f * cos_w0,
89 1.0f - alpha
90 });
91 }
92
93 static Coefficients allpass(float freq_hz, float Q, float sample_rate) {
94 auto [w0, alpha] = compute_w0_alpha(freq_hz, Q, sample_rate);
95 float cos_w0 = std::cos(w0);
96 float a0 = 1.0f + alpha;
97 return normalize(a0, {
98 1.0f - alpha,
99 -2.0f * cos_w0,
100 1.0f + alpha,
101 -2.0f * cos_w0,
102 1.0f - alpha
103 });
104 }
105
108 static Coefficients peaking_eq(float freq_hz, float Q, float gain_db, float sample_rate) {
109 auto [w0, alpha] = compute_w0_alpha(freq_hz, Q, sample_rate);
110 float A = std::pow(10.0f, gain_db / 40.0f);
111 float cos_w0 = std::cos(w0);
112 float a0 = 1.0f + alpha / A;
113 return normalize(a0, {
114 1.0f + alpha * A,
115 -2.0f * cos_w0,
116 1.0f - alpha * A,
117 -2.0f * cos_w0,
118 1.0f - alpha / A
119 });
120 }
121
123 static Coefficients low_shelf(float freq_hz, float gain_db, float sample_rate, float S = 1.0f) {
124 constexpr float pi_value = 3.14159265358979323846f;
125 float A = std::pow(10.0f, gain_db / 40.0f);
126 float w0 = 2.0f * pi_value * freq_hz / sample_rate;
127 float cos_w0 = std::cos(w0);
128 float alpha = std::sin(w0) / 2.0f * std::sqrt((A + 1.0f / A) * (1.0f / S - 1.0f) + 2.0f);
129 float sqrtA2alpha = 2.0f * std::sqrt(A) * alpha;
130 float a0 = (A + 1.0f) + (A - 1.0f) * cos_w0 + sqrtA2alpha;
131 return normalize(a0, {
132 A * ((A + 1.0f) - (A - 1.0f) * cos_w0 + sqrtA2alpha),
133 2.0f * A * ((A - 1.0f) - (A + 1.0f) * cos_w0),
134 A * ((A + 1.0f) - (A - 1.0f) * cos_w0 - sqrtA2alpha),
135 -2.0f * ((A - 1.0f) + (A + 1.0f) * cos_w0),
136 (A + 1.0f) + (A - 1.0f) * cos_w0 - sqrtA2alpha
137 });
138 }
139
141 static Coefficients high_shelf(float freq_hz, float gain_db, float sample_rate, float S = 1.0f) {
142 constexpr float pi_value = 3.14159265358979323846f;
143 float A = std::pow(10.0f, gain_db / 40.0f);
144 float w0 = 2.0f * pi_value * freq_hz / sample_rate;
145 float cos_w0 = std::cos(w0);
146 float alpha = std::sin(w0) / 2.0f * std::sqrt((A + 1.0f / A) * (1.0f / S - 1.0f) + 2.0f);
147 float sqrtA2alpha = 2.0f * std::sqrt(A) * alpha;
148 float a0 = (A + 1.0f) - (A - 1.0f) * cos_w0 + sqrtA2alpha;
149 return normalize(a0, {
150 A * ((A + 1.0f) + (A - 1.0f) * cos_w0 + sqrtA2alpha),
151 -2.0f * A * ((A - 1.0f) + (A + 1.0f) * cos_w0),
152 A * ((A + 1.0f) + (A - 1.0f) * cos_w0 - sqrtA2alpha),
153 2.0f * ((A - 1.0f) - (A + 1.0f) * cos_w0),
154 (A + 1.0f) - (A - 1.0f) * cos_w0 - sqrtA2alpha
155 });
156 }
157
158 // ── High-order Butterworth via cascaded biquads ─────────────────────
159
163 static std::vector<Coefficients> butterworth_lowpass(int order, float freq_hz, float sample_rate) {
164 int num_sections = order / 2;
165 std::vector<Coefficients> result;
166 result.reserve(static_cast<size_t>(num_sections));
167 constexpr float pi_value = 3.14159265358979323846f;
168
169 for (int k = 0; k < num_sections; ++k) {
170 // Q for each section of Butterworth cascade
171 float angle = pi_value * (2.0f * static_cast<float>(k) + 1.0f) / (2.0f * static_cast<float>(order));
172 float Q = 1.0f / (2.0f * std::cos(angle));
173 result.push_back(lowpass(freq_hz, Q, sample_rate));
174 }
175 return result;
176 }
177
179 static std::vector<Coefficients> butterworth_highpass(int order, float freq_hz, float sample_rate) {
180 int num_sections = order / 2;
181 std::vector<Coefficients> result;
182 result.reserve(static_cast<size_t>(num_sections));
183 constexpr float pi_value = 3.14159265358979323846f;
184
185 for (int k = 0; k < num_sections; ++k) {
186 float angle = pi_value * (2.0f * static_cast<float>(k) + 1.0f) / (2.0f * static_cast<float>(order));
187 float Q = 1.0f / (2.0f * std::cos(angle));
188 result.push_back(highpass(freq_hz, Q, sample_rate));
189 }
190 return result;
191 }
192
193private:
194 static constexpr float pi = 3.14159265358979323846f;
195
196 struct W0Alpha { float w0; float alpha; };
197
198 static W0Alpha compute_w0_alpha(float freq_hz, float Q, float sample_rate) {
199 float w0 = 2.0f * pi * freq_hz / sample_rate;
200 float alpha = std::sin(w0) / (2.0f * Q);
201 return {w0, alpha};
202 }
203
204 static Coefficients normalize(float a0, Coefficients raw) {
205 float inv = 1.0f / a0;
206 return {
207 raw.b0 * inv, raw.b1 * inv, raw.b2 * inv,
208 raw.a1 * inv, raw.a2 * inv
209 };
210 }
211};
212
213} // namespace pulp::signal
Definition additive_bank.hpp:218
BiquadCoefficientsT< float > BiquadCoefficients
Definition biquad.hpp:29
Filter coefficient generation utilities.
Definition filter_design.hpp:30
static Coefficients allpass(float freq_hz, float Q, float sample_rate)
Definition filter_design.hpp:93
static Coefficients highpass(float freq_hz, float Q, float sample_rate)
Definition filter_design.hpp:54
static Coefficients peaking_eq(float freq_hz, float Q, float gain_db, float sample_rate)
Peaking EQ filter.
Definition filter_design.hpp:108
static std::vector< Coefficients > butterworth_highpass(int order, float freq_hz, float sample_rate)
Generate cascaded biquad coefficients for an Nth-order Butterworth highpass.
Definition filter_design.hpp:179
static Coefficients bandpass(float freq_hz, float Q, float sample_rate)
Definition filter_design.hpp:67
static std::vector< Coefficients > butterworth_lowpass(int order, float freq_hz, float sample_rate)
Generate cascaded biquad coefficients for an Nth-order Butterworth lowpass.
Definition filter_design.hpp:163
static Coefficients notch(float freq_hz, float Q, float sample_rate)
Definition filter_design.hpp:80
static Coefficients high_shelf(float freq_hz, float gain_db, float sample_rate, float S=1.0f)
High shelf filter.
Definition filter_design.hpp:141
static Coefficients low_shelf(float freq_hz, float gain_db, float sample_rate, float S=1.0f)
Low shelf filter.
Definition filter_design.hpp:123
static Coefficients lowpass(float freq_hz, float Q, float sample_rate)
Definition filter_design.hpp:41
BiquadCoefficients Coefficients
Biquad coefficient set (normalized: a0 = 1).
Definition filter_design.hpp:37