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