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