Skip to main content

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