Skip to main content

rodio/source/
zero.rs

1use std::time::Duration;
2
3use dasp_sample::Sample as DaspSample;
4
5use super::SeekError;
6use crate::common::{ChannelCount, SampleRate};
7use crate::{Sample, Source};
8
9/// An source that produces samples with value zero (silence). Depending on if
10/// it where created with [`Zero::new`] or [`Zero::new_samples`] it can be never
11/// ending or finite.
12#[derive(Copy, Clone, Debug)]
13pub struct Zero {
14    channels: ChannelCount,
15    sample_rate: SampleRate,
16    total_samples: Option<usize>,
17    position: usize,
18}
19
20impl Zero {
21    /// Create a new source that never ends and produces total silence.
22    #[inline]
23    pub fn new(channels: ChannelCount, sample_rate: SampleRate) -> Self {
24        Self {
25            channels,
26            sample_rate,
27            total_samples: None,
28            position: 0,
29        }
30    }
31
32    /// Create a new source that never ends and produces total silence.
33    #[inline]
34    pub fn new_samples(
35        channels: ChannelCount,
36        sample_rate: SampleRate,
37        num_samples: usize,
38    ) -> Self {
39        Self {
40            channels,
41            sample_rate,
42            total_samples: Some(num_samples),
43            position: 0,
44        }
45    }
46}
47
48impl Iterator for Zero {
49    type Item = Sample;
50
51    #[inline]
52    fn next(&mut self) -> Option<Self::Item> {
53        if let Some(total_samples) = self.total_samples {
54            if self.position < total_samples {
55                self.position += 1;
56            } else {
57                return None;
58            }
59        }
60
61        Some(Sample::EQUILIBRIUM)
62    }
63
64    #[inline]
65    fn size_hint(&self) -> (usize, Option<usize>) {
66        match self.total_samples {
67            Some(total_samples) => {
68                let remaining = total_samples - self.position;
69                (remaining, Some(remaining))
70            }
71            None => (usize::MAX, None),
72        }
73    }
74}
75
76impl Source for Zero {
77    #[inline]
78    fn current_span_len(&self) -> Option<usize> {
79        self.total_samples
80    }
81
82    #[inline]
83    fn channels(&self) -> ChannelCount {
84        self.channels
85    }
86
87    #[inline]
88    fn sample_rate(&self) -> SampleRate {
89        self.sample_rate
90    }
91
92    fn total_duration(&self) -> Option<Duration> {
93        self.total_samples.map(|total| {
94            let sample_rate = self.sample_rate.get() as u64;
95            let frames = total / self.channels.get() as usize;
96            let secs = frames as u64 / sample_rate;
97            let nanos = ((frames as u64 % sample_rate) * 1_000_000_000) / sample_rate;
98            Duration::new(secs, nanos as u32)
99        })
100    }
101
102    fn try_seek(&mut self, pos: Duration) -> Result<(), SeekError> {
103        if let (Some(total_samples), Some(total_duration)) =
104            (self.total_samples, self.total_duration())
105        {
106            let mut target = pos;
107            if target > total_duration {
108                target = total_duration;
109            }
110
111            let target_samples = (target.as_secs_f32()
112                * self.sample_rate.get() as f32
113                * self.channels.get() as f32) as usize;
114            let target_samples = target_samples.min(total_samples);
115
116            self.position = target_samples;
117        }
118
119        Ok(())
120    }
121}