VCV Rack API v2
Loading...
Searching...
No Matches
filter.hpp
Go to the documentation of this file.
1#pragma once
2#include <dsp/common.hpp>
3
4
5namespace rack {
6namespace dsp {
7
8
13template <typename T = float>
14struct TRCFilter {
15 T c = 0.f;
16 T xstate[1];
17 T ystate[1];
18
20 reset();
21 }
22
23 void reset() {
24 xstate[0] = 0.f;
25 ystate[0] = 0.f;
26 }
27
30 void setCutoff(T r) {
31 c = 2.f / r;
32 }
36 void setCutoffFreq(T f) {
37 setCutoff(2.f * M_PI * f);
38 }
39 void process(T x) {
40 T y = (x + xstate[0] - ystate[0] * (1 - c)) / (1 + c);
41 xstate[0] = x;
42 ystate[0] = y;
43 }
44 T lowpass() {
45 return ystate[0];
46 }
48 return xstate[0] - ystate[0];
49 }
50};
51
53
54
58template <typename T = float>
60 T out = 0.f;
61 T lambda = 0.f;
62
63 void reset() {
64 out = 0.f;
65 }
66
67 void setLambda(T lambda) {
68 this->lambda = lambda;
69 }
70
72 void setTau(T tau) {
73 this->lambda = 1 / tau;
74 }
75
76 T process(T deltaTime, T in) {
77 T y = out + (in - out) * lambda * deltaTime;
78 // If no change was made between the old and new output, assume T granularity is too small and snap output to input
79 out = simd::ifelse(out == y, in, y);
80 return out;
81 }
82
84 return process(1.f, in);
85 }
86};
87
89
90
93template <typename T = float>
95 T out = 0.f;
96 T lambda = 0.f;
97
98 void reset() {
99 out = 0.f;
100 }
101
103 this->lambda = lambda;
104 }
105
106 void setTau(T tau) {
107 this->lambda = 1 / tau;
108 }
109
110 T process(T deltaTime, T in) {
111 T y = out + (in - out) * lambda * deltaTime;
112 out = simd::fmax(y, in);
113 return out;
114 }
117 return out;
118 }
120 DEPRECATED void setRate(T r) {
121 lambda = 1.f - r;
122 }
124 return process(1.f, x);
125 }
126};
127
129
130
132template <typename T = float>
134 T out = 0.f;
135 T rise = 0.f;
136 T fall = 0.f;
137
138 void reset() {
139 out = 0.f;
140 }
141
142 void setRiseFall(T rise, T fall) {
143 this->rise = rise;
144 this->fall = fall;
145 }
146 T process(T deltaTime, T in) {
147 out = simd::clamp(in, out - fall * deltaTime, out + rise * deltaTime);
148 return out;
149 }
151 return process(1.f, in);
152 }
153};
154
156
157
159template <typename T = float>
161 T out = 0.f;
162 T riseLambda = 0.f;
163 T fallLambda = 0.f;
164
165 void reset() {
166 out = 0.f;
167 }
168
170 this->riseLambda = riseLambda;
171 this->fallLambda = fallLambda;
172 }
173 void setRiseFallTau(T riseTau, T fallTau) {
174 this->riseLambda = 1 / riseTau;
175 this->fallLambda = 1 / fallTau;
176 }
177 T process(T deltaTime, T in) {
178 T lambda = simd::ifelse(in > out, riseLambda, fallLambda);
179 T y = out + (in - out) * lambda * deltaTime;
180 // If the change from the old out to the new out is too small for floats, set `in` directly.
181 out = simd::ifelse(out == y, in, y);
182 return out;
183 }
185 return process(1.f, in);
186 }
187};
188
190
191
195template <int B_ORDER, int A_ORDER, typename T = float>
196struct IIRFilter {
199 T b[B_ORDER] = {};
203 T a[A_ORDER - 1] = {};
209 T x[B_ORDER - 1];
211 T y[A_ORDER - 1];
212
214 reset();
215 }
216
217 void reset() {
218 for (int i = 1; i < B_ORDER; i++) {
219 x[i - 1] = 0.f;
220 }
221 for (int i = 1; i < A_ORDER; i++) {
222 y[i - 1] = 0.f;
223 }
224 }
225
226 void setCoefficients(const T* b, const T* a) {
227 for (int i = 0; i < B_ORDER; i++) {
228 this->b[i] = b[i];
229 }
230 for (int i = 1; i < A_ORDER; i++) {
231 this->a[i - 1] = a[i - 1];
232 }
233 }
234
235 T process(T in) {
236 T out = 0.f;
237 // Add x state
238 if (0 < B_ORDER) {
239 out = b[0] * in;
240 }
241 for (int i = 1; i < B_ORDER; i++) {
242 out += b[i] * x[i - 1];
243 }
244 // Subtract y state
245 for (int i = 1; i < A_ORDER; i++) {
246 out -= a[i - 1] * y[i - 1];
247 }
248 // Shift x state
249 for (int i = B_ORDER - 1; i >= 2; i--) {
250 x[i - 1] = x[i - 2];
251 }
252 x[0] = in;
253 // Shift y state
254 for (int i = A_ORDER - 1; i >= 2; i--) {
255 y[i - 1] = y[i - 2];
256 }
257 y[0] = out;
258 return out;
259 }
260
264 std::complex<T> getTransferFunction(T s) {
265 // Compute sum(a_k z^-k) / sum(b_k z^-k) where z = e^(i s)
266 std::complex<T> bSum(b[0], 0);
267 std::complex<T> aSum(1, 0);
268 for (int i = 1; i < std::max(B_ORDER, A_ORDER); i++) {
269 T p = -i * s;
270 std::complex<T> z(simd::cos(p), simd::sin(p));
271 if (i < B_ORDER)
272 bSum += b[i] * z;
273 if (i < A_ORDER)
274 aSum += a[i - 1] * z;
275 }
276 return bSum / aSum;
277 }
278
280 // T hReal, hImag;
281 // getTransferFunction(2 * M_PI * f, &hReal, &hImag);
282 // return simd::hypot(hReal, hImag);
283 return simd::abs(getTransferFunction(2 * M_PI * f));
284 }
285
287 return simd::arg(getTransferFunction(2 * M_PI * f));
288 }
289};
290
291
292template <typename T = float>
293struct TBiquadFilter : IIRFilter<3, 3, T> {
306
308 setParameters(LOWPASS, 0.f, 0.f, 1.f);
309 }
310
316 void setParameters(Type type, float f, float Q, float V) {
317 float K = std::tan(M_PI * f);
318 switch (type) {
319 case LOWPASS_1POLE: {
320 this->a[0] = -std::exp(-2.f * M_PI * f);
321 this->a[1] = 0.f;
322 this->b[0] = 1.f + this->a[0];
323 this->b[1] = 0.f;
324 this->b[2] = 0.f;
325 } break;
326
327 case HIGHPASS_1POLE: {
328 this->a[0] = std::exp(-2.f * M_PI * (0.5f - f));
329 this->a[1] = 0.f;
330 this->b[0] = 1.f - this->a[0];
331 this->b[1] = 0.f;
332 this->b[2] = 0.f;
333 } break;
334
335 case LOWPASS: {
336 float norm = 1.f / (1.f + K / Q + K * K);
337 this->b[0] = K * K * norm;
338 this->b[1] = 2.f * this->b[0];
339 this->b[2] = this->b[0];
340 this->a[0] = 2.f * (K * K - 1.f) * norm;
341 this->a[1] = (1.f - K / Q + K * K) * norm;
342 } break;
343
344 case HIGHPASS: {
345 float norm = 1.f / (1.f + K / Q + K * K);
346 this->b[0] = norm;
347 this->b[1] = -2.f * this->b[0];
348 this->b[2] = this->b[0];
349 this->a[0] = 2.f * (K * K - 1.f) * norm;
350 this->a[1] = (1.f - K / Q + K * K) * norm;
351
352 } break;
353
354 case LOWSHELF: {
355 float sqrtV = std::sqrt(V);
356 if (V >= 1.f) {
357 float norm = 1.f / (1.f + M_SQRT2 * K + K * K);
358 this->b[0] = (1.f + M_SQRT2 * sqrtV * K + V * K * K) * norm;
359 this->b[1] = 2.f * (V * K * K - 1.f) * norm;
360 this->b[2] = (1.f - M_SQRT2 * sqrtV * K + V * K * K) * norm;
361 this->a[0] = 2.f * (K * K - 1.f) * norm;
362 this->a[1] = (1.f - M_SQRT2 * K + K * K) * norm;
363 }
364 else {
365 float norm = 1.f / (1.f + M_SQRT2 / sqrtV * K + K * K / V);
366 this->b[0] = (1.f + M_SQRT2 * K + K * K) * norm;
367 this->b[1] = 2.f * (K * K - 1) * norm;
368 this->b[2] = (1.f - M_SQRT2 * K + K * K) * norm;
369 this->a[0] = 2.f * (K * K / V - 1.f) * norm;
370 this->a[1] = (1.f - M_SQRT2 / sqrtV * K + K * K / V) * norm;
371 }
372 } break;
373
374 case HIGHSHELF: {
375 float sqrtV = std::sqrt(V);
376 if (V >= 1.f) {
377 float norm = 1.f / (1.f + M_SQRT2 * K + K * K);
378 this->b[0] = (V + M_SQRT2 * sqrtV * K + K * K) * norm;
379 this->b[1] = 2.f * (K * K - V) * norm;
380 this->b[2] = (V - M_SQRT2 * sqrtV * K + K * K) * norm;
381 this->a[0] = 2.f * (K * K - 1.f) * norm;
382 this->a[1] = (1.f - M_SQRT2 * K + K * K) * norm;
383 }
384 else {
385 float norm = 1.f / (1.f / V + M_SQRT2 / sqrtV * K + K * K);
386 this->b[0] = (1.f + M_SQRT2 * K + K * K) * norm;
387 this->b[1] = 2.f * (K * K - 1.f) * norm;
388 this->b[2] = (1.f - M_SQRT2 * K + K * K) * norm;
389 this->a[0] = 2.f * (K * K - 1.f / V) * norm;
390 this->a[1] = (1.f / V - M_SQRT2 / sqrtV * K + K * K) * norm;
391 }
392 } break;
393
394 case BANDPASS: {
395 float norm = 1.f / (1.f + K / Q + K * K);
396 this->b[0] = K / Q * norm;
397 this->b[1] = 0.f;
398 this->b[2] = -this->b[0];
399 this->a[0] = 2.f * (K * K - 1.f) * norm;
400 this->a[1] = (1.f - K / Q + K * K) * norm;
401 } break;
402
403 case PEAK: {
404 if (V >= 1.f) {
405 float norm = 1.f / (1.f + K / Q + K * K);
406 this->b[0] = (1.f + K / Q * V + K * K) * norm;
407 this->b[1] = 2.f * (K * K - 1.f) * norm;
408 this->b[2] = (1.f - K / Q * V + K * K) * norm;
409 this->a[0] = this->b[1];
410 this->a[1] = (1.f - K / Q + K * K) * norm;
411 }
412 else {
413 float norm = 1.f / (1.f + K / Q / V + K * K);
414 this->b[0] = (1.f + K / Q + K * K) * norm;
415 this->b[1] = 2.f * (K * K - 1.f) * norm;
416 this->b[2] = (1.f - K / Q + K * K) * norm;
417 this->a[0] = this->b[1];
418 this->a[1] = (1.f - K / Q / V + K * K) * norm;
419 }
420 } break;
421
422 case NOTCH: {
423 float norm = 1.f / (1.f + K / Q + K * K);
424 this->b[0] = (1.f + K * K) * norm;
425 this->b[1] = 2.f * (K * K - 1.f) * norm;
426 this->b[2] = this->b[0];
427 this->a[0] = this->b[1];
428 this->a[1] = (1.f - K / Q + K * K) * norm;
429 } break;
430
431 default: break;
432 }
433 }
434};
435
437
438
439} // namespace dsp
440} // namespace rack
#define DEPRECATED
Attribute for deprecated functions and symbols.
Definition common.hpp:24
TBiquadFilter BiquadFilter
Definition filter.hpp:436
TSlewLimiter SlewLimiter
Definition filter.hpp:155
TExponentialSlewLimiter ExponentialSlewLimiter
Definition filter.hpp:189
TRCFilter RCFilter
Definition filter.hpp:52
TPeakFilter PeakFilter
Definition filter.hpp:128
TExponentialFilter ExponentialFilter
Definition filter.hpp:88
float_4 arg(std::complex< float_4 > a)
Definition functions.hpp:222
float_4 abs(float_4 a)
Definition functions.hpp:212
float_4 fmax(float_4 x, float_4 b)
Definition functions.hpp:91
float_4 clamp(float_4 x, float_4 a=0.f, float_4 b=1.f)
Definition functions.hpp:252
float ifelse(bool cond, float a, float b)
Definition functions.hpp:50
Root namespace for the Rack API.
Definition AudioDisplay.hpp:9
Digital IIR filter processor.
Definition filter.hpp:196
IIRFilter()
Definition filter.hpp:213
T x[B_ORDER - 1]
input state x[0] = x_{n-1} x[1] = x_{n-2} etc.
Definition filter.hpp:209
T process(T in)
Definition filter.hpp:235
T getFrequencyPhase(T f)
Definition filter.hpp:286
T y[A_ORDER - 1]
output state
Definition filter.hpp:211
std::complex< T > getTransferFunction(T s)
Computes the complex transfer function $H(s)$ at a particular frequency s: normalized angular frequen...
Definition filter.hpp:264
T getFrequencyResponse(T f)
Definition filter.hpp:279
T b[B_ORDER]
transfer function numerator coefficients: b_0, b_1, etc.
Definition filter.hpp:199
T a[A_ORDER - 1]
transfer function denominator coefficients: a_1, a_2, etc.
Definition filter.hpp:203
void setCoefficients(const T *b, const T *a)
Definition filter.hpp:226
void reset()
Definition filter.hpp:217
Definition filter.hpp:293
TBiquadFilter()
Definition filter.hpp:307
Type
Definition filter.hpp:294
@ HIGHSHELF
Definition filter.hpp:300
@ NUM_TYPES
Definition filter.hpp:304
@ NOTCH
Definition filter.hpp:303
@ LOWPASS
Definition filter.hpp:297
@ BANDPASS
Definition filter.hpp:301
@ HIGHPASS
Definition filter.hpp:298
@ PEAK
Definition filter.hpp:302
@ LOWSHELF
Definition filter.hpp:299
@ HIGHPASS_1POLE
Definition filter.hpp:296
@ LOWPASS_1POLE
Definition filter.hpp:295
void setParameters(Type type, float f, float Q, float V)
Calculates and sets the biquad transfer function coefficients.
Definition filter.hpp:316
Applies exponential smoothing to a signal with the ODE .
Definition filter.hpp:59
T lambda
Definition filter.hpp:61
T process(T deltaTime, T in)
Definition filter.hpp:76
void setLambda(T lambda)
Definition filter.hpp:67
DEPRECATED T process(T in)
Definition filter.hpp:83
void setTau(T tau)
Sets .
Definition filter.hpp:72
void reset()
Definition filter.hpp:63
T out
Definition filter.hpp:60
Behaves like ExponentialFilter but with different lambas when the RHS of the ODE is positive or negat...
Definition filter.hpp:160
T out
Definition filter.hpp:161
T fallLambda
Definition filter.hpp:163
void reset()
Definition filter.hpp:165
void setRiseFall(T riseLambda, T fallLambda)
Definition filter.hpp:169
void setRiseFallTau(T riseTau, T fallTau)
Definition filter.hpp:173
DEPRECATED T process(T in)
Definition filter.hpp:184
T riseLambda
Definition filter.hpp:162
T process(T deltaTime, T in)
Definition filter.hpp:177
Like ExponentialFilter but jumps immediately to higher values.
Definition filter.hpp:94
DEPRECATED T process(T x)
Definition filter.hpp:123
T out
Definition filter.hpp:95
DEPRECATED T peak()
Use the return value of process() instead.
Definition filter.hpp:116
T lambda
Definition filter.hpp:96
void setTau(T tau)
Definition filter.hpp:106
void setLambda(T lambda)
Definition filter.hpp:102
T process(T deltaTime, T in)
Definition filter.hpp:110
void reset()
Definition filter.hpp:98
DEPRECATED void setRate(T r)
Use setLambda() instead.
Definition filter.hpp:120
The simplest possible analog filter using an Euler solver.
Definition filter.hpp:14
T ystate[1]
Definition filter.hpp:17
T xstate[1]
Definition filter.hpp:16
T c
Definition filter.hpp:15
void reset()
Definition filter.hpp:23
T lowpass()
Definition filter.hpp:44
void setCutoff(T r)
Sets the cutoff angular frequency in radians.
Definition filter.hpp:30
void process(T x)
Definition filter.hpp:39
TRCFilter()
Definition filter.hpp:19
void setCutoffFreq(T f)
Sets the cutoff frequency.
Definition filter.hpp:36
T highpass()
Definition filter.hpp:47
Limits the derivative of the output by a rise and fall speed, in units/s.
Definition filter.hpp:133
void setRiseFall(T rise, T fall)
Definition filter.hpp:142
DEPRECATED T process(T in)
Definition filter.hpp:150
T out
Definition filter.hpp:134
T fall
Definition filter.hpp:136
void reset()
Definition filter.hpp:138
T rise
Definition filter.hpp:135
T process(T deltaTime, T in)
Definition filter.hpp:146