mirror of
https://github.com/RustAudio/rodio
synced 2024-12-14 06:02:31 +00:00
155 lines
3.6 KiB
Rust
155 lines
3.6 KiB
Rust
//! A simple source of samples coming from a static buffer.
|
|
//!
|
|
//! The `StaticSamplesBuffer` struct can be used to treat a list of values as a `Source`.
|
|
//!
|
|
//! # Example
|
|
//!
|
|
//! ```
|
|
//! use rodio::static_buffer::StaticSamplesBuffer;
|
|
//! let _ = StaticSamplesBuffer::new(1, 44100, &[1i16, 2, 3, 4, 5, 6]);
|
|
//! ```
|
|
//!
|
|
|
|
use std::slice::Iter as SliceIter;
|
|
use std::time::Duration;
|
|
|
|
use crate::source::SeekError;
|
|
use crate::{Sample, Source};
|
|
|
|
/// A buffer of samples treated as a source.
|
|
#[derive(Clone)]
|
|
pub struct StaticSamplesBuffer<S>
|
|
where
|
|
S: 'static,
|
|
{
|
|
data: SliceIter<'static, S>,
|
|
channels: u16,
|
|
sample_rate: u32,
|
|
duration: Duration,
|
|
}
|
|
|
|
impl<S> StaticSamplesBuffer<S>
|
|
where
|
|
S: Sample,
|
|
{
|
|
/// Builds a new `StaticSamplesBuffer`.
|
|
///
|
|
/// # Panic
|
|
///
|
|
/// - Panics if the number of channels is zero.
|
|
/// - Panics if the samples rate is zero.
|
|
/// - Panics if the length of the buffer is larger than approximately 16 billion elements.
|
|
/// This is because the calculation of the duration would overflow.
|
|
///
|
|
pub fn new(channels: u16, sample_rate: u32, data: &'static [S]) -> StaticSamplesBuffer<S> {
|
|
assert!(channels != 0);
|
|
assert!(sample_rate != 0);
|
|
|
|
let duration_ns = 1_000_000_000u64.checked_mul(data.len() as u64).unwrap()
|
|
/ sample_rate as u64
|
|
/ channels as u64;
|
|
let duration = Duration::new(
|
|
duration_ns / 1_000_000_000,
|
|
(duration_ns % 1_000_000_000) as u32,
|
|
);
|
|
|
|
StaticSamplesBuffer {
|
|
data: data.iter(),
|
|
channels,
|
|
sample_rate,
|
|
duration,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<S> Source for StaticSamplesBuffer<S>
|
|
where
|
|
S: Sample,
|
|
{
|
|
#[inline]
|
|
fn current_frame_len(&self) -> Option<usize> {
|
|
None
|
|
}
|
|
|
|
#[inline]
|
|
fn channels(&self) -> u16 {
|
|
self.channels
|
|
}
|
|
|
|
#[inline]
|
|
fn sample_rate(&self) -> u32 {
|
|
self.sample_rate
|
|
}
|
|
|
|
#[inline]
|
|
fn total_duration(&self) -> Option<Duration> {
|
|
Some(self.duration)
|
|
}
|
|
|
|
#[inline]
|
|
fn try_seek(&mut self, _: Duration) -> Result<(), SeekError> {
|
|
Err(SeekError::NotSupported {
|
|
underlying_source: std::any::type_name::<Self>(),
|
|
})
|
|
}
|
|
}
|
|
|
|
impl<S> Iterator for StaticSamplesBuffer<S>
|
|
where
|
|
S: Sample + Clone,
|
|
{
|
|
type Item = S;
|
|
|
|
#[inline]
|
|
fn next(&mut self) -> Option<S> {
|
|
self.data.next().cloned()
|
|
}
|
|
|
|
#[inline]
|
|
fn size_hint(&self) -> (usize, Option<usize>) {
|
|
self.data.size_hint()
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use crate::source::Source;
|
|
use crate::static_buffer::StaticSamplesBuffer;
|
|
|
|
#[test]
|
|
fn basic() {
|
|
let _ = StaticSamplesBuffer::new(1, 44100, &[0i16, 0, 0, 0, 0, 0]);
|
|
}
|
|
|
|
#[test]
|
|
#[should_panic]
|
|
fn panic_if_zero_channels() {
|
|
StaticSamplesBuffer::new(0, 44100, &[0i16, 0, 0, 0, 0, 0]);
|
|
}
|
|
|
|
#[test]
|
|
#[should_panic]
|
|
fn panic_if_zero_sample_rate() {
|
|
StaticSamplesBuffer::new(1, 0, &[0i16, 0, 0, 0, 0, 0]);
|
|
}
|
|
|
|
#[test]
|
|
fn duration_basic() {
|
|
let buf = StaticSamplesBuffer::new(2, 2, &[0i16, 0, 0, 0, 0, 0]);
|
|
let dur = buf.total_duration().unwrap();
|
|
assert_eq!(dur.as_secs(), 1);
|
|
assert_eq!(dur.subsec_nanos(), 500_000_000);
|
|
}
|
|
|
|
#[test]
|
|
fn iteration() {
|
|
let mut buf = StaticSamplesBuffer::new(1, 44100, &[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);
|
|
}
|
|
}
|