1use crate::buffer::{AudioBuffer, AudioBufferOptions};
4use crate::context::{
5 AudioContextRegistration, AudioContextState, AudioParamId, ConcreteBaseAudioContext,
6 DESTINATION_NODE_ID,
7};
8use crate::decoding::decode_media_data;
9use crate::events::{Event, EventHandler, EventType};
10use crate::node::{AudioNode, AudioNodeOptions};
11use crate::param::AudioParamDescriptor;
12use crate::periodic_wave::{PeriodicWave, PeriodicWaveOptions};
13use crate::{node, AudioListener, RENDER_QUANTUM_SIZE};
14
15use std::future::Future;
16
17#[allow(clippy::module_name_repetitions)]
23pub trait BaseAudioContext {
24 #[doc(hidden)] fn base(&self) -> &ConcreteBaseAudioContext;
27
28 fn decode_audio_data_sync<R: std::io::Read + Send + Sync + 'static>(
69 &self,
70 input: R,
71 ) -> Result<AudioBuffer, Box<dyn std::error::Error + Send + Sync>> {
72 decode_media_data(input, self.sample_rate())
73 }
74
75 fn decode_audio_data<R: std::io::Read + Send + Sync + 'static>(
96 &self,
97 input: R,
98 ) -> impl Future<Output = Result<AudioBuffer, Box<dyn std::error::Error + Send + Sync>>>
99 + Send
100 + 'static {
101 let sample_rate = self.sample_rate();
102 async move { decode_media_data(input, sample_rate) }
103 }
104
105 #[must_use]
111 fn create_buffer(
112 &self,
113 number_of_channels: usize,
114 length: usize,
115 sample_rate: f32,
116 ) -> AudioBuffer {
117 let options = AudioBufferOptions {
118 number_of_channels,
119 length,
120 sample_rate,
121 };
122
123 AudioBuffer::new(options)
124 }
125
126 #[must_use]
128 fn create_analyser(&self) -> node::AnalyserNode {
129 node::AnalyserNode::new(self.base(), node::AnalyserOptions::default())
130 }
131
132 #[must_use]
134 fn create_biquad_filter(&self) -> node::BiquadFilterNode {
135 node::BiquadFilterNode::new(self.base(), node::BiquadFilterOptions::default())
136 }
137
138 #[must_use]
140 fn create_buffer_source(&self) -> node::AudioBufferSourceNode {
141 node::AudioBufferSourceNode::new(self.base(), node::AudioBufferSourceOptions::default())
142 }
143
144 #[must_use]
146 fn create_constant_source(&self) -> node::ConstantSourceNode {
147 node::ConstantSourceNode::new(self.base(), node::ConstantSourceOptions::default())
148 }
149
150 #[must_use]
152 fn create_convolver(&self) -> node::ConvolverNode {
153 node::ConvolverNode::new(self.base(), node::ConvolverOptions::default())
154 }
155
156 #[must_use]
158 fn create_channel_merger(&self, number_of_inputs: usize) -> node::ChannelMergerNode {
159 let opts = node::ChannelMergerOptions {
160 number_of_inputs,
161 ..node::ChannelMergerOptions::default()
162 };
163 node::ChannelMergerNode::new(self.base(), opts)
164 }
165
166 #[must_use]
168 fn create_channel_splitter(&self, number_of_outputs: usize) -> node::ChannelSplitterNode {
169 let opts = node::ChannelSplitterOptions {
170 number_of_outputs,
171 ..node::ChannelSplitterOptions::default()
172 };
173 node::ChannelSplitterNode::new(self.base(), opts)
174 }
175
176 #[must_use]
178 fn create_delay(&self, max_delay_time: f64) -> node::DelayNode {
179 let opts = node::DelayOptions {
180 max_delay_time,
181 ..node::DelayOptions::default()
182 };
183 node::DelayNode::new(self.base(), opts)
184 }
185
186 #[must_use]
188 fn create_dynamics_compressor(&self) -> node::DynamicsCompressorNode {
189 node::DynamicsCompressorNode::new(self.base(), node::DynamicsCompressorOptions::default())
190 }
191
192 #[must_use]
194 fn create_gain(&self) -> node::GainNode {
195 node::GainNode::new(self.base(), node::GainOptions::default())
196 }
197
198 #[must_use]
207 fn create_iir_filter(&self, feedforward: Vec<f64>, feedback: Vec<f64>) -> node::IIRFilterNode {
208 let options = node::IIRFilterOptions {
209 audio_node_options: AudioNodeOptions::default(),
210 feedforward,
211 feedback,
212 };
213 node::IIRFilterNode::new(self.base(), options)
214 }
215
216 #[must_use]
218 fn create_oscillator(&self) -> node::OscillatorNode {
219 node::OscillatorNode::new(self.base(), node::OscillatorOptions::default())
220 }
221
222 #[must_use]
224 fn create_panner(&self) -> node::PannerNode {
225 node::PannerNode::new(self.base(), node::PannerOptions::default())
226 }
227
228 #[must_use]
233 fn create_periodic_wave(&self, options: PeriodicWaveOptions) -> PeriodicWave {
234 PeriodicWave::new(self.base(), options)
235 }
236
237 #[must_use]
246 fn create_script_processor(
247 &self,
248 buffer_size: usize,
249 number_of_input_channels: usize,
250 number_of_output_channels: usize,
251 ) -> node::ScriptProcessorNode {
252 let options = node::ScriptProcessorOptions {
253 buffer_size,
254 number_of_input_channels,
255 number_of_output_channels,
256 };
257
258 node::ScriptProcessorNode::new(self.base(), options)
259 }
260
261 #[must_use]
263 fn create_stereo_panner(&self) -> node::StereoPannerNode {
264 node::StereoPannerNode::new(self.base(), node::StereoPannerOptions::default())
265 }
266
267 #[must_use]
269 fn create_wave_shaper(&self) -> node::WaveShaperNode {
270 node::WaveShaperNode::new(self.base(), node::WaveShaperOptions::default())
271 }
272
273 #[must_use]
276 fn destination(&self) -> node::AudioDestinationNode {
277 let registration = AudioContextRegistration {
278 id: DESTINATION_NODE_ID,
279 context: self.base().clone(),
280 };
281 let channel_config = self.base().destination_channel_config();
282 node::AudioDestinationNode::from_raw_parts(registration, channel_config)
283 }
284
285 #[must_use]
287 fn listener(&self) -> AudioListener {
288 self.base().listener()
289 }
290
291 #[must_use]
293 fn sample_rate(&self) -> f32 {
294 self.base().sample_rate()
295 }
296
297 #[must_use]
299 fn state(&self) -> AudioContextState {
300 self.base().state()
301 }
302
303 #[must_use]
306 fn current_time(&self) -> f64 {
307 self.base().current_time()
308 }
309
310 #[must_use]
312 fn render_quantum_size(&self) -> usize {
313 RENDER_QUANTUM_SIZE
314 }
315
316 #[must_use]
320 fn create_audio_param(
321 &self,
322 opts: AudioParamDescriptor,
323 dest: &AudioContextRegistration,
324 ) -> (crate::param::AudioParam, AudioParamId) {
325 let param = self.base().register(move |registration| {
326 let (node, proc) = crate::param::audio_param_pair(opts, registration);
327
328 (node, Box::new(proc))
329 });
330
331 self.base().queue_audio_param_connect(¶m, dest.id());
333
334 let proc_id = AudioParamId(param.registration().id().0);
335 (param, proc_id)
336 }
337
338 fn set_onstatechange<F: FnMut(Event) + Send + 'static>(&self, mut callback: F) {
343 let callback = move |_| {
344 callback(Event {
345 type_: "statechange",
346 })
347 };
348
349 self.base().set_event_handler(
350 EventType::StateChange,
351 EventHandler::Multiple(Box::new(callback)),
352 );
353 }
354
355 fn clear_onstatechange(&self) {
357 self.base().clear_event_handler(EventType::StateChange);
358 }
359
360 #[cfg(test)]
361 fn mock_registration(&self) -> AudioContextRegistration {
362 AudioContextRegistration {
363 id: crate::context::AudioNodeId(0),
364 context: self.base().clone(),
365 }
366 }
367}
368
369#[cfg(test)]
370mod tests {
371 use super::*;
372 use crate::context::OfflineAudioContext;
373
374 use float_eq::assert_float_eq;
375
376 fn require_send_sync_static<T: Send + Sync + 'static>(_: T) {}
377
378 #[test]
379 fn test_decode_audio_data_sync() {
380 let context = OfflineAudioContext::new(1, 1, 44100.);
381 let file = std::fs::File::open("samples/sample.wav").unwrap();
382 let audio_buffer = context.decode_audio_data_sync(file).unwrap();
383
384 assert_eq!(audio_buffer.sample_rate(), 44100.);
385 assert_eq!(audio_buffer.length(), 142_187);
386 assert_eq!(audio_buffer.number_of_channels(), 2);
387 assert_float_eq!(audio_buffer.duration(), 3.224, abs_all <= 0.001);
388
389 let left_start = &audio_buffer.get_channel_data(0)[0..100];
390 let right_start = &audio_buffer.get_channel_data(1)[0..100];
391 assert!(left_start != right_start);
393 }
394
395 #[test]
396 fn test_decode_audio_data_future_send_static() {
397 let context = OfflineAudioContext::new(1, 1, 44100.);
398 let file = std::fs::File::open("samples/sample.wav").unwrap();
399 let future = context.decode_audio_data(file);
400 require_send_sync_static(future);
401 }
402
403 #[test]
404 fn test_decode_audio_data_async() {
405 use futures::executor;
406 let context = OfflineAudioContext::new(1, 1, 44100.);
407 let file = std::fs::File::open("samples/sample.wav").unwrap();
408 let future = context.decode_audio_data(file);
409 let audio_buffer = executor::block_on(future).unwrap();
410
411 assert_eq!(audio_buffer.sample_rate(), 44100.);
412 assert_eq!(audio_buffer.length(), 142_187);
413 assert_eq!(audio_buffer.number_of_channels(), 2);
414 assert_float_eq!(audio_buffer.duration(), 3.224, abs_all <= 0.001);
415
416 let left_start = &audio_buffer.get_channel_data(0)[0..100];
417 let right_start = &audio_buffer.get_channel_data(1)[0..100];
418 assert!(left_start != right_start);
420 }
421
422 #[allow(dead_code)]
425 fn test_decode_audio_data_empty() {
426 let context = OfflineAudioContext::new(1, 1, 44100.);
427 let file = std::fs::File::open("samples/empty_2c.wav").unwrap();
428 let audio_buffer = context.decode_audio_data_sync(file).unwrap();
429 assert_eq!(audio_buffer.length(), 0);
430 }
431
432 #[test]
433 fn test_decode_audio_data_decoding_error() {
434 let context = OfflineAudioContext::new(1, 1, 44100.);
435 let file = std::fs::File::open("samples/corrupt.wav").unwrap();
436 assert!(context.decode_audio_data_sync(file).is_err());
437 }
438
439 #[test]
440 fn test_create_buffer() {
441 let number_of_channels = 3;
442 let length = 2000;
443 let sample_rate = 96_000.;
444
445 let context = OfflineAudioContext::new(1, 1, 44100.);
446 let buffer = context.create_buffer(number_of_channels, length, sample_rate);
447
448 assert_eq!(buffer.number_of_channels(), 3);
449 assert_eq!(buffer.length(), 2000);
450 assert_float_eq!(buffer.sample_rate(), 96000., abs_all <= 0.);
451 }
452}