1use std::time::Duration;
2
3use crate::{Sample, Source};
4
5use super::SeekError;
6
7const NS_PER_SECOND: u128 = 1_000_000_000;
8
9pub fn skip_duration<I>(mut input: I, duration: Duration) -> SkipDuration<I>
11where
12 I: Source,
13 I::Item: Sample,
14{
15 do_skip_duration(&mut input, duration);
16 SkipDuration {
17 input,
18 skipped_duration: duration,
19 }
20}
21
22fn do_skip_duration<I>(input: &mut I, mut duration: Duration)
24where
25 I: Source,
26 I::Item: Sample,
27{
28 while duration > Duration::new(0, 0) {
29 if input.current_frame_len().is_none() {
30 do_skip_duration_unchecked(input, duration);
32 return;
33 }
34
35 let frame_len: usize = input.current_frame_len().unwrap();
38 if frame_len == 0 {
41 return;
42 }
43
44 let ns_per_sample: u128 =
45 NS_PER_SECOND / input.sample_rate() as u128 / input.channels() as u128;
46
47 if frame_len as u128 * ns_per_sample > duration.as_nanos() {
49 skip_samples(input, (duration.as_nanos() / ns_per_sample) as usize);
50 return;
51 }
52
53 skip_samples(input, frame_len);
54
55 duration -= Duration::from_nanos((frame_len * ns_per_sample as usize) as u64);
56 }
57}
58
59fn do_skip_duration_unchecked<I>(input: &mut I, duration: Duration)
62where
63 I: Source,
64 I::Item: Sample,
65{
66 let samples_per_channel: u128 =
67 duration.as_nanos() * input.sample_rate() as u128 / NS_PER_SECOND;
68 let samples_to_skip: u128 = samples_per_channel * input.channels() as u128;
69
70 skip_samples(input, samples_to_skip as usize);
71}
72
73fn skip_samples<I>(input: &mut I, n: usize)
75where
76 I: Source,
77 I::Item: Sample,
78{
79 for _ in 0..n {
80 if input.next().is_none() {
81 break;
82 }
83 }
84}
85
86#[derive(Clone, Debug)]
88pub struct SkipDuration<I> {
89 input: I,
90 skipped_duration: Duration,
91}
92
93impl<I> SkipDuration<I>
94where
95 I: Source,
96 I::Item: Sample,
97{
98 #[inline]
100 pub fn inner(&self) -> &I {
101 &self.input
102 }
103
104 #[inline]
106 pub fn inner_mut(&mut self) -> &mut I {
107 &mut self.input
108 }
109
110 #[inline]
112 pub fn into_inner(self) -> I {
113 self.input
114 }
115}
116
117impl<I> Iterator for SkipDuration<I>
118where
119 I: Source,
120 I::Item: Sample,
121{
122 type Item = <I as Iterator>::Item;
123
124 #[inline]
125 fn next(&mut self) -> Option<Self::Item> {
126 self.input.next()
127 }
128
129 #[inline]
130 fn size_hint(&self) -> (usize, Option<usize>) {
131 self.input.size_hint()
132 }
133}
134
135impl<I> Source for SkipDuration<I>
136where
137 I: Source,
138 I::Item: Sample,
139{
140 #[inline]
141 fn current_frame_len(&self) -> Option<usize> {
142 self.input.current_frame_len()
143 }
144
145 #[inline]
146 fn channels(&self) -> u16 {
147 self.input.channels()
148 }
149
150 #[inline]
151 fn sample_rate(&self) -> u32 {
152 self.input.sample_rate()
153 }
154
155 #[inline]
156 fn total_duration(&self) -> Option<Duration> {
157 self.input.total_duration().map(|val| {
158 val.checked_sub(self.skipped_duration)
159 .unwrap_or_else(|| Duration::from_secs(0))
160 })
161 }
162
163 #[inline]
164 fn try_seek(&mut self, pos: Duration) -> Result<(), SeekError> {
165 self.input.try_seek(pos)
166 }
167}
168
169#[cfg(test)]
170mod tests {
171 use std::time::Duration;
172
173 use crate::buffer::SamplesBuffer;
174 use crate::source::Source;
175
176 fn test_skip_duration_samples_left(
177 channels: u16,
178 sample_rate: u32,
179 seconds: u32,
180 seconds_to_skip: u32,
181 ) {
182 let data: Vec<f32> = (1..=(sample_rate * channels as u32 * seconds))
183 .map(|_| 0f32)
184 .collect();
185 let test_buffer = SamplesBuffer::new(channels, sample_rate, data);
186 let seconds_left = seconds.saturating_sub(seconds_to_skip);
187
188 let samples_left_expected = (sample_rate * channels as u32 * seconds_left) as usize;
189 let samples_left = test_buffer
190 .skip_duration(Duration::from_secs(seconds_to_skip as u64))
191 .count();
192
193 assert_eq!(samples_left, samples_left_expected);
194 }
195
196 macro_rules! skip_duration_test_block {
197 ($(channels: $ch:expr, sample rate: $sr:expr, seconds: $sec:expr, seconds to skip: $sec_to_skip:expr;)+) => {
198 $(
199 test_skip_duration_samples_left($ch, $sr, $sec, $sec_to_skip);
200 )+
201 }
202 }
203
204 #[test]
205 fn skip_duration_shorter_than_source() {
206 skip_duration_test_block! {
207 channels: 1, sample rate: 44100, seconds: 5, seconds to skip: 3;
208 channels: 1, sample rate: 96000, seconds: 5, seconds to skip: 3;
209
210 channels: 2, sample rate: 44100, seconds: 5, seconds to skip: 3;
211 channels: 2, sample rate: 96000, seconds: 5, seconds to skip: 3;
212
213 channels: 4, sample rate: 44100, seconds: 5, seconds to skip: 3;
214 channels: 4, sample rate: 96000, seconds: 5, seconds to skip: 3;
215 }
216 }
217
218 #[test]
219 fn skip_duration_zero_duration() {
220 skip_duration_test_block! {
221 channels: 1, sample rate: 44100, seconds: 5, seconds to skip: 0;
222 channels: 1, sample rate: 96000, seconds: 5, seconds to skip: 0;
223
224 channels: 2, sample rate: 44100, seconds: 5, seconds to skip: 0;
225 channels: 2, sample rate: 96000, seconds: 5, seconds to skip: 0;
226
227 channels: 4, sample rate: 44100, seconds: 5, seconds to skip: 0;
228 channels: 4, sample rate: 96000, seconds: 5, seconds to skip: 0;
229 }
230 }
231
232 #[test]
233 fn skip_duration_longer_than_source() {
234 skip_duration_test_block! {
235 channels: 1, sample rate: 44100, seconds: 1, seconds to skip: 5;
236 channels: 1, sample rate: 96000, seconds: 10, seconds to skip: 11;
237
238 channels: 2, sample rate: 44100, seconds: 1, seconds to skip: 5;
239 channels: 2, sample rate: 96000, seconds: 10, seconds to skip: 11;
240
241 channels: 4, sample rate: 44100, seconds: 1, seconds to skip: 5;
242 channels: 4, sample rate: 96000, seconds: 10, seconds to skip: 11;
243 }
244 }
245
246 #[test]
247 fn skip_duration_equal_to_source_length() {
248 skip_duration_test_block! {
249 channels: 1, sample rate: 44100, seconds: 1, seconds to skip: 1;
250 channels: 1, sample rate: 96000, seconds: 10, seconds to skip: 10;
251
252 channels: 2, sample rate: 44100, seconds: 1, seconds to skip: 1;
253 channels: 2, sample rate: 96000, seconds: 10, seconds to skip: 10;
254
255 channels: 4, sample rate: 44100, seconds: 1, seconds to skip: 1;
256 channels: 4, sample rate: 96000, seconds: 10, seconds to skip: 10;
257 }
258 }
259}