1use num_complex::Complex64;
2use num_traits::Float;
3use std::f64::consts::{PI, TAU};
4use thiserror::Error;
5
6#[derive(Error, Debug)]
7pub enum SvfError {
8 #[error("the sample rate must be set first")]
9 NoSampleRate,
10 #[error("the frequency is higher than nyqist")]
11 FrequencyOverNyqist,
12 #[error("the frequency is 0 or lower than 0")]
13 FrequencyTooLow,
14 #[error("q is lower than zero")]
15 NegativeQ,
16 #[error("fatal number conversion error")]
17 Fatal,
18}
19
20#[derive(Default, Clone, PartialEq, Eq)]
22pub enum FilterType {
23 #[default]
24 Lowpass,
25 Highpass,
26 Bandpass,
27 Notch,
28 Peak,
29 Allpass,
30 Bell,
31 Lowshelf,
32 Highshelf,
33}
34
35#[derive(Default)]
38pub struct Svf<F: Float> {
39 coefficients: SvfCoefficients<F>,
40 ic1eq: F,
41 ic2eq: F,
42}
43
44#[derive(Default, Clone, PartialEq, Eq)]
46pub struct SvfCoefficients<F: Float> {
47 filter_type: FilterType,
48 sample_rate: F,
49 cutoff: F,
50 gain: F,
51 q: F,
52 a1: F,
53 a2: F,
54 a3: F,
55 m0: F,
56 m1: F,
57 m2: F,
58}
59
60impl<F: Float + Default> Svf<F> {
61 pub fn new(
70 filter_type: FilterType,
71 sample_rate: F,
72 cutoff: F,
73 q: F,
74 gain: F,
75 ) -> Result<Self, SvfError> {
76 let mut svf = Self::default();
77 svf.set(filter_type, sample_rate, cutoff, q, gain)?;
78 Ok(svf)
79 }
80
81 #[inline]
83 pub fn process(&mut self, input: &[F], output: &mut [F]) {
84 output
85 .iter_mut()
86 .zip(input)
87 .for_each(|(out_sample, in_sample)| {
88 *out_sample = self.tick(*in_sample);
89 });
90 }
91
92 #[inline]
95 pub fn reset(&mut self) {
96 self.ic1eq = F::zero();
97 self.ic2eq = F::zero();
98 }
99
100 #[inline]
109 pub fn set(
110 &mut self,
111 filter_type: FilterType,
112 sample_rate: F,
113 cutoff: F,
114 q: F,
115 gain: F,
116 ) -> Result<(), SvfError> {
117 self.coefficients
118 .set(filter_type, sample_rate, cutoff, q, gain)
119 }
120
121 pub fn set_coeffs(&mut self, coefficients: SvfCoefficients<F>) {
123 self.coefficients = coefficients;
124 }
125
126 #[inline]
129 pub fn tick(&mut self, input: F) -> F {
130 let v0 = input;
131 let v3 = v0 - self.ic2eq;
132 let v1 = self.coefficients.a1 * self.ic1eq + self.coefficients.a2 * v3;
133 let v2 = self.ic2eq + self.coefficients.a2 * self.ic1eq + self.coefficients.a3 * v3;
134 let two = F::one() + F::one();
135 self.ic1eq = two * v1 - self.ic1eq;
136 self.ic2eq = two * v2 - self.ic2eq;
137
138 self.coefficients.m0 * v0 + self.coefficients.m1 * v1 + self.coefficients.m2 * v2
139 }
140
141 pub fn coefficients(&self) -> &SvfCoefficients<F> {
144 &self.coefficients
145 }
146
147 pub fn get_response(&self, frequency: f64) -> Result<Complex64, SvfError> {
150 SvfResponse::response(&self.coefficients, frequency)
151 }
152}
153
154impl<F: Float> SvfCoefficients<F> {
155 pub fn set(
164 &mut self,
165 filter_type: FilterType,
166 sample_rate: F,
167 cutoff_frequency: F,
168 q: F,
169 gain: F,
170 ) -> Result<(), SvfError> {
171 if q < F::zero() {
172 return Err(SvfError::NegativeQ);
173 }
174 if cutoff_frequency > sample_rate / F::from(2.0).unwrap() {
175 return Err(SvfError::FrequencyOverNyqist);
176 }
177 self.filter_type = filter_type;
178 self.sample_rate = sample_rate;
179 self.cutoff = cutoff_frequency;
180 self.q = q;
181 self.gain = gain;
182
183 match self.filter_type {
184 FilterType::Lowpass => {
185 let g =
186 F::tan(F::from(PI).ok_or(SvfError::Fatal)? * self.cutoff / self.sample_rate);
187 let k = F::one() / self.q;
188 self.a1 = F::one() / (F::one() + g * (g + k));
189 self.a2 = g * self.a1;
190 self.a3 = g * self.a2;
191 self.m0 = F::zero();
192 self.m1 = F::zero();
193 self.m2 = F::one();
194 }
195 FilterType::Highpass => {
196 let g =
197 F::tan(F::from(PI).ok_or(SvfError::Fatal)? * self.cutoff / self.sample_rate);
198 let k = F::one() / self.q;
199 self.a1 = F::one() / (F::one() + g * (g + k));
200 self.a2 = g * self.a1;
201 self.a3 = g * self.a2;
202 self.m0 = F::one();
203 self.m1 = -k;
204 self.m2 = -F::one();
205 }
206 FilterType::Bandpass => {
207 let g =
208 F::tan(F::from(PI).ok_or(SvfError::Fatal)? * self.cutoff / self.sample_rate);
209 let k = F::one() / self.q;
210 self.a1 = F::one() / (F::one() + g * (g + k));
211 self.a2 = g * self.a1;
212 self.a3 = g * self.a2;
213 self.m0 = F::zero();
214 self.m1 = F::one();
215 self.m2 = F::zero();
216 }
217 FilterType::Notch => {
218 let g =
219 F::tan(F::from(PI).ok_or(SvfError::Fatal)? * self.cutoff / self.sample_rate);
220 let k = F::one() / self.q;
221 self.a1 = F::one() / (F::one() + g * (g + k));
222 self.a2 = g * self.a1;
223 self.a3 = g * self.a2;
224 self.m0 = F::one();
225 self.m0 = F::one();
226 self.m1 = -k;
227 self.m2 = F::zero();
228 }
229 FilterType::Peak => {
230 let g =
231 F::tan(F::from(PI).ok_or(SvfError::Fatal)? * self.cutoff / self.sample_rate);
232 let k = F::one() / self.q;
233 self.a1 = F::one() / (F::one() + g * (g + k));
234 self.a2 = g * self.a1;
235 self.a3 = g * self.a2;
236 self.m0 = F::one();
237 self.m1 = -k;
238 self.m2 = F::from(-2.).ok_or(SvfError::Fatal)?;
239 }
240 FilterType::Allpass => {
241 let g =
242 F::tan(F::from(PI).ok_or(SvfError::Fatal)? * self.cutoff / self.sample_rate);
243 let k = F::one() / self.q;
244 self.a1 = F::one() / (F::one() + g * (g + k));
245 self.a2 = g * self.a1;
246 self.a3 = g * self.a2;
247 self.m0 = F::one();
248 self.m1 = F::from(-2.).ok_or(SvfError::Fatal)? * k;
249 self.m2 = F::zero();
250 }
251 FilterType::Bell => {
252 let a = F::sqrt(self.gain);
253 let g =
254 F::tan(F::from(PI).ok_or(SvfError::Fatal)? * self.cutoff / self.sample_rate);
255 let k = F::one() / (self.q * a);
256 self.a1 = F::one() / (F::one() + g * (g + k));
257 self.a2 = g * self.a1;
258 self.a3 = g * self.a2;
259 self.m0 = F::one();
260 self.m1 = k * (a * a - F::one());
261 self.m2 = F::zero();
262 }
263 FilterType::Lowshelf => {
264 let a = F::sqrt(self.gain);
265 let g =
266 F::tan(F::from(PI).ok_or(SvfError::Fatal)? * self.cutoff / self.sample_rate)
267 / F::sqrt(a);
268 let k = F::one() / self.q;
269 self.a1 = F::one() / (F::one() + g * (g + k));
270 self.a2 = g * self.a1;
271 self.a3 = g * self.a2;
272 self.m0 = F::one();
273 self.m1 = k * (a - F::one());
274 self.m2 = a * a - F::one();
275 }
276 FilterType::Highshelf => {
277 let a = F::sqrt(self.gain);
278 let g =
279 F::tan(F::from(PI).ok_or(SvfError::Fatal)? * self.cutoff / self.sample_rate)
280 * F::sqrt(a);
281 let k = F::one() / self.q;
282 self.a1 = F::one() / (F::one() + g * (g + k));
283 self.a2 = g * self.a1;
284 self.a3 = g * self.a2;
285 self.m0 = a * a;
286 self.m1 = k * (F::one() - a) * a;
287 self.m2 = F::one() - a * a;
288 }
289 }
290 Ok(())
291 }
292}
293
294pub struct SvfResponse;
296impl SvfResponse {
297 pub fn response<F: Float>(
300 coeffs: &SvfCoefficients<F>,
301 frequency: f64,
302 ) -> Result<Complex64, SvfError> {
303 if frequency <= 0.0 {
304 return Err(SvfError::FrequencyTooLow);
305 }
306 let nyquist = coeffs.sample_rate.to_f64().ok_or(SvfError::Fatal)? / 2.0;
307 if frequency > nyquist {
308 return Err(SvfError::FrequencyOverNyqist);
309 }
310
311 match coeffs.filter_type {
312 FilterType::Lowpass => SvfResponse::lowpass_response(coeffs, frequency),
313 FilterType::Highpass => SvfResponse::highpass_response(coeffs, frequency),
314 FilterType::Bandpass => SvfResponse::bandpass_response(coeffs, frequency),
315 FilterType::Notch => SvfResponse::notch_response(coeffs, frequency),
316 FilterType::Peak => SvfResponse::peak_response(coeffs, frequency),
317 FilterType::Allpass => SvfResponse::allpass_response(coeffs, frequency),
318 FilterType::Bell => SvfResponse::bell_response(coeffs, frequency),
319 FilterType::Lowshelf => SvfResponse::lowshelf_response(coeffs, frequency),
320 FilterType::Highshelf => SvfResponse::highshelf_response(coeffs, frequency),
321 }
322 }
323
324 fn lowpass_response<F: Float>(
325 coeffs: &SvfCoefficients<F>,
326 frequency: f64,
327 ) -> Result<Complex64, SvfError> {
328 let g = f64::tan(
329 PI * coeffs.cutoff.to_f64().ok_or(SvfError::Fatal)?
330 / coeffs.sample_rate.to_f64().ok_or(SvfError::Fatal)?,
331 );
332 let k = 1.0 / coeffs.q.to_f64().ok_or(SvfError::Fatal)?;
333 let f = frequency * TAU / coeffs.sample_rate.to_f64().ok_or(SvfError::Fatal)?;
334 let z = Complex64::from_polar(1.0, f);
335 let response = (g * g * (1.0 + z) * (1.0 + z))
336 / ((z - 1.0) * (z - 1.0) + g * g * (1.0 + z) * (1.0 + z) + g * k * (z * z - 1.0));
337 Ok(response)
338 }
339
340 fn highpass_response<F: Float>(
341 coeffs: &SvfCoefficients<F>,
342 frequency: f64,
343 ) -> Result<Complex64, SvfError> {
344 let g = f64::tan(
345 PI * coeffs.cutoff.to_f64().ok_or(SvfError::Fatal)?
346 / coeffs.sample_rate.to_f64().ok_or(SvfError::Fatal)?,
347 );
348 let k = 1.0 / coeffs.q.to_f64().ok_or(SvfError::Fatal)?;
349 let f = frequency * TAU / coeffs.sample_rate.to_f64().ok_or(SvfError::Fatal)?;
350 let z = Complex64::from_polar(1.0, f);
351 let response = ((z - 1.0) * (z - 1.0))
352 / ((z - 1.0) * (z - 1.0) + g * g * (1.0 + z) * (1.0 + z) + g * k * (z * z - 1.0));
353 Ok(response)
354 }
355
356 fn bandpass_response<F: Float>(
357 coeffs: &SvfCoefficients<F>,
358 frequency: f64,
359 ) -> Result<Complex64, SvfError> {
360 let g = f64::tan(
361 PI * coeffs.cutoff.to_f64().ok_or(SvfError::Fatal)?
362 / coeffs.sample_rate.to_f64().ok_or(SvfError::Fatal)?,
363 );
364 let k = 1.0 / coeffs.q.to_f64().ok_or(SvfError::Fatal)?;
365 let f = frequency * TAU / coeffs.sample_rate.to_f64().ok_or(SvfError::Fatal)?;
366 let z = Complex64::from_polar(1.0, f);
367 let response = (g * (z * z - 1.0))
368 / ((z - 1.0) * (z - 1.0) + g * g * (1.0 + z) * (1.0 + z) + g * k * (z * z - 1.0));
369 Ok(response)
370 }
371
372 fn notch_response<F: Float>(
373 coeffs: &SvfCoefficients<F>,
374 frequency: f64,
375 ) -> Result<Complex64, SvfError> {
376 let g = f64::tan(
377 PI * coeffs.cutoff.to_f64().ok_or(SvfError::Fatal)?
378 / coeffs.sample_rate.to_f64().ok_or(SvfError::Fatal)?,
379 );
380 let k = 1.0 / coeffs.q.to_f64().ok_or(SvfError::Fatal)?;
381 let f = frequency * TAU / coeffs.sample_rate.to_f64().ok_or(SvfError::Fatal)?;
382 let z = Complex64::from_polar(1.0, f);
383 let response = ((z - 1.0) * (z - 1.0) + g * g * (1.0 + z) * (1.0 + z))
384 / ((z - 1.0) * (z - 1.0) + g * g * (1.0 + z) * (1.0 + z) + g * k * (z * z - 1.0));
385 Ok(response)
386 }
387
388 fn peak_response<F: Float>(
389 coeffs: &SvfCoefficients<F>,
390 frequency: f64,
391 ) -> Result<Complex64, SvfError> {
392 let g = f64::tan(
393 PI * coeffs.cutoff.to_f64().ok_or(SvfError::Fatal)?
394 / coeffs.sample_rate.to_f64().ok_or(SvfError::Fatal)?,
395 );
396 let k = 1.0 / coeffs.q.to_f64().ok_or(SvfError::Fatal)?;
397 let f = frequency * TAU / coeffs.sample_rate.to_f64().ok_or(SvfError::Fatal)?;
398 let z = Complex64::from_polar(1.0, f);
399 let response = -((1.0 + g + (g - 1.0) * z) * (-1.0 + g + z + g * z))
401 / ((z - 1.0) * (z - 1.0) + g * g * (1.0 + z) * (1.0 + z) + g * k * (z * z - 1.0));
402 Ok(response)
403 }
404
405 fn allpass_response<F: Float>(
406 coeffs: &SvfCoefficients<F>,
407 frequency: f64,
408 ) -> Result<Complex64, SvfError> {
409 let g = f64::tan(
410 PI * coeffs.cutoff.to_f64().ok_or(SvfError::Fatal)?
411 / coeffs.sample_rate.to_f64().ok_or(SvfError::Fatal)?,
412 );
413 let k = 1.0 / coeffs.q.to_f64().ok_or(SvfError::Fatal)?;
414 let f = frequency * TAU / coeffs.sample_rate.to_f64().ok_or(SvfError::Fatal)?;
415 let z = Complex64::from_polar(1.0, f);
416 let response =
417 ((z - 1.0) * (z - 1.0) + g * g * (1.0 + z) * (1.0 + z) + g * (k - k * z * z))
418 / ((z - 1.0) * (z - 1.0) + g * g * (1.0 + z) * (1.0 + z) + g * k * (z * z - 1.0));
419 Ok(response)
420 }
421
422 fn bell_response<F: Float>(
423 coeffs: &SvfCoefficients<F>,
424 frequency: f64,
425 ) -> Result<Complex64, SvfError> {
426 let a = f64::sqrt(coeffs.gain.to_f64().ok_or(SvfError::Fatal)?);
427 let g = f64::tan(
428 PI * coeffs.cutoff.to_f64().ok_or(SvfError::Fatal)?
429 / coeffs.sample_rate.to_f64().ok_or(SvfError::Fatal)?,
430 );
431 let k = 1.0 / coeffs.q.to_f64().ok_or(SvfError::Fatal)?;
432 let z = Complex64::from_polar(
433 1.0,
434 frequency * TAU / coeffs.sample_rate.to_f64().ok_or(SvfError::Fatal)?,
435 );
436 let response = (g * k * (z * z - 1.0)
437 + a * (g * (1.0 + z) * ((a * a - 1.0) * k / a * (z - 1.0))
438 + ((z - 1.0) * (z - 1.0) + g * g * (1.0 + z) * (1.0 + z))))
439 / (g * k * (z * z - 1.0) + a * ((z - 1.0) * (z - 1.0) + g * g * (z + 1.0) * (z + 1.0)));
440 Ok(response)
441 }
442
443 fn lowshelf_response<F: Float>(
444 coeffs: &SvfCoefficients<F>,
445 frequency: f64,
446 ) -> Result<Complex64, SvfError> {
447 let a = f64::sqrt(coeffs.gain.to_f64().ok_or(SvfError::Fatal)?);
448 let g = f64::tan(
449 PI * coeffs.cutoff.to_f64().ok_or(SvfError::Fatal)?
450 / coeffs.sample_rate.to_f64().ok_or(SvfError::Fatal)?,
451 );
452 let k = 1.0 / coeffs.q.to_f64().ok_or(SvfError::Fatal)?;
453 let z = Complex64::from_polar(
454 1.0,
455 frequency * TAU / coeffs.sample_rate.to_f64().ok_or(SvfError::Fatal)?,
456 );
457 let sqrt_a = f64::sqrt(a);
458 let response = (a * (z - 1.0) * (z - 1.0)
459 + g * g * a * a * (z + 1.0) * (z + 1.0)
460 + sqrt_a * g * a * k * (z * z - 1.0))
461 / (a * (z - 1.0) * (z - 1.0)
462 + g * g * (1.0 + z) * (1.0 + z)
463 + sqrt_a * g * k * (z * z - 1.0));
464 Ok(response)
465 }
466
467 fn highshelf_response<F: Float>(
468 coeffs: &SvfCoefficients<F>,
469 frequency: f64,
470 ) -> Result<Complex64, SvfError> {
471 let a = f64::sqrt(coeffs.gain.to_f64().ok_or(SvfError::Fatal)?);
472 let g = f64::tan(
473 PI * coeffs.cutoff.to_f64().ok_or(SvfError::Fatal)?
474 / coeffs.sample_rate.to_f64().ok_or(SvfError::Fatal)?,
475 );
476 let k = 1.0 / coeffs.q.to_f64().ok_or(SvfError::Fatal)?;
477 let z = Complex64::from_polar(
478 1.0,
479 frequency * TAU / coeffs.sample_rate.to_f64().ok_or(SvfError::Fatal)?,
480 );
481 let sqrt_a = f64::sqrt(a);
482 let response = (sqrt_a
483 * g
484 * (1.0 + z)
485 * (-(a - 1.0) * a * k * (z - 1.0) + sqrt_a * g * (1.0 - a * a) * (1.0 + z))
486 + a * a
487 * ((z - 1.0) * (z - 1.0)
488 + a * g * g * (1.0 + z) * (1.0 + z)
489 + sqrt_a * g * k * (z * z - 1.0)))
490 / ((z - 1.0) * (z - 1.0)
491 + a * g * g * (1.0 + z) * (1.0 + z)
492 + sqrt_a * g * k * (z * z - 1.0));
493 Ok(response)
494 }
495}
496
497#[cfg(test)]
498mod tests {
499 use super::*;
500
501 #[test]
502 fn it_works() {
503 let mut filter = Svf::<f32>::default();
504 filter
505 .set(FilterType::Lowpass, 44100.0, 400.0, f32::sqrt(2.0), 0.0)
506 .unwrap();
507 let _response = filter.get_response(20.0).unwrap();
508 let input = vec![0.0; 100];
509 let mut output = vec![0.0; 100];
510 filter.process(&input, &mut output);
511 }
512}