1use crate::buffer::{AudioBuffer, AudioBufferOptions};
4use crate::context::{
5 AudioContextRegistration, AudioContextState, AudioParamId, ConcreteBaseAudioContext,
6 DESTINATION_NODE_ID,
7};
8use crate::decoding::MediaDecoder;
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>(
67 &self,
68 input: R,
69 ) -> Result<AudioBuffer, Box<dyn std::error::Error + Send + Sync>> {
70 let mut buffer = MediaDecoder::try_new(input)?
72 .collect::<Result<Vec<_>, _>>()?
73 .into_iter()
74 .reduce(|mut accum, item| {
75 accum.extend(&item);
76 accum
77 })
78 .unwrap_or_else(|| AudioBuffer::from(vec![vec![]], self.sample_rate()));
80
81 buffer.resample(self.sample_rate());
83
84 Ok(buffer)
85 }
86
87 fn decode_audio_data<R: std::io::Read + Send + Sync + 'static>(
106 &self,
107 input: R,
108 ) -> impl Future<Output = Result<AudioBuffer, Box<dyn std::error::Error + Send + Sync>>>
109 + Send
110 + 'static {
111 let sample_rate = self.sample_rate();
112 async move {
113 let mut buffer = MediaDecoder::try_new(input)?
115 .collect::<Result<Vec<_>, _>>()?
116 .into_iter()
117 .reduce(|mut accum, item| {
118 accum.extend(&item);
119 accum
120 })
121 .unwrap_or_else(|| AudioBuffer::from(vec![vec![]], sample_rate));
123
124 buffer.resample(sample_rate);
126
127 Ok(buffer)
128 }
129 }
130
131 #[must_use]
137 fn create_buffer(
138 &self,
139 number_of_channels: usize,
140 length: usize,
141 sample_rate: f32,
142 ) -> AudioBuffer {
143 let options = AudioBufferOptions {
144 number_of_channels,
145 length,
146 sample_rate,
147 };
148
149 AudioBuffer::new(options)
150 }
151
152 #[must_use]
154 fn create_analyser(&self) -> node::AnalyserNode {
155 node::AnalyserNode::new(self.base(), node::AnalyserOptions::default())
156 }
157
158 #[must_use]
160 fn create_biquad_filter(&self) -> node::BiquadFilterNode {
161 node::BiquadFilterNode::new(self.base(), node::BiquadFilterOptions::default())
162 }
163
164 #[must_use]
166 fn create_buffer_source(&self) -> node::AudioBufferSourceNode {
167 node::AudioBufferSourceNode::new(self.base(), node::AudioBufferSourceOptions::default())
168 }
169
170 #[must_use]
172 fn create_constant_source(&self) -> node::ConstantSourceNode {
173 node::ConstantSourceNode::new(self.base(), node::ConstantSourceOptions::default())
174 }
175
176 #[must_use]
178 fn create_convolver(&self) -> node::ConvolverNode {
179 node::ConvolverNode::new(self.base(), node::ConvolverOptions::default())
180 }
181
182 #[must_use]
184 fn create_channel_merger(&self, number_of_inputs: usize) -> node::ChannelMergerNode {
185 let opts = node::ChannelMergerOptions {
186 number_of_inputs,
187 ..node::ChannelMergerOptions::default()
188 };
189 node::ChannelMergerNode::new(self.base(), opts)
190 }
191
192 #[must_use]
194 fn create_channel_splitter(&self, number_of_outputs: usize) -> node::ChannelSplitterNode {
195 let opts = node::ChannelSplitterOptions {
196 number_of_outputs,
197 ..node::ChannelSplitterOptions::default()
198 };
199 node::ChannelSplitterNode::new(self.base(), opts)
200 }
201
202 #[must_use]
204 fn create_delay(&self, max_delay_time: f64) -> node::DelayNode {
205 let opts = node::DelayOptions {
206 max_delay_time,
207 ..node::DelayOptions::default()
208 };
209 node::DelayNode::new(self.base(), opts)
210 }
211
212 #[must_use]
214 fn create_dynamics_compressor(&self) -> node::DynamicsCompressorNode {
215 node::DynamicsCompressorNode::new(self.base(), node::DynamicsCompressorOptions::default())
216 }
217
218 #[must_use]
220 fn create_gain(&self) -> node::GainNode {
221 node::GainNode::new(self.base(), node::GainOptions::default())
222 }
223
224 #[must_use]
233 fn create_iir_filter(&self, feedforward: Vec<f64>, feedback: Vec<f64>) -> node::IIRFilterNode {
234 let options = node::IIRFilterOptions {
235 audio_node_options: AudioNodeOptions::default(),
236 feedforward,
237 feedback,
238 };
239 node::IIRFilterNode::new(self.base(), options)
240 }
241
242 #[must_use]
244 fn create_oscillator(&self) -> node::OscillatorNode {
245 node::OscillatorNode::new(self.base(), node::OscillatorOptions::default())
246 }
247
248 #[must_use]
250 fn create_panner(&self) -> node::PannerNode {
251 node::PannerNode::new(self.base(), node::PannerOptions::default())
252 }
253
254 #[must_use]
259 fn create_periodic_wave(&self, options: PeriodicWaveOptions) -> PeriodicWave {
260 PeriodicWave::new(self.base(), options)
261 }
262
263 #[must_use]
272 fn create_script_processor(
273 &self,
274 buffer_size: usize,
275 number_of_input_channels: usize,
276 number_of_output_channels: usize,
277 ) -> node::ScriptProcessorNode {
278 let options = node::ScriptProcessorOptions {
279 buffer_size,
280 number_of_input_channels,
281 number_of_output_channels,
282 };
283
284 node::ScriptProcessorNode::new(self.base(), options)
285 }
286
287 #[must_use]
289 fn create_stereo_panner(&self) -> node::StereoPannerNode {
290 node::StereoPannerNode::new(self.base(), node::StereoPannerOptions::default())
291 }
292
293 #[must_use]
295 fn create_wave_shaper(&self) -> node::WaveShaperNode {
296 node::WaveShaperNode::new(self.base(), node::WaveShaperOptions::default())
297 }
298
299 #[must_use]
302 fn destination(&self) -> node::AudioDestinationNode {
303 let registration = AudioContextRegistration {
304 id: DESTINATION_NODE_ID,
305 context: self.base().clone(),
306 };
307 let channel_config = self.base().destination_channel_config();
308 node::AudioDestinationNode::from_raw_parts(registration, channel_config)
309 }
310
311 #[must_use]
313 fn listener(&self) -> AudioListener {
314 self.base().listener()
315 }
316
317 #[must_use]
319 fn sample_rate(&self) -> f32 {
320 self.base().sample_rate()
321 }
322
323 #[must_use]
325 fn state(&self) -> AudioContextState {
326 self.base().state()
327 }
328
329 #[must_use]
332 fn current_time(&self) -> f64 {
333 self.base().current_time()
334 }
335
336 #[must_use]
338 fn render_quantum_size(&self) -> usize {
339 RENDER_QUANTUM_SIZE
340 }
341
342 #[must_use]
346 fn create_audio_param(
347 &self,
348 opts: AudioParamDescriptor,
349 dest: &AudioContextRegistration,
350 ) -> (crate::param::AudioParam, AudioParamId) {
351 let param = self.base().register(move |registration| {
352 let (node, proc) = crate::param::audio_param_pair(opts, registration);
353
354 (node, Box::new(proc))
355 });
356
357 self.base().queue_audio_param_connect(¶m, dest.id());
359
360 let proc_id = AudioParamId(param.registration().id().0);
361 (param, proc_id)
362 }
363
364 fn set_onstatechange<F: FnMut(Event) + Send + 'static>(&self, mut callback: F) {
369 let callback = move |_| {
370 callback(Event {
371 type_: "statechange",
372 })
373 };
374
375 self.base().set_event_handler(
376 EventType::StateChange,
377 EventHandler::Multiple(Box::new(callback)),
378 );
379 }
380
381 fn clear_onstatechange(&self) {
383 self.base().clear_event_handler(EventType::StateChange);
384 }
385
386 #[cfg(test)]
387 fn mock_registration(&self) -> AudioContextRegistration {
388 AudioContextRegistration {
389 id: crate::context::AudioNodeId(0),
390 context: self.base().clone(),
391 }
392 }
393}
394
395#[cfg(test)]
396mod tests {
397 use super::*;
398 use crate::context::OfflineAudioContext;
399
400 use float_eq::assert_float_eq;
401
402 fn require_send_sync_static<T: Send + Sync + 'static>(_: T) {}
403
404 #[test]
405 fn test_decode_audio_data_sync() {
406 let context = OfflineAudioContext::new(1, 1, 44100.);
407 let file = std::fs::File::open("samples/sample.wav").unwrap();
408 let audio_buffer = context.decode_audio_data_sync(file).unwrap();
409
410 assert_eq!(audio_buffer.sample_rate(), 44100.);
411 assert_eq!(audio_buffer.length(), 142_187);
412 assert_eq!(audio_buffer.number_of_channels(), 2);
413 assert_float_eq!(audio_buffer.duration(), 3.224, abs_all <= 0.001);
414
415 let left_start = &audio_buffer.get_channel_data(0)[0..100];
416 let right_start = &audio_buffer.get_channel_data(1)[0..100];
417 assert!(left_start != right_start);
419 }
420
421 #[test]
422 fn test_decode_audio_data_future_send_static() {
423 let context = OfflineAudioContext::new(1, 1, 44100.);
424 let file = std::fs::File::open("samples/sample.wav").unwrap();
425 let future = context.decode_audio_data(file);
426 require_send_sync_static(future);
427 }
428
429 #[test]
430 fn test_decode_audio_data_async() {
431 use futures::executor;
432 let context = OfflineAudioContext::new(1, 1, 44100.);
433 let file = std::fs::File::open("samples/sample.wav").unwrap();
434 let future = context.decode_audio_data(file);
435 let audio_buffer = executor::block_on(future).unwrap();
436
437 assert_eq!(audio_buffer.sample_rate(), 44100.);
438 assert_eq!(audio_buffer.length(), 142_187);
439 assert_eq!(audio_buffer.number_of_channels(), 2);
440 assert_float_eq!(audio_buffer.duration(), 3.224, abs_all <= 0.001);
441
442 let left_start = &audio_buffer.get_channel_data(0)[0..100];
443 let right_start = &audio_buffer.get_channel_data(1)[0..100];
444 assert!(left_start != right_start);
446 }
447
448 #[allow(dead_code)]
451 fn test_decode_audio_data_empty() {
452 let context = OfflineAudioContext::new(1, 1, 44100.);
453 let file = std::fs::File::open("samples/empty_2c.wav").unwrap();
454 let audio_buffer = context.decode_audio_data_sync(file).unwrap();
455 assert_eq!(audio_buffer.length(), 0);
456 }
457
458 #[test]
459 fn test_decode_audio_data_decoding_error() {
460 let context = OfflineAudioContext::new(1, 1, 44100.);
461 let file = std::fs::File::open("samples/corrupt.wav").unwrap();
462 assert!(context.decode_audio_data_sync(file).is_err());
463 }
464
465 #[test]
466 fn test_create_buffer() {
467 let number_of_channels = 3;
468 let length = 2000;
469 let sample_rate = 96_000.;
470
471 let context = OfflineAudioContext::new(1, 1, 44100.);
472 let buffer = context.create_buffer(number_of_channels, length, sample_rate);
473
474 assert_eq!(buffer.number_of_channels(), 3);
475 assert_eq!(buffer.length(), 2000);
476 assert_float_eq!(buffer.sample_rate(), 96000., abs_all <= 0.);
477 }
478}