1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
crate::ix!();
impl ProcessBlockMono for BiquadFilter {
/// This is a function that processes a block
/// of audio data. It takes a mutable
/// reference to `self` (which is an instance
/// of `BiquadFilter`), a pointer to the input
/// audio data (`data`), and an optional
/// pointer to the output audio data (`out`).
///
unsafe fn process_block_mono(
&mut self,
data: *mut f32,
out: Option<*mut f32>)
{
// This is a loop that processes each
// sample in the audio block. `BLOCK_SIZE`
// is assumed to be defined elsewhere.
//
for k in 0..BLOCK_SIZE {
// These lines call the `process`
// method on each of the filter
// coefficients.
//
// It's unclear what these methods do
// without more context, but it's
// likely that they update the
// internal state of the filter.
//
self.a1.process();
self.a2.process();
self.b0.process();
self.b1.process();
self.b2.process();
// These lines calculate the filter
// output for the current sample.
//
// The input sample is converted to
// a `f64`, and then the output is
// computed using the filter
// coefficients (`b0`, `b1`, `b2`,
// `a1`, `a2`) and the current and
// previous input and output samples
// (`reg0`, `reg1`).
//
let input: f64 = *data.add(k) as f64;
let op = input * self.b0.v[0] + self.reg0[0];
self.reg0[0] = input * self.b1.v[0] - self.a1.v[0] * op + self.reg1[0];
self.reg1[0] = input * self.b2.v[0] - self.a2.v[0] * op;
// This code writes the output sample
// to the output buffer if `out` is
// `Some`. Otherwise, it writes the
// output sample back to the input
// buffer.
//
// The `as f32` conversion is
// necessary because the output sample
// is computed as a `f64`, but the
// output buffer expects `f32`
// samples.
//
match out {
Some(out) => {
*out.add(k) = op as f32;
},
None => {
*data.add(k) = op as f32;
}
}
}
// Finally, the code calls
// `flush_denormal` on the `reg0` and
// `reg1` buffers to ensure that any
// denormalized numbers are flushed to
// zero.
//
flush_denormal(&mut self.reg0[0]);
flush_denormal(&mut self.reg1[0]);
}
}