1use std::f32::consts::PI;
2use std::time::Duration;
3
4use crate::Source;
5
6use super::SeekError;
7
8pub fn low_pass<I>(input: I, freq: u32) -> BltFilter<I>
12where
13 I: Source<Item = f32>,
14{
15 low_pass_with_q(input, freq, 0.5)
16}
17
18pub fn high_pass<I>(input: I, freq: u32) -> BltFilter<I>
19where
20 I: Source<Item = f32>,
21{
22 high_pass_with_q(input, freq, 0.5)
23}
24
25pub fn low_pass_with_q<I>(input: I, freq: u32, q: f32) -> BltFilter<I>
27where
28 I: Source<Item = f32>,
29{
30 BltFilter {
31 input,
32 formula: BltFormula::LowPass { freq, q },
33 applier: None,
34 x_n1: 0.0,
35 x_n2: 0.0,
36 y_n1: 0.0,
37 y_n2: 0.0,
38 }
39}
40
41pub fn high_pass_with_q<I>(input: I, freq: u32, q: f32) -> BltFilter<I>
43where
44 I: Source<Item = f32>,
45{
46 BltFilter {
47 input,
48 formula: BltFormula::HighPass { freq, q },
49 applier: None,
50 x_n1: 0.0,
51 x_n2: 0.0,
52 y_n1: 0.0,
53 y_n2: 0.0,
54 }
55}
56
57#[derive(Clone, Debug)]
59pub struct BltFilter<I> {
60 input: I,
61 formula: BltFormula,
62 applier: Option<BltApplier>,
63 x_n1: f32,
64 x_n2: f32,
65 y_n1: f32,
66 y_n2: f32,
67}
68
69impl<I> BltFilter<I> {
70 pub fn to_low_pass(&mut self, freq: u32) {
72 self.to_low_pass_with_q(freq, 0.5);
73 }
74
75 pub fn to_high_pass(&mut self, freq: u32) {
77 self.to_high_pass_with_q(freq, 0.5);
78 }
79
80 pub fn to_low_pass_with_q(&mut self, freq: u32, q: f32) {
82 self.formula = BltFormula::LowPass { freq, q };
83 self.applier = None;
84 }
85
86 pub fn to_high_pass_with_q(&mut self, freq: u32, q: f32) {
88 self.formula = BltFormula::HighPass { freq, q };
89 self.applier = None;
90 }
91
92 #[inline]
94 pub fn inner(&self) -> &I {
95 &self.input
96 }
97
98 #[inline]
100 pub fn inner_mut(&mut self) -> &mut I {
101 &mut self.input
102 }
103
104 #[inline]
106 pub fn into_inner(self) -> I {
107 self.input
108 }
109}
110
111impl<I> Iterator for BltFilter<I>
112where
113 I: Source<Item = f32>,
114{
115 type Item = f32;
116
117 #[inline]
118 fn next(&mut self) -> Option<f32> {
119 let last_in_frame = self.input.current_frame_len() == Some(1);
120
121 if self.applier.is_none() {
122 self.applier = Some(self.formula.to_applier(self.input.sample_rate()));
123 }
124
125 let sample = match self.input.next() {
126 None => return None,
127 Some(s) => s,
128 };
129
130 let result = self
131 .applier
132 .as_ref()
133 .unwrap()
134 .apply(sample, self.x_n1, self.x_n2, self.y_n1, self.y_n2);
135
136 self.y_n2 = self.y_n1;
137 self.x_n2 = self.x_n1;
138 self.y_n1 = result;
139 self.x_n1 = sample;
140
141 if last_in_frame {
142 self.applier = None;
143 }
144
145 Some(result)
146 }
147
148 #[inline]
149 fn size_hint(&self) -> (usize, Option<usize>) {
150 self.input.size_hint()
151 }
152}
153
154impl<I> ExactSizeIterator for BltFilter<I> where I: Source<Item = f32> + ExactSizeIterator {}
155
156impl<I> Source for BltFilter<I>
157where
158 I: Source<Item = f32>,
159{
160 #[inline]
161 fn current_frame_len(&self) -> Option<usize> {
162 self.input.current_frame_len()
163 }
164
165 #[inline]
166 fn channels(&self) -> u16 {
167 self.input.channels()
168 }
169
170 #[inline]
171 fn sample_rate(&self) -> u32 {
172 self.input.sample_rate()
173 }
174
175 #[inline]
176 fn total_duration(&self) -> Option<Duration> {
177 self.input.total_duration()
178 }
179
180 #[inline]
181 fn try_seek(&mut self, pos: Duration) -> Result<(), SeekError> {
182 self.input.try_seek(pos)
183 }
184}
185
186#[derive(Clone, Debug)]
187enum BltFormula {
188 LowPass { freq: u32, q: f32 },
189 HighPass { freq: u32, q: f32 },
190}
191
192impl BltFormula {
193 fn to_applier(&self, sampling_frequency: u32) -> BltApplier {
194 match *self {
195 BltFormula::LowPass { freq, q } => {
196 let w0 = 2.0 * PI * freq as f32 / sampling_frequency as f32;
197
198 let alpha = w0.sin() / (2.0 * q);
199 let b1 = 1.0 - w0.cos();
200 let b0 = b1 / 2.0;
201 let b2 = b0;
202 let a0 = 1.0 + alpha;
203 let a1 = -2.0 * w0.cos();
204 let a2 = 1.0 - alpha;
205
206 BltApplier {
207 b0: b0 / a0,
208 b1: b1 / a0,
209 b2: b2 / a0,
210 a1: a1 / a0,
211 a2: a2 / a0,
212 }
213 }
214 BltFormula::HighPass { freq, q } => {
215 let w0 = 2.0 * PI * freq as f32 / sampling_frequency as f32;
216 let cos_w0 = w0.cos();
217 let alpha = w0.sin() / (2.0 * q);
218
219 let b0 = (1.0 + cos_w0) / 2.0;
220 let b1 = -1.0 - cos_w0;
221 let b2 = b0;
222 let a0 = 1.0 + alpha;
223 let a1 = -2.0 * cos_w0;
224 let a2 = 1.0 - alpha;
225
226 BltApplier {
227 b0: b0 / a0,
228 b1: b1 / a0,
229 b2: b2 / a0,
230 a1: a1 / a0,
231 a2: a2 / a0,
232 }
233 }
234 }
235 }
236}
237
238#[derive(Clone, Debug)]
239struct BltApplier {
240 b0: f32,
241 b1: f32,
242 b2: f32,
243 a1: f32,
244 a2: f32,
245}
246
247impl BltApplier {
248 #[inline]
249 fn apply(&self, x_n: f32, x_n1: f32, x_n2: f32, y_n1: f32, y_n2: f32) -> f32 {
250 self.b0 * x_n + self.b1 * x_n1 + self.b2 * x_n2 - self.a1 * y_n1 - self.a2 * y_n2
251 }
252}