Skip to content

Commit 57d0400

Browse files
committed
add optimizations to TripleBufferNode
1 parent cd453f8 commit 57d0400

File tree

1 file changed

+92
-9
lines changed

1 file changed

+92
-9
lines changed

crates/firewheel-nodes/src/triple_buffer.rs

Lines changed: 92 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,24 @@ impl<'a> OutputAudioData<'a> {
172172
.map(|s| s.consumer.read().buffers.as_slice())
173173
}
174174

175+
/// Get the latest channels of audio data, along with a "generation" value.
176+
///
177+
/// The generation value is equal to how many times the buffer has been updated
178+
/// since the node was first created. This can be used to quickly check if the
179+
/// buffer differs from the previous read.
180+
///
181+
/// The samples are in de-interleaved format (one `Vec` for each channel). The
182+
/// length of each `Vec` will be equal to the `window_size` parameter at the
183+
/// time the buffer was last updated.
184+
///
185+
/// If the node is not currently active, then this will return `None`.
186+
pub fn channels_with_generation<'b>(&'b mut self) -> Option<(&'b [Vec<f32>], u64)> {
187+
self.guarded_state.as_mut().map(|s| {
188+
let data = s.consumer.read();
189+
(data.buffers.as_slice(), data.generation)
190+
})
191+
}
192+
175193
/// Peek the audio data that is currently in the buffer without checking if
176194
/// there is new data.
177195
///
@@ -211,9 +229,12 @@ impl AudioNode for TripleBufferNode {
211229
let sample_rate = cx.stream_info.sample_rate;
212230
let max_window_size_frames = config.max_window_size.as_frames(sample_rate) as usize;
213231

214-
let (producer, consumer) = triple_buffer::triple_buffer::<TripleBufferData>(
215-
&TripleBufferData::new(config.channels.get().get() as usize, max_window_size_frames),
216-
);
232+
let (producer, consumer) =
233+
triple_buffer::triple_buffer::<TripleBufferData>(&TripleBufferData::new(
234+
config.channels.get().get() as usize,
235+
max_window_size_frames,
236+
0,
237+
));
217238

218239
let state = cx.custom_state_mut::<TripleBufferState>().unwrap();
219240

@@ -244,6 +265,10 @@ impl AudioNode for TripleBufferNode {
244265
tmp_ring_buffer,
245266
ring_buf_ptr: 0,
246267
active_state,
268+
generation: 0,
269+
prev_publish_was_silent: true,
270+
num_silent_frames_in_tmp: window_size_frames,
271+
tmp_buffer_needs_cleared: false,
247272
}
248273
}
249274
}
@@ -261,6 +286,11 @@ struct Processor {
261286

262287
// The processor only uses this when a new stream has started.
263288
active_state: Arc<Mutex<Option<ActiveState>>>,
289+
generation: u64,
290+
291+
prev_publish_was_silent: bool,
292+
num_silent_frames_in_tmp: usize,
293+
tmp_buffer_needs_cleared: bool,
264294
}
265295

