1use std::any::Any;
2use std::sync::atomic::Ordering;
3use std::sync::Arc;
4
5use crate::buffer::AudioBuffer;
6use crate::context::{AudioContextRegistration, AudioParamId, BaseAudioContext};
7use crate::param::{AudioParam, AudioParamDescriptor, AutomationRate};
8use crate::render::{
9 AudioParamValues, AudioProcessor, AudioRenderQuantum, AudioWorkletGlobalScope,
10};
11use crate::{assert_valid_time_value, AtomicF64, RENDER_QUANTUM_SIZE};
12
13use super::{AudioNode, AudioScheduledSourceNode, ChannelConfig};
14
15#[derive(Clone, Debug)]
30pub struct AudioBufferSourceOptions {
31 pub buffer: Option<AudioBuffer>,
32 pub detune: f32,
33 pub loop_: bool,
34 pub loop_start: f64,
35 pub loop_end: f64,
36 pub playback_rate: f32,
37}
38
39impl Default for AudioBufferSourceOptions {
40 fn default() -> Self {
41 Self {
42 buffer: None,
43 detune: 0.,
44 loop_: false,
45 loop_start: 0.,
46 loop_end: 0.,
47 playback_rate: 1.,
48 }
49 }
50}
51
52#[derive(Debug, Copy, Clone)]
53struct PlaybackInfo {
54 prev_frame_index: usize,
55 k: f64,
56}
57
58#[derive(Debug, Clone, Copy)]
59struct LoopState {
60 pub is_looping: bool,
61 pub start: f64,
62 pub end: f64,
63}
64
65#[derive(Debug, Clone)]
67enum ControlMessage {
68 StartWithOffsetAndDuration(f64, f64, f64),
69 Stop(f64),
70 Loop(bool),
71 LoopStart(f64),
72 LoopEnd(f64),
73}
74
75#[derive(Debug)]
108pub struct AudioBufferSourceNode {
109 registration: AudioContextRegistration,
110 channel_config: ChannelConfig,
111 detune: AudioParam, playback_rate: AudioParam, buffer_time: Arc<AtomicF64>,
114 buffer: Option<AudioBuffer>,
115 loop_state: LoopState,
116 has_start: bool,
117}
118
119impl AudioNode for AudioBufferSourceNode {
120 fn registration(&self) -> &AudioContextRegistration {
121 &self.registration
122 }
123
124 fn channel_config(&self) -> &ChannelConfig {
125 &self.channel_config
126 }
127
128 fn number_of_inputs(&self) -> usize {
129 0
130 }
131
132 fn number_of_outputs(&self) -> usize {
133 1
134 }
135}
136
137impl AudioScheduledSourceNode for AudioBufferSourceNode {
138 fn start(&mut self) {
139 let start = self.registration.context().current_time();
140 self.start_at_with_offset_and_duration(start, 0., f64::MAX);
141 }
142
143 fn start_at(&mut self, when: f64) {
144 self.start_at_with_offset_and_duration(when, 0., f64::MAX);
145 }
146
147 fn stop(&mut self) {
148 let stop = self.registration.context().current_time();
149 self.stop_at(stop);
150 }
151
152 fn stop_at(&mut self, when: f64) {
153 assert_valid_time_value(when);
154 assert!(
155 self.has_start,
156 "InvalidStateError - cannot stop before start"
157 );
158
159 self.registration.post_message(ControlMessage::Stop(when));
160 }
161}
162
163impl AudioBufferSourceNode {
164 pub fn new<C: BaseAudioContext>(context: &C, options: AudioBufferSourceOptions) -> Self {
166 let AudioBufferSourceOptions {
167 buffer,
168 detune,
169 loop_,
170 loop_start,
171 loop_end,
172 playback_rate,
173 } = options;
174
175 let mut node = context.base().register(move |registration| {
176 let detune_param_options = AudioParamDescriptor {
179 name: String::new(),
180 min_value: f32::MIN,
181 max_value: f32::MAX,
182 default_value: 0.,
183 automation_rate: AutomationRate::K,
184 };
185 let (mut d_param, d_proc) =
186 context.create_audio_param(detune_param_options, ®istration);
187 d_param.set_automation_rate_constrained(true);
188 d_param.set_value(detune);
189
190 let playback_rate_param_options = AudioParamDescriptor {
191 name: String::new(),
192 min_value: f32::MIN,
193 max_value: f32::MAX,
194 default_value: 1.,
195 automation_rate: AutomationRate::K,
196 };
197 let (mut pr_param, pr_proc) =
198 context.create_audio_param(playback_rate_param_options, ®istration);
199 pr_param.set_automation_rate_constrained(true);
200 pr_param.set_value(playback_rate);
201
202 let loop_state = LoopState {
203 is_looping: loop_,
204 start: loop_start,
205 end: loop_end,
206 };
207
208 let renderer = AudioBufferSourceRenderer {
209 start_time: f64::MAX,
210 stop_time: f64::MAX,
211 duration: f64::MAX,
212 offset: 0.,
213 buffer: None,
214 detune: d_proc,
215 playback_rate: pr_proc,
216 loop_state,
217 render_state: AudioBufferRendererState::default(),
218 };
219
220 let node = Self {
221 registration,
222 channel_config: ChannelConfig::default(),
223 detune: d_param,
224 playback_rate: pr_param,
225 buffer_time: Arc::clone(&renderer.render_state.buffer_time),
226 buffer: None,
227 loop_state,
228 has_start: false,
229 };
230
231 (node, Box::new(renderer))
232 });
233
234 if let Some(buf) = buffer {
236 node.set_buffer(buf);
237 }
238
239 node
240 }
241
242 pub fn start_at_with_offset(&mut self, start: f64, offset: f64) {
248 self.start_at_with_offset_and_duration(start, offset, f64::MAX);
249 }
250
251 pub fn start_at_with_offset_and_duration(&mut self, start: f64, offset: f64, duration: f64) {
257 assert_valid_time_value(start);
258 assert_valid_time_value(offset);
259 assert_valid_time_value(duration);
260 assert!(
261 !self.has_start,
262 "InvalidStateError - Cannot call `start` twice"
263 );
264
265 self.has_start = true;
266 let control = ControlMessage::StartWithOffsetAndDuration(start, offset, duration);
267 self.registration.post_message(control);
268 }
269
270 pub fn buffer(&self) -> Option<&AudioBuffer> {
272 self.buffer.as_ref()
273 }
274
275 pub fn set_buffer(&mut self, audio_buffer: AudioBuffer) {
282 let clone = audio_buffer.clone();
283
284 assert!(
285 self.buffer.is_none(),
286 "InvalidStateError - cannot assign buffer twice",
287 );
288 self.buffer = Some(audio_buffer);
289
290 self.registration.post_message(clone);
291 }
292
293 pub fn playback_rate(&self) -> &AudioParam {
300 &self.playback_rate
301 }
302
303 pub fn position(&self) -> f64 {
310 self.buffer_time.load(Ordering::Relaxed)
311 }
312
313 pub fn detune(&self) -> &AudioParam {
318 &self.detune
319 }
320
321 #[allow(clippy::missing_panics_doc)]
323 pub fn loop_(&self) -> bool {
324 self.loop_state.is_looping
325 }
326
327 pub fn set_loop(&mut self, value: bool) {
328 self.loop_state.is_looping = value;
329 self.registration.post_message(ControlMessage::Loop(value));
330 }
331
332 pub fn loop_start(&self) -> f64 {
334 self.loop_state.start
335 }
336
337 pub fn set_loop_start(&mut self, value: f64) {
338 self.loop_state.start = value;
339 self.registration
340 .post_message(ControlMessage::LoopStart(value));
341 }
342
343 pub fn loop_end(&self) -> f64 {
345 self.loop_state.end
346 }
347
348 pub fn set_loop_end(&mut self, value: f64) {
349 self.loop_state.end = value;
350 self.registration
351 .post_message(ControlMessage::LoopEnd(value));
352 }
353}
354
355struct AudioBufferRendererState {
356 buffer_time: Arc<AtomicF64>,
357 started: bool,
358 entered_loop: bool,
359 buffer_time_elapsed: f64,
360 is_aligned: bool,
361 ended: bool,
362}
363
364impl Default for AudioBufferRendererState {
365 fn default() -> Self {
366 Self {
367 buffer_time: Arc::new(AtomicF64::new(0.)),
368 started: false,
369 entered_loop: false,
370 buffer_time_elapsed: 0.,
371 is_aligned: false,
372 ended: false,
373 }
374 }
375}
376
377struct AudioBufferSourceRenderer {
378 start_time: f64,
379 stop_time: f64,
380 offset: f64,
381 duration: f64,
382 buffer: Option<AudioBuffer>,
383 detune: AudioParamId,
384 playback_rate: AudioParamId,
385 loop_state: LoopState,
386 render_state: AudioBufferRendererState,
387}
388
389impl AudioBufferSourceRenderer {
390 fn handle_control_message(&mut self, control: &ControlMessage) {
391 match control {
392 ControlMessage::StartWithOffsetAndDuration(when, offset, duration) => {
393 self.start_time = *when;
394 self.offset = *offset;
395 self.duration = *duration;
396 }
397 ControlMessage::Stop(when) => self.stop_time = *when,
398 ControlMessage::Loop(is_looping) => self.loop_state.is_looping = *is_looping,
399 ControlMessage::LoopStart(loop_start) => self.loop_state.start = *loop_start,
400 ControlMessage::LoopEnd(loop_end) => self.loop_state.end = *loop_end,
401 }
402
403 self.clamp_loop_boundaries();
404 }
405
406 fn clamp_loop_boundaries(&mut self) {
407 if let Some(buffer) = &self.buffer {
408 let duration = buffer.duration();
409
410 if self.loop_state.start < 0. {
412 self.loop_state.start = 0.;
413 } else if self.loop_state.start > duration {
414 self.loop_state.start = duration;
415 }
416
417 if self.loop_state.end <= 0. || self.loop_state.end > duration {
419 self.loop_state.end = duration;
420 }
421 }
422 }
423}
424
425impl AudioProcessor for AudioBufferSourceRenderer {
426 fn process(
427 &mut self,
428 _inputs: &[AudioRenderQuantum], outputs: &mut [AudioRenderQuantum],
430 params: AudioParamValues<'_>,
431 scope: &AudioWorkletGlobalScope,
432 ) -> bool {
433 let output = &mut outputs[0];
435
436 if self.render_state.ended {
437 output.make_silent();
438 return false;
439 }
440
441 let sample_rate = scope.sample_rate as f64;
442 let dt = 1. / sample_rate;
443 let block_duration = dt * RENDER_QUANTUM_SIZE as f64;
444 let next_block_time = scope.current_time + block_duration;
445
446 if self.buffer.is_none() && self.start_time != f64::MAX {
450 output.make_silent();
451 self.render_state.ended = true;
452 scope.send_ended_event();
453 return false;
454 }
455
456 if self.start_time >= next_block_time {
458 output.make_silent();
459 if self.stop_time <= next_block_time {
461 self.render_state.ended = true;
462 scope.send_ended_event();
463 return false;
464 }
465
466 return self.start_time != f64::MAX;
469 }
470
471 let buffer = match &self.buffer {
473 None => {
474 output.make_silent();
475 return false;
478 }
479 Some(b) => b,
480 };
481
482 let LoopState {
483 is_looping,
484 start: loop_start,
485 end: loop_end,
486 } = self.loop_state;
487
488 let mut actual_loop_start = 0.;
490 let mut actual_loop_end = 0.;
491
492 let detune = params.get(&self.detune)[0] as f64;
495 let playback_rate = params.get(&self.playback_rate)[0] as f64;
496 let computed_playback_rate = playback_rate * (detune / 1200.).exp2();
497
498 let buffer_length = buffer.length();
499 let buffer_duration = buffer.duration();
500 let sampling_ratio = buffer.sample_rate() as f64 / sample_rate;
504
505 let mut buffer_time = self.render_state.buffer_time.load(Ordering::Relaxed);
508
509 output.set_number_of_channels(buffer.number_of_channels());
510
511 let block_time = scope.current_time;
514
515 if !self.render_state.started && self.start_time < block_time {
520 self.start_time = block_time;
521 }
522
523 if self.start_time == block_time && self.offset == 0. {
531 self.render_state.is_aligned = true;
532 }
533
534 if sampling_ratio != 1. || computed_playback_rate != 1. {
536 self.render_state.is_aligned = false;
537 }
538
539 if loop_start != 0. || loop_end != buffer_duration {
545 self.render_state.is_aligned = false;
546 }
547
548 if buffer_time + block_duration > self.duration
552 || block_time + block_duration > self.stop_time
553 {
554 self.render_state.is_aligned = false;
555 }
556
557 if self.render_state.is_aligned {
558 if self.start_time == block_time {
562 self.render_state.started = true;
563 }
564
565 if buffer_time + block_duration > buffer_duration {
567 let end_index = buffer.length();
568 let mut loop_point_index: Option<usize> = None;
571
572 buffer
573 .channels()
574 .iter()
575 .zip(output.channels_mut().iter_mut())
576 .for_each(|(buffer_channel, output_channel)| {
577 let buffer_channel = buffer_channel.as_slice();
579 let mut start_index = (buffer_time * sample_rate).round() as usize;
580 let mut offset = 0;
581
582 for (index, o) in output_channel.iter_mut().enumerate() {
583 let mut buffer_index = start_index + index - offset;
584
585 *o = if buffer_index < end_index {
586 buffer_channel[buffer_index]
587 } else {
588 if is_looping && buffer_index >= end_index {
589 loop_point_index = Some(index);
590 start_index = 0;
592 offset = index;
593 buffer_index = 0;
594 }
595
596 if is_looping {
597 buffer_channel[buffer_index]
598 } else {
599 0.
600 }
601 };
602 }
603 });
604
605 if let Some(loop_point_index) = loop_point_index {
606 buffer_time = ((RENDER_QUANTUM_SIZE - loop_point_index) as f64 / sample_rate)
607 % buffer_duration;
608 } else {
609 buffer_time += block_duration;
610 }
611 } else {
612 let start_index = (buffer_time * sample_rate).round() as usize;
613 let end_index = start_index + RENDER_QUANTUM_SIZE;
614 buffer
616 .channels()
617 .iter()
618 .zip(output.channels_mut().iter_mut())
619 .for_each(|(buffer_channel, output_channel)| {
620 let buffer_channel = buffer_channel.as_slice();
621 output_channel.copy_from_slice(&buffer_channel[start_index..end_index]);
622 });
623
624 buffer_time += block_duration;
625 }
626
627 self.render_state.buffer_time_elapsed += block_duration;
628 } else {
629 if is_looping {
633 if loop_start >= 0. && loop_end > 0. && loop_start < loop_end {
634 actual_loop_start = loop_start;
635 actual_loop_end = loop_end;
636 } else {
637 actual_loop_start = 0.;
638 actual_loop_end = buffer_duration;
639 }
640 } else {
641 self.render_state.entered_loop = false;
642 }
643
644 let mut playback_infos = [None; RENDER_QUANTUM_SIZE];
647
648 for (i, playback_info) in playback_infos.iter_mut().enumerate() {
650 let current_time = block_time + i as f64 * dt;
651
652 if !self.render_state.started && almost::equal(current_time, self.start_time) {
655 self.start_time = current_time;
656 }
657
658 if almost::equal(self.render_state.buffer_time_elapsed, self.duration) {
659 self.render_state.buffer_time_elapsed = self.duration;
660 }
661
662 if current_time < self.start_time
668 || current_time >= self.stop_time
669 || self.render_state.buffer_time_elapsed >= self.duration
670 {
671 continue; }
673
674 if !self.render_state.started {
676 let delta = current_time - self.start_time;
677 self.offset += delta * computed_playback_rate;
679 self.offset = self.offset.max(0.).min(buffer_duration);
681
682 if is_looping && computed_playback_rate >= 0. && self.offset > actual_loop_end {
683 self.offset = actual_loop_end;
684 }
685
686 if is_looping && computed_playback_rate < 0. && self.offset < actual_loop_start
687 {
688 self.offset = actual_loop_start;
689 }
690
691 buffer_time = self.offset;
692 self.render_state.buffer_time_elapsed = (delta * computed_playback_rate).abs();
693 self.render_state.started = true;
694 }
695
696 if is_looping {
697 if almost::equal(buffer_time, actual_loop_end) {
698 buffer_time = actual_loop_end;
699 }
700
701 if almost::equal(buffer_time, actual_loop_start) {
702 buffer_time = actual_loop_start;
703 }
704
705 if !self.render_state.entered_loop {
706 if self.offset < actual_loop_end && buffer_time >= actual_loop_start {
708 self.render_state.entered_loop = true;
709 }
710
711 if self.offset >= actual_loop_end && buffer_time < actual_loop_end {
713 self.render_state.entered_loop = true;
714 }
715 }
716
717 if self.render_state.entered_loop {
719 while buffer_time >= actual_loop_end {
720 buffer_time -= actual_loop_end - actual_loop_start;
721 }
722
723 while buffer_time < actual_loop_start {
724 buffer_time += actual_loop_end - actual_loop_start;
725 }
726 }
727 }
728
729 if almost::zero(buffer_time) {
730 buffer_time = 0.
731 }
732
733 if buffer_time >= 0. && buffer_time < buffer_duration {
734 let position = buffer_time * sampling_ratio;
735 let playhead = position * sample_rate;
736 let playhead_floored = playhead.floor();
737 let prev_frame_index = playhead_floored as usize; let k = playhead - playhead_floored;
739
740 if prev_frame_index < buffer_length {
744 *playback_info = Some(PlaybackInfo {
745 prev_frame_index,
746 k,
747 });
748 }
749 }
750
751 let time_incr = dt * computed_playback_rate;
752 buffer_time += time_incr;
753 self.render_state.buffer_time_elapsed += time_incr.abs();
754 }
755
756 buffer
758 .channels()
759 .iter()
760 .zip(output.channels_mut().iter_mut())
761 .for_each(|(buffer_channel, output_channel)| {
762 let buffer_channel = buffer_channel.as_slice();
763
764 playback_infos
765 .iter()
766 .zip(output_channel.iter_mut())
767 .for_each(|(playhead, o)| {
768 *o = match playhead {
769 Some(PlaybackInfo {
770 prev_frame_index,
771 k,
772 }) => {
773 let prev_sample = buffer_channel[*prev_frame_index] as f64;
775 let next_sample = match buffer_channel.get(prev_frame_index + 1)
776 {
777 Some(val) => *val as f64,
778 None => {
780 if is_looping {
781 if playback_rate >= 0. {
782 let start_playhead =
783 actual_loop_start * sample_rate;
784 let start_index = if start_playhead.floor()
785 == start_playhead
786 {
787 start_playhead as usize
788 } else {
789 start_playhead as usize + 1
790 };
791
792 buffer_channel[start_index] as f64
793 } else {
794 let end_playhead =
795 actual_loop_end * sample_rate;
796 let end_index = end_playhead as usize;
797 buffer_channel[end_index] as f64
798 }
799 } else {
800 if almost::equal(*k, 1.) || *prev_frame_index == 0 {
808 0.
809 } else {
810 let prev_prev_sample =
813 buffer_channel[*prev_frame_index - 1];
814 2. * prev_sample - prev_prev_sample as f64
815 }
816 }
817 }
818 };
819
820 (1. - k).mul_add(prev_sample, k * next_sample) as f32
821 }
822 None => 0.,
823 };
824 });
825 });
826 }
827
828 self.render_state
830 .buffer_time
831 .store(buffer_time, Ordering::Relaxed);
832
833 if next_block_time >= self.stop_time
838 || self.render_state.buffer_time_elapsed >= self.duration
839 || !is_looping
840 && (computed_playback_rate > 0. && buffer_time >= buffer_duration
841 || computed_playback_rate < 0. && buffer_time < 0.)
842 {
843 self.render_state.ended = true;
844 scope.send_ended_event();
845 }
846
847 true
848 }
849
850 fn onmessage(&mut self, msg: &mut dyn Any) {
851 if let Some(control) = msg.downcast_ref::<ControlMessage>() {
852 self.handle_control_message(control);
853 return;
854 };
855
856 if let Some(buffer) = msg.downcast_mut::<AudioBuffer>() {
857 if let Some(current_buffer) = &mut self.buffer {
858 std::mem::swap(current_buffer, buffer);
860 } else {
861 let tombstone_buffer = AudioBuffer {
863 channels: Default::default(),
864 sample_rate: Default::default(),
865 };
866 self.buffer = Some(std::mem::replace(buffer, tombstone_buffer));
867 self.clamp_loop_boundaries();
868 }
869 return;
870 };
871
872 log::warn!("AudioBufferSourceRenderer: Dropping incoming message {msg:?}");
873 }
874
875 fn before_drop(&mut self, scope: &AudioWorkletGlobalScope) {
876 if !self.render_state.ended
877 && (scope.current_time >= self.start_time || scope.current_time >= self.stop_time)
878 {
879 scope.send_ended_event();
880 self.render_state.ended = true;
881 }
882 }
883}
884
885#[cfg(test)]
886mod tests {
887 use float_eq::assert_float_eq;
888 use std::f32::consts::PI;
889 use std::sync::atomic::{AtomicBool, Ordering};
890 use std::sync::{Arc, Mutex};
891
892 use crate::context::{BaseAudioContext, OfflineAudioContext};
893 use crate::AudioBufferOptions;
894 use crate::RENDER_QUANTUM_SIZE;
895
896 use super::*;
897
898 #[test]
899 fn test_construct_with_options_and_run() {
900 let sample_rate = 44100.;
901 let length = RENDER_QUANTUM_SIZE;
902 let mut context = OfflineAudioContext::new(1, length, sample_rate);
903
904 let buffer = AudioBuffer::from(vec![vec![1.; RENDER_QUANTUM_SIZE]], sample_rate);
905 let options = AudioBufferSourceOptions {
906 buffer: Some(buffer),
907 ..Default::default()
908 };
909 let mut src = AudioBufferSourceNode::new(&context, options);
910 src.connect(&context.destination());
911 src.start();
912 let res = context.start_rendering_sync();
913
914 assert_float_eq!(
915 res.channel_data(0).as_slice()[..],
916 &[1.; RENDER_QUANTUM_SIZE][..],
917 abs_all <= 0.
918 );
919 }
920
921 #[test]
922 fn test_playing_some_file() {
923 let context = OfflineAudioContext::new(2, RENDER_QUANTUM_SIZE, 44_100.);
924
925 let file = std::fs::File::open("samples/sample.wav").unwrap();
926 let expected = context.decode_audio_data_sync(file).unwrap();
927
928 [44100, 48000].iter().for_each(|sr| {
931 let decoding_context = OfflineAudioContext::new(2, RENDER_QUANTUM_SIZE, *sr as f32);
932
933 let mut filename = "samples/sample-".to_owned();
934 filename.push_str(&sr.to_string());
935 filename.push_str(".wav");
936
937 let file = std::fs::File::open("samples/sample.wav").unwrap();
938 let audio_buffer = decoding_context.decode_audio_data_sync(file).unwrap();
939
940 assert_eq!(audio_buffer.sample_rate(), *sr as f32);
941
942 let mut context = OfflineAudioContext::new(2, RENDER_QUANTUM_SIZE, 44_100.);
943
944 let mut src = context.create_buffer_source();
945 src.set_buffer(audio_buffer);
946 src.connect(&context.destination());
947 src.start_at(context.current_time());
948 src.stop_at(context.current_time() + 128.);
949
950 let res = context.start_rendering_sync();
951 let diff_abs = if *sr == 44100 {
952 0. } else {
954 5e-3 };
956
957 assert_eq!(res.number_of_channels(), expected.number_of_channels());
959
960 assert_float_eq!(
962 res.channel_data(0).as_slice()[..],
963 expected.get_channel_data(0)[0..128],
964 abs_all <= diff_abs
965 );
966
967 assert_float_eq!(
968 res.channel_data(1).as_slice()[..],
969 expected.get_channel_data(1)[0..128],
970 abs_all <= diff_abs
971 );
972 });
973 }
974
975 #[test]
977 fn test_sub_quantum_start_1() {
978 let sample_rate = 48_000.;
979 let mut context = OfflineAudioContext::new(1, RENDER_QUANTUM_SIZE, sample_rate);
980
981 let mut dirac = context.create_buffer(1, 1, sample_rate);
982 dirac.copy_to_channel(&[1.], 0);
983
984 let mut src = context.create_buffer_source();
985 src.connect(&context.destination());
986 src.set_buffer(dirac);
987 src.start_at(1. / sample_rate as f64);
988
989 let result = context.start_rendering_sync();
990 let channel = result.get_channel_data(0);
991
992 let mut expected = vec![0.; RENDER_QUANTUM_SIZE];
993 expected[1] = 1.;
994
995 assert_float_eq!(channel[..], expected[..], abs_all <= 0.);
996 }
997
998 #[test]
1000 fn test_sub_quantum_start_2() {
1001 let sample_rate = 44_100.;
1002 let length_in_seconds = 4.;
1003 let mut context =
1004 OfflineAudioContext::new(2, (length_in_seconds * sample_rate) as usize, sample_rate);
1005
1006 let mut dirac = context.create_buffer(2, 512, sample_rate);
1007 dirac.copy_to_channel(&[1.], 0);
1008 dirac.copy_to_channel(&[1.], 1);
1009
1010 let sample_offsets = [0, 3, 512, 517, 1000, 1005, 20000, 21234, 37590];
1011
1012 sample_offsets.iter().for_each(|index| {
1013 let time_in_seconds = *index as f64 / sample_rate as f64;
1014
1015 let mut src = context.create_buffer_source();
1016 src.set_buffer(dirac.clone());
1017 src.connect(&context.destination());
1018 src.start_at(time_in_seconds);
1019 });
1020
1021 let res = context.start_rendering_sync();
1022
1023 let channel_left = res.get_channel_data(0);
1024 let channel_right = res.get_channel_data(1);
1025 assert_float_eq!(channel_left[..], channel_right[..], abs_all <= 0.);
1027 sample_offsets.iter().for_each(|index| {
1030 assert_ne!(
1031 channel_left[*index], 0.,
1032 "non zero sample at index {:?}",
1033 index
1034 );
1035 });
1036 }
1037
1038 #[test]
1039 fn test_sub_sample_start() {
1040 let sample_rate = 48_000.;
1042 let mut context = OfflineAudioContext::new(1, RENDER_QUANTUM_SIZE, sample_rate);
1043
1044 let mut dirac = context.create_buffer(1, 1, sample_rate);
1045 dirac.copy_to_channel(&[1.], 0);
1046
1047 let mut src = context.create_buffer_source();
1048 src.connect(&context.destination());
1049 src.set_buffer(dirac);
1050 src.start_at(1.5 / sample_rate as f64);
1051
1052 let result = context.start_rendering_sync();
1053 let channel = result.get_channel_data(0);
1054
1055 let mut expected = vec![0.; RENDER_QUANTUM_SIZE];
1056 expected[2] = 0.5;
1057
1058 assert_float_eq!(channel[..], expected[..], abs_all <= 0.);
1059 }
1060
1061 #[test]
1062 fn test_sub_quantum_stop_fast_track() {
1063 let sample_rate = 48_000.;
1064 let mut context = OfflineAudioContext::new(1, RENDER_QUANTUM_SIZE, sample_rate);
1065
1066 let mut dirac = context.create_buffer(1, RENDER_QUANTUM_SIZE, sample_rate);
1067 dirac.copy_to_channel(&[0., 0., 0., 0., 1.], 0);
1068
1069 let mut src = context.create_buffer_source();
1070 src.connect(&context.destination());
1071 src.set_buffer(dirac);
1072 src.start_at(0. / sample_rate as f64);
1073 src.stop_at(4. / sample_rate as f64);
1075
1076 let result = context.start_rendering_sync();
1077 let channel = result.get_channel_data(0);
1078 let expected = vec![0.; RENDER_QUANTUM_SIZE];
1079
1080 assert_float_eq!(channel[..], expected[..], abs_all <= 0.);
1081 }
1082
1083 #[test]
1084 fn test_sub_quantum_stop_slow_track() {
1085 let sample_rate = 48_000.;
1086 let mut context = OfflineAudioContext::new(1, RENDER_QUANTUM_SIZE, sample_rate);
1087
1088 let mut dirac = context.create_buffer(1, RENDER_QUANTUM_SIZE, sample_rate);
1089 dirac.copy_to_channel(&[0., 0., 0., 1.], 0);
1090
1091 let mut src = context.create_buffer_source();
1092 src.connect(&context.destination());
1093 src.set_buffer(dirac);
1094
1095 src.start_at(1. / sample_rate as f64);
1096 src.stop_at(4. / sample_rate as f64);
1097
1098 let result = context.start_rendering_sync();
1099 let channel = result.get_channel_data(0);
1100 let expected = vec![0.; RENDER_QUANTUM_SIZE];
1101
1102 assert_float_eq!(channel[..], expected[..], abs_all <= 0.);
1103 }
1104
1105 #[test]
1106 fn test_sub_sample_stop_fast_track() {
1107 let sample_rate = 48_000.;
1108 let mut context = OfflineAudioContext::new(1, RENDER_QUANTUM_SIZE, sample_rate);
1109
1110 let mut dirac = context.create_buffer(1, RENDER_QUANTUM_SIZE, sample_rate);
1111 dirac.copy_to_channel(&[0., 0., 0., 0., 1., 1.], 0);
1112
1113 let mut src = context.create_buffer_source();
1114 src.connect(&context.destination());
1115 src.set_buffer(dirac);
1116 src.start_at(0. / sample_rate as f64);
1117 src.stop_at(4.5 / sample_rate as f64);
1119
1120 let result = context.start_rendering_sync();
1121 let channel = result.get_channel_data(0);
1122
1123 let mut expected = vec![0.; 128];
1124 expected[4] = 1.;
1125
1126 assert_float_eq!(channel[..], expected[..], abs_all <= 0.);
1127 }
1128
1129 #[test]
1130 fn test_sub_sample_stop_slow_track() {
1131 let sample_rate = 48_000.;
1132 let mut context = OfflineAudioContext::new(1, RENDER_QUANTUM_SIZE, sample_rate);
1133
1134 let mut dirac = context.create_buffer(1, RENDER_QUANTUM_SIZE, sample_rate);
1135 dirac.copy_to_channel(&[0., 0., 0., 0., 1., 1.], 0);
1136
1137 let mut src = context.create_buffer_source();
1138 src.connect(&context.destination());
1139 src.set_buffer(dirac);
1140 src.start_at(1. / sample_rate as f64);
1141 src.stop_at(5.5 / sample_rate as f64);
1143
1144 let result = context.start_rendering_sync();
1145 let channel = result.get_channel_data(0);
1146
1147 let mut expected = vec![0.; 128];
1148 expected[5] = 1.;
1149
1150 assert_float_eq!(channel[..], expected[..], abs_all <= 0.);
1151 }
1152
1153 #[test]
1154 fn test_start_in_the_past() {
1155 let sample_rate = 48_000.;
1156 let mut context = OfflineAudioContext::new(1, 2 * RENDER_QUANTUM_SIZE, sample_rate);
1157
1158 let mut dirac = context.create_buffer(1, 1, sample_rate);
1159 dirac.copy_to_channel(&[1.], 0);
1160
1161 context.suspend_sync((128. / sample_rate).into(), |context| {
1162 let mut src = context.create_buffer_source();
1163 src.connect(&context.destination());
1164 src.set_buffer(dirac);
1165 src.start_at(0.);
1166 });
1167
1168 let result = context.start_rendering_sync();
1169 let channel = result.get_channel_data(0);
1170
1171 let mut expected = vec![0.; 2 * RENDER_QUANTUM_SIZE];
1172 expected[128] = 1.;
1173
1174 assert_float_eq!(channel[..], expected[..], abs_all <= 0.);
1175 }
1176
1177 #[test]
1178 fn test_audio_buffer_resampling() {
1179 [22_500, 38_000, 43_800, 48_000, 96_000]
1180 .iter()
1181 .for_each(|sr| {
1182 let freq = 1.;
1183 let base_sr = 44_100;
1184 let mut context = OfflineAudioContext::new(1, base_sr, base_sr as f32);
1185
1186 let buf_sr = *sr;
1188 let sample_rate = buf_sr as f32;
1190 let mut buffer = context.create_buffer(1, buf_sr, sample_rate);
1191 let mut sine = vec![];
1192
1193 for i in 0..buf_sr {
1194 let phase = freq * i as f32 / buf_sr as f32 * 2. * PI;
1195 let sample = phase.sin();
1196 sine.push(sample);
1197 }
1198
1199 buffer.copy_to_channel(&sine[..], 0);
1200
1201 let mut src = context.create_buffer_source();
1202 src.connect(&context.destination());
1203 src.set_buffer(buffer);
1204 src.start_at(0. / sample_rate as f64);
1205
1206 let result = context.start_rendering_sync();
1207 let channel = result.get_channel_data(0);
1208
1209 let mut expected = vec![];
1211
1212 for i in 0..base_sr {
1213 let phase = freq * i as f32 / base_sr as f32 * 2. * PI;
1214 let sample = phase.sin();
1215 expected.push(sample);
1216 }
1217
1218 assert_float_eq!(channel[..], expected[..], abs_all <= 1e-6);
1219 });
1220 }
1221
1222 #[test]
1223 fn test_playback_rate() {
1224 let sample_rate = 44_100;
1225 let mut context = OfflineAudioContext::new(1, sample_rate, sample_rate as f32);
1226
1227 let mut buffer = context.create_buffer(1, sample_rate, sample_rate as f32);
1228 let mut sine = vec![];
1229
1230 for i in 0..sample_rate {
1232 let phase = i as f32 / sample_rate as f32 * 2. * PI;
1233 let sample = phase.sin();
1234 sine.push(sample);
1235 }
1236
1237 buffer.copy_to_channel(&sine[..], 0);
1238
1239 let mut src = context.create_buffer_source();
1240 src.connect(&context.destination());
1241 src.set_buffer(buffer);
1242 src.playback_rate.set_value(0.5);
1243 src.start();
1244
1245 let result = context.start_rendering_sync();
1246 let channel = result.get_channel_data(0);
1247
1248 let mut expected = vec![];
1250
1251 for i in 0..sample_rate {
1252 let phase = i as f32 / sample_rate as f32 * PI;
1253 let sample = phase.sin();
1254 expected.push(sample);
1255 }
1256
1257 assert_float_eq!(channel[..], expected[..], abs_all <= 1e-6);
1258 }
1259
1260 #[test]
1261 fn test_negative_playback_rate() {
1262 let sample_rate = 44_100;
1263 let mut context = OfflineAudioContext::new(1, sample_rate, sample_rate as f32);
1264
1265 let mut buffer = context.create_buffer(1, sample_rate, sample_rate as f32);
1266 let mut sine = vec![];
1267
1268 for i in 0..sample_rate {
1270 let phase = i as f32 / sample_rate as f32 * 2. * PI;
1271 let sample = phase.sin();
1272 sine.push(sample);
1273 }
1274
1275 buffer.copy_to_channel(&sine[..], 0);
1276
1277 let mut src = context.create_buffer_source();
1278 src.connect(&context.destination());
1279 src.set_buffer(buffer.clone());
1280 src.playback_rate.set_value(-1.);
1281 src.start_at_with_offset(context.current_time(), buffer.duration());
1282
1283 let result = context.start_rendering_sync();
1284 let channel = result.get_channel_data(0);
1285
1286 let mut expected: Vec<f32> = sine.into_iter().rev().collect();
1288 expected.pop();
1291 expected.insert(0, 0.);
1292
1293 assert_float_eq!(channel[..], expected[..], abs_all <= 1e-6);
1294 }
1295
1296 #[test]
1297 fn test_detune() {
1298 let sample_rate = 44_100;
1299 let mut context = OfflineAudioContext::new(1, sample_rate, sample_rate as f32);
1300
1301 let mut buffer = context.create_buffer(1, sample_rate, sample_rate as f32);
1302 let mut sine = vec![];
1303
1304 for i in 0..sample_rate {
1306 let phase = i as f32 / sample_rate as f32 * 2. * PI;
1307 let sample = phase.sin();
1308 sine.push(sample);
1309 }
1310
1311 buffer.copy_to_channel(&sine[..], 0);
1312
1313 let mut src = context.create_buffer_source();
1314 src.connect(&context.destination());
1315 src.set_buffer(buffer);
1316 src.detune.set_value(-1200.);
1317 src.start();
1318
1319 let result = context.start_rendering_sync();
1320 let channel = result.get_channel_data(0);
1321
1322 let mut expected = vec![];
1324
1325 for i in 0..sample_rate {
1326 let phase = i as f32 / sample_rate as f32 * PI;
1327 let sample = phase.sin();
1328 expected.push(sample);
1329 }
1330
1331 assert_float_eq!(channel[..], expected[..], abs_all <= 1e-6);
1332 }
1333
1334 #[test]
1335 fn test_end_of_file_fast_track() {
1336 let sample_rate = 48_000.;
1337 let mut context = OfflineAudioContext::new(1, RENDER_QUANTUM_SIZE * 2, sample_rate);
1338
1339 let mut buffer = context.create_buffer(1, 129, sample_rate);
1340 let mut data = vec![0.; 129];
1341 data[0] = 1.;
1342 data[128] = 1.;
1343 buffer.copy_to_channel(&data, 0);
1344
1345 let mut src = context.create_buffer_source();
1346 src.connect(&context.destination());
1347 src.set_buffer(buffer);
1348 src.start_at(0. / sample_rate as f64);
1349
1350 let result = context.start_rendering_sync();
1351 let channel = result.get_channel_data(0);
1352
1353 let mut expected = vec![0.; 256];
1354 expected[0] = 1.;
1355 expected[128] = 1.;
1356
1357 assert_float_eq!(channel[..], expected[..], abs_all <= 0.);
1358 }
1359
1360 #[test]
1361 fn test_end_of_file_slow_track_1() {
1362 let sample_rate = 48_000.;
1363 let mut context = OfflineAudioContext::new(1, RENDER_QUANTUM_SIZE * 2, sample_rate);
1364
1365 let mut buffer = context.create_buffer(1, 129, sample_rate);
1366 let mut data = vec![0.; 129];
1367 data[0] = 1.;
1368 data[128] = 1.;
1369 buffer.copy_to_channel(&data, 0);
1370
1371 let mut src = context.create_buffer_source();
1372 src.connect(&context.destination());
1373 src.set_buffer(buffer);
1374 src.start_at(1. / sample_rate as f64);
1375
1376 let result = context.start_rendering_sync();
1377 let channel = result.get_channel_data(0);
1378
1379 let mut expected = vec![0.; 256];
1380 expected[1] = 1.;
1381 expected[129] = 1.;
1382
1383 assert_float_eq!(channel[..], expected[..], abs_all <= 1e-10);
1384 }
1385
1386 #[test]
1387 fn test_with_duration_0() {
1388 let sample_rate = 48_000.;
1389 let mut context = OfflineAudioContext::new(1, RENDER_QUANTUM_SIZE, sample_rate);
1390
1391 let mut dirac = context.create_buffer(1, RENDER_QUANTUM_SIZE, sample_rate);
1392 dirac.copy_to_channel(&[0., 0., 0., 0., 1., 1.], 0);
1393
1394 let mut src = context.create_buffer_source();
1395 src.connect(&context.destination());
1396 src.set_buffer(dirac);
1397 src.start_at_with_offset_and_duration(0., 0., 4.5 / sample_rate as f64);
1399
1400 let result = context.start_rendering_sync();
1401 let channel = result.get_channel_data(0);
1402
1403 let mut expected = vec![0.; 128];
1404 expected[4] = 1.;
1405
1406 assert_float_eq!(channel[..], expected[..], abs_all <= 0.);
1407 }
1408
1409 #[test]
1410 fn test_with_duration_1() {
1411 let sample_rate = 48_000.;
1412 let mut context = OfflineAudioContext::new(1, RENDER_QUANTUM_SIZE, sample_rate);
1413
1414 let mut dirac = context.create_buffer(1, RENDER_QUANTUM_SIZE, sample_rate);
1415 dirac.copy_to_channel(&[0., 0., 0., 0., 1., 1.], 0);
1416
1417 let mut src = context.create_buffer_source();
1418 src.connect(&context.destination());
1419 src.set_buffer(dirac);
1420 src.start_at_with_offset_and_duration(
1424 1. / sample_rate as f64,
1425 0. / sample_rate as f64,
1426 4.5 / sample_rate as f64,
1427 );
1428
1429 let result = context.start_rendering_sync();
1430 let channel = result.get_channel_data(0);
1431
1432 let mut expected = vec![0.; 128];
1433 expected[5] = 1.;
1434
1435 assert_float_eq!(channel[..], expected[..], abs_all <= 0.);
1436 }
1437
1438 #[test]
1439 fn test_with_duration_2() {
1441 let sample_rate = 32_768.;
1442 let mut context = OfflineAudioContext::new(1, RENDER_QUANTUM_SIZE, sample_rate);
1443
1444 let mut buffer = context.create_buffer(1, RENDER_QUANTUM_SIZE, sample_rate);
1445 buffer.copy_to_channel(&[1.; RENDER_QUANTUM_SIZE], 0);
1446
1447 let start_grain_index = 3.1;
1448 let end_grain_index = 37.2;
1449
1450 let mut src = context.create_buffer_source();
1451 src.connect(&context.destination());
1452 src.set_buffer(buffer);
1453
1454 src.start_at_with_offset_and_duration(
1455 start_grain_index / sample_rate as f64,
1456 0.,
1457 (end_grain_index - start_grain_index) / sample_rate as f64,
1458 );
1459
1460 let result = context.start_rendering_sync();
1461 let channel = result.get_channel_data(0);
1462
1463 let mut expected = [1.; RENDER_QUANTUM_SIZE];
1464 for s in expected
1465 .iter_mut()
1466 .take(start_grain_index.floor() as usize + 1)
1467 {
1468 *s = 0.;
1469 }
1470 for s in expected
1471 .iter_mut()
1472 .take(RENDER_QUANTUM_SIZE)
1473 .skip(end_grain_index.ceil() as usize)
1474 {
1475 *s = 0.;
1476 }
1477
1478 assert_float_eq!(channel[..], expected[..], abs_all <= 0.);
1479 }
1480
1481 #[test]
1482 fn test_with_offset() {
1483 let sample_rate = 48_000.;
1485 let mut context = OfflineAudioContext::new(1, RENDER_QUANTUM_SIZE, sample_rate);
1486
1487 let mut dirac = context.create_buffer(1, RENDER_QUANTUM_SIZE, sample_rate);
1488 dirac.copy_to_channel(&[0., 0., 0., 0., 1., 1.], 0);
1489
1490 let mut src = context.create_buffer_source();
1491 src.connect(&context.destination());
1492 src.set_buffer(dirac);
1493 src.start_at_with_offset_and_duration(
1497 0. / sample_rate as f64,
1498 1. / sample_rate as f64,
1499 3.5 / sample_rate as f64,
1500 );
1501
1502 let result = context.start_rendering_sync();
1503 let channel = result.get_channel_data(0);
1504
1505 let mut expected = vec![0.; 128];
1506 expected[3] = 1.;
1507
1508 assert_float_eq!(channel[..], expected[..], abs_all <= 0.);
1509 }
1510
1511 #[test]
1512 fn test_null_buffer_start_ends_before_start_time() {
1513 let sample_rate = 48_000.;
1514 let mut context = OfflineAudioContext::new(1, sample_rate as usize, sample_rate);
1515
1516 let mut src = context.create_buffer_source();
1517 src.connect(&context.destination());
1518
1519 let ended = Arc::new(AtomicBool::new(false));
1520 let ended_clone = Arc::clone(&ended);
1521 src.set_onended(move |_| {
1522 ended_clone.store(true, Ordering::Relaxed);
1523 });
1524
1525 src.start_at(0.75);
1526 context.suspend_sync(0.5, move |context| {
1527 assert!(ended.load(Ordering::Relaxed));
1528 src.set_buffer(context.create_buffer(1, 1, sample_rate));
1529 });
1530
1531 let result = context.start_rendering_sync();
1532 assert_float_eq!(
1533 result.get_channel_data(0)[..],
1534 vec![0.; sample_rate as usize][..],
1535 abs_all <= 0.
1536 );
1537 }
1538
1539 #[test]
1540 fn test_reverse_playback_with_duration() {
1541 let sample_rate = 48_000.;
1542 let mut context = OfflineAudioContext::new(1, RENDER_QUANTUM_SIZE, sample_rate);
1543
1544 let mut buffer = context.create_buffer(1, 5, sample_rate);
1545 buffer.copy_to_channel(&[1., 2., 3., 4., 5.], 0);
1546
1547 let mut src = context.create_buffer_source();
1548 src.connect(&context.destination());
1549 src.set_buffer(buffer.clone());
1550 src.playback_rate().set_value(-1.);
1551 src.start_at_with_offset_and_duration(0., buffer.duration(), 2. / sample_rate as f64);
1552
1553 let result = context.start_rendering_sync();
1554 let mut expected = vec![0.; RENDER_QUANTUM_SIZE];
1555 expected[1] = 5.;
1556
1557 assert_float_eq!(result.get_channel_data(0)[..], expected[..], abs_all <= 0.);
1558 }
1559
1560 #[test]
1561 fn test_offset_larger_than_buffer_duration() {
1562 let sample_rate = 48_000.;
1563 let mut context = OfflineAudioContext::new(1, RENDER_QUANTUM_SIZE, sample_rate);
1564 let mut buffer = context.create_buffer(1, 13, sample_rate);
1565 buffer.copy_to_channel(&[1.; 13], 0);
1566
1567 let mut src = context.create_buffer_source();
1568 src.set_buffer(buffer);
1569 src.start_at_with_offset(0., 64. / sample_rate as f64); let result = context.start_rendering_sync();
1572 let channel = result.get_channel_data(0);
1573
1574 let expected = [0.; RENDER_QUANTUM_SIZE];
1575 assert_float_eq!(channel[..], expected[..], abs_all <= 0.);
1576 }
1577
1578 #[test]
1579 fn test_fast_track_loop_mono() {
1580 let sample_rate = 48_000.;
1581 let len = RENDER_QUANTUM_SIZE * 4;
1582
1583 for buffer_len in [
1584 RENDER_QUANTUM_SIZE / 2 - 1,
1585 RENDER_QUANTUM_SIZE / 2,
1586 RENDER_QUANTUM_SIZE / 2 + 1,
1587 RENDER_QUANTUM_SIZE - 1,
1588 RENDER_QUANTUM_SIZE,
1589 RENDER_QUANTUM_SIZE + 1,
1590 RENDER_QUANTUM_SIZE * 2 - 1,
1591 RENDER_QUANTUM_SIZE * 2,
1592 RENDER_QUANTUM_SIZE * 2 + 1,
1593 ] {
1594 let mut context = OfflineAudioContext::new(1, len, sample_rate);
1595
1596 let mut dirac = context.create_buffer(1, buffer_len, sample_rate);
1597 dirac.copy_to_channel(&[1.], 0);
1598
1599 let mut src = context.create_buffer_source();
1600 src.connect(&context.destination());
1601 src.set_loop(true);
1602 src.set_buffer(dirac);
1603 src.start();
1604
1605 let result = context.start_rendering_sync();
1606 let channel = result.get_channel_data(0);
1607
1608 let mut expected = vec![0.; len];
1609 for i in (0..len).step_by(buffer_len) {
1610 expected[i] = 1.;
1611 }
1612
1613 assert_float_eq!(channel[..], expected[..], abs_all <= 1e-10);
1614 }
1615 }
1616
1617 #[test]
1618 fn test_slow_track_loop_mono() {
1619 let sample_rate = 48_000.;
1620 let len = RENDER_QUANTUM_SIZE * 4;
1621
1622 for buffer_len in [
1623 RENDER_QUANTUM_SIZE / 2 - 1,
1624 RENDER_QUANTUM_SIZE / 2,
1625 RENDER_QUANTUM_SIZE / 2 + 1,
1626 RENDER_QUANTUM_SIZE - 1,
1627 RENDER_QUANTUM_SIZE,
1628 RENDER_QUANTUM_SIZE + 1,
1629 RENDER_QUANTUM_SIZE * 2 - 1,
1630 RENDER_QUANTUM_SIZE * 2,
1631 RENDER_QUANTUM_SIZE * 2 + 1,
1632 ] {
1633 let mut context = OfflineAudioContext::new(1, len, sample_rate);
1634
1635 let mut dirac = context.create_buffer(1, buffer_len, sample_rate);
1636 dirac.copy_to_channel(&[1.], 0);
1637
1638 let mut src = context.create_buffer_source();
1639 src.connect(&context.destination());
1640 src.set_loop(true);
1641 src.set_buffer(dirac);
1642 src.start_at(1. / sample_rate as f64);
1643
1644 let result = context.start_rendering_sync();
1645 let channel = result.get_channel_data(0);
1646
1647 let mut expected = vec![0.; len];
1648 for i in (1..len).step_by(buffer_len) {
1649 expected[i] = 1.;
1650 }
1651
1652 assert_float_eq!(channel[..], expected[..], abs_all <= 1e-9);
1653 }
1654 }
1655
1656 #[test]
1657 fn test_fast_track_loop_stereo() {
1658 let sample_rate = 48_000.;
1659 let len = RENDER_QUANTUM_SIZE * 4;
1660
1661 for buffer_len in [
1662 RENDER_QUANTUM_SIZE / 2 - 1,
1663 RENDER_QUANTUM_SIZE / 2,
1664 RENDER_QUANTUM_SIZE / 2 + 1,
1665 RENDER_QUANTUM_SIZE - 1,
1666 RENDER_QUANTUM_SIZE,
1667 RENDER_QUANTUM_SIZE + 1,
1668 RENDER_QUANTUM_SIZE * 2 - 1,
1669 RENDER_QUANTUM_SIZE * 2,
1670 RENDER_QUANTUM_SIZE * 2 + 1,
1671 ] {
1672 let mut context = OfflineAudioContext::new(2, len, sample_rate);
1673 let mut dirac = context.create_buffer(2, buffer_len, sample_rate);
1674 dirac.copy_to_channel(&[1.], 0);
1675 dirac.copy_to_channel(&[0., 1.], 1);
1676
1677 let mut src = context.create_buffer_source();
1678 src.connect(&context.destination());
1679 src.set_loop(true);
1680 src.set_buffer(dirac);
1681 src.start();
1682
1683 let result = context.start_rendering_sync();
1684
1685 let mut expected_left: Vec<f32> = vec![0.; len];
1686 let mut expected_right = vec![0.; len];
1687 for i in (0..len).step_by(buffer_len) {
1688 expected_left[i] = 1.;
1689
1690 if i < expected_right.len() - 1 {
1691 expected_right[i + 1] = 1.;
1692 }
1693 }
1694
1695 assert_float_eq!(
1696 result.get_channel_data(0)[..],
1697 expected_left[..],
1698 abs_all <= 1e-10
1699 );
1700 assert_float_eq!(
1701 result.get_channel_data(1)[..],
1702 expected_right[..],
1703 abs_all <= 1e-10
1704 );
1705 }
1706 }
1707
1708 #[test]
1709 fn test_slow_track_loop_stereo() {
1710 let sample_rate = 48_000.;
1711 let len = RENDER_QUANTUM_SIZE * 4;
1712
1713 for buffer_len in [
1714 RENDER_QUANTUM_SIZE / 2 - 1,
1715 RENDER_QUANTUM_SIZE / 2,
1716 RENDER_QUANTUM_SIZE / 2 + 1,
1717 RENDER_QUANTUM_SIZE - 1,
1718 RENDER_QUANTUM_SIZE,
1719 RENDER_QUANTUM_SIZE + 1,
1720 RENDER_QUANTUM_SIZE * 2 - 1,
1721 RENDER_QUANTUM_SIZE * 2,
1722 RENDER_QUANTUM_SIZE * 2 + 1,
1723 ] {
1724 let mut context = OfflineAudioContext::new(2, len, sample_rate);
1725 let mut dirac = context.create_buffer(2, buffer_len, sample_rate);
1726 dirac.copy_to_channel(&[1.], 0);
1727 dirac.copy_to_channel(&[0., 1.], 1);
1728
1729 let mut src = context.create_buffer_source();
1730 src.connect(&context.destination());
1731 src.set_loop(true);
1732 src.set_buffer(dirac);
1733 src.start_at(1. / sample_rate as f64);
1734
1735 let result = context.start_rendering_sync();
1736
1737 let mut expected_left: Vec<f32> = vec![0.; len];
1738 let mut expected_right = vec![0.; len];
1739 for i in (1..len).step_by(buffer_len) {
1740 expected_left[i] = 1.;
1741
1742 if i < expected_right.len() - 1 {
1743 expected_right[i + 1] = 1.;
1744 }
1745 }
1746
1747 assert_float_eq!(
1748 result.get_channel_data(0)[..],
1749 expected_left[..],
1750 abs_all <= 1e-9
1751 );
1752 assert_float_eq!(
1753 result.get_channel_data(1)[..],
1754 expected_right[..],
1755 abs_all <= 1e-9
1756 );
1757 }
1758 }
1759
1760 #[test]
1761 fn test_reverse_loop_boundaries() {
1762 let sample_rate = 48_000.;
1763 let mut context = OfflineAudioContext::new(1, RENDER_QUANTUM_SIZE, sample_rate);
1764
1765 let mut buffer = context.create_buffer(1, 5, sample_rate);
1766 buffer.copy_to_channel(&[1., 2., 3., 4., 5.], 0);
1767
1768 let mut src = context.create_buffer_source();
1769 src.connect(&context.destination());
1770 src.set_buffer(buffer);
1771 src.set_loop(true);
1772 src.set_loop_start(1. / sample_rate as f64);
1773 src.set_loop_end(4. / sample_rate as f64);
1774 src.playback_rate().set_value(-1.);
1775 src.start_at_with_offset(0., 3. / sample_rate as f64);
1776
1777 let result = context.start_rendering_sync();
1778 let expected = [4., 3., 2., 4., 3., 2., 4., 3.];
1779 assert_float_eq!(result.get_channel_data(0)[..8], expected[..], abs_all <= 0.);
1780 }
1781
1782 #[test]
1783 fn test_loop_out_of_bounds() {
1784 [
1785 (-2., -1., 0.),
1787 (-1., -2., 0.),
1788 (0., 0., 0.),
1789 (-1., 2., 0.),
1790 (2., -1., 1e-10),
1792 (1., 1., 1e-10),
1793 (2., 3., 1e-10),
1794 (3., 2., 1e-10),
1795 ]
1796 .iter()
1797 .for_each(|(loop_start, loop_end, error)| {
1798 let sample_rate = 48_000.;
1799 let length = sample_rate as usize / 10;
1800 let mut context = OfflineAudioContext::new(1, length, sample_rate);
1801
1802 let buffer_size = 500;
1803 let mut buffer = context.create_buffer(1, buffer_size, sample_rate);
1804 let data = vec![1.; 1];
1805 buffer.copy_to_channel(&data, 0);
1806
1807 let mut src = context.create_buffer_source();
1808 src.connect(&context.destination());
1809 src.set_buffer(buffer);
1810
1811 src.set_loop(true);
1812 src.set_loop_start(*loop_start); src.set_loop_end(*loop_end); src.start();
1815
1816 let result = context.start_rendering_sync(); let channel = result.get_channel_data(0);
1818
1819 let mut expected = vec![0.; length];
1828 for i in (0..length).step_by(buffer_size) {
1829 expected[i] = 1.;
1830 }
1831
1832 assert_float_eq!(channel[..], expected[..], abs_all <= error);
1833 });
1834 }
1835
1836 #[test]
1837 fn test_end_of_file_fast_track_2() {
1841 let sample_rate = 48_000.;
1842 let mut context = OfflineAudioContext::new(1, RENDER_QUANTUM_SIZE, sample_rate);
1843
1844 let mut buffer = context.create_buffer(1, 5, sample_rate);
1845 let data = vec![1.; 1];
1846 buffer.copy_to_channel(&data, 0);
1847
1848 let mut src = context.create_buffer_source();
1849 src.connect(&context.destination());
1850 src.set_buffer(buffer);
1851 src.start_at(0.);
1853 src.stop_at(125. / sample_rate as f64);
1855
1856 let result = context.start_rendering_sync();
1857 let channel = result.get_channel_data(0);
1858
1859 let mut expected = vec![0.; 128];
1860 expected[0] = 1.;
1861
1862 assert_float_eq!(channel[..], expected[..], abs_all <= 0.);
1863 }
1864
1865 #[test]
1866 fn test_end_of_file_slow_track_2() {
1870 let sample_rate = 48_000.;
1871 let mut context = OfflineAudioContext::new(1, RENDER_QUANTUM_SIZE, sample_rate);
1872
1873 let mut buffer = context.create_buffer(1, 5, sample_rate);
1874 let data = vec![1.; 1];
1875 buffer.copy_to_channel(&data, 0);
1876
1877 let mut src = context.create_buffer_source();
1878 src.connect(&context.destination());
1879 src.set_buffer(buffer);
1880 src.start_at(1. / sample_rate as f64);
1882 src.stop_at(125. / sample_rate as f64);
1884
1885 let result = context.start_rendering_sync();
1886 let channel = result.get_channel_data(0);
1887
1888 let mut expected = vec![0.; 128];
1889 expected[1] = 1.;
1890
1891 assert_float_eq!(channel[..], expected[..], abs_all <= 0.);
1892 }
1893
1894 #[test]
1895 fn test_loop_no_restart_suspend() {
1896 let sample_rate = 48_000.;
1897 let result_size = RENDER_QUANTUM_SIZE * 2;
1898 let mut context = OfflineAudioContext::new(1, result_size, sample_rate);
1899
1900 let mut buffer = context.create_buffer(1, 1, sample_rate);
1901 let data = vec![1.; 1];
1902 buffer.copy_to_channel(&data, 0);
1903
1904 let mut src = context.create_buffer_source();
1905 src.connect(&context.destination());
1906 src.set_buffer(buffer);
1907 src.start_at(0.);
1908
1909 context.suspend_sync(RENDER_QUANTUM_SIZE as f64 / sample_rate as f64, move |_| {
1910 src.set_loop(true);
1911 });
1912
1913 let result = context.start_rendering_sync();
1914 let channel = result.get_channel_data(0);
1915
1916 let mut expected = vec![0.; result_size];
1917 expected[0] = 1.;
1918
1919 assert_float_eq!(channel[..], expected[..], abs_all <= 0.);
1920 }
1921
1922 #[test]
1923 fn test_loop_no_restart_onended_fast_track() {
1924 let sample_rate = 48_000.;
1925 let result_size = RENDER_QUANTUM_SIZE * 4;
1927 let mut context = OfflineAudioContext::new(1, result_size, sample_rate);
1928
1929 let mut buffer = context.create_buffer(1, 1, sample_rate);
1930 let data = vec![1.; 1];
1931 buffer.copy_to_channel(&data, 0);
1932
1933 let mut src = context.create_buffer_source();
1934 src.connect(&context.destination());
1935 src.set_buffer(buffer);
1936 src.start_at(0.);
1938
1939 let src = Arc::new(Mutex::new(src));
1940 let clone = Arc::clone(&src);
1941 src.lock().unwrap().set_onended(move |_| {
1942 clone.lock().unwrap().set_loop(true);
1943 });
1944
1945 let result = context.start_rendering_sync();
1946 let channel = result.get_channel_data(0);
1947
1948 let mut expected = vec![0.; result_size];
1949 expected[0] = 1.;
1950
1951 assert_float_eq!(channel[..], expected[..], abs_all <= 0.);
1952 }
1953
1954 #[test]
1955 fn test_loop_no_restart_onended_slow_track() {
1956 let sample_rate = 48_000.;
1957 let result_size = RENDER_QUANTUM_SIZE * 4;
1959 let mut context = OfflineAudioContext::new(1, result_size, sample_rate);
1960
1961 let mut buffer = context.create_buffer(1, 1, sample_rate);
1962 let data = vec![1.; 1];
1963 buffer.copy_to_channel(&data, 0);
1964
1965 let mut src = context.create_buffer_source();
1966 src.connect(&context.destination());
1967 src.set_buffer(buffer);
1968 src.start_at(1. / sample_rate as f64);
1970
1971 let src = Arc::new(Mutex::new(src));
1972 let clone = Arc::clone(&src);
1973 src.lock().unwrap().set_onended(move |_| {
1974 clone.lock().unwrap().set_loop(true);
1975 });
1976
1977 let result = context.start_rendering_sync();
1978 let channel = result.get_channel_data(0);
1979
1980 let mut expected = vec![0.; result_size];
1981 expected[1] = 1.;
1982
1983 assert_float_eq!(channel[..], expected[..], abs_all <= 0.);
1984 }
1985
1986 #[test]
1987 fn test_subsample_buffer_stitching() {
1991 [(44_100., 44_100., 9.0957e-5), (44_100., 43_800., 3.8986e-3)]
1992 .iter()
1993 .for_each(|(sample_rate, buffer_rate, error_threshold)| {
1994 let sample_rate = *sample_rate;
1995 let buffer_rate = *buffer_rate;
1996 let buffer_length = 30;
1997 let frequency = 440.;
1998
1999 let length = buffer_length * 15;
2001 let mut context = OfflineAudioContext::new(2, length, sample_rate);
2002
2003 let mut wave_signal = vec![0.; context.length()];
2004 let omega = 2. * PI / buffer_rate * frequency;
2005 wave_signal.iter_mut().enumerate().for_each(|(i, s)| {
2006 *s = (omega * i as f32).sin();
2007 });
2008
2009 for k in (0..context.length()).step_by(buffer_length) {
2013 let mut buffer = AudioBuffer::new(AudioBufferOptions {
2014 number_of_channels: 1,
2015 length: buffer_length,
2016 sample_rate: buffer_rate,
2017 });
2018 buffer.copy_to_channel(&wave_signal[k..k + buffer_length], 0);
2019
2020 let mut src = AudioBufferSourceNode::new(
2021 &context,
2022 AudioBufferSourceOptions {
2023 buffer: Some(buffer),
2024 ..Default::default()
2025 },
2026 );
2027 src.connect(&context.destination());
2028 src.start_at(k as f64 / buffer_rate as f64);
2029 }
2030
2031 let mut expected = vec![0.; context.length()];
2032 let omega = 2. * PI / sample_rate * frequency;
2033 expected.iter_mut().enumerate().for_each(|(i, s)| {
2034 *s = (omega * i as f32).sin();
2035 });
2036
2037 let result = context.start_rendering_sync();
2038 let actual = result.get_channel_data(0);
2039
2040 assert_float_eq!(actual[..], expected[..], abs_all <= error_threshold);
2041 });
2042 }
2043
2044 #[test]
2045 fn test_onended_before_drop() {
2046 let sample_rate = 48_000.;
2047 let result_size = RENDER_QUANTUM_SIZE;
2048 let mut context = OfflineAudioContext::new(1, result_size, sample_rate);
2049 let mut buffer = context.create_buffer(1, result_size * 2, sample_rate);
2051 let data = vec![1.; 1];
2052 buffer.copy_to_channel(&data, 0);
2053
2054 let mut src = context.create_buffer_source();
2055 src.connect(&context.destination());
2056 src.set_buffer(buffer);
2057 src.start();
2058
2059 let onended_called = Arc::new(AtomicBool::new(false));
2060 let onended_called_clone = Arc::clone(&onended_called);
2061
2062 src.set_onended(move |_| {
2063 onended_called_clone.store(true, Ordering::SeqCst);
2064 });
2065
2066 let result = context.start_rendering_sync();
2067 let channel = result.get_channel_data(0);
2068
2069 let mut expected = vec![0.; result_size];
2070 expected[0] = 1.;
2071
2072 assert_float_eq!(channel[..], expected[..], abs_all <= 0.);
2073 assert!(onended_called.load(Ordering::SeqCst));
2074 }
2075}