Skip to content

Commit 063bd5e

Browse files
committed
ScriptProcessorNode: support bufferSize
1 parent 4642657 commit 063bd5e

File tree

2 files changed

+61
-25
lines changed

2 files changed

+61
-25
lines changed

examples/script_processor.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ fn main() {
2727
..AudioContextOptions::default()
2828
});
2929

30-
let node = context.create_script_processor(128, 1, 1);
30+
let node = context.create_script_processor(512, 1, 1);
3131
node.set_onaudioprocess(|e| {
3232
let mut rng = rand::thread_rng();
3333
e.output_buffer

src/node/script_processor.rs

Lines changed: 60 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,9 @@ impl ScriptProcessorNode {
5050

5151
context.base().register(move |registration| {
5252
let render = ScriptProcessorRenderer {
53-
buffer: None,
53+
input_buffer: Vec::with_capacity(buffer_size / RENDER_QUANTUM_SIZE),
54+
output_buffer: Vec::with_capacity(buffer_size / RENDER_QUANTUM_SIZE),
55+
next_output_buffer: Vec::with_capacity(buffer_size / RENDER_QUANTUM_SIZE),
5456
buffer_size,
5557
number_of_output_channels,
5658
};
@@ -111,14 +113,16 @@ impl ScriptProcessorNode {
111113
}
112114

113115
struct ScriptProcessorRenderer {
114-
buffer: Option<AudioRenderQuantum>, // TODO buffer_size
116+
input_buffer: Vec<AudioRenderQuantum>,
117+
output_buffer: Vec<AudioRenderQuantum>,
118+
next_output_buffer: Vec<AudioRenderQuantum>,
115119
buffer_size: usize,
116120
number_of_output_channels: usize,
117121
}
118122

119123
// SAFETY:
120-
// AudioRenderQuantums are not Send but we promise the `buffer` is None before we ship it to the
121-
// render thread.
124+
// AudioRenderQuantums are not Send but we promise the `buffer` VecDeque is empty before we ship it
125+
// to the render thread.
122126
#[allow(clippy::non_send_fields_in_send_ty)]
123127
unsafe impl Send for ScriptProcessorRenderer {}
124128

@@ -134,34 +138,66 @@ impl AudioProcessor for ScriptProcessorRenderer {
134138
let input = &inputs[0];
135139
let output = &mut outputs[0];
136140

137-
let mut silence = input.clone();
138-
silence.make_silent();
139-
if let Some(buffer) = self.buffer.replace(silence) {
140-
*output = buffer;
141+
output.make_silent();
142+
143+
let number_of_quanta = self.input_buffer.capacity();
144+
145+
self.input_buffer.push(input.clone());
146+
if self.input_buffer.len() == number_of_quanta {
147+
// convert self.input_buffer to an AudioBuffer
148+
let number_of_input_channels = self
149+
.input_buffer
150+
.iter()
151+
.map(|i| i.number_of_channels())
152+
.max()
153+
.unwrap();
154+
let mut input_samples = vec![vec![0.; self.buffer_size]; number_of_input_channels];
155+
self.input_buffer.iter().enumerate().for_each(|(i, b)| {
156+
let offset = RENDER_QUANTUM_SIZE * i;
157+
b.channels()
158+
.iter()
159+
.zip(input_samples.iter_mut())
160+
.for_each(|(c, o)| {
161+
o[offset..(offset + RENDER_QUANTUM_SIZE)].copy_from_slice(c);
162+
});
163+
});
164+
let input_buffer = AudioBuffer::from(input_samples, scope.sample_rate);
165+
166+
// create a suitable output AudioBuffer
167+
let output_samples = vec![vec![0.; self.buffer_size]; self.number_of_output_channels];
168+
let output_buffer = AudioBuffer::from(output_samples, scope.sample_rate);
169+
170+
// emit event to control thread
171+
let playback_time =
172+
scope.current_time + self.buffer_size as f64 / scope.sample_rate as f64;
173+
scope.send_audio_processing_event(input_buffer, output_buffer, playback_time);
174+
175+
// clear existing input buffer
176+
self.input_buffer.clear();
177+
178+
// move next output buffer into current output buffer
179+
std::mem::swap(&mut self.output_buffer, &mut self.next_output_buffer);
180+
// fill next output buffer with silence
181+
self.next_output_buffer.clear();
182+
let silence = output.clone();
183+
self.next_output_buffer.resize(number_of_quanta, silence);
141184
}
142185

143-
// TODO buffer_size
144-
let input_samples = input.channels().iter().map(|c| c.to_vec()).collect();
145-
let input_buffer = AudioBuffer::from(input_samples, scope.sample_rate);
146-
let output_samples = vec![vec![0.; RENDER_QUANTUM_SIZE]; self.number_of_output_channels];
147-
let output_buffer = AudioBuffer::from(output_samples, scope.sample_rate);
148-
149-
let playback_time =
150-
scope.current_time + (RENDER_QUANTUM_SIZE as f32 / scope.sample_rate) as f64; // TODO
151-
scope.send_audio_processing_event(input_buffer, output_buffer, playback_time);
186+
if !self.output_buffer.is_empty() {
187+
*output = self.output_buffer.remove(0);
188+
}
152189

153190
true // TODO - spec says false but that seems weird
154191
}
155192

156193
fn onmessage(&mut self, msg: &mut dyn Any) {
157194
if let Some(buffer) = msg.downcast_mut::<AudioBuffer>() {
158-
if let Some(render_quantum) = &mut self.buffer {
159-
buffer
160-
.channels()
161-
.iter()
162-
.zip(render_quantum.channels_mut())
163-
.for_each(|(i, o)| o.copy_from_slice(i.as_slice())); // TODO bounds check
164-
}
195+
buffer.channels().iter().enumerate().for_each(|(i, c)| {
196+
c.as_slice()
197+
.chunks(RENDER_QUANTUM_SIZE)
198+
.zip(self.next_output_buffer.iter_mut())
199+
.for_each(|(s, o)| o.channel_data_mut(i).copy_from_slice(s))
200+
});
165201
return;
166202
};
167203

0 commit comments

Comments
 (0)