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