1 use std::time::Duration;
2 
3 use crate::{Sample, Source};
4 
5 const NS_PER_SECOND: u128 = 1_000_000_000;
6 
7 /// Internal function that builds a `SkipDuration` object.
skip_duration<I>(mut input: I, duration: Duration) -> SkipDuration<I> where I: Source, I::Item: Sample,8 pub fn skip_duration<I>(mut input: I, duration: Duration) -> SkipDuration<I>
9 where
10     I: Source,
11     I::Item: Sample,
12 {
13     do_skip_duration(&mut input, duration);
14     SkipDuration {
15         input,
16         skipped_duration: duration,
17     }
18 }
19 
20 /// Skips specified `duration` of the given `input` source from it's current position.
do_skip_duration<I>(input: &mut I, mut duration: Duration) where I: Source, I::Item: Sample,21 fn do_skip_duration<I>(input: &mut I, mut duration: Duration)
22 where
23     I: Source,
24     I::Item: Sample,
25 {
26     while duration > Duration::new(0, 0) {
27         if input.current_frame_len().is_none() {
28             // Sample rate and the amount of channels will be the same till the end.
29             do_skip_duration_unchecked(input, duration);
30             return;
31         }
32 
33         // .unwrap() safety: if `current_frame_len()` is None, the body of the `if` statement
34         // above returns before we get here.
35         let frame_len: usize = input.current_frame_len().unwrap();
36         let ns_per_sample: u128 =
37             NS_PER_SECOND / input.sample_rate() as u128 / input.channels() as u128;
38 
39         // Check if we need to skip only part of the current frame.
40         if frame_len as u128 * ns_per_sample > duration.as_nanos() {
41             skip_samples(input, (duration.as_nanos() / ns_per_sample) as usize);
42             return;
43         }
44 
45         skip_samples(input, frame_len as usize);
46 
47         duration -= Duration::from_nanos((frame_len * ns_per_sample as usize) as u64);
48     }
49 }
50 
51 /// Skips specified `duration` from the `input` source assuming that sample rate
52 /// and amount of channels are not changing.
do_skip_duration_unchecked<I>(input: &mut I, duration: Duration) where I: Source, I::Item: Sample,53 fn do_skip_duration_unchecked<I>(input: &mut I, duration: Duration)
54 where
55     I: Source,
56     I::Item: Sample,
57 {
58     let samples_per_channel: u128 =
59         duration.as_nanos() * input.sample_rate() as u128 / NS_PER_SECOND;
60     let samples_to_skip: u128 = samples_per_channel * input.channels() as u128;
61 
62     skip_samples(input, samples_to_skip as usize);
63 }
64 
65 /// Skips `n` samples from the given `input` source.
skip_samples<I>(input: &mut I, n: usize) where I: Source, I::Item: Sample,66 fn skip_samples<I>(input: &mut I, n: usize)
67 where
68     I: Source,
69     I::Item: Sample,
70 {
71     for _ in 0..n {
72         if input.next().is_none() {
73             break;
74         }
75     }
76 }
77 
78 /// A source that skips specified duration of the given source from it's current position.
79 #[derive(Clone, Debug)]
80 pub struct SkipDuration<I> {
81     input: I,
82     skipped_duration: Duration,
83 }
84 
85 impl<I> SkipDuration<I>
86 where
87     I: Source,
88     I::Item: Sample,
89 {
90     /// Returns a reference to the inner source.
91     #[inline]
inner(&self) -> &I92     pub fn inner(&self) -> &I {
93         &self.input
94     }
95 
96     /// Returns a mutable reference to the inner source.
97     #[inline]
inner_mut(&mut self) -> &mut I98     pub fn inner_mut(&mut self) -> &mut I {
99         &mut self.input
100     }
101 
102     /// Returns the inner source.
103     #[inline]
into_inner(self) -> I104     pub fn into_inner(self) -> I {
105         self.input
106     }
107 }
108 
109 impl<I> Iterator for SkipDuration<I>
110 where
111     I: Source,
112     I::Item: Sample,
113 {
114     type Item = <I as Iterator>::Item;
115 
116     #[inline]
next(&mut self) -> Option<Self::Item>117     fn next(&mut self) -> Option<Self::Item> {
118         self.input.next()
119     }
120 
121     #[inline]
size_hint(&self) -> (usize, Option<usize>)122     fn size_hint(&self) -> (usize, Option<usize>) {
123         self.input.size_hint()
124     }
125 }
126 
127 impl<I> Source for SkipDuration<I>
128 where
129     I: Source,
130     I::Item: Sample,
131 {
132     #[inline]
current_frame_len(&self) -> Option<usize>133     fn current_frame_len(&self) -> Option<usize> {
134         self.input.current_frame_len()
135     }
136 
137     #[inline]
channels(&self) -> u16138     fn channels(&self) -> u16 {
139         self.input.channels()
140     }
141 
142     #[inline]
sample_rate(&self) -> u32143     fn sample_rate(&self) -> u32 {
144         self.input.sample_rate()
145     }
146 
147     #[inline]
total_duration(&self) -> Option<Duration>148     fn total_duration(&self) -> Option<Duration> {
149         self.input.total_duration().map(|val| {
150             val.checked_sub(self.skipped_duration)
151                 .unwrap_or_else(|| Duration::from_secs(0))
152         })
153     }
154 }
155 
156 #[cfg(test)]
157 mod tests {
158     use std::time::Duration;
159 
160     use crate::buffer::SamplesBuffer;
161     use crate::source::Source;
162 
test_skip_duration_samples_left( channels: u16, sample_rate: u32, seconds: u32, seconds_to_skip: u32, )163     fn test_skip_duration_samples_left(
164         channels: u16,
165         sample_rate: u32,
166         seconds: u32,
167         seconds_to_skip: u32,
168     ) {
169         let data: Vec<f32> = (1..=(sample_rate * channels as u32 * seconds))
170             .map(|_| 0f32)
171             .collect();
172         let test_buffer = SamplesBuffer::new(channels, sample_rate, data);
173         let seconds_left = seconds.saturating_sub(seconds_to_skip);
174 
175         let samples_left_expected = (sample_rate * channels as u32 * seconds_left) as usize;
176         let samples_left = test_buffer
177             .skip_duration(Duration::from_secs(seconds_to_skip as u64))
178             .count();
179 
180         assert_eq!(samples_left, samples_left_expected);
181     }
182 
183     macro_rules! skip_duration_test_block {
184         ($(channels: $ch:expr, sample rate: $sr:expr, seconds: $sec:expr, seconds to skip: $sec_to_skip:expr;)+) => {
185             $(
186                 test_skip_duration_samples_left($ch, $sr, $sec, $sec_to_skip);
187             )+
188         }
189     }
190 
191     #[test]
skip_duration_shorter_than_source()192     fn skip_duration_shorter_than_source() {
193         skip_duration_test_block! {
194             channels: 1, sample rate: 44100, seconds: 5, seconds to skip: 3;
195             channels: 1, sample rate: 96000, seconds: 5, seconds to skip: 3;
196 
197             channels: 2, sample rate: 44100, seconds: 5, seconds to skip: 3;
198             channels: 2, sample rate: 96000, seconds: 5, seconds to skip: 3;
199 
200             channels: 4, sample rate: 44100, seconds: 5, seconds to skip: 3;
201             channels: 4, sample rate: 96000, seconds: 5, seconds to skip: 3;
202         }
203     }
204 
205     #[test]
skip_duration_zero_duration()206     fn skip_duration_zero_duration() {
207         skip_duration_test_block! {
208             channels: 1, sample rate: 44100, seconds: 5, seconds to skip: 0;
209             channels: 1, sample rate: 96000, seconds: 5, seconds to skip: 0;
210 
211             channels: 2, sample rate: 44100, seconds: 5, seconds to skip: 0;
212             channels: 2, sample rate: 96000, seconds: 5, seconds to skip: 0;
213 
214             channels: 4, sample rate: 44100, seconds: 5, seconds to skip: 0;
215             channels: 4, sample rate: 96000, seconds: 5, seconds to skip: 0;
216         }
217     }
218 
219     #[test]
skip_duration_longer_than_source()220     fn skip_duration_longer_than_source() {
221         skip_duration_test_block! {
222             channels: 1, sample rate: 44100, seconds: 1, seconds to skip: 5;
223             channels: 1, sample rate: 96000, seconds: 10, seconds to skip: 11;
224 
225             channels: 2, sample rate: 44100, seconds: 1, seconds to skip: 5;
226             channels: 2, sample rate: 96000, seconds: 10, seconds to skip: 11;
227 
228             channels: 4, sample rate: 44100, seconds: 1, seconds to skip: 5;
229             channels: 4, sample rate: 96000, seconds: 10, seconds to skip: 11;
230         }
231     }
232 
233     #[test]
skip_duration_equal_to_source_length()234     fn skip_duration_equal_to_source_length() {
235         skip_duration_test_block! {
236             channels: 1, sample rate: 44100, seconds: 1, seconds to skip: 1;
237             channels: 1, sample rate: 96000, seconds: 10, seconds to skip: 10;
238 
239             channels: 2, sample rate: 44100, seconds: 1, seconds to skip: 1;
240             channels: 2, sample rate: 96000, seconds: 10, seconds to skip: 10;
241 
242             channels: 4, sample rate: 44100, seconds: 1, seconds to skip: 1;
243             channels: 4, sample rate: 96000, seconds: 10, seconds to skip: 10;
244         }
245     }
246 }
247