Skip to content

Commit dc3fab7

Browse files
committed
Offline rendering optim: don't use copy_to_channel
1 parent 992eade commit dc3fab7

File tree

1 file changed

+22
-27
lines changed

1 file changed

+22
-27
lines changed

src/render/thread.rs

Lines changed: 22 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use futures_channel::{mpsc, oneshot};
1313
use futures_util::StreamExt as _;
1414

1515
use super::AudioRenderQuantum;
16-
use crate::buffer::{AudioBuffer, AudioBufferOptions};
16+
use crate::buffer::AudioBuffer;
1717
use crate::context::{
1818
AudioContextState, AudioNodeId, OfflineAudioContext, OfflineAudioContextCallback,
1919
};
@@ -240,13 +240,10 @@ impl RenderThread {
240240
) -> AudioBuffer {
241241
let length = context.length();
242242

243-
let options = AudioBufferOptions {
244-
number_of_channels: self.number_of_channels,
245-
length,
246-
sample_rate: self.sample_rate,
247-
};
243+
// construct a properly sized output buffer
244+
let mut buffer = Vec::with_capacity(self.number_of_channels);
245+
buffer.resize_with(buffer.capacity(), || Vec::with_capacity(length));
248246

249-
let mut buffer = AudioBuffer::new(options);
250247
let num_frames = (length + RENDER_QUANTUM_SIZE - 1) / RENDER_QUANTUM_SIZE;
251248

252249
// Handle initial control messages
@@ -271,7 +268,7 @@ impl RenderThread {
271268
}
272269
}
273270

274-
buffer
271+
AudioBuffer::from(buffer, self.sample_rate)
275272
}
276273

277274
// Render method of the `OfflineAudioContext::start_rendering`
@@ -286,13 +283,10 @@ impl RenderThread {
286283
mut resume_receiver: mpsc::Receiver<()>,
287284
event_loop: &EventLoop,
288285
) -> AudioBuffer {
289-
let options = AudioBufferOptions {
290-
number_of_channels: self.number_of_channels,
291-
length,
292-
sample_rate: self.sample_rate,
293-
};
286+
// construct a properly sized output buffer
287+
let mut buffer = Vec::with_capacity(self.number_of_channels);
288+
buffer.resize_with(buffer.capacity(), || Vec::with_capacity(length));
294289

295-
let mut buffer = AudioBuffer::new(options);
296290
let num_frames = (length + RENDER_QUANTUM_SIZE - 1) / RENDER_QUANTUM_SIZE;
297291

298292
// Handle addition/removal of nodes/edges
@@ -318,11 +312,11 @@ impl RenderThread {
318312
}
319313
}
320314

321-
buffer
315+
AudioBuffer::from(buffer, self.sample_rate)
322316
}
323317

324318
/// Render a single quantum into an AudioBuffer
325-
fn render_offline_quantum(&mut self, buffer: &mut AudioBuffer) {
319+
fn render_offline_quantum(&mut self, buffer: &mut [Vec<f32>]) {
326320
// Update time
327321
let current_frame = self
328322
.frames_played
@@ -346,17 +340,18 @@ impl RenderThread {
346340
#[cfg(not(any(target_arch = "x86", target_arch = "x86_64", target_arch = "aarch64")))]
347341
let rendered = graph.render(&scope);
348342

349-
rendered
350-
.channels()
351-
.iter()
352-
.enumerate()
353-
.for_each(|(channel_number, rendered_channel)| {
354-
buffer.copy_to_channel_with_offset(
355-
rendered_channel,
356-
channel_number,
357-
current_frame as usize,
358-
);
359-
});
343+
// Use a specialized copyToChannel implementation for performance
344+
let remaining = (buffer[0].capacity() - buffer[0].len()).min(RENDER_QUANTUM_SIZE);
345+
let channels = rendered.channels();
346+
buffer.iter_mut().enumerate().for_each(|(i, b)| {
347+
let c = channels
348+
.get(i)
349+
.map(AsRef::as_ref)
350+
// When there are no input nodes for the destination, only a single silent channel
351+
// is emitted. So manually pad the missing channels with silence
352+
.unwrap_or(&[0.; RENDER_QUANTUM_SIZE]);
353+
b.extend_from_slice(&c[..remaining]);
354+
});
360355
}
361356

362357
pub fn render<S: FromSample<f32> + Clone>(&mut self, output_buffer: &mut [S]) {

0 commit comments

Comments
 (0)