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