1#![cfg_attr(not(test), no_std)]
2
3use core::f64::consts::{PI, TAU};
4use num_complex::Complex64;
5use num_traits::Float;
6use thiserror::Error;
7
8#[derive(Error, Debug)]
9pub enum SvfError {
10 #[error("the sample rate must be set first")]
11 NoSampleRate,
12 #[error("the frequency is higher than nyqist")]
13 FrequencyOverNyqist,
14 #[error("the frequency is 0 or lower than 0")]
15 FrequencyTooLow,
16 #[error("q is lower than zero")]
17 NegativeQ,
18 #[error("fatal number conversion error")]
19 Fatal,
20}
21
22#[derive(Default, Clone, PartialEq, Eq)]
24pub enum FilterType {
25 #[default]
26 Lowpass,
27 Highpass,
28 Bandpass,
29 Notch,
30 Peak,
31 Allpass,
32 Bell,
33 Lowshelf,
34 Highshelf,
35}
36
37#[derive(Default)]
40pub struct Svf<F: Float> {
41 coefficients: SvfCoefficients<F>,
42 ic1eq: F,
43 ic2eq: F,
44}
45
46#[derive(Default, Clone, PartialEq, Eq)]
48pub struct SvfCoefficients<F: Float> {
49 filter_type: FilterType,
50 sample_rate: F,
51 cutoff: F,
52 gain: F,
53 q: F,
54 a1: F,
55 a2: F,
56 a3: F,
57 m0: F,
58 m1: F,
59 m2: F,
60}
61
62impl<F: Float + Default> Svf<F> {
63 pub fn new(
72 filter_type: FilterType,
73 sample_rate: F,
74 cutoff: F,
75 q: F,
76 gain: F,
77 ) -> Result<Self, SvfError> {
78 let mut svf = Self::default();
79 svf.set(filter_type, sample_rate, cutoff, q, gain)?;
80 Ok(svf)
81 }
82
83 #[inline]
85 pub fn process(&mut self, input: &[F], output: &mut [F]) {
86 output
87 .iter_mut()
88 .zip(input)
89 .for_each(|(out_sample, in_sample)| {
90 *out_sample = self.tick(*in_sample);
91 });
92 }
93
94 #[inline]
97 pub fn reset(&mut self) {
98 self.ic1eq = F::zero();
99 self.ic2eq = F::zero();
100 }
101
102 #[inline]
111 pub fn set(
112 &mut self,
113 filter_type: FilterType,
114 sample_rate: F,
115 cutoff: F,
116 q: F,
117 gain: F,
118 ) -> Result<(), SvfError> {
119 self.coefficients
120 .set(filter_type, sample_rate, cutoff, q, gain)
121 }
122
123 pub fn set_coeffs(&mut self, coefficients: SvfCoefficients<F>) {
125 self.coefficients = coefficients;
126 }
127
128 #[inline]
131 pub fn tick(&mut self, input: F) -> F {
132 let v0 = input;
133 let v3 = v0 - self.ic2eq;
134 let v1 = self.coefficients.a1 * self.ic1eq + self.coefficients.a2 * v3;
135 let v2 = self.ic2eq + self.coefficients.a2 * self.ic1eq + self.coefficients.a3 * v3;
136 let two = F::one() + F::one();
137 self.ic1eq = two * v1 - self.ic1eq;
138 self.ic2eq = two * v2 - self.ic2eq;
139
140 self.coefficients.m0 * v0 + self.coefficients.m1 * v1 + self.coefficients.m2 * v2
141 }
142
143 pub fn coefficients(&self) -> &SvfCoefficients<F> {
146 &self.coefficients
147 }
148
149 pub fn get_response(&self, frequency: f64) -> Result<Complex64, SvfError> {
152 SvfResponse::response(&self.coefficients, frequency)
153 }
154}
155
156impl<F: Float> SvfCoefficients<F> {
157 pub fn set(
166 &mut self,
167 filter_type: FilterType,
168 sample_rate: F,
169 cutoff_frequency: F,
170 q: F,
171 gain: F,
172 ) -> Result<(), SvfError> {
173 if q < F::zero() {
174 return Err(SvfError::NegativeQ);
175 }
176 if cutoff_frequency > sample_rate / F::from(2.0).unwrap() {
177 return Err(SvfError::FrequencyOverNyqist);
178 }
179 self.filter_type = filter_type;
180 self.sample_rate = sample_rate;
181 self.cutoff = cutoff_frequency;
182 self.q = q;
183 self.gain = gain;
184
185 match self.filter_type {
186 FilterType::Lowpass => {
187 let g =
188 F::tan(F::from(PI).ok_or(SvfError::Fatal)? * self.cutoff / self.sample_rate);
189 let k = F::one() / self.q;
190 self.a1 = F::one() / (F::one() + g * (g + k));
191 self.a2 = g * self.a1;
192 self.a3 = g * self.a2;
193 self.m0 = F::zero();
194 self.m1 = F::zero();
195 self.m2 = F::one();
196 }
197 FilterType::Highpass => {
198 let g =
199 F::tan(F::from(PI).ok_or(SvfError::Fatal)? * self.cutoff / self.sample_rate);
200 let k = F::one() / self.q;
201 self.a1 = F::one() / (F::one() + g * (g + k));
202 self.a2 = g * self.a1;
203 self.a3 = g * self.a2;
204 self.m0 = F::one();
205 self.m1 = -k;
206 self.m2 = -F::one();
207 }
208 FilterType::Bandpass => {
209 let g =
210 F::tan(F::from(PI).ok_or(SvfError::Fatal)? * self.cutoff / self.sample_rate);
211 let k = F::one() / self.q;
212 self.a1 = F::one() / (F::one() + g * (g + k));
213 self.a2 = g * self.a1;
214 self.a3 = g * self.a2;
215 self.m0 = F::zero();
216 self.m1 = F::one();
217 self.m2 = F::zero();
218 }
219 FilterType::Notch => {
220 let g =
221 F::tan(F::from(PI).ok_or(SvfError::Fatal)? * self.cutoff / self.sample_rate);
222 let k = F::one() / self.q;
223 self.a1 = F::one() / (F::one() + g * (g + k));
224 self.a2 = g * self.a1;
225 self.a3 = g * self.a2;
226 self.m0 = F::one();
227 self.m1 = -k;
228 self.m2 = F::zero();
229 }
230 FilterType::Peak => {
231 let g =
232 F::tan(F::from(PI).ok_or(SvfError::Fatal)? * self.cutoff / self.sample_rate);
233 let k = F::one() / self.q;
234 self.a1 = F::one() / (F::one() + g * (g + k));
235 self.a2 = g * self.a1;
236 self.a3 = g * self.a2;
237 self.m0 = F::one();
238 self.m1 = -k;
239 self.m2 = F::from(-2).ok_or(SvfError::Fatal)?;
240 }
241 FilterType::Allpass => {
242 let g =
243 F::tan(F::from(PI).ok_or(SvfError::Fatal)? * self.cutoff / self.sample_rate);
244 let k = F::one() / self.q;
245 self.a1 = F::one() / (F::one() + g * (g + k));
246 self.a2 = g * self.a1;
247 self.a3 = g * self.a2;
248 self.m0 = F::one();
249 self.m1 = F::from(-2).ok_or(SvfError::Fatal)? * k;
250 self.m2 = F::zero();
251 }
252 FilterType::Bell => {
253 let a = F::powf(
254 F::from(10).ok_or(SvfError::Fatal)?,
255 self.gain / F::from(40).unwrap(),
256 );
257 let g =
258 F::tan(F::from(PI).ok_or(SvfError::Fatal)? * self.cutoff / self.sample_rate);
259 let k = F::one() / (self.q * a);
260 self.a1 = F::one() / (F::one() + g * (g + k));
261 self.a2 = g * self.a1;
262 self.a3 = g * self.a2;
263 self.m0 = F::one();
264 self.m1 = k * (a * a - F::one());
265 self.m2 = F::zero();
266 }
267 FilterType::Lowshelf => {
268 let a = F::powf(
269 F::from(10).ok_or(SvfError::Fatal)?,
270 self.gain / F::from(40).unwrap(),
271 );
272 let g =
273 F::tan(F::from(PI).ok_or(SvfError::Fatal)? * self.cutoff / self.sample_rate)
274 / F::sqrt(a);
275 let k = F::one() / self.q;
276 self.a1 = F::one() / (F::one() + g * (g + k));
277 self.a2 = g * self.a1;
278 self.a3 = g * self.a2;
279 self.m0 = F::one();
280 self.m1 = k * (a - F::one());
281 self.m2 = a * a - F::one();
282 }
283 FilterType::Highshelf => {
284 let a = F::powf(
285 F::from(10).ok_or(SvfError::Fatal)?,
286 self.gain / F::from(40).unwrap(),
287 );
288 let g =
289 F::tan(F::from(PI).ok_or(SvfError::Fatal)? * self.cutoff / self.sample_rate)
290 * F::sqrt(a);
291 let k = F::one() / self.q;
292 self.a1 = F::one() / (F::one() + g * (g + k));
293 self.a2 = g * self.a1;
294 self.a3 = g * self.a2;
295 self.m0 = a * a;
296 self.m1 = k * (F::one() - a) * a;
297 self.m2 = F::one() - a * a;
298 }
299 }
300 Ok(())
301 }
302}
303
304pub struct SvfResponse;
306impl SvfResponse {
307 pub fn response<F: Float>(
310 coeffs: &SvfCoefficients<F>,
311 frequency: f64,
312 ) -> Result<Complex64, SvfError> {
313 if frequency <= 0.0 {
314 return Err(SvfError::FrequencyTooLow);
315 }
316 let nyquist = coeffs.sample_rate.to_f64().ok_or(SvfError::Fatal)? / 2.0;
317 if frequency > nyquist {
318 return Err(SvfError::FrequencyOverNyqist);
319 }
320
321 match coeffs.filter_type {
322 FilterType::Lowpass => SvfResponse::lowpass_response(coeffs, frequency),
323 FilterType::Highpass => SvfResponse::highpass_response(coeffs, frequency),
324 FilterType::Bandpass => SvfResponse::bandpass_response(coeffs, frequency),
325 FilterType::Notch => SvfResponse::notch_response(coeffs, frequency),
326 FilterType::Peak => SvfResponse::peak_response(coeffs, frequency),
327 FilterType::Allpass => SvfResponse::allpass_response(coeffs, frequency),
328 FilterType::Bell => SvfResponse::bell_response(coeffs, frequency),
329 FilterType::Lowshelf => SvfResponse::lowshelf_response(coeffs, frequency),
330 FilterType::Highshelf => SvfResponse::highshelf_response(coeffs, frequency),
331 }
332 }
333
334 fn lowpass_response<F: Float>(
335 coeffs: &SvfCoefficients<F>,
336 frequency: f64,
337 ) -> Result<Complex64, SvfError> {
338 let g = f64::tan(
339 PI * coeffs.cutoff.to_f64().ok_or(SvfError::Fatal)?
340 / coeffs.sample_rate.to_f64().ok_or(SvfError::Fatal)?,
341 );
342 let k = 1.0 / coeffs.q.to_f64().ok_or(SvfError::Fatal)?;
343 let f = frequency * TAU / coeffs.sample_rate.to_f64().ok_or(SvfError::Fatal)?;
344 let z = Complex64::from_polar(1.0, f);
345 let response = (g * g * (1.0 + z) * (1.0 + z))
346 / ((z - 1.0) * (z - 1.0) + g * g * (1.0 + z) * (1.0 + z) + g * k * (z * z - 1.0));
347 Ok(response)
348 }
349
350 fn highpass_response<F: Float>(
351 coeffs: &SvfCoefficients<F>,
352 frequency: f64,
353 ) -> Result<Complex64, SvfError> {
354 let g = f64::tan(
355 PI * coeffs.cutoff.to_f64().ok_or(SvfError::Fatal)?
356 / coeffs.sample_rate.to_f64().ok_or(SvfError::Fatal)?,
357 );
358 let k = 1.0 / coeffs.q.to_f64().ok_or(SvfError::Fatal)?;
359 let f = frequency * TAU / coeffs.sample_rate.to_f64().ok_or(SvfError::Fatal)?;
360 let z = Complex64::from_polar(1.0, f);
361 let response = ((z - 1.0) * (z - 1.0))
362 / ((z - 1.0) * (z - 1.0) + g * g * (1.0 + z) * (1.0 + z) + g * k * (z * z - 1.0));
363 Ok(response)
364 }
365
366 fn bandpass_response<F: Float>(
367 coeffs: &SvfCoefficients<F>,
368 frequency: f64,
369 ) -> Result<Complex64, SvfError> {
370 let g = f64::tan(
371 PI * coeffs.cutoff.to_f64().ok_or(SvfError::Fatal)?
372 / coeffs.sample_rate.to_f64().ok_or(SvfError::Fatal)?,
373 );
374 let k = 1.0 / coeffs.q.to_f64().ok_or(SvfError::Fatal)?;
375 let f = frequency * TAU / coeffs.sample_rate.to_f64().ok_or(SvfError::Fatal)?;
376 let z = Complex64::from_polar(1.0, f);
377 let response = (g * (z * z - 1.0))
378 / ((z - 1.0) * (z - 1.0) + g * g * (1.0 + z) * (1.0 + z) + g * k * (z * z - 1.0));
379 Ok(response)
380 }
381
382 fn notch_response<F: Float>(
383 coeffs: &SvfCoefficients<F>,
384 frequency: f64,
385 ) -> Result<Complex64, SvfError> {
386 let g = f64::tan(
387 PI * coeffs.cutoff.to_f64().ok_or(SvfError::Fatal)?
388 / coeffs.sample_rate.to_f64().ok_or(SvfError::Fatal)?,
389 );
390 let k = 1.0 / coeffs.q.to_f64().ok_or(SvfError::Fatal)?;
391 let f = frequency * TAU / coeffs.sample_rate.to_f64().ok_or(SvfError::Fatal)?;
392 let z = Complex64::from_polar(1.0, f);
393 let response = ((z - 1.0) * (z - 1.0) + g * g * (1.0 + z) * (1.0 + z))
394 / ((z - 1.0) * (z - 1.0) + g * g * (1.0 + z) * (1.0 + z) + g * k * (z * z - 1.0));
395 Ok(response)
396 }
397
398 fn peak_response<F: Float>(
399 coeffs: &SvfCoefficients<F>,
400 frequency: f64,
401 ) -> Result<Complex64, SvfError> {
402 let g = f64::tan(
403 PI * coeffs.cutoff.to_f64().ok_or(SvfError::Fatal)?
404 / coeffs.sample_rate.to_f64().ok_or(SvfError::Fatal)?,
405 );
406 let k = 1.0 / coeffs.q.to_f64().ok_or(SvfError::Fatal)?;
407 let f = frequency * TAU / coeffs.sample_rate.to_f64().ok_or(SvfError::Fatal)?;
408 let z = Complex64::from_polar(1.0, f);
409 let response = -((1.0 + g + (g - 1.0) * z) * (-1.0 + g + z + g * z))
411 / ((z - 1.0) * (z - 1.0) + g * g * (1.0 + z) * (1.0 + z) + g * k * (z * z - 1.0));
412 Ok(response)
413 }
414
415 fn allpass_response<F: Float>(
416 coeffs: &SvfCoefficients<F>,
417 frequency: f64,
418 ) -> Result<Complex64, SvfError> {
419 let g = f64::tan(
420 PI * coeffs.cutoff.to_f64().ok_or(SvfError::Fatal)?
421 / coeffs.sample_rate.to_f64().ok_or(SvfError::Fatal)?,
422 );
423 let k = 1.0 / coeffs.q.to_f64().ok_or(SvfError::Fatal)?;
424 let f = frequency * TAU / coeffs.sample_rate.to_f64().ok_or(SvfError::Fatal)?;
425 let z = Complex64::from_polar(1.0, f);
426 let response =
427 ((z - 1.0) * (z - 1.0) + g * g * (1.0 + z) * (1.0 + z) + g * (k - k * z * z))
428 / ((z - 1.0) * (z - 1.0) + g * g * (1.0 + z) * (1.0 + z) + g * k * (z * z - 1.0));
429 Ok(response)
430 }
431
432 fn bell_response<F: Float>(
433 coeffs: &SvfCoefficients<F>,
434 frequency: f64,
435 ) -> Result<Complex64, SvfError> {
436 let a = f64::sqrt(coeffs.gain.to_f64().ok_or(SvfError::Fatal)?);
437 let g = f64::tan(
438 PI * coeffs.cutoff.to_f64().ok_or(SvfError::Fatal)?
439 / coeffs.sample_rate.to_f64().ok_or(SvfError::Fatal)?,
440 );
441 let k = 1.0 / coeffs.q.to_f64().ok_or(SvfError::Fatal)?;
442 let z = Complex64::from_polar(
443 1.0,
444 frequency * TAU / coeffs.sample_rate.to_f64().ok_or(SvfError::Fatal)?,
445 );
446 let response = (g * k * (z * z - 1.0)
447 + a * (g * (1.0 + z) * ((a * a - 1.0) * k / a * (z - 1.0))
448 + ((z - 1.0) * (z - 1.0) + g * g * (1.0 + z) * (1.0 + z))))
449 / (g * k * (z * z - 1.0) + a * ((z - 1.0) * (z - 1.0) + g * g * (z + 1.0) * (z + 1.0)));
450 Ok(response)
451 }
452
453 fn lowshelf_response<F: Float>(
454 coeffs: &SvfCoefficients<F>,
455 frequency: f64,
456 ) -> Result<Complex64, SvfError> {
457 let a = f64::sqrt(coeffs.gain.to_f64().ok_or(SvfError::Fatal)?);
458 let g = f64::tan(
459 PI * coeffs.cutoff.to_f64().ok_or(SvfError::Fatal)?
460 / coeffs.sample_rate.to_f64().ok_or(SvfError::Fatal)?,
461 );
462 let k = 1.0 / coeffs.q.to_f64().ok_or(SvfError::Fatal)?;
463 let z = Complex64::from_polar(
464 1.0,
465 frequency * TAU / coeffs.sample_rate.to_f64().ok_or(SvfError::Fatal)?,
466 );
467 let sqrt_a = f64::sqrt(a);
468 let response = (a * (z - 1.0) * (z - 1.0)
469 + g * g * a * a * (z + 1.0) * (z + 1.0)
470 + sqrt_a * g * a * k * (z * z - 1.0))
471 / (a * (z - 1.0) * (z - 1.0)
472 + g * g * (1.0 + z) * (1.0 + z)
473 + sqrt_a * g * k * (z * z - 1.0));
474 Ok(response)
475 }
476
477 fn highshelf_response<F: Float>(
478 coeffs: &SvfCoefficients<F>,
479 frequency: f64,
480 ) -> Result<Complex64, SvfError> {
481 let a = f64::sqrt(coeffs.gain.to_f64().ok_or(SvfError::Fatal)?);
482 let g = f64::tan(
483 PI * coeffs.cutoff.to_f64().ok_or(SvfError::Fatal)?
484 / coeffs.sample_rate.to_f64().ok_or(SvfError::Fatal)?,
485 );
486 let k = 1.0 / coeffs.q.to_f64().ok_or(SvfError::Fatal)?;
487 let z = Complex64::from_polar(
488 1.0,
489 frequency * TAU / coeffs.sample_rate.to_f64().ok_or(SvfError::Fatal)?,
490 );
491 let sqrt_a = f64::sqrt(a);
492 let response = (sqrt_a
493 * g
494 * (1.0 + z)
495 * (-(a - 1.0) * a * k * (z - 1.0) + sqrt_a * g * (1.0 - a * a) * (1.0 + z))
496 + a * a
497 * ((z - 1.0) * (z - 1.0)
498 + a * g * g * (1.0 + z) * (1.0 + z)
499 + sqrt_a * g * k * (z * z - 1.0)))
500 / ((z - 1.0) * (z - 1.0)
501 + a * g * g * (1.0 + z) * (1.0 + z)
502 + sqrt_a * g * k * (z * z - 1.0));
503 Ok(response)
504 }
505}
506
507#[cfg(test)]
508mod tests {
509 use super::*;
510
511 fn generate_sine<F: Float>(sample_rate: f64, frequency: f64, num_samples: usize) -> Vec<F> {
512 (0..num_samples)
513 .map(|i| F::from((2.0 * PI * frequency * i as f64 / sample_rate).sin()).unwrap())
514 .collect()
515 }
516
517 fn rms_db<F: Float>(data: &[F]) -> F {
518 let sum_of_squares = data.iter().fold(F::zero(), |acc, &x| acc + x * x);
519 let mean_of_squares = sum_of_squares / F::from(data.len()).unwrap();
520 let rms = mean_of_squares.sqrt();
521 let twenty = F::from(20.0).unwrap();
522 twenty * rms.log10()
523 }
524
525 struct Point {
526 freq: f64,
527 expected_gain_db: f64,
528 }
529
530 fn test_fiter(mut filter: Svf<f64>, points: &[Point]) {
531 let sample_rate = filter.coefficients.sample_rate;
532 let num_samples = sample_rate as usize;
533 let mut output = vec![0.0; num_samples];
534
535 for point in points {
536 let sine = generate_sine::<f64>(sample_rate, point.freq, num_samples);
537 filter.reset();
538 filter.process(&sine, &mut output);
539 assert_eq!(rms_db(&output).round(), point.expected_gain_db);
540 }
541 }
542
543 #[test]
544 fn test_lowpass() {
545 test_fiter(
546 Svf::new(FilterType::Lowpass, 44100.0, 1000.0, 0.71, 0.0).unwrap(),
547 &[
548 Point {
549 freq: 20.0,
550 expected_gain_db: -3.0,
551 },
552 Point {
553 freq: 500.0,
554 expected_gain_db: -3.0,
555 },
556 Point {
557 freq: 1000.0,
558 expected_gain_db: -6.0,
559 },
560 Point {
561 freq: 5000.0,
562 expected_gain_db: -32.0,
563 },
564 Point {
565 freq: 10000.0,
566 expected_gain_db: -46.0,
567 },
568 Point {
569 freq: 20000.0,
570 expected_gain_db: -79.0,
571 },
572 ],
573 );
574 }
575
576 #[test]
577 fn test_highpass() {
578 test_fiter(
579 Svf::new(FilterType::Highpass, 44100.0, 1000.0, 0.71, 0.0).unwrap(),
580 &[
581 Point {
582 freq: 20.0,
583 expected_gain_db: -70.0,
584 },
585 Point {
586 freq: 500.0,
587 expected_gain_db: -15.0,
588 },
589 Point {
590 freq: 1000.0,
591 expected_gain_db: -6.0,
592 },
593 Point {
594 freq: 5000.0,
595 expected_gain_db: -3.0,
596 },
597 Point {
598 freq: 10000.0,
599 expected_gain_db: -3.0,
600 },
601 Point {
602 freq: 20000.0,
603 expected_gain_db: -3.0,
604 },
605 ],
606 );
607 }
608
609 #[test]
610 fn test_bandpass() {
611 test_fiter(
612 Svf::new(FilterType::Bandpass, 44100.0, 1000.0, 0.71, 0.0).unwrap(),
613 &[
614 Point {
615 freq: 20.0,
616 expected_gain_db: -37.0,
617 },
618 Point {
619 freq: 500.0,
620 expected_gain_db: -9.0,
621 },
622 Point {
623 freq: 1000.0,
624 expected_gain_db: -6.0,
625 },
626 Point {
627 freq: 5000.0,
628 expected_gain_db: -17.0,
629 },
630 Point {
631 freq: 10000.0,
632 expected_gain_db: -25.0,
633 },
634 Point {
635 freq: 20000.0,
636 expected_gain_db: -43.0,
637 },
638 ],
639 );
640 }
641
642 #[test]
643 fn test_notch() {
644 test_fiter(
645 Svf::new(FilterType::Notch, 44100.0, 1000.0, 0.71, 0.0).unwrap(),
646 &[
647 Point {
648 freq: 20.0,
649 expected_gain_db: -3.0,
650 },
651 Point {
652 freq: 500.0,
653 expected_gain_db: -6.0,
654 },
655 Point {
656 freq: 1000.0,
657 expected_gain_db: -42.0,
658 },
659 Point {
660 freq: 5000.0,
661 expected_gain_db: -3.0,
662 },
663 Point {
664 freq: 10000.0,
665 expected_gain_db: -3.0,
666 },
667 Point {
668 freq: 20000.0,
669 expected_gain_db: -3.0,
670 },
671 ],
672 );
673 }
674
675 #[test]
676 fn test_peak() {
677 test_fiter(
678 Svf::new(FilterType::Peak, 44100.0, 1000.0, 0.71, 0.0).unwrap(),
679 &[
680 Point {
681 freq: 20.0,
682 expected_gain_db: -3.0,
683 },
684 Point {
685 freq: 500.0,
686 expected_gain_db: -1.0,
687 },
688 Point {
689 freq: 1000.0,
690 expected_gain_db: 0.0,
691 },
692 Point {
693 freq: 5000.0,
694 expected_gain_db: -3.0,
695 },
696 Point {
697 freq: 10000.0,
698 expected_gain_db: -3.0,
699 },
700 Point {
701 freq: 20000.0,
702 expected_gain_db: -3.0,
703 },
704 ],
705 );
706 }
707
708 #[test]
709 fn test_bell() {
710 test_fiter(
711 Svf::new(FilterType::Bell, 44100.0, 1000.0, 0.71, 3.0).unwrap(),
712 &[
713 Point {
714 freq: 20.0,
715 expected_gain_db: -3.0,
716 },
717 Point {
718 freq: 500.0,
719 expected_gain_db: -2.0,
720 },
721 Point {
722 freq: 1000.0,
723 expected_gain_db: 0.0,
724 },
725 Point {
726 freq: 5000.0,
727 expected_gain_db: -3.0,
728 },
729 Point {
730 freq: 10000.0,
731 expected_gain_db: -3.0,
732 },
733 Point {
734 freq: 20000.0,
735 expected_gain_db: -3.0,
736 },
737 ],
738 );
739
740 test_fiter(
741 Svf::new(FilterType::Bell, 44100.0, 1000.0, 0.71, -3.0).unwrap(),
742 &[
743 Point {
744 freq: 20.0,
745 expected_gain_db: -3.0,
746 },
747 Point {
748 freq: 500.0,
749 expected_gain_db: -4.0,
750 },
751 Point {
752 freq: 1000.0,
753 expected_gain_db: -6.0,
754 },
755 Point {
756 freq: 5000.0,
757 expected_gain_db: -3.0,
758 },
759 Point {
760 freq: 10000.0,
761 expected_gain_db: -3.0,
762 },
763 Point {
764 freq: 20000.0,
765 expected_gain_db: -3.0,
766 },
767 ],
768 );
769 }
770
771 #[test]
772 fn test_lowshelf() {
773 test_fiter(
774 Svf::new(FilterType::Lowshelf, 44100.0, 1000.0, 0.71, -6.0).unwrap(),
775 &[
776 Point {
777 freq: 20.0,
778 expected_gain_db: -9.0,
779 },
780 Point {
781 freq: 500.0,
782 expected_gain_db: -9.0,
783 },
784 Point {
785 freq: 1000.0,
786 expected_gain_db: -6.0,
787 },
788 Point {
789 freq: 5000.0,
790 expected_gain_db: -3.0,
791 },
792 Point {
793 freq: 10000.0,
794 expected_gain_db: -3.0,
795 },
796 Point {
797 freq: 20000.0,
798 expected_gain_db: -3.0,
799 },
800 ],
801 );
802
803 test_fiter(
804 Svf::new(FilterType::Lowshelf, 44100.0, 1000.0, 0.71, 6.0).unwrap(),
805 &[
806 Point {
807 freq: 20.0,
808 expected_gain_db: 3.0,
809 },
810 Point {
811 freq: 500.0,
812 expected_gain_db: 3.0,
813 },
814 Point {
815 freq: 1000.0,
816 expected_gain_db: 0.0,
817 },
818 Point {
819 freq: 5000.0,
820 expected_gain_db: -3.0,
821 },
822 Point {
823 freq: 10000.0,
824 expected_gain_db: -3.0,
825 },
826 Point {
827 freq: 20000.0,
828 expected_gain_db: -3.0,
829 },
830 ],
831 );
832 }
833
834 #[test]
835 fn test_highshelf() {
836 test_fiter(
837 Svf::new(FilterType::Highshelf, 44100.0, 1000.0, 0.71, -6.0).unwrap(),
838 &[
839 Point {
840 freq: 20.0,
841 expected_gain_db: -3.0,
842 },
843 Point {
844 freq: 500.0,
845 expected_gain_db: -3.0,
846 },
847 Point {
848 freq: 1000.0,
849 expected_gain_db: -6.0,
850 },
851 Point {
852 freq: 5000.0,
853 expected_gain_db: -9.0,
854 },
855 Point {
856 freq: 10000.0,
857 expected_gain_db: -9.0,
858 },
859 Point {
860 freq: 20000.0,
861 expected_gain_db: -9.0,
862 },
863 ],
864 );
865
866 test_fiter(
867 Svf::new(FilterType::Highshelf, 44100.0, 1000.0, 0.71, 6.0).unwrap(),
868 &[
869 Point {
870 freq: 20.0,
871 expected_gain_db: -3.0,
872 },
873 Point {
874 freq: 500.0,
875 expected_gain_db: -3.0,
876 },
877 Point {
878 freq: 1000.0,
879 expected_gain_db: 0.0,
880 },
881 Point {
882 freq: 5000.0,
883 expected_gain_db: 3.0,
884 },
885 Point {
886 freq: 10000.0,
887 expected_gain_db: 3.0,
888 },
889 Point {
890 freq: 20000.0,
891 expected_gain_db: 3.0,
892 },
893 ],
894 );
895 }
896}