Skip to content

Commit 0f1df1a

Browse files
committed
Extend canonical AudioWorkletNode example, add message passing
1 parent 7d10ff7 commit 0f1df1a

File tree

1 file changed

+42
-3
lines changed

1 file changed

+42
-3
lines changed

examples/worklet.rs

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,12 @@ use web_audio_api::{AudioParam, AudioParamDescriptor, AutomationRate};
1818
//
1919
// `WEB_AUDIO_LATENCY=playback cargo run --release --example worklet`
2020

21+
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
22+
enum NoiseColor {
23+
White, // zero mean, constant variance, uncorrelated in time
24+
Red, // zero mean, constant variance, serially correlated in time
25+
}
26+
2127
/// Audio source node emitting white noise (random samples)
2228
struct WhiteNoiseNode {
2329
/// handle to the audio context, required for all audio nodes
@@ -63,7 +69,10 @@ impl WhiteNoiseNode {
6369
let (param, proc) = context.create_audio_param(param_opts, &registration);
6470

6571
// setup the processor, this will run in the render thread
66-
let render = WhiteNoiseProcessor { amplitude: proc };
72+
let render = WhiteNoiseProcessor {
73+
amplitude: proc,
74+
color: NoiseColor::White,
75+
};
6776

6877
// setup the audio node, this will live in the control thread (user facing)
6978
let node = WhiteNoiseNode {
@@ -80,10 +89,15 @@ impl WhiteNoiseNode {
8089
fn amplitude(&self) -> &AudioParam {
8190
&self.amplitude
8291
}
92+
93+
fn set_noise_color(&self, color: NoiseColor) {
94+
self.registration.post_message(color);
95+
}
8396
}
8497

8598
struct WhiteNoiseProcessor {
8699
amplitude: AudioParamId,
100+
color: NoiseColor,
87101
}
88102

89103
impl AudioProcessor for WhiteNoiseProcessor {
@@ -109,16 +123,34 @@ impl AudioProcessor for WhiteNoiseProcessor {
109123
// 128 (a-rate), so use `cycle` to be able to zip it with the output buffer
110124
let amplitude_values_cycled = amplitude_values.iter().cycle();
111125

126+
let mut prev_sample = 0.; // TODO, inherit from previous render quantum
127+
112128
buf.iter_mut()
113129
.zip(amplitude_values_cycled)
114130
.for_each(|(output_sample, amplitude)| {
115-
let rand: f32 = rng.gen_range(-1.0..1.0);
116-
*output_sample = *amplitude * rand
131+
let mut value: f32 = rng.gen_range(-1.0..1.0);
132+
if self.color == NoiseColor::Red {
133+
// red noise samples correlate with their previous value
134+
value = value * 0.2 + prev_sample * 0.8;
135+
prev_sample = value;
136+
}
137+
*output_sample = *amplitude * value
117138
})
118139
});
119140

120141
true // source node will always be active
121142
}
143+
144+
fn onmessage(&mut self, msg: Box<dyn std::any::Any + Send + 'static>) {
145+
// handle incoming signals requesting for change of color
146+
if let Some(&color) = msg.downcast_ref::<NoiseColor>() {
147+
self.color = color;
148+
return;
149+
}
150+
151+
// ignore other incoming messages
152+
log::warn!("WhiteNoiseProcessor: Ignoring incoming message");
153+
}
122154
}
123155

124156
fn main() {
@@ -145,5 +177,12 @@ fn main() {
145177
noise.connect(&context.destination());
146178

147179
// enjoy listening
180+
println!("Low volume");
181+
std::thread::sleep(std::time::Duration::from_secs(2));
182+
println!("High volume");
183+
std::thread::sleep(std::time::Duration::from_secs(2));
184+
185+
println!("Switch to red noise");
186+
noise.set_noise_color(NoiseColor::Red);
148187
std::thread::sleep(std::time::Duration::from_secs(4));
149188
}

0 commit comments

Comments
 (0)