From c3d573db9f96961fe28ec26608932ea757c05a5d Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Thu, 9 Feb 2017 13:04:04 +0100 Subject: [PATCH] Add a SamplesBuffer struct --- src/buffer.rs | 124 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 1 + 2 files changed, 125 insertions(+) create mode 100644 src/buffer.rs diff --git a/src/buffer.rs b/src/buffer.rs new file mode 100644 index 0000000..fd83b4c --- /dev/null +++ b/src/buffer.rs @@ -0,0 +1,124 @@ +//! A simple source of samples coming from a buffer. + +use std::time::Duration; +use std::vec::IntoIter as VecIntoIter; + +use source::Source; + +use Sample; + +/// The input of the mixer. +pub struct SamplesBuffer { + data: VecIntoIter, + channels: u16, + samples_rate: u32, + duration: Duration, +} + +impl SamplesBuffer where S: Sample { + /// Builds a new `SamplesBuffer`. + /// + /// # Panic + /// + /// - Panics if the number of channels is zero. + /// - Panics if the samples rate is zero. + /// - Panics if the length of the buffer is superior to approximatively 16 billion elements. + /// This is because the calculation of the duration would overflow. + /// + pub fn new(channels: u16, samples_rate: u32, data: D) -> SamplesBuffer + where D: Into> + { + assert!(channels != 0); + assert!(samples_rate != 0); + + let data = data.into(); + let duration_ns = 1_000_000_000u64.checked_mul(data.len() as u64).unwrap() / samples_rate as u64 / channels as u64; + let duration = Duration::new(duration_ns / 1_000_000_000, (duration_ns % 1_000_000_000) as u32); + + SamplesBuffer { + data: data.into_iter(), + channels: channels, + samples_rate: samples_rate, + duration: duration, + } + } +} + +impl Source for SamplesBuffer where S: Sample { + #[inline] + fn get_current_frame_len(&self) -> Option { + None + } + + #[inline] + fn get_channels(&self) -> u16 { + self.channels + } + + #[inline] + fn get_samples_rate(&self) -> u32 { + self.samples_rate + } + + #[inline] + fn get_total_duration(&self) -> Option { + Some(self.duration) + } +} + +impl Iterator for SamplesBuffer where S: Sample { + type Item = S; + + #[inline] + fn next(&mut self) -> Option { + self.data.next() + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.data.size_hint() + } +} + +#[cfg(test)] +mod tests { + use buffer::SamplesBuffer; + use source::Source; + + #[test] + fn basic() { + let _ = SamplesBuffer::new(1, 44100, vec![0i16, 0, 0, 0, 0, 0]); + } + + #[test] + #[should_panic] + fn panic_if_zero_channels() { + SamplesBuffer::new(0, 44100, vec![0i16, 0, 0, 0, 0, 0]); + } + + #[test] + #[should_panic] + fn panic_if_zero_samples_rate() { + SamplesBuffer::new(1, 0, vec![0i16, 0, 0, 0, 0, 0]); + } + + #[test] + fn duration_basic() { + let buf = SamplesBuffer::new(2, 2, vec![0i16, 0, 0, 0, 0, 0]); + let dur = buf.get_total_duration().unwrap(); + assert_eq!(dur.as_secs(), 1); + assert_eq!(dur.subsec_nanos(), 500_000_000); + } + + #[test] + fn iteration() { + let mut buf = SamplesBuffer::new(1, 44100, vec![1i16, 2, 3, 4, 5, 6]); + assert_eq!(buf.next(), Some(1)); + assert_eq!(buf.next(), Some(2)); + assert_eq!(buf.next(), Some(3)); + assert_eq!(buf.next(), Some(4)); + assert_eq!(buf.next(), Some(5)); + assert_eq!(buf.next(), Some(6)); + assert_eq!(buf.next(), None); + } +} diff --git a/src/lib.rs b/src/lib.rs index f4cdea0..74eff3a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -75,6 +75,7 @@ mod conversions; mod engine; mod sink; +pub mod buffer; pub mod decoder; pub mod dynamic_mixer; pub mod queue;