Skip to content

Commit 12fa04c

Browse files
committed
BiquadFilterNode: improve cache locality, do not use heap
Vec vs ArrayVec makes no difference in performance but it does save a deallocation when the node drops. The cache locality (due to packing the x and y values together) makes a very subtle improvement locally (a few percent in the biquad bench)
1 parent c47dcd9 commit 12fa04c

File tree

1 file changed

+17
-26
lines changed

1 file changed

+17
-26
lines changed

src/node/biquad_filter.rs

Lines changed: 17 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
use std::any::Any;
33
use std::f64::consts::{PI, SQRT_2};
44

5+
use arrayvec::ArrayVec;
56
use num_complex::Complex;
67

78
use crate::context::{AudioContextRegistration, AudioParamId, BaseAudioContext};
@@ -396,10 +397,7 @@ impl BiquadFilterNode {
396397
frequency: f_proc,
397398
q: q_proc,
398399
type_,
399-
x1: Vec::with_capacity(MAX_CHANNELS),
400-
x2: Vec::with_capacity(MAX_CHANNELS),
401-
y1: Vec::with_capacity(MAX_CHANNELS),
402-
y2: Vec::with_capacity(MAX_CHANNELS),
400+
xy: ArrayVec::new(),
403401
};
404402

405403
let node = Self {
@@ -549,10 +547,7 @@ struct BiquadFilterRenderer {
549547
/// `BiquadFilterType`
550548
type_: BiquadFilterType,
551549
// keep filter state for each channel
552-
x1: Vec<f64>,
553-
x2: Vec<f64>,
554-
y1: Vec<f64>,
555-
y2: Vec<f64>,
550+
xy: ArrayVec<[f64; 4], MAX_CHANNELS>,
556551
}
557552

558553
impl AudioProcessor for BiquadFilterRenderer {
@@ -572,10 +567,10 @@ impl AudioProcessor for BiquadFilterRenderer {
572567
if input.is_silent() {
573568
let mut ended = true;
574569

575-
if self.x1.iter().any(|&v| v.is_normal())
576-
|| self.x2.iter().any(|&v| v.is_normal())
577-
|| self.y1.iter().any(|&v| v.is_normal())
578-
|| self.y2.iter().any(|&v| v.is_normal())
570+
if self
571+
.xy
572+
.iter()
573+
.any(|v| v.iter().copied().any(f64::is_normal))
579574
{
580575
ended = false;
581576
}
@@ -595,16 +590,16 @@ impl AudioProcessor for BiquadFilterRenderer {
595590
// see https://webaudio.github.io/web-audio-api/#channels-tail-time
596591
let num_channels = input.number_of_channels();
597592

598-
if num_channels != self.x1.len() {
599-
self.x1.resize(num_channels, 0.);
600-
self.x2.resize(num_channels, 0.);
601-
self.y1.resize(num_channels, 0.);
602-
self.y2.resize(num_channels, 0.);
593+
if num_channels != self.xy.len() {
594+
self.xy.truncate(num_channels);
595+
for _ in self.xy.len()..num_channels {
596+
self.xy.push([0.; 4]);
597+
}
603598
}
604599

605600
output.set_number_of_channels(num_channels);
606601
} else {
607-
let num_channels = self.x1.len();
602+
let num_channels = self.xy.len();
608603
output.set_number_of_channels(num_channels);
609604
}
610605

@@ -655,10 +650,9 @@ impl AudioProcessor for BiquadFilterRenderer {
655650
input.channel_data(channel_number)
656651
};
657652
// retrieve state from previous block
658-
let mut x1 = self.x1[channel_number];
659-
let mut x2 = self.x2[channel_number];
660-
let mut y1 = self.y1[channel_number];
661-
let mut y2 = self.y2[channel_number];
653+
let (mut x1, mut x2, mut y1, mut y2) = match self.xy[channel_number] {
654+
[x1, x2, y1, y2] => (x1, x2, y1, y2),
655+
};
662656

663657
output_channel
664658
.iter_mut()
@@ -680,10 +674,7 @@ impl AudioProcessor for BiquadFilterRenderer {
680674
});
681675

682676
// store channel state for next block
683-
self.x1[channel_number] = x1;
684-
self.x2[channel_number] = x2;
685-
self.y1[channel_number] = y1;
686-
self.y2[channel_number] = y2;
677+
self.xy[channel_number] = [x1, x2, y1, y2];
687678
}
688679

689680
true

0 commit comments

Comments
 (0)