Skip to main content

rodio/source/
skip.rs

1use std::time::Duration;
2
3use super::SeekError;
4use crate::common::{ChannelCount, SampleRate};
5use crate::math::NANOS_PER_SEC;
6use crate::Source;
7
8/// Internal function that builds a `SkipDuration` object.
9pub 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
20/// Skips specified `duration` of the given `input` source from it's current position.
21fn 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            // Sample rate and the amount of channels will be the same till the end.
28            do_skip_duration_unchecked(input, duration);
29            return;
30        }
31
32        // .unwrap() safety: if `current_span_len()` is None, the body of the `if` statement
33        // above returns before we get here.
34        let span_len: usize = input.current_span_len().unwrap();
35        // If span_len is zero, then there is no more data to skip. Instead
36        // just bail out.
37        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        // Check if we need to skip only part of the current span.
48        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
60/// Skips specified `duration` from the `input` source assuming that sample rate
61/// and amount of channels are not changing.
62fn 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
73/// Skips `n` samples from the given `input` source.
74fn 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/// A source that skips specified duration of the given source from it's current position.
86#[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    /// Returns a reference to the inner source.
97    #[inline]
98    pub fn inner(&self) -> &I {
99        &self.input
100    }
101
102    /// Returns a mutable reference to the inner source.
103    #[inline]
104    pub fn inner_mut(&mut self) -> &mut I {
105        &mut self.input
106    }
107
108    /// Returns the inner source.
109    #[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}