rodio/
static_buffer.rs

1//! A simple source of samples coming from a static buffer.
2//!
3//! The `StaticSamplesBuffer` struct can be used to treat a list of values as a `Source`.
4//!
5//! # Example
6//!
7//! ```
8//! use rodio::static_buffer::StaticSamplesBuffer;
9//! let _ = StaticSamplesBuffer::new(1, 44100, &[1.0, 2.0, 3.0, 4.0, 5.0, 6.0]);
10//! ```
11//!
12
13use std::slice::Iter as SliceIter;
14use std::time::Duration;
15
16use crate::common::{ChannelCount, SampleRate};
17use crate::source::SeekError;
18use crate::{Sample, Source};
19
20/// A buffer of samples treated as a source.
21#[derive(Clone)]
22pub struct StaticSamplesBuffer {
23    data: SliceIter<'static, Sample>,
24    channels: ChannelCount,
25    sample_rate: SampleRate,
26    duration: Duration,
27}
28
29impl StaticSamplesBuffer {
30    /// Builds a new `StaticSamplesBuffer`.
31    ///
32    /// # Panic
33    ///
34    /// - Panics if the number of channels is zero.
35    /// - Panics if the samples rate is zero.
36    /// - Panics if the length of the buffer is larger than approximately 16 billion elements.
37    ///   This is because the calculation of the duration would overflow.
38    ///
39    pub fn new(
40        channels: ChannelCount,
41        sample_rate: SampleRate,
42        data: &'static [Sample],
43    ) -> StaticSamplesBuffer {
44        assert!(channels != 0);
45        assert!(sample_rate != 0);
46
47        let duration_ns = 1_000_000_000u64.checked_mul(data.len() as u64).unwrap()
48            / sample_rate as u64
49            / channels as u64;
50        let duration = Duration::new(
51            duration_ns / 1_000_000_000,
52            (duration_ns % 1_000_000_000) as u32,
53        );
54
55        StaticSamplesBuffer {
56            data: data.iter(),
57            channels,
58            sample_rate,
59            duration,
60        }
61    }
62}
63
64impl Source for StaticSamplesBuffer {
65    #[inline]
66    fn current_span_len(&self) -> Option<usize> {
67        None
68    }
69
70    #[inline]
71    fn channels(&self) -> ChannelCount {
72        self.channels
73    }
74
75    #[inline]
76    fn sample_rate(&self) -> SampleRate {
77        self.sample_rate
78    }
79
80    #[inline]
81    fn total_duration(&self) -> Option<Duration> {
82        Some(self.duration)
83    }
84
85    #[inline]
86    fn try_seek(&mut self, _: Duration) -> Result<(), SeekError> {
87        Err(SeekError::NotSupported {
88            underlying_source: std::any::type_name::<Self>(),
89        })
90    }
91}
92
93impl Iterator for StaticSamplesBuffer {
94    type Item = Sample;
95
96    #[inline]
97    fn next(&mut self) -> Option<Self::Item> {
98        self.data.next().cloned()
99    }
100
101    #[inline]
102    fn size_hint(&self) -> (usize, Option<usize>) {
103        self.data.size_hint()
104    }
105}
106
107#[cfg(test)]
108mod tests {
109    use crate::source::Source;
110    use crate::static_buffer::StaticSamplesBuffer;
111
112    #[test]
113    fn basic() {
114        let _ = StaticSamplesBuffer::new(1, 44100, &[0.0, 0.0, 0.0, 0.0, 0.0, 0.0]);
115    }
116
117    #[test]
118    #[should_panic]
119    fn panic_if_zero_channels() {
120        StaticSamplesBuffer::new(0, 44100, &[0.0, 0.0, 0.0, 0.0, 0.0, 0.0]);
121    }
122
123    #[test]
124    #[should_panic]
125    fn panic_if_zero_sample_rate() {
126        StaticSamplesBuffer::new(1, 0, &[0.0, 0.0, 0.0, 0.0, 0.0, 0.0]);
127    }
128
129    #[test]
130    fn duration_basic() {
131        let buf = StaticSamplesBuffer::new(2, 2, &[0.0, 0.0, 0.0, 0.0, 0.0, 0.0]);
132        let dur = buf.total_duration().unwrap();
133        assert_eq!(dur.as_secs(), 1);
134        assert_eq!(dur.subsec_nanos(), 500_000_000);
135    }
136
137    #[test]
138    fn iteration() {
139        let mut buf = StaticSamplesBuffer::new(1, 44100, &[1.0, 2.0, 3.0, 4.0, 5.0, 6.0]);
140        assert_eq!(buf.next(), Some(1.0));
141        assert_eq!(buf.next(), Some(2.0));
142        assert_eq!(buf.next(), Some(3.0));
143        assert_eq!(buf.next(), Some(4.0));
144        assert_eq!(buf.next(), Some(5.0));
145        assert_eq!(buf.next(), Some(6.0));
146        assert_eq!(buf.next(), None);
147    }
148}