rodio/source/
delay.rs
1use std::time::Duration;
2
3use crate::{Sample, Source};
4
5use super::SeekError;
6
7fn remaining_samples(until_playback: Duration, sample_rate: u32, channels: u16) -> usize {
8 let ns = until_playback.as_secs() * 1_000_000_000 + until_playback.subsec_nanos() as u64;
9 let samples = ns * channels as u64 * sample_rate as u64 / 1_000_000_000;
10 samples as usize
11}
12
13pub fn delay<I>(input: I, duration: Duration) -> Delay<I>
15where
16 I: Source,
17 I::Item: Sample,
18{
19 Delay {
20 remaining_samples: remaining_samples(duration, input.sample_rate(), input.channels()),
21 requested_duration: duration,
22 input,
23 }
24}
25
26#[derive(Clone, Debug)]
28pub struct Delay<I> {
29 input: I,
30 remaining_samples: usize,
31 requested_duration: Duration,
32}
33
34impl<I> Delay<I>
35where
36 I: Source,
37 I::Item: Sample,
38{
39 #[inline]
41 pub fn inner(&self) -> &I {
42 &self.input
43 }
44
45 #[inline]
47 pub fn inner_mut(&mut self) -> &mut I {
48 &mut self.input
49 }
50
51 #[inline]
53 pub fn into_inner(self) -> I {
54 self.input
55 }
56}
57
58impl<I> Iterator for Delay<I>
59where
60 I: Source,
61 I::Item: Sample,
62{
63 type Item = <I as Iterator>::Item;
64
65 #[inline]
66 fn next(&mut self) -> Option<<I as Iterator>::Item> {
67 if self.remaining_samples >= 1 {
68 self.remaining_samples -= 1;
69 Some(Sample::zero_value())
70 } else {
71 self.input.next()
72 }
73 }
74
75 #[inline]
76 fn size_hint(&self) -> (usize, Option<usize>) {
77 let (min, max) = self.input.size_hint();
78 (
79 min + self.remaining_samples,
80 max.map(|v| v + self.remaining_samples),
81 )
82 }
83}
84
85impl<I> Source for Delay<I>
86where
87 I: Iterator + Source,
88 I::Item: Sample,
89{
90 #[inline]
91 fn current_frame_len(&self) -> Option<usize> {
92 self.input
93 .current_frame_len()
94 .map(|val| val + self.remaining_samples)
95 }
96
97 #[inline]
98 fn channels(&self) -> u16 {
99 self.input.channels()
100 }
101
102 #[inline]
103 fn sample_rate(&self) -> u32 {
104 self.input.sample_rate()
105 }
106
107 #[inline]
108 fn total_duration(&self) -> Option<Duration> {
109 self.input
110 .total_duration()
111 .map(|val| val + self.requested_duration)
112 }
113
114 #[inline]
128 fn try_seek(&mut self, pos: Duration) -> Result<(), SeekError> {
129 if pos < self.requested_duration {
130 self.input.try_seek(Duration::ZERO)?;
131 let until_playback = self.requested_duration - pos;
132 self.remaining_samples =
133 remaining_samples(until_playback, self.sample_rate(), self.channels());
134 }
135 let compensated_for_delay = pos.saturating_sub(self.requested_duration);
136 self.input.try_seek(compensated_for_delay)
137 }
138}