1use crate::context::{AudioContextRegistration, AudioParamId, BaseAudioContext};
2use crate::param::{AudioParam, AudioParamDescriptor};
3use crate::render::{
4    AudioParamValues, AudioProcessor, AudioRenderQuantum, AudioWorkletGlobalScope,
5};
6use crate::RENDER_QUANTUM_SIZE;
7
8use super::{AudioNode, AudioNodeOptions, ChannelConfig, ChannelInterpretation};
9
10use std::cell::{Cell, RefCell, RefMut};
11use std::rc::Rc;
12
13#[derive(Clone, Debug)]
19pub struct DelayOptions {
20    pub max_delay_time: f64,
21    pub delay_time: f64,
22    pub audio_node_options: AudioNodeOptions,
23}
24
25impl Default for DelayOptions {
26    fn default() -> Self {
27        Self {
28            max_delay_time: 1.,
29            delay_time: 0.,
30            audio_node_options: AudioNodeOptions::default(),
31        }
32    }
33}
34
35#[derive(Copy, Clone, Debug, Default)]
36struct PlaybackInfo {
37    prev_block_index: usize,
38    prev_frame_index: usize,
39    k: f32,
40}
41
42#[derive(Debug)]
100pub struct DelayNode {
101    reader_registration: AudioContextRegistration,
102    writer_registration: AudioContextRegistration,
103    delay_time: AudioParam,
104    channel_config: ChannelConfig,
105}
106
107impl AudioNode for DelayNode {
108    fn registration(&self) -> &AudioContextRegistration {
114        &self.writer_registration
115    }
116
117    fn channel_config(&self) -> &ChannelConfig {
118        &self.channel_config
119    }
120
121    fn number_of_inputs(&self) -> usize {
122        1
123    }
124
125    fn number_of_outputs(&self) -> usize {
126        1
127    }
128
129    fn connect_from_output_to_input<'a>(
131        &self,
132        dest: &'a dyn AudioNode,
133        output: usize,
134        input: usize,
135    ) -> &'a dyn AudioNode {
136        assert!(
137            self.context() == dest.context(),
138            "InvalidAccessError - Attempting to connect nodes from different contexts",
139        );
140
141        assert!(
142            self.number_of_outputs() > output,
143            "IndexSizeError - output port {} is out of bounds",
144            output
145        );
146
147        assert!(
148            dest.number_of_inputs() > input,
149            "IndexSizeError - input port {} is out of bounds",
150            input
151        );
152
153        self.context().connect(
154            self.reader_registration.id(),
155            dest.registration().id(),
156            output,
157            input,
158        );
159
160        dest
161    }
162
163    fn disconnect(&self) {
165        self.context()
166            .disconnect(self.reader_registration.id(), None, None, None);
167    }
168
169    fn disconnect_dest(&self, dest: &dyn AudioNode) {
177        assert!(
178            self.context() == dest.context(),
179            "InvalidAccessError - Attempting to disconnect nodes from different contexts"
180        );
181
182        self.context().disconnect(
183            self.reader_registration.id(),
184            None,
185            Some(dest.registration().id()),
186            None,
187        );
188    }
189
190    fn disconnect_output(&self, output: usize) {
197        assert!(
198            self.number_of_outputs() > output,
199            "IndexSizeError - output port {} is out of bounds",
200            output
201        );
202
203        self.context()
204            .disconnect(self.reader_registration.id(), Some(output), None, None);
205    }
206
207    fn disconnect_dest_from_output(&self, dest: &dyn AudioNode, output: usize) {
216        assert!(
217            self.context() == dest.context(),
218            "InvalidAccessError - Attempting to disconnect nodes from different contexts"
219        );
220
221        assert!(
222            self.number_of_outputs() > output,
223            "IndexSizeError - output port {} is out of bounds",
224            output
225        );
226
227        self.context().disconnect(
228            self.reader_registration.id(),
229            Some(output),
230            Some(dest.registration().id()),
231            None,
232        );
233    }
234
235    fn disconnect_dest_from_output_to_input(
246        &self,
247        dest: &dyn AudioNode,
248        output: usize,
249        input: usize,
250    ) {
251        assert!(
252            self.context() == dest.context(),
253            "InvalidAccessError - Attempting to disconnect nodes from different contexts"
254        );
255
256        assert!(
257            self.number_of_outputs() > output,
258            "IndexSizeError - output port {} is out of bounds",
259            output
260        );
261
262        assert!(
263            dest.number_of_inputs() > input,
264            "IndexSizeError - input port {} is out of bounds",
265            input
266        );
267
268        self.context().disconnect(
269            self.reader_registration.id(),
270            Some(output),
271            Some(dest.registration().id()),
272            Some(input),
273        );
274    }
275}
276
277impl DelayNode {
278    pub fn new<C: BaseAudioContext>(context: &C, options: DelayOptions) -> Self {
284        let sample_rate = context.sample_rate() as f64;
285
286        assert!(
291            options.max_delay_time > 0. && options.max_delay_time < 180.,
292            "NotSupportedError - maxDelayTime MUST be greater than zero and less than three minutes",
293        );
294
295        let max_delay_time = options.max_delay_time;
300        let num_quanta =
301            (max_delay_time * sample_rate / RENDER_QUANTUM_SIZE as f64).ceil() as usize;
302        let ring_buffer = Vec::with_capacity(num_quanta + 1);
303
304        let shared_ring_buffer = Rc::new(RefCell::new(ring_buffer));
305        let shared_ring_buffer_clone = Rc::clone(&shared_ring_buffer);
306
307        let last_written_index = Rc::new(Cell::<Option<usize>>::new(None));
309        let last_written_index_clone = Rc::clone(&last_written_index);
310
311        let latest_frame_written = Rc::new(Cell::new(u64::MAX));
314        let latest_frame_written_clone = Rc::clone(&latest_frame_written);
315
316        let node = context.base().register(move |writer_registration| {
317            let node = context.base().register(move |reader_registration| {
318                let param_opts = AudioParamDescriptor {
319                    name: String::new(),
320                    min_value: 0.,
321                    max_value: max_delay_time as f32,
322                    default_value: 0.,
323                    automation_rate: crate::param::AutomationRate::A,
324                };
325                let (param, proc) = context.create_audio_param(param_opts, &reader_registration);
326
327                param.set_value(options.delay_time as f32);
328
329                let reader_render = DelayReader {
330                    delay_time: proc,
331                    ring_buffer: shared_ring_buffer_clone,
332                    index: 0,
333                    last_written_index: last_written_index_clone,
334                    in_cycle: false,
335                    last_written_index_checked: None,
336                    latest_frame_written: latest_frame_written_clone,
337                };
338
339                let node = DelayNode {
340                    reader_registration,
341                    writer_registration,
342                    channel_config: options.audio_node_options.into(),
343                    delay_time: param,
344                };
345
346                (node, Box::new(reader_render))
347            });
348
349            let writer_render = DelayWriter {
350                ring_buffer: shared_ring_buffer,
351                index: 0,
352                last_written_index,
353                latest_frame_written,
354            };
355
356            (node, Box::new(writer_render))
357        });
358
359        let writer_id = node.writer_registration.id();
360        let reader_id = node.reader_registration.id();
361        context.base().mark_cycle_breaker(&node.writer_registration);
365        context.base().connect(writer_id, reader_id, 0, 0);
366
367        node
368    }
369
370    pub fn delay_time(&self) -> &AudioParam {
372        &self.delay_time
373    }
374}
375
376struct DelayWriter {
377    ring_buffer: Rc<RefCell<Vec<AudioRenderQuantum>>>,
378    index: usize,
379    latest_frame_written: Rc<Cell<u64>>,
380    last_written_index: Rc<Cell<Option<usize>>>,
381}
382
383#[allow(clippy::non_send_fields_in_send_ty)]
387unsafe impl Send for DelayWriter {}
388
389trait RingBufferChecker {
390    fn ring_buffer_mut(&self) -> RefMut<'_, Vec<AudioRenderQuantum>>;
391
392    #[inline(always)]
396    fn check_ring_buffer_size(&self, render_quantum: &AudioRenderQuantum) {
397        let mut ring_buffer = self.ring_buffer_mut();
398
399        if ring_buffer.len() < ring_buffer.capacity() {
400            let len = ring_buffer.capacity();
401            let mut silence = render_quantum.clone();
402            silence.make_silent();
403
404            ring_buffer.resize(len, silence);
405        }
406    }
407}
408
409impl Drop for DelayWriter {
410    fn drop(&mut self) {
411        let last_written_index = if self.index == 0 {
412            self.ring_buffer.borrow().capacity() - 1
413        } else {
414            self.index - 1
415        };
416
417        self.last_written_index.set(Some(last_written_index));
418    }
419}
420
421impl RingBufferChecker for DelayWriter {
422    #[inline(always)]
423    fn ring_buffer_mut(&self) -> RefMut<'_, Vec<AudioRenderQuantum>> {
424        self.ring_buffer.borrow_mut()
425    }
426}
427
428impl AudioProcessor for DelayWriter {
429    fn process(
430        &mut self,
431        inputs: &[AudioRenderQuantum],
432        outputs: &mut [AudioRenderQuantum],
433        _params: AudioParamValues<'_>,
434        scope: &AudioWorkletGlobalScope,
435    ) -> bool {
436        let input = inputs[0].clone();
438        let output = &mut outputs[0];
439
440        self.check_ring_buffer_size(&input);
443        self.check_ring_buffer_up_down_mix(&input);
446
447        let mut buffer = self.ring_buffer.borrow_mut();
449        buffer[self.index] = input;
450
451        self.index = (self.index + 1) % buffer.capacity();
453        self.latest_frame_written.set(scope.current_frame);
454
455        output.make_silent();
458
459        false
461    }
462
463    fn has_side_effects(&self) -> bool {
464        true }
466}
467
468impl DelayWriter {
469    #[inline(always)]
470    fn check_ring_buffer_up_down_mix(&self, input: &AudioRenderQuantum) {
471        let mut ring_buffer = self.ring_buffer_mut();
480        let buffer_number_of_channels = ring_buffer[0].number_of_channels();
481        let input_number_of_channels = input.number_of_channels();
482
483        if buffer_number_of_channels != input_number_of_channels {
484            for render_quantum in ring_buffer.iter_mut() {
485                render_quantum.mix(input_number_of_channels, ChannelInterpretation::Speakers);
486            }
487        }
488    }
489}
490
491struct DelayReader {
492    delay_time: AudioParamId,
493    ring_buffer: Rc<RefCell<Vec<AudioRenderQuantum>>>,
494    index: usize,
495    latest_frame_written: Rc<Cell<u64>>,
496    in_cycle: bool,
497    last_written_index: Rc<Cell<Option<usize>>>,
498    last_written_index_checked: Option<usize>,
500}
501
502#[allow(clippy::non_send_fields_in_send_ty)]
506unsafe impl Send for DelayReader {}
507
508impl RingBufferChecker for DelayReader {
509    #[inline(always)]
510    fn ring_buffer_mut(&self) -> RefMut<'_, Vec<AudioRenderQuantum>> {
511        self.ring_buffer.borrow_mut()
512    }
513}
514
515impl AudioProcessor for DelayReader {
516    fn process(
517        &mut self,
518        _inputs: &[AudioRenderQuantum], outputs: &mut [AudioRenderQuantum],
520        params: AudioParamValues<'_>,
521        scope: &AudioWorkletGlobalScope,
522    ) -> bool {
523        let output = &mut outputs[0];
525        self.check_ring_buffer_size(output);
528
529        let ring_buffer = self.ring_buffer.borrow();
530
531        let number_of_channels = ring_buffer[0].number_of_channels();
533        output.set_number_of_channels(number_of_channels);
534
535        if !self.in_cycle {
536            let latest_frame_written = self.latest_frame_written.get();
538            self.in_cycle = latest_frame_written != scope.current_frame;
540            }
543
544        let delay = params.get(&self.delay_time);
546        let sample_rate = scope.sample_rate as f64;
547        let dt = 1. / sample_rate;
548        let quantum_duration = RENDER_QUANTUM_SIZE as f64 * dt;
549        let ring_size = ring_buffer.len() as i32;
550        let ring_index = self.index as i32;
551        let mut playback_infos = [PlaybackInfo::default(); RENDER_QUANTUM_SIZE];
552
553        if delay.len() == 1 {
554            playback_infos[0] = Self::get_playback_infos(
555                f64::from(delay[0]),
556                self.in_cycle,
557                0.,
558                quantum_duration,
559                sample_rate,
560                ring_size,
561                ring_index,
562            );
563
564            for i in 1..RENDER_QUANTUM_SIZE {
565                let PlaybackInfo {
566                    prev_block_index,
567                    prev_frame_index,
568                    k,
569                } = playback_infos[i - 1];
570
571                let mut prev_block_index = prev_block_index;
572                let mut prev_frame_index = prev_frame_index + 1;
573
574                if prev_frame_index >= RENDER_QUANTUM_SIZE {
575                    prev_block_index = (prev_block_index + 1) % ring_buffer.len();
576                    prev_frame_index = 0;
577                }
578
579                playback_infos[i] = PlaybackInfo {
580                    prev_block_index,
581                    prev_frame_index,
582                    k,
583                };
584            }
585        } else {
586            delay
587                .iter()
588                .zip(playback_infos.iter_mut())
589                .enumerate()
590                .for_each(|(index, (&d, infos))| {
591                    *infos = Self::get_playback_infos(
592                        f64::from(d),
593                        self.in_cycle,
594                        index as f64,
595                        quantum_duration,
596                        sample_rate,
597                        ring_size,
598                        ring_index,
599                    );
600                });
601        }
602
603        let mut is_actively_processing = false;
608
609        for (channel_number, output_channel) in output.channels_mut().iter_mut().enumerate() {
611            let mut block_index = playback_infos[0].prev_block_index;
613            let mut channel_data = ring_buffer[block_index].channel_data(channel_number);
614
615            output_channel
616                .iter_mut()
617                .zip(playback_infos.iter_mut())
618                .for_each(|(o, infos)| {
619                    let PlaybackInfo {
620                        prev_block_index,
621                        prev_frame_index,
622                        k,
623                    } = *infos;
624
625                    let mut next_block_index = prev_block_index;
627                    let mut next_frame_index = prev_frame_index + 1;
628
629                    if next_frame_index >= RENDER_QUANTUM_SIZE {
630                        next_block_index = (next_block_index + 1) % ring_buffer.len();
631                        next_frame_index = 0;
632                    }
633
634                    if block_index != prev_block_index {
638                        block_index = prev_block_index;
639                        channel_data = ring_buffer[block_index].channel_data(channel_number);
640                    }
641
642                    let prev_sample = channel_data[prev_frame_index];
643
644                    if block_index != next_block_index {
646                        block_index = next_block_index;
647                        channel_data = ring_buffer[block_index].channel_data(channel_number);
648                    }
649
650                    let next_sample = channel_data[next_frame_index];
651
652                    let value = (1. - k).mul_add(prev_sample, k * next_sample);
653
654                    if value.is_normal() {
655                        is_actively_processing = true;
656                    }
657
658                    *o = value;
659                });
660        }
661
662        if !is_actively_processing {
663            output.make_silent();
664        }
665
666        if matches!(self.last_written_index_checked, Some(index) if index == self.index) {
667            return false;
668        }
669
670        let last_written_index = self.last_written_index.get();
675
676        if last_written_index.is_some() && self.last_written_index_checked.is_none() {
677            self.last_written_index_checked = last_written_index;
678        }
679        self.index = (self.index + 1) % ring_buffer.capacity();
681
682        true
683    }
684}
685
686impl DelayReader {
687    #[inline(always)]
688    fn get_playback_infos(
689        delay: f64,
690        in_cycle: bool,
691        sample_index: f64,
692        quantum_duration: f64,
693        sample_rate: f64,
694        ring_size: i32,
695        ring_index: i32,
696    ) -> PlaybackInfo {
697        let clamped_delay = if in_cycle {
700            delay.max(quantum_duration)
701        } else {
702            delay
703        };
704        let num_samples = clamped_delay * sample_rate;
705        let position = sample_index - num_samples;
707        let position_floored = position.floor();
708        let num_frames = RENDER_QUANTUM_SIZE as i32;
710
711        let block_offset = (position_floored / num_frames as f64).floor();
714        let mut prev_block_index = ring_index + block_offset as i32;
716        if prev_block_index < 0 {
718            prev_block_index += ring_size;
719        }
720
721        let mut frame_offset = position_floored as i32 % num_frames;
723        if frame_offset == 0 {
725            frame_offset = -num_frames;
726        }
727
728        let prev_frame_index = if frame_offset <= 0 {
729            num_frames + frame_offset
730        } else {
731            frame_offset
733        };
734
735        let k = (position - position_floored) as f32;
737
738        PlaybackInfo {
739            prev_block_index: prev_block_index as usize,
740            prev_frame_index: prev_frame_index as usize,
741            k,
742        }
743    }
744}
745
746#[cfg(test)]
747mod tests {
748    use float_eq::assert_float_eq;
749
750    use crate::context::OfflineAudioContext;
751    use crate::node::AudioScheduledSourceNode;
752
753    use super::*;
754
755    #[test]
756    fn test_audioparam_value_applies_immediately() {
757        let context = OfflineAudioContext::new(1, 128, 48_000.);
758        let options = DelayOptions {
759            delay_time: 0.12,
760            ..Default::default()
761        };
762        let src = DelayNode::new(&context, options);
763        assert_float_eq!(src.delay_time.value(), 0.12, abs_all <= 0.);
764    }
765
766    #[test]
767    fn test_sample_accurate() {
768        for delay_in_samples in [128., 131., 197.].iter() {
769            let sample_rate = 48_000.;
770            let mut context = OfflineAudioContext::new(1, 256, sample_rate);
771
772            let delay = context.create_delay(2.);
773            delay.delay_time.set_value(delay_in_samples / sample_rate);
774            delay.connect(&context.destination());
775
776            let mut dirac = context.create_buffer(1, 1, sample_rate);
777            dirac.copy_to_channel(&[1.], 0);
778
779            let mut src = context.create_buffer_source();
780            src.connect(&delay);
781            src.set_buffer(dirac);
782            src.start_at(0.);
783
784            let result = context.start_rendering_sync();
785            let channel = result.get_channel_data(0);
786
787            let mut expected = vec![0.; 256];
788            expected[*delay_in_samples as usize] = 1.;
789
790            assert_float_eq!(channel[..], expected[..], abs_all <= 0.00001);
791        }
792    }
793
794    #[test]
795    fn test_sub_sample_accurate_1() {
796        let delay_in_samples = 128.5;
797        let sample_rate = 48_000.;
798        let mut context = OfflineAudioContext::new(1, 256, sample_rate);
799
800        let delay = context.create_delay(2.);
801        delay.delay_time.set_value(delay_in_samples / sample_rate);
802        delay.connect(&context.destination());
803
804        let mut dirac = context.create_buffer(1, 1, sample_rate);
805        dirac.copy_to_channel(&[1.], 0);
806
807        let mut src = context.create_buffer_source();
808        src.connect(&delay);
809        src.set_buffer(dirac);
810        src.start_at(0.);
811
812        let result = context.start_rendering_sync();
813        let channel = result.get_channel_data(0);
814
815        let mut expected = vec![0.; 256];
816        expected[128] = 0.5;
817        expected[129] = 0.5;
818
819        assert_float_eq!(channel[..], expected[..], abs_all <= 0.00001);
820    }
821
822    #[test]
823    fn test_sub_sample_accurate_2() {
824        let delay_in_samples = 128.8;
825        let sample_rate = 48_000.;
826        let mut context = OfflineAudioContext::new(1, 256, sample_rate);
827
828        let delay = context.create_delay(2.);
829        delay.delay_time.set_value(delay_in_samples / sample_rate);
830        delay.connect(&context.destination());
831
832        let mut dirac = context.create_buffer(1, 1, sample_rate);
833        dirac.copy_to_channel(&[1.], 0);
834
835        let mut src = context.create_buffer_source();
836        src.connect(&delay);
837        src.set_buffer(dirac);
838        src.start_at(0.);
839
840        let result = context.start_rendering_sync();
841        let channel = result.get_channel_data(0);
842
843        let mut expected = vec![0.; 256];
844        expected[128] = 0.2;
845        expected[129] = 0.8;
846
847        assert_float_eq!(channel[..], expected[..], abs_all <= 1e-5);
848    }
849
850    #[test]
851    fn test_multichannel() {
852        let delay_in_samples = 128.;
853        let sample_rate = 48_000.;
854        let mut context = OfflineAudioContext::new(2, 2 * 128, sample_rate);
855
856        let delay = context.create_delay(2.);
857        delay.delay_time.set_value(delay_in_samples / sample_rate);
858        delay.connect(&context.destination());
859
860        let mut two_chan_dirac = context.create_buffer(2, 256, sample_rate);
861        two_chan_dirac.copy_to_channel(&[1.], 0);
863        two_chan_dirac.copy_to_channel(&[0., 1.], 1);
864
865        let mut src = context.create_buffer_source();
866        src.connect(&delay);
867        src.set_buffer(two_chan_dirac);
868        src.start_at(0.);
869
870        let result = context.start_rendering_sync();
871
872        let channel_left = result.get_channel_data(0);
873        let mut expected_left = vec![0.; 256];
874        expected_left[128] = 1.;
875        assert_float_eq!(channel_left[..], expected_left[..], abs_all <= 1e-5);
876
877        let channel_right = result.get_channel_data(1);
878        let mut expected_right = vec![0.; 256];
879        expected_right[128 + 1] = 1.;
880        assert_float_eq!(channel_right[..], expected_right[..], abs_all <= 1e-5);
881    }
882
883    #[test]
884    fn test_input_number_of_channels_change() {
885        let delay_in_samples = 128.;
886        let sample_rate = 48_000.;
887        let mut context = OfflineAudioContext::new(2, 3 * 128, sample_rate);
888
889        let delay = context.create_delay(2.);
890        delay.delay_time.set_value(delay_in_samples / sample_rate);
891        delay.connect(&context.destination());
892
893        let mut one_chan_dirac = context.create_buffer(1, 128, sample_rate);
894        one_chan_dirac.copy_to_channel(&[1.], 0);
895
896        let mut src1 = context.create_buffer_source();
897        src1.connect(&delay);
898        src1.set_buffer(one_chan_dirac);
899        src1.start_at(0.);
900
901        let mut two_chan_dirac = context.create_buffer(2, 256, sample_rate);
902        two_chan_dirac.copy_to_channel(&[1.], 0);
904        two_chan_dirac.copy_to_channel(&[0., 1.], 1);
905        let mut src2 = context.create_buffer_source();
907        src2.connect(&delay);
908        src2.set_buffer(two_chan_dirac);
909        src2.start_at(delay_in_samples as f64 / sample_rate as f64);
910
911        let result = context.start_rendering_sync();
912
913        let channel_left = result.get_channel_data(0);
914        let mut expected_left = vec![0.; 3 * 128];
915        expected_left[128] = 1.;
916        expected_left[256] = 1.;
917        assert_float_eq!(channel_left[..], expected_left[..], abs_all <= 1e-5);
918
919        let channel_right = result.get_channel_data(1);
920        let mut expected_right = vec![0.; 3 * 128];
921        expected_right[128] = 1.;
922        expected_right[256 + 1] = 1.;
923        assert_float_eq!(channel_right[..], expected_right[..], abs_all <= 1e-5);
924    }
925
926    #[test]
927    fn test_node_stays_alive_long_enough() {
928        for _ in 0..10 {
930            let sample_rate = 48_000.;
931            let mut context = OfflineAudioContext::new(1, 5 * 128, sample_rate);
932
933            {
938                let delay = context.create_delay(1.);
939                delay.delay_time.set_value(128. / sample_rate);
940                delay.connect(&context.destination());
941
942                let mut dirac = context.create_buffer(1, 1, sample_rate);
943                dirac.copy_to_channel(&[1.], 0);
944
945                let mut src = context.create_buffer_source();
946                src.connect(&delay);
947                src.set_buffer(dirac);
948                src.start_at(128. * 3. / sample_rate as f64);
951            } let result = context.start_rendering_sync();
954            let mut expected = vec![0.; 5 * 128];
955            expected[4 * 128] = 1.;
957
958            assert_float_eq!(result.get_channel_data(0), &expected[..], abs_all <= 1e-5);
959        }
960    }
961
962    #[test]
963    fn test_subquantum_delay() {
964        for i in 0..128 {
965            let sample_rate = 48_000.;
966            let mut context = OfflineAudioContext::new(1, 128, sample_rate);
967
968            let delay = context.create_delay(1.);
969            delay.delay_time.set_value(i as f32 / sample_rate);
970            delay.connect(&context.destination());
971
972            let mut dirac = context.create_buffer(1, 1, sample_rate);
973            dirac.copy_to_channel(&[1.], 0);
974
975            let mut src = context.create_buffer_source();
976            src.connect(&delay);
977            src.set_buffer(dirac);
978            src.start_at(0.);
979
980            let result = context.start_rendering_sync();
981            let channel = result.get_channel_data(0);
982
983            let mut expected = vec![0.; 128];
984            expected[i] = 1.;
985
986            assert_float_eq!(channel[..], expected[..], abs_all <= 1e-5);
987        }
988    }
989
990    #[test]
991    fn test_min_delay_when_in_loop() {
992        let sample_rate = 48_000.;
993        let mut context = OfflineAudioContext::new(1, 256, sample_rate);
994
995        let delay = context.create_delay(1.);
996        delay.delay_time.set_value(1. / sample_rate);
997        delay.connect(&context.destination());
998        let gain = context.create_gain();
1001        gain.gain().set_value(0.);
1002        delay.connect(&gain);
1003        gain.connect(&delay);
1004
1005        let mut dirac = context.create_buffer(1, 1, sample_rate);
1006        dirac.copy_to_channel(&[1.], 0);
1007
1008        let mut src = context.create_buffer_source();
1009        src.connect(&delay);
1010        src.set_buffer(dirac);
1011        src.start_at(0.);
1012
1013        let result = context.start_rendering_sync();
1014        let channel = result.get_channel_data(0);
1015
1016        let mut expected = vec![0.; 256];
1017        expected[128] = 1.;
1018
1019        assert_float_eq!(channel[..], expected[..], abs_all <= 0.);
1020    }
1021
1022    #[test]
1026    fn test_max_delay() {
1027        use std::f32::consts::PI;
1028
1029        for &delay_time_seconds in [1., 1.5].iter() {
1030            let sample_rate = 44100.0;
1031            let render_length = 4 * sample_rate as usize;
1032
1033            let mut context = OfflineAudioContext::new(1, render_length, sample_rate);
1034
1035            let tone_frequency = 20.;
1037            let tone_length_seconds = 2.;
1038            let tone_length = tone_length_seconds as usize * sample_rate as usize;
1039            let mut tone_buffer = context.create_buffer(1, tone_length, sample_rate);
1040            let tone_data = tone_buffer.get_channel_data_mut(0);
1041
1042            for (i, s) in tone_data.iter_mut().enumerate() {
1043                *s = (tone_frequency * 2.0 * PI * i as f32 / sample_rate).sin();
1044            }
1045
1046            let mut buffer_source = context.create_buffer_source();
1047            buffer_source.set_buffer(tone_buffer.clone());
1048
1049            let delay = context.create_delay(delay_time_seconds); delay.delay_time.set_value(delay_time_seconds as f32);
1051
1052            buffer_source.connect(&delay);
1053            delay.connect(&context.destination());
1054            buffer_source.start_at(0.);
1055
1056            let output = context.start_rendering_sync();
1057            let source = tone_buffer.get_channel_data(0);
1058            let rendered = output.get_channel_data(0);
1059
1060            let delay_time_frames = (delay_time_seconds * sample_rate as f64) as usize;
1061            let tone_length_frames = (tone_length_seconds * sample_rate as f64) as usize;
1062
1063            for (i, s) in rendered.iter().enumerate() {
1064                if i < delay_time_frames {
1065                    assert_eq!(*s, 0.);
1066                } else if i >= delay_time_frames && i < delay_time_frames + tone_length_frames {
1067                    let j = i - delay_time_frames;
1068                    assert_eq!(*s, source[j]);
1069                } else {
1070                    assert_eq!(*s, 0.);
1071                }
1072            }
1073        }
1074    }
1075
1076    #[test]
1077    fn test_max_delay_smaller_than_quantum_size() {
1078        for _ in 0..10 {
1083            let sample_rate = 48_000.;
1084            let mut context = OfflineAudioContext::new(1, 256, sample_rate);
1085
1086            let delay = context.create_delay((64. / sample_rate).into());
1088            delay.delay_time.set_value(64. / sample_rate);
1090            delay.connect(&context.destination());
1091
1092            let gain = context.create_gain();
1094            gain.gain().set_value(0.);
1095            delay.connect(&gain);
1096            gain.connect(&delay);
1097
1098            let mut dirac = context.create_buffer(1, 1, sample_rate);
1099            dirac.copy_to_channel(&[1.], 0);
1100
1101            let mut src = context.create_buffer_source();
1102            src.connect(&delay);
1103            src.set_buffer(dirac);
1104            src.start_at(0.);
1105
1106            let result = context.start_rendering_sync();
1107            let channel = result.get_channel_data(0);
1108
1109            let mut expected = vec![0.; 256];
1110            expected[128] = 1.;
1111
1112            assert_float_eq!(channel[..], expected[..], abs_all <= 0.);
1113        }
1114    }
1115
1116    #[test]
1122    fn test_max_delay_multiple_of_quantum_size_1() {
1123        let sample_rate = 48_000.;
1125        let mut context = OfflineAudioContext::new(1, 256, sample_rate);
1126
1127        let max_delay = 128. / sample_rate;
1128        let delay = context.create_delay(max_delay.into());
1129        delay.delay_time.set_value(max_delay);
1130        delay.connect(&context.destination());
1131
1132        let mut dirac = context.create_buffer(1, 1, sample_rate);
1133        dirac.copy_to_channel(&[1.], 0);
1134
1135        let mut src = context.create_buffer_source();
1136        src.connect(&delay);
1137        src.set_buffer(dirac);
1138        src.start_at(0.);
1139
1140        let result = context.start_rendering_sync();
1141        let channel = result.get_channel_data(0);
1142
1143        let mut expected = vec![0.; 256];
1144        expected[128] = 1.;
1145
1146        assert_float_eq!(channel[..], expected[..], abs_all <= 1e-5);
1147    }
1148
1149    #[test]
1150    fn test_max_delay_multiple_of_quantum_size_2() {
1151        let sample_rate = 48_000.;
1153        let mut context = OfflineAudioContext::new(1, 3 * 128, sample_rate);
1154
1155        let max_delay = 128. * 2. / sample_rate;
1156        let delay = context.create_delay(max_delay.into());
1157        delay.delay_time.set_value(max_delay);
1158        delay.connect(&context.destination());
1159
1160        let mut dirac = context.create_buffer(1, 1, sample_rate);
1161        dirac.copy_to_channel(&[1.], 0);
1162
1163        let mut src = context.create_buffer_source();
1164        src.connect(&delay);
1165        src.set_buffer(dirac);
1166        src.start_at(0.);
1167
1168        let result = context.start_rendering_sync();
1169        let channel = result.get_channel_data(0);
1170
1171        let mut expected = vec![0.; 3 * 128];
1172        expected[256] = 1.;
1173
1174        assert_float_eq!(channel[..], expected[..], abs_all <= 1e-5);
1175    }
1176
1177    #[test]
1178    fn test_subquantum_delay_dynamic_lifetime() {
1179        let sample_rate = 48_000.;
1180        let mut context = OfflineAudioContext::new(1, 3 * 128, sample_rate);
1181
1182        {
1187            let delay = context.create_delay(1.);
1188            delay.delay_time.set_value(64_f32 / sample_rate);
1189            delay.connect(&context.destination());
1190
1191            let mut src = context.create_constant_source();
1193            src.connect(&delay);
1194            src.start_at(0.);
1195            src.stop_at(120. / sample_rate as f64);
1196        } let result = context.start_rendering_sync();
1199        let channel = result.get_channel_data(0);
1200
1201        let mut expected = vec![0.; 3 * 128];
1202        expected[64..64 + 120].fill(1.);
1203
1204        assert_float_eq!(channel[..], expected[..], abs_all <= 1e-5);
1205    }
1206}