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