@@ -18,6 +18,12 @@ use web_audio_api::{AudioParam, AudioParamDescriptor, AutomationRate};
18
18
//
19
19
// `WEB_AUDIO_LATENCY=playback cargo run --release --example worklet`
20
20
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
+
21
27
/// Audio source node emitting white noise (random samples)
22
28
struct WhiteNoiseNode {
23
29
/// handle to the audio context, required for all audio nodes
@@ -63,7 +69,10 @@ impl WhiteNoiseNode {
63
69
let ( param, proc) = context. create_audio_param ( param_opts, & registration) ;
64
70
65
71
// 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
+ } ;
67
76
68
77
// setup the audio node, this will live in the control thread (user facing)
69
78
let node = WhiteNoiseNode {
@@ -80,10 +89,15 @@ impl WhiteNoiseNode {
80
89
fn amplitude ( & self ) -> & AudioParam {
81
90
& self . amplitude
82
91
}
92
+
93
+ fn set_noise_color ( & self , color : NoiseColor ) {
94
+ self . registration . post_message ( color) ;
95
+ }
83
96
}
84
97
85
98
struct WhiteNoiseProcessor {
86
99
amplitude : AudioParamId ,
100
+ color : NoiseColor ,
87
101
}
88
102
89
103
impl AudioProcessor for WhiteNoiseProcessor {
@@ -109,16 +123,34 @@ impl AudioProcessor for WhiteNoiseProcessor {
109
123
// 128 (a-rate), so use `cycle` to be able to zip it with the output buffer
110
124
let amplitude_values_cycled = amplitude_values. iter ( ) . cycle ( ) ;
111
125
126
+ let mut prev_sample = 0. ; // TODO, inherit from previous render quantum
127
+
112
128
buf. iter_mut ( )
113
129
. zip ( amplitude_values_cycled)
114
130
. 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
117
138
} )
118
139
} ) ;
119
140
120
141
true // source node will always be active
121
142
}
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
+ }
122
154
}
123
155
124
156
fn main ( ) {
@@ -145,5 +177,12 @@ fn main() {
145
177
noise. connect ( & context. destination ( ) ) ;
146
178
147
179
// 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 ) ;
148
187
std:: thread:: sleep ( std:: time:: Duration :: from_secs ( 4 ) ) ;
149
188
}
0 commit comments