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