266296
impl AudioNodeProcessor for Processor {
@@ -290,12 +320,15 @@ impl AudioNodeProcessor for Processor {
290320
if !self.params.enabled {
291321
if was_enabled {
292322
{
293-
let out_buffer = producer.input_buffer_mut();
323+
let buffer = producer.input_buffer_mut();
294324

295-
for out_ch in out_buffer.buffers.iter_mut() {
296-
out_ch.clear();
297-
out_ch.resize(self.window_size_frames, 0.0);
325+
for buf_ch in buffer.buffers.iter_mut() {
326+
buf_ch.clear();
327+
buf_ch.resize(self.window_size_frames, 0.0);
298328
}
329+
330+
self.generation += 1;
331+
buffer.generation = self.generation;
299332
}
300333

301334
producer.publish();
@@ -304,12 +337,17 @@ impl AudioNodeProcessor for Processor {
304337
tmp_ch.clear();
305338
tmp_ch.resize(self.window_size_frames, 0.0);
306339
}
340+
307341
self.ring_buf_ptr = 0;
342+
self.prev_publish_was_silent = true;
343+
self.num_silent_frames_in_tmp = self.window_size_frames;
344+
self.tmp_buffer_needs_cleared = false;
308345
}
309346

310347
return ProcessStatus::ClearAllOutputs;
311348
}
312349

350+
let mut resized = false;
313351
if self.tmp_ring_buffer[0].len() != self.window_size_frames {
314352
let prev_window_size_frames = self.tmp_ring_buffer[0].len();
315353

@@ -348,6 +386,27 @@ impl AudioNodeProcessor for Processor {
348386
}
349387

350388
self.ring_buf_ptr = 0;
389+
self.num_silent_frames_in_tmp = 0;
390+
resized = true;
391+
}
392+
393+
let input_is_silent = info
394+
.in_silence_mask
395+
.all_channels_silent(buffers.inputs.len());
396+
if input_is_silent {
397+
self.num_silent_frames_in_tmp =
398+
(self.num_silent_frames_in_tmp + info.frames).min(self.window_size_frames);
399+
} else {
400+
self.num_silent_frames_in_tmp = 0;
401+
}
402+
403+
if self.num_silent_frames_in_tmp == self.window_size_frames
404+
&& self.prev_publish_was_silent
405+
&& !resized
406+
{
407+
// The previous publish already contained silence, so no need to publish again.
408+
self.tmp_buffer_needs_cleared = true;
409+
return ProcessStatus::ClearAllOutputs;
351410
}
352411

353412
if info.frames >= self.window_size_frames {
@@ -357,7 +416,18 @@ impl AudioNodeProcessor for Processor {
357416
.copy_from_slice(&in_ch[info.frames - self.window_size_frames..info.frames]);
358417
}
359418
self.ring_buf_ptr = 0;
419+
self.tmp_buffer_needs_cleared = false;
360420
} else {
421+
if self.tmp_buffer_needs_cleared {
422+
self.tmp_buffer_needs_cleared = false;
423+
424+
for tmp_ch in self.tmp_ring_buffer.iter_mut() {
425+
tmp_ch.clear();
426+
tmp_ch.resize(self.window_size_frames, 0.0);
427+
}
428+
self.ring_buf_ptr = 0;
429+
}
430+
361431
let first_copy_frames = info.frames.min(self.window_size_frames - self.ring_buf_ptr);
362432
let second_copy_frames = info.frames - first_copy_frames;
363433

@@ -399,10 +469,15 @@ impl AudioNodeProcessor for Processor {
399469
buf_ch.extend_from_slice(&tmp_ch[0..second_copy_frames]);
400470
}
401471
}
472+
473+
self.generation += 1;
474+
buffer.generation = self.generation;
402475
}
403476

404477
producer.publish();
405478

479+
self.prev_publish_was_silent = self.num_silent_frames_in_tmp == self.window_size_frames;
480+
406481
ProcessStatus::ClearAllOutputs
407482
}
408483

@@ -430,11 +505,17 @@ impl AudioNodeProcessor for Processor {
430505
})
431506
.collect();
432507
self.ring_buf_ptr = 0;
508+
self.num_silent_frames_in_tmp = self.window_size_frames;
509+
self.tmp_buffer_needs_cleared = false;
510+
self.prev_publish_was_silent = true;
511+
512+
self.generation += 1;
433513

434514
let (producer, consumer) =
435515
triple_buffer::triple_buffer::<TripleBufferData>(&TripleBufferData::new(
436516
self.config.channels.get().get() as usize,
437517
self.max_window_size_frames,
518+
self.generation,
438519
));
439520

440521
*self.active_state.lock().unwrap() = Some(ActiveState {
@@ -451,10 +532,11 @@ impl AudioNodeProcessor for Processor {
451532
struct TripleBufferData {
452533
buffers: Vec<Vec<f32>>,
453534
max_frames: usize,
535+
generation: u64,
454536
}
455537

456538
impl TripleBufferData {
457-
fn new(num_channels: usize, max_frames: usize) -> Self {
539+
fn new(num_channels: usize, max_frames: usize, generation: u64) -> Self {
458540
let mut buffers = Vec::new();
459541
buffers.reserve_exact(num_channels);
460542

@@ -470,12 +552,13 @@ impl TripleBufferData {
470552
Self {
471553
buffers,
472554
max_frames,
555+
generation,
473556
}
474557
}
475558
}
476559

477560
impl Clone for TripleBufferData {
478561
fn clone(&self) -> Self {
479-
Self::new(self.buffers.len(), self.max_frames)
562+
Self::new(self.buffers.len(), self.max_frames, self.generation)
480563
}
481564
}

0 commit comments

Comments
 (0)