Skip to main content

bae_rs/modifiers/
bandpass.rs

1//! # Band Pass
2
3use super::*;
4
5/// -12dB per octave BandPass filter.
6pub struct BandPass {
7    central_f: MathT,
8    quality: MathT,
9    a0: MathT,
10    b1: MathT,
11    b2: MathT,
12    x1: SampleT,
13    x2: SampleT,
14    y1: SampleT,
15    y2: SampleT,
16}
17
18impl BandPass {
19    /// Creates a new BandPass object from the given central frequency and q
20    /// value.
21    /// 
22    /// The filter's quality is set to the central frequency divided by the
23    /// difference between the corner frequencies.
24    pub fn new(f: MathT, q: MathT) -> Self {
25        let mut bp = BandPass {
26            central_f: f,
27            quality: q,
28            a0: 0.0,
29            b1: 0.0,
30            b2: 0.0,
31            x1: SampleT::default(),
32            x2: SampleT::default(),
33            y1: SampleT::default(),
34            y2: SampleT::default(),
35        };
36
37        bp.reset();
38
39        bp
40    }
41
42    /// Creates a new BandPass object from given corner frequencies.
43    pub fn from_corners(f: (MathT,MathT)) -> Self {
44        let mut bp = BandPass {
45            central_f: (f.0*f.1).abs().sqrt(),
46            quality: (f.0*f.1).abs().sqrt()/(f.1-f.0).abs(),
47            a0: 0.0,
48            b1: 0.0,
49            b2: 0.0,
50            x1: SampleT::default(),
51            x2: SampleT::default(),
52            y1: SampleT::default(),
53            y2: SampleT::default(),
54        };
55
56        bp.reset();
57
58        bp
59    }
60
61    /// Returns the central frequency of the filter.
62    pub fn get_central_frequency(&self) -> MathT {
63        self.central_f
64    }
65
66    /// Sets a new central frequency.
67    pub fn set_central_frequency(&mut self, f: MathT) {
68        self.central_f = f;
69
70        self.reset();
71    }
72
73    /// Returns the quality of the filter.
74    pub fn get_quality(&self) -> MathT {
75        self.quality
76    }
77
78    /// Sets the quality of the filter.
79    /// 
80    /// The filter's quality is set to the central frequency divided by the
81    /// difference between the corner frequencies.
82    pub fn set_quality(&mut self, q: MathT) {
83        self.quality = q;
84
85        self.reset();
86    }
87
88    /// Returns the corner frequencies of the filter.
89    pub fn get_corner_frequencies(&self) -> (MathT,MathT) {
90        let b = -self.central_f/self.quality;
91
92        let (p,n) = quadratic(1.0, b, -self.central_f*self.central_f);
93        let fl = if p > 0.0 {
94            p
95        } else {
96            n
97        };
98        let fh = fl + b;
99
100        if fl < fh {
101            (fl, fh)
102        } else {
103            (fh, fl)
104        }
105    }
106
107    /// Sets the corner frequencies of the filter.
108    pub fn set_corner_frequencies(&mut self, f: (MathT,MathT)) {
109        self.central_f = (f.0 * f.1).sqrt();
110        self.quality = self.central_f/(f.0-f.1).abs();
111
112        self.reset();
113    }
114
115    fn reset(&mut self) {
116        let (fh, fl) = self.get_corner_frequencies();
117
118        let theta_l = (std::f64::consts::PI * fl * INV_SAMPLE_RATE).tan();
119        let theta_h = (std::f64::consts::PI * fh * INV_SAMPLE_RATE).tan();
120
121        let al = 1.0 / (1.0+theta_l);
122        let ah = 1.0 / (1.0+theta_h);
123
124        let bl = (1.0-theta_l) / (1.0+theta_l);
125        let bh = (1.0-theta_h) / (1.0+theta_h);
126
127        self.a0 = (1.0-al) * ah;
128        self.b1 = bl + bh;
129        self.b2 = bl * bh;
130    }
131}
132
133impl Modifier for BandPass {
134    fn process(&mut self, x: SampleT) -> SampleT {
135        let y = (self.a0 * (x - self.x2) as MathT +
136            self.b1 * self.y1 as MathT - 
137            self.b2 * self.y2 as MathT) as SampleT;
138
139        self.y2 = self.y1;
140        self.y1 = y;
141        self.x2 = self.x1;
142        self.x1 = x;
143
144        y
145    }
146}
147
148fn quadratic(a: MathT, b: MathT, c: MathT) -> (MathT,MathT) {
149    (
150        (-b + (b*b - 4.0*a*c).sqrt())/(2.0*a),
151        (-b - (b*b - 4.0*a*c).sqrt())/(2.0*a)
152    )
153}
154
155impl Clone for BandPass {
156    fn clone(&self) -> Self {
157        BandPass {
158            central_f: self.central_f,
159            quality: self.quality,
160            a0: self.a0,
161            b1: self.b1,
162            b2: self.b2,
163            x1: SampleT::default(),
164            x2: SampleT::default(),
165            y1: SampleT::default(),
166            y2: SampleT::default(),
167        }
168    }
169}