1#![doc = include_str!("../README.md")]
2
3mod fir;
5mod iir;
6
7pub use iir::{
9 Biquad, BiquadFilterType, FilterRow, Peq, compute_peq_response, peq_butterworth_highpass,
10 peq_butterworth_lowpass, peq_butterworth_q, peq_equal, peq_format_apo, peq_format_aupreset,
11 peq_format_rme_channel, peq_format_rme_room, peq_linkwitzriley_highpass,
12 peq_linkwitzriley_lowpass, peq_linkwitzriley_q, peq_loudness_gain, peq_preamp_gain,
13 peq_preamp_gain_max, peq_print, peq_spl,
14};
15
16pub use fir::{
18 Fir, FirBank, FirFilterType, WindowType, compute_fir_bank_response, fir_bank_preamp_gain,
19 fir_bank_spl, generate_window,
20};
21
22pub fn bw2q(bw: f64) -> f64 {
28 let two_pow_bw = 2.0_f64.powf(bw);
29 two_pow_bw.sqrt() / (two_pow_bw - 1.0)
30}
31
32pub fn q2bw(q: f64) -> f64 {
34 let q2 = (2.0 * q * q + 1.0) / (2.0 * q * q);
35 (q2 + (q2 * q2 - 1.0).sqrt()).log(2.0)
36}
37
38pub const DEFAULT_Q_HIGH_LOW_PASS: f64 = 1.0 / std::f64::consts::SQRT_2;
41pub const DEFAULT_Q_HIGH_LOW_SHELF: f64 = 1.0668676536332304; pub const SRATE: f64 = 48000.0;
46
47#[cfg(test)]
52mod tests {
53 use super::*;
54
55 fn approx_eq(a: f64, b: f64, tol: f64) -> bool {
56 (a - b).abs() <= tol
57 }
58
59 #[test]
60 fn test_bw_q_roundtrip() {
61 let qs = [0.5, 1.0, 2.0, 5.0];
62 for &q in &qs {
63 let bw = q2bw(q);
64 let q2 = bw2q(bw);
65 assert!(
66 approx_eq(q, q2, 1e-9),
67 "roundtrip failed: q={} -> bw={} -> q2={}",
68 q,
69 bw,
70 q2
71 );
72 }
73 }
74}