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