1use std::f64::consts::{PI, SQRT_2};
6
7use smallvec::SmallVec;
8
9use crate::block::{Chunk, Tick};
10use crate::node::{AudioNodeEngine, AudioNodeMessage, AudioNodeType, BlockInfo, ChannelInfo};
11use crate::param::{Param, ParamType};
12
13#[derive(Copy, Clone, Debug)]
14pub struct BiquadFilterNodeOptions {
15 pub filter: FilterType,
16 pub frequency: f32,
17 pub detune: f32,
18 pub q: f32,
19 pub gain: f32,
20}
21
22#[derive(Copy, Clone, Debug)]
23pub enum FilterType {
24 LowPass,
25 HighPass,
26 BandPass,
27 LowShelf,
28 HighShelf,
29 Peaking,
30 Notch,
31 AllPass,
32}
33
34impl Default for BiquadFilterNodeOptions {
35 fn default() -> Self {
36 BiquadFilterNodeOptions {
37 filter: FilterType::LowPass,
38 frequency: 350.,
39 detune: 0.,
40 q: 1.,
41 gain: 0.,
42 }
43 }
44}
45
46#[derive(Copy, Clone, Debug)]
47pub enum BiquadFilterNodeMessage {
48 SetFilterType(FilterType),
49}
50
51#[derive(Default, Copy, Clone, PartialEq)]
54struct BiquadState {
55 x1: f64,
57 x2: f64,
59 y1: f64,
61 y2: f64,
63}
64
65impl BiquadState {
66 fn update(&mut self, x: f64, y: f64) {
68 self.x2 = self.x1;
69 self.x1 = x;
70 self.y2 = self.y1;
71 self.y1 = y;
72 }
73}
74
75#[derive(AudioNodeCommon)]
77pub(crate) struct BiquadFilterNode {
78 channel_info: ChannelInfo,
79 filter: FilterType,
80 frequency: Param,
81 detune: Param,
82 q: Param,
83 gain: Param,
84 b0: f64,
88 b1: f64,
92 b2: f64,
96 a1: f64,
100 a2: f64,
104 state: SmallVec<[BiquadState; 2]>,
108}
109
110impl BiquadFilterNode {
111 pub fn new(
112 options: BiquadFilterNodeOptions,
113 channel_info: ChannelInfo,
114 sample_rate: f32,
115 ) -> Self {
116 let mut ret = Self {
117 channel_info,
118 filter: options.filter,
119 frequency: Param::new(options.frequency),
120 gain: Param::new(options.gain),
121 q: Param::new(options.q),
122 detune: Param::new(options.detune),
123 b0: 0.,
124 b1: 0.,
125 b2: 0.,
126 a1: 0.,
127 a2: 0.,
128 state: SmallVec::new(),
129 };
130 ret.update_coefficients(sample_rate);
131 ret
132 }
133
134 pub fn update_parameters(&mut self, info: &BlockInfo, tick: Tick) -> bool {
135 let mut changed = self.frequency.update(info, tick);
136 changed |= self.detune.update(info, tick);
137 changed |= self.q.update(info, tick);
138 changed |= self.gain.update(info, tick);
139
140 if changed {
141 self.update_coefficients(info.sample_rate);
142 }
143 changed
144 }
145
146 fn constant_z_transform(&mut self, b0: f64) {
148 self.b0 = b0;
149 self.b1 = 0.;
150 self.b2 = 0.;
151 self.a1 = 0.;
152 self.a2 = 0.;
153 }
154
155 fn update_coefficients(&mut self, fs: f32) {
159 let g: f64 = self.gain.value().into();
160 let q: f64 = self.q.value().into();
161 let freq: f64 = self.frequency.value().into();
162 let f0: f64 = freq * (2.0_f64).powf(self.detune.value() as f64 / 1200.);
163 let fs: f64 = fs.into();
164 let f0 = if f0 > fs / 2. || !f0.is_finite() {
167 fs / 2.
168 } else if f0 < 0. {
169 0.
170 } else {
171 f0
172 };
173
174 let normalized = f0 / fs;
175 let a = 10.0_f64.powf(g / 40.);
176
177 match self.filter {
180 FilterType::LowPass => {
181 if normalized == 1. {
182 self.constant_z_transform(1.);
183 return;
184 } else if normalized == 0. {
185 self.constant_z_transform(0.);
186 return;
187 }
188 },
189 FilterType::HighPass => {
190 if normalized == 1. {
191 self.constant_z_transform(0.);
192 return;
193 } else if normalized == 0. {
194 self.constant_z_transform(1.);
195 return;
196 }
197 },
198 FilterType::LowShelf => {
199 if normalized == 1. {
200 self.constant_z_transform(a * a);
201 return;
202 } else if normalized == 0. {
203 self.constant_z_transform(1.);
204 return;
205 }
206 },
207 FilterType::HighShelf => {
208 if normalized == 1. {
209 self.constant_z_transform(1.);
210 return;
211 } else if normalized == 0. {
212 self.constant_z_transform(a * a);
213 return;
214 }
215 },
216 FilterType::Peaking => {
217 if normalized == 0. || normalized == 1. {
218 self.constant_z_transform(1.);
219 return;
220 } else if q <= 0. {
221 self.constant_z_transform(a * a);
222 return;
223 }
224 },
225 FilterType::AllPass => {
226 if normalized == 0. || normalized == 1. {
227 self.constant_z_transform(1.);
228 return;
229 } else if q <= 0. {
230 self.constant_z_transform(-1.);
231 return;
232 }
233 },
234 FilterType::Notch => {
235 if normalized == 0. || normalized == 1. {
236 self.constant_z_transform(1.);
237 return;
238 } else if q <= 0. {
239 self.constant_z_transform(0.);
240 return;
241 }
242 },
243 FilterType::BandPass => {
244 if normalized == 0. || normalized == 1. {
245 self.constant_z_transform(0.);
246 return;
247 } else if q <= 0. {
248 self.constant_z_transform(1.);
249 return;
250 }
251 },
252 }
253
254 let omega0 = 2. * PI * normalized;
255 let sin_omega = omega0.sin();
256 let cos_omega = omega0.cos();
257 let alpha_q = sin_omega / (2. * q);
258 let alpha_q_db = sin_omega / (2. * 10.0_f64.powf(q / 20.));
259 let alpha_s = sin_omega / SQRT_2;
260
261 let a0;
263
264 match self.filter {
265 FilterType::LowPass => {
266 self.b0 = (1. - cos_omega) / 2.;
267 self.b1 = 1. - cos_omega;
268 self.b2 = self.b1 / 2.;
269 a0 = 1. + alpha_q_db;
270 self.a1 = -2. * cos_omega;
271 self.a2 = 1. - alpha_q_db;
272 },
273 FilterType::HighPass => {
274 self.b0 = (1. + cos_omega) / 2.;
275 self.b1 = -(1. + cos_omega);
276 self.b2 = -self.b1 / 2.;
277 a0 = 1. + alpha_q_db;
278 self.a1 = -2. * cos_omega;
279 self.a2 = 1. - alpha_q_db;
280 },
281 FilterType::BandPass => {
282 self.b0 = alpha_q;
283 self.b1 = 0.;
284 self.b2 = -alpha_q;
285 a0 = 1. + alpha_q;
286 self.a1 = -2. * cos_omega;
287 self.a2 = 1. - alpha_q;
288 },
289 FilterType::Notch => {
290 self.b0 = 1.;
291 self.b1 = -2. * cos_omega;
292 self.b2 = 1.;
293 a0 = 1. + alpha_q;
294 self.a1 = -2. * cos_omega;
295 self.a2 = 1. - alpha_q;
296 },
297 FilterType::AllPass => {
298 self.b0 = 1. - alpha_q;
299 self.b1 = -2. * cos_omega;
300 self.b2 = 1. + alpha_q;
301 a0 = 1. + alpha_q;
302 self.a1 = -2. * cos_omega;
303 self.a2 = 1. - alpha_q;
304 },
305 FilterType::Peaking => {
306 self.b0 = 1. + alpha_q * a;
307 self.b1 = -2. * cos_omega;
308 self.b2 = 1. - alpha_q * a;
309 a0 = 1. + alpha_q / a;
310 self.a1 = -2. * cos_omega;
311 self.a2 = 1. - alpha_q / a;
312 },
313 FilterType::LowShelf => {
314 let alpha_rt_a = 2. * alpha_s * a.sqrt();
315 self.b0 = a * ((a + 1.) - (a - 1.) * cos_omega + alpha_rt_a);
316 self.b1 = 2. * a * ((a - 1.) - (a + 1.) * cos_omega);
317 self.b2 = a * ((a + 1.) - (a - 1.) * cos_omega - alpha_rt_a);
318 a0 = (a + 1.) + (a - 1.) * cos_omega + alpha_rt_a;
319 self.a1 = -2. * ((a - 1.) + (a + 1.) * cos_omega);
320 self.a2 = (a + 1.) + (a - 1.) * cos_omega - alpha_rt_a;
321 },
322 FilterType::HighShelf => {
323 let alpha_rt_a = 2. * alpha_s * a.sqrt();
324 self.b0 = a * ((a + 1.) + (a - 1.) * cos_omega + alpha_rt_a);
325 self.b1 = -2. * a * ((a - 1.) + (a + 1.) * cos_omega);
326 self.b2 = a * ((a + 1.) + (a - 1.) * cos_omega - alpha_rt_a);
327 a0 = (a + 1.) - (a - 1.) * cos_omega + alpha_rt_a;
328 self.a1 = 2. * ((a - 1.) - (a + 1.) * cos_omega);
329 self.a2 = (a + 1.) - (a - 1.) * cos_omega - alpha_rt_a;
330 },
331 }
332 self.b0 /= a0;
333 self.b1 /= a0;
334 self.b2 /= a0;
335 self.a1 /= a0;
336 self.a2 /= a0;
337 }
338}
339
340impl AudioNodeEngine for BiquadFilterNode {
341 fn node_type(&self) -> AudioNodeType {
342 AudioNodeType::BiquadFilterNode
343 }
344
345 fn process(&mut self, mut inputs: Chunk, info: &BlockInfo) -> Chunk {
346 debug_assert!(inputs.len() == 1);
347 self.state
348 .resize(inputs.blocks[0].chan_count() as usize, Default::default());
349 self.update_parameters(info, Tick(0));
350
351 let repeat_or_silence = inputs.blocks[0].is_silence() || inputs.blocks[0].is_repeat();
358
359 if repeat_or_silence && !self.state.iter().all(|s| *s == self.state[0]) {
360 inputs.blocks[0].explicit_repeat();
364 } else {
365 inputs.blocks[0].explicit_silence();
368 }
369
370 {
371 let mut iter = inputs.blocks[0].iter();
372 while let Some(mut frame) = iter.next() {
373 self.update_parameters(info, frame.tick());
374 frame.mutate_with(|sample, chan| {
375 let state = &mut self.state[chan as usize];
376 let x0 = *sample as f64;
377 let y0 = self.b0 * x0 + self.b1 * state.x1 + self.b2 * state.x2 -
378 self.a1 * state.y1 -
379 self.a2 * state.y2;
380 *sample = y0 as f32;
381 state.update(x0, y0);
382 });
383 }
384 }
385
386 if inputs.blocks[0].is_repeat() {
387 let state = self.state[0];
388 self.state.iter_mut().for_each(|s| *s = state);
389 }
390
391 inputs
392 }
393
394 fn get_param(&mut self, id: ParamType) -> &mut Param {
395 match id {
396 ParamType::Frequency => &mut self.frequency,
397 ParamType::Detune => &mut self.detune,
398 ParamType::Q => &mut self.q,
399 ParamType::Gain => &mut self.gain,
400 _ => panic!("Unknown param {:?} for BiquadFilterNode", id),
401 }
402 }
403
404 fn message_specific(&mut self, message: AudioNodeMessage, sample_rate: f32) {
405 if let AudioNodeMessage::BiquadFilterNode(m) = message {
406 match m {
407 BiquadFilterNodeMessage::SetFilterType(f) => {
408 self.filter = f;
409 self.update_coefficients(sample_rate);
410 },
411 }
412 }
413 }
414}