1use std::time::Duration;
2
3use super::SeekError;
4use crate::common::{ChannelCount, SampleRate};
5use crate::math::NANOS_PER_SEC;
6use crate::Source;
7
8pub fn skip_duration<I>(mut input: I, duration: Duration) -> SkipDuration<I>
10where
11 I: Source,
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{
25 while duration > Duration::new(0, 0) {
26 if input.current_span_len().is_none() {
27 do_skip_duration_unchecked(input, duration);
29 return;
30 }
31
32 let span_len: usize = input.current_span_len().unwrap();
35 if span_len == 0 {
38 return;
39 }
40
41 let sample_rate = input.sample_rate().get() as u128;
42 let channels = input.channels().get() as u128;
43
44 let samples_per_channel = duration.as_nanos() * sample_rate / NANOS_PER_SEC as u128;
45 let samples_to_skip: u128 = samples_per_channel * channels;
46
47 if span_len as u128 > samples_to_skip {
49 skip_samples(input, samples_to_skip as usize);
50 return;
51 }
52
53 duration -= Duration::from_nanos(
54 (NANOS_PER_SEC as u128 * span_len as u128 / channels / sample_rate) as u64,
55 );
56 skip_samples(input, span_len);
57 }
58}
59
60fn do_skip_duration_unchecked<I>(input: &mut I, duration: Duration)
63where
64 I: Source,
65{
66 let samples_per_channel: u128 =
67 duration.as_nanos() * input.sample_rate().get() as u128 / NANOS_PER_SEC as u128;
68 let samples_to_skip: u128 = samples_per_channel * input.channels().get() 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{
78 for _ in 0..n {
79 if input.next().is_none() {
80 break;
81 }
82 }
83}
84
85#[derive(Clone, Debug)]
87pub struct SkipDuration<I> {
88 input: I,
89 skipped_duration: Duration,
90}
91
92impl<I> SkipDuration<I>
93where
94 I: Source,
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{
119 type Item = <I as Iterator>::Item;
120
121 #[inline]
122 fn next(&mut self) -> Option<Self::Item> {
123 self.input.next()
124 }
125
126 #[inline]
127 fn size_hint(&self) -> (usize, Option<usize>) {
128 self.input.size_hint()
129 }
130}
131
132impl<I> Source for SkipDuration<I>
133where
134 I: Source,
135{
136 #[inline]
137 fn current_span_len(&self) -> Option<usize> {
138 self.input.current_span_len()
139 }
140
141 #[inline]
142 fn channels(&self) -> ChannelCount {
143 self.input.channels()
144 }
145
146 #[inline]
147 fn sample_rate(&self) -> SampleRate {
148 self.input.sample_rate()
149 }
150
151 #[inline]
152 fn total_duration(&self) -> Option<Duration> {
153 self.input.total_duration().map(|val| {
154 val.checked_sub(self.skipped_duration)
155 .unwrap_or_else(|| Duration::from_secs(0))
156 })
157 }
158
159 #[inline]
160 fn try_seek(&mut self, pos: Duration) -> Result<(), SeekError> {
161 self.input.try_seek(pos + self.skipped_duration)
162 }
163}
164
165#[cfg(test)]
166mod tests {
167 use std::time::Duration;
168
169 use crate::buffer::SamplesBuffer;
170 use crate::common::{ChannelCount, SampleRate};
171 use crate::math::nz;
172 use crate::source::Source;
173 use crate::Sample;
174 use dasp_sample::Sample as DaspSample;
175
176 fn test_skip_duration_samples_left(
177 channels: ChannelCount,
178 sample_rate: SampleRate,
179 seconds: u32,
180 seconds_to_skip: u32,
181 ) {
182 let buf_len = (sample_rate.get() * channels.get() as u32 * seconds) as usize;
183 assert!(buf_len < 10 * 1024 * 1024);
184 let data: Vec<Sample> = vec![Sample::EQUILIBRIUM; buf_len];
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 =
189 (sample_rate.get() * channels.get() as u32 * seconds_left) as usize;
190 let samples_left = test_buffer
191 .skip_duration(Duration::from_secs(seconds_to_skip as u64))
192 .count();
193
194 assert_eq!(samples_left, samples_left_expected);
195 }
196
197 macro_rules! skip_duration_test_block {
198 ($(channels: $ch:expr, sample rate: $sr:expr, seconds: $sec:expr, seconds to skip: $sec_to_skip:expr;)+) => {
199 $(
200 test_skip_duration_samples_left(nz!($ch), nz!($sr), $sec, $sec_to_skip);
201 )+
202 }
203 }
204
205 #[test]
206 fn skip_duration_shorter_than_source() {
207 skip_duration_test_block! {
208 channels: 1, sample rate: 44100, seconds: 5, seconds to skip: 3;
209 channels: 1, sample rate: 96000, seconds: 5, seconds to skip: 3;
210
211 channels: 2, sample rate: 44100, seconds: 5, seconds to skip: 3;
212 channels: 2, sample rate: 96000, seconds: 5, seconds to skip: 3;
213
214 channels: 4, sample rate: 44100, seconds: 5, seconds to skip: 3;
215 channels: 4, sample rate: 96000, seconds: 5, seconds to skip: 3;
216 }
217 }
218
219 #[test]
220 fn skip_duration_zero_duration() {
221 skip_duration_test_block! {
222 channels: 1, sample rate: 44100, seconds: 5, seconds to skip: 0;
223 channels: 1, sample rate: 96000, seconds: 5, seconds to skip: 0;
224
225 channels: 2, sample rate: 44100, seconds: 5, seconds to skip: 0;
226 channels: 2, sample rate: 96000, seconds: 5, seconds to skip: 0;
227
228 channels: 4, sample rate: 44100, seconds: 5, seconds to skip: 0;
229 channels: 4, sample rate: 96000, seconds: 5, seconds to skip: 0;
230 }
231 }
232
233 #[test]
234 fn skip_duration_longer_than_source() {
235 skip_duration_test_block! {
236 channels: 1, sample rate: 44100, seconds: 1, seconds to skip: 5;
237 channels: 1, sample rate: 96000, seconds: 10, seconds to skip: 11;
238
239 channels: 2, sample rate: 44100, seconds: 1, seconds to skip: 5;
240 channels: 2, sample rate: 96000, seconds: 10, seconds to skip: 11;
241
242 channels: 4, sample rate: 44100, seconds: 1, seconds to skip: 5;
243 channels: 4, sample rate: 96000, seconds: 10, seconds to skip: 11;
244 }
245 }
246
247 #[test]
248 fn skip_duration_equal_to_source_length() {
249 skip_duration_test_block! {
250 channels: 1, sample rate: 44100, seconds: 1, seconds to skip: 1;
251 channels: 1, sample rate: 96000, seconds: 10, seconds to skip: 10;
252
253 channels: 2, sample rate: 44100, seconds: 1, seconds to skip: 1;
254 channels: 2, sample rate: 96000, seconds: 10, seconds to skip: 10;
255
256 channels: 4, sample rate: 44100, seconds: 1, seconds to skip: 1;
257 channels: 4, sample rate: 96000, seconds: 10, seconds to skip: 10;
258 }
259 }
260}