1use crate::common::{ChannelCount, SampleRate};
2use crate::Source;
3use std::f32::consts::PI;
4use std::time::Duration;
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_span = self.input.current_span_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 = self.input.next()?;
126 let result = self
127 .applier
128 .as_ref()
129 .unwrap()
130 .apply(sample, self.x_n1, self.x_n2, self.y_n1, self.y_n2);
131
132 self.y_n2 = self.y_n1;
133 self.x_n2 = self.x_n1;
134 self.y_n1 = result;
135 self.x_n1 = sample;
136
137 if last_in_span {
138 self.applier = None;
139 }
140
141 Some(result)
142 }
143
144 #[inline]
145 fn size_hint(&self) -> (usize, Option<usize>) {
146 self.input.size_hint()
147 }
148}
149
150impl<I> ExactSizeIterator for BltFilter<I> where I: Source<Item = f32> + ExactSizeIterator {}
151
152impl<I> Source for BltFilter<I>
153where
154 I: Source<Item = f32>,
155{
156 #[inline]
157 fn current_span_len(&self) -> Option<usize> {
158 self.input.current_span_len()
159 }
160
161 #[inline]
162 fn channels(&self) -> ChannelCount {
163 self.input.channels()
164 }
165
166 #[inline]
167 fn sample_rate(&self) -> SampleRate {
168 self.input.sample_rate()
169 }
170
171 #[inline]
172 fn total_duration(&self) -> Option<Duration> {
173 self.input.total_duration()
174 }
175
176 #[inline]
177 fn try_seek(&mut self, pos: Duration) -> Result<(), SeekError> {
178 self.input.try_seek(pos)
179 }
180}
181
182#[derive(Clone, Debug)]
183enum BltFormula {
184 LowPass { freq: u32, q: f32 },
185 HighPass { freq: u32, q: f32 },
186}
187
188impl BltFormula {
189 fn to_applier(&self, sampling_frequency: u32) -> BltApplier {
190 match *self {
191 BltFormula::LowPass { freq, q } => {
192 let w0 = 2.0 * PI * freq as f32 / sampling_frequency as f32;
193
194 let alpha = w0.sin() / (2.0 * q);
195 let b1 = 1.0 - w0.cos();
196 let b0 = b1 / 2.0;
197 let b2 = b0;
198 let a0 = 1.0 + alpha;
199 let a1 = -2.0 * w0.cos();
200 let a2 = 1.0 - alpha;
201
202 BltApplier {
203 b0: b0 / a0,
204 b1: b1 / a0,
205 b2: b2 / a0,
206 a1: a1 / a0,
207 a2: a2 / a0,
208 }
209 }
210 BltFormula::HighPass { freq, q } => {
211 let w0 = 2.0 * PI * freq as f32 / sampling_frequency as f32;
212 let cos_w0 = w0.cos();
213 let alpha = w0.sin() / (2.0 * q);
214
215 let b0 = (1.0 + cos_w0) / 2.0;
216 let b1 = -1.0 - cos_w0;
217 let b2 = b0;
218 let a0 = 1.0 + alpha;
219 let a1 = -2.0 * cos_w0;
220 let a2 = 1.0 - alpha;
221
222 BltApplier {
223 b0: b0 / a0,
224 b1: b1 / a0,
225 b2: b2 / a0,
226 a1: a1 / a0,
227 a2: a2 / a0,
228 }
229 }
230 }
231 }
232}
233
234#[derive(Clone, Debug)]
235struct BltApplier {
236 b0: f32,
237 b1: f32,
238 b2: f32,
239 a1: f32,
240 a2: f32,
241}
242
243impl BltApplier {
244 #[inline]
245 fn apply(&self, x_n: f32, x_n1: f32, x_n2: f32, y_n1: f32, y_n2: f32) -> f32 {
246 self.b0 * x_n + self.b1 * x_n1 + self.b2 * x_n2 - self.a1 * y_n1 - self.a2 * y_n2
247 }
248}