diff --git a/examples/mix.rs b/examples/mix.rs index a89dd57..365fff1 100644 --- a/examples/mix.rs +++ b/examples/mix.rs @@ -3,20 +3,20 @@ use std::num::NonZeroU32; use fon::{ - chan::{Ch32, Channel}, + samp::{Samp32, Sample}, Audio, Frame, Sink, Stream, }; #[derive(Debug)] -pub struct Mixer<'a, Chan: Channel, const CH: usize> { +pub struct Mixer<'a, Samp: Sample, const CH: usize> { index: usize, - audio: &'a mut Audio, + audio: &'a mut Audio, } #[allow(single_use_lifetimes)] -impl<'a, Chan: Channel, const CH: usize> Mixer<'a, Chan, CH> { +impl<'a, Samp: Sample, const CH: usize> Mixer<'a, Samp, CH> { #[inline(always)] - fn new(audio: &'a mut Audio) -> Self { + fn new(audio: &'a mut Audio) -> Self { let index = 0; Mixer { index, audio } @@ -25,8 +25,8 @@ impl<'a, Chan: Channel, const CH: usize> Mixer<'a, Chan, CH> { // Using '_ results in reserved lifetime error. #[allow(single_use_lifetimes)] -impl<'a, Chan: Channel, const CH: usize> Sink - for Mixer<'a, Chan, CH> +impl<'a, Samp: Sample, const CH: usize> Sink + for Mixer<'a, Samp, CH> { #[inline(always)] fn sample_rate(&self) -> NonZeroU32 { @@ -39,14 +39,14 @@ impl<'a, Chan: Channel, const CH: usize> Sink } #[inline(always)] - fn sink_with(&mut self, iter: &mut dyn Iterator>) { + fn sink_with(&mut self, iter: &mut dyn Iterator>) { let mut this = self; - Sink::::sink_with(&mut this, iter) + Sink::::sink_with(&mut this, iter) } } -impl Sink - for &mut Mixer<'_, Chan, CH> +impl Sink + for &mut Mixer<'_, Samp, CH> { #[inline(always)] fn sample_rate(&self) -> NonZeroU32 { @@ -59,11 +59,11 @@ impl Sink } #[inline(always)] - fn sink_with(&mut self, iter: &mut dyn Iterator>) { + fn sink_with(&mut self, iter: &mut dyn Iterator>) { for frame in self.audio.iter_mut().skip(self.index) { if let Some(other) = iter.next() { for (channel, chan) in - frame.channels_mut().iter_mut().zip(other.channels()) + frame.samples_mut().iter_mut().zip(other.samples()) { *channel += *chan; } @@ -75,7 +75,7 @@ impl Sink } } -fn load_file(in_hz: u32, in_file: &str) -> Audio { +fn load_file(in_hz: u32, in_file: &str) -> Audio { // Load file as f32 buffer. let rawfile = std::fs::read(in_file).unwrap(); let mut audio = Vec::new(); @@ -86,11 +86,11 @@ fn load_file(in_hz: u32, in_file: &str) -> Audio { Audio::with_f32_buffer(in_hz, audio) } -fn save_file(name: &str, audio: &Audio) -> std::io::Result<()> { +fn save_file(name: &str, audio: &Audio) -> std::io::Result<()> { // Convert audio to byte buffer let mut samples = Vec::::new(); for frame in audio.iter() { - for channel in frame.channels() { + for channel in frame.samples() { samples.extend(channel.to_f32().to_le_bytes()); } } diff --git a/examples/resample.rs b/examples/resample.rs index a09877b..252b721 100644 --- a/examples/resample.rs +++ b/examples/resample.rs @@ -1,6 +1,6 @@ use std::convert::TryInto; -use fon::{chan::Ch32, Audio}; +use fon::{samp::Samp32, Audio}; // Resample an audio file from one sample rate to another. fn resample(in_hz: u32, in_file: &str, out_hz: u32, out_file: &str) { @@ -11,9 +11,9 @@ fn resample(in_hz: u32, in_file: &str, out_hz: u32, out_file: &str) { audio.push(f32::from_le_bytes(sample.try_into().unwrap())); } // Create type-safe audio type from f32 buffer. - let audio = Audio::::with_f32_buffer(in_hz, audio); + let audio = Audio::::with_f32_buffer(in_hz, audio); // Stream resampler into new audio type. - let mut audio = Audio::::with_audio(out_hz, &audio); + let mut audio = Audio::::with_audio(out_hz, &audio); // Write file as f32 buffer. let mut bytes = Vec::new(); for sample in audio.as_f32_slice() { diff --git a/examples/sawtooth.rs b/examples/sawtooth.rs index 5899265..eb3f4fa 100644 --- a/examples/sawtooth.rs +++ b/examples/sawtooth.rs @@ -1,12 +1,12 @@ use fon::{ - chan::{Ch16, Ch32}, + samp::{Samp16, Samp32}, pos::Mono, Audio, }; fn main() { // Create mono 32-bit floating point audio buffer. - let mut a = Audio::::with_silence(48_000, 256); + let mut a = Audio::::with_silence(48_000, 256); let mut counter = 0.0; for f in a.iter_mut() { f[Mono] = counter.into(); @@ -15,7 +15,7 @@ fn main() { } // Convert to 16-Bit audio format - let mut audio = Audio::::with_audio(48_000, &a); + let mut audio = Audio::::with_audio(48_000, &a); // Print out converted wave. for (sample, other) in diff --git a/src/audio.rs b/src/audio.rs index 274c885..e663ea6 100644 --- a/src/audio.rs +++ b/src/audio.rs @@ -12,7 +12,7 @@ use core::{ #[cfg(not(test))] use crate::math::Libm; use crate::{ - chan::{Ch16, Ch24, Ch32, Ch64, Channel}, + samp::{Samp16, Samp24, Samp32, Samp64, Sample}, frame::Frame, Sink, Stream, }; @@ -20,18 +20,18 @@ use crate::{ /// Audio buffer (fixed-size array of audio [`Frame`](crate::frame::Frame)s at /// sample rate specified in hertz). #[derive(Debug)] -pub struct Audio { +pub struct Audio { // Sample rate of the audio in hertz. sample_rate: NonZeroU32, // Audio frames. - frames: Box<[Frame]>, + frames: Box<[Frame]>, } -impl Audio { +impl Audio { /// Construct an `Audio` buffer with all all samples set to zero. #[inline(always)] pub fn with_silence(hz: u32, len: usize) -> Self { - Self::with_frames(hz, vec![Frame::::default(); len]) + Self::with_frames(hz, vec![Frame::::default(); len]) } /// Construct an `Audio` buffer with owned sample data. You can get @@ -40,7 +40,7 @@ impl Audio { #[inline(always)] pub fn with_frames(hz: u32, frames: B) -> Self where - B: Into]>>, + B: Into]>>, { Audio { sample_rate: hz.try_into().unwrap(), @@ -51,17 +51,17 @@ impl Audio { /// Construct an `Audio` buffer from another `Audio` buffer of a different /// format. #[inline(always)] - pub fn with_audio(hz: u32, audio: &Audio) -> Self + pub fn with_audio(hz: u32, audio: &Audio) -> Self where - Ch: Channel, - Ch32: From, - Chan: From, + S: Sample, + Samp32: From, + Samp: From, { let len = audio.len() as f64 * hz as f64 / audio.sample_rate().get() as f64; let mut output = Self::with_silence(hz, len.ceil() as usize); let mut stream = Stream::new(hz); - let mut sink = crate::SinkTo::<_, Chan, _, CH, N>::new(output.sink()); + let mut sink = crate::SinkTo::<_, Samp, _, CH, N>::new(output.sink()); stream.pipe(audio, &mut sink); stream.flush(&mut sink); output @@ -69,37 +69,37 @@ impl Audio { /// Get an audio frame. #[inline(always)] - pub fn get(&self, index: usize) -> Option> { + pub fn get(&self, index: usize) -> Option> { self.frames.get(index).cloned() } /// Get a mutable reference to an audio frame. #[inline(always)] - pub fn get_mut(&mut self, index: usize) -> Option<&mut Frame> { + pub fn get_mut(&mut self, index: usize) -> Option<&mut Frame> { self.frames.get_mut(index) } /// Get a slice of all audio frames. #[inline(always)] - pub fn as_slice(&self) -> &[Frame] { + pub fn as_slice(&self) -> &[Frame] { &self.frames } /// Get a slice of all audio frames. #[inline(always)] - pub fn as_mut_slice(&mut self) -> &mut [Frame] { + pub fn as_mut_slice(&mut self) -> &mut [Frame] { &mut self.frames } /// Returns an iterator over the audio frames. #[inline(always)] - pub fn iter(&self) -> Iter<'_, Frame> { + pub fn iter(&self) -> Iter<'_, Frame> { self.frames.iter() } /// Returns an iterator that allows modifying each audio frame. #[inline(always)] - pub fn iter_mut(&mut self) -> IterMut<'_, Frame> { + pub fn iter_mut(&mut self) -> IterMut<'_, Frame> { self.frames.iter_mut() } @@ -125,13 +125,13 @@ impl Audio { #[inline(always)] pub fn silence(&mut self) { for f in self.frames.iter_mut() { - *f = Frame::::default() + *f = Frame::::default() } } /// Sink audio into this audio buffer from a `Stream`. #[inline(always)] - pub fn sink(&mut self) -> AudioSink<'_, Chan, CH> { + pub fn sink(&mut self) -> AudioSink<'_, Samp, CH> { AudioSink { index: 0, audio: self, @@ -141,15 +141,15 @@ impl Audio { /// Returned from [`Audio::sink()`](crate::Audio::sink). #[derive(Debug)] -pub struct AudioSink<'a, Chan: Channel, const CH: usize> { +pub struct AudioSink<'a, Samp: Sample, const CH: usize> { index: usize, - audio: &'a mut Audio, + audio: &'a mut Audio, } // Using '_ results in reserved lifetime error. #[allow(single_use_lifetimes)] -impl<'a, Chan: Channel, const CH: usize> Sink - for AudioSink<'a, Chan, CH> +impl<'a, Samp: Sample, const CH: usize> Sink + for AudioSink<'a, Samp, CH> { #[inline(always)] fn sample_rate(&self) -> NonZeroU32 { @@ -162,14 +162,14 @@ impl<'a, Chan: Channel, const CH: usize> Sink } #[inline(always)] - fn sink_with(&mut self, iter: &mut dyn Iterator>) { + fn sink_with(&mut self, iter: &mut dyn Iterator>) { let mut this = self; - Sink::::sink_with(&mut this, iter) + Sink::::sink_with(&mut this, iter) } } -impl Sink - for &mut AudioSink<'_, Chan, CH> +impl Sink + for &mut AudioSink<'_, Samp, CH> { #[inline(always)] fn sample_rate(&self) -> NonZeroU32 { @@ -182,7 +182,7 @@ impl Sink } #[inline(always)] - fn sink_with(&mut self, iter: &mut dyn Iterator>) { + fn sink_with(&mut self, iter: &mut dyn Iterator>) { for frame in self.audio.iter_mut().skip(self.index) { *frame = if let Some(frame) = iter.next() { frame @@ -194,7 +194,7 @@ impl Sink } } -impl Audio { +impl Audio { /// Construct an `Audio` buffer from an `i16` buffer. #[allow(unsafe_code)] pub fn with_i16_buffer(hz: u32, buffer: B) -> Self @@ -203,14 +203,14 @@ impl Audio { { let buffer: Box<[i16]> = buffer.into(); let bytes = buffer.len() * size_of::(); - let len = bytes / size_of::>(); - assert_eq!(0, bytes % size_of::>()); + let len = bytes / size_of::>(); + assert_eq!(0, bytes % size_of::>()); let slice = Box::<[i16]>::into_raw(buffer); - let frames: Box<[Frame]> = unsafe { - let ptr = (*slice).as_mut_ptr() as *mut Frame; + let frames: Box<[Frame]> = unsafe { + let ptr = (*slice).as_mut_ptr() as *mut Frame; Box::from_raw(from_raw_parts_mut(ptr, len)) }; - let frames: Vec> = frames.into(); + let frames: Vec> = frames.into(); Audio::with_frames(hz, frames) } @@ -227,7 +227,7 @@ impl Audio { } } -impl Audio { +impl Audio { /// Construct an `Audio` buffer from an `u8` buffer. #[allow(unsafe_code)] pub fn with_u8_buffer(hz: u32, buffer: B) -> Self @@ -236,14 +236,14 @@ impl Audio { { let buffer: Box<[u8]> = buffer.into(); let bytes = buffer.len() * size_of::(); - let len = bytes / size_of::>(); - assert_eq!(0, bytes % size_of::>()); + let len = bytes / size_of::>(); + assert_eq!(0, bytes % size_of::>()); let slice = Box::<[u8]>::into_raw(buffer); - let frames: Box<[Frame]> = unsafe { - let ptr = (*slice).as_mut_ptr() as *mut Frame; + let frames: Box<[Frame]> = unsafe { + let ptr = (*slice).as_mut_ptr() as *mut Frame; Box::from_raw(from_raw_parts_mut(ptr, len)) }; - let frames: Vec> = frames.into(); + let frames: Vec> = frames.into(); Audio::with_frames(hz, frames) } @@ -260,7 +260,7 @@ impl Audio { } } -impl Audio { +impl Audio { /// Construct an `Audio` buffer from an `f32` buffer. #[allow(unsafe_code)] pub fn with_f32_buffer(hz: u32, buffer: B) -> Self @@ -269,14 +269,14 @@ impl Audio { { let buffer: Box<[f32]> = buffer.into(); let bytes = buffer.len() * size_of::(); - let len = bytes / size_of::>(); - assert_eq!(0, bytes % size_of::>()); + let len = bytes / size_of::>(); + assert_eq!(0, bytes % size_of::>()); let slice = Box::<[f32]>::into_raw(buffer); - let frames: Box<[Frame]> = unsafe { - let ptr = (*slice).as_mut_ptr() as *mut Frame; + let frames: Box<[Frame]> = unsafe { + let ptr = (*slice).as_mut_ptr() as *mut Frame; Box::from_raw(from_raw_parts_mut(ptr, len)) }; - let frames: Vec> = frames.into(); + let frames: Vec> = frames.into(); Audio::with_frames(hz, frames) } @@ -293,7 +293,7 @@ impl Audio { } } -impl Audio { +impl Audio { /// Construct an `Audio` buffer from an `f64` buffer. #[allow(unsafe_code)] pub fn with_f64_buffer(hz: u32, buffer: B) -> Self @@ -302,14 +302,14 @@ impl Audio { { let buffer: Box<[f64]> = buffer.into(); let bytes = buffer.len() * size_of::(); - let len = bytes / size_of::>(); - assert_eq!(0, bytes % size_of::>()); + let len = bytes / size_of::>(); + assert_eq!(0, bytes % size_of::>()); let slice = Box::<[f64]>::into_raw(buffer); - let frames: Box<[Frame]> = unsafe { - let ptr = (*slice).as_mut_ptr() as *mut Frame; + let frames: Box<[Frame]> = unsafe { + let ptr = (*slice).as_mut_ptr() as *mut Frame; Box::from_raw(from_raw_parts_mut(ptr, len)) }; - let frames: Vec> = frames.into(); + let frames: Vec> = frames.into(); Audio::with_frames(hz, frames) } @@ -326,32 +326,32 @@ impl Audio { } } -impl From> for Vec> +impl From> for Vec> where - Chan: Channel, + Samp: Sample, { /// Get internal sample data as `Vec` of audio frames. - fn from(audio: Audio) -> Self { + fn from(audio: Audio) -> Self { audio.frames.into() } } -impl From> - for Box<[Frame]> +impl From> + for Box<[Frame]> { /// Get internal sample data as `Vec` of audio frames. - fn from(audio: Audio) -> Self { - let audio: Vec> = audio.frames.into(); + fn from(audio: Audio) -> Self { + let audio: Vec> = audio.frames.into(); audio.into() } } -impl From> for Box<[i16]> { +impl From> for Box<[i16]> { /// Get internal sample data as boxed slice of *i16*. #[allow(unsafe_code)] - fn from(audio: Audio) -> Self { - let mut frames: Vec> = audio.frames.into(); - let capacity = frames.len() * size_of::>() / 2; + fn from(audio: Audio) -> Self { + let mut frames: Vec> = audio.frames.into(); + let capacity = frames.len() * size_of::>() / 2; let buffer: Box<[i16]> = unsafe { let ptr = frames.as_mut_ptr() as *mut i16; Box::from_raw(from_raw_parts_mut(ptr, capacity)) @@ -360,12 +360,12 @@ impl From> for Box<[i16]> { } } -impl From> for Box<[u8]> { +impl From> for Box<[u8]> { /// Get internal sample data as boxed slice of *u8*. #[allow(unsafe_code)] - fn from(audio: Audio) -> Self { - let mut frames: Vec> = audio.frames.into(); - let capacity = frames.len() * size_of::>() / 3; + fn from(audio: Audio) -> Self { + let mut frames: Vec> = audio.frames.into(); + let capacity = frames.len() * size_of::>() / 3; let buffer: Box<[u8]> = unsafe { let ptr = frames.as_mut_ptr() as *mut u8; Box::from_raw(from_raw_parts_mut(ptr, capacity)) @@ -374,12 +374,12 @@ impl From> for Box<[u8]> { } } -impl From> for Box<[f32]> { +impl From> for Box<[f32]> { /// Get internal sample data as boxed slice of *f32*. #[allow(unsafe_code)] - fn from(audio: Audio) -> Self { - let mut frames: Vec> = audio.frames.into(); - let capacity = frames.len() * size_of::>() / 4; + fn from(audio: Audio) -> Self { + let mut frames: Vec> = audio.frames.into(); + let capacity = frames.len() * size_of::>() / 4; let buffer: Box<[f32]> = unsafe { let ptr = frames.as_mut_ptr() as *mut f32; Box::from_raw(from_raw_parts_mut(ptr, capacity)) @@ -388,12 +388,12 @@ impl From> for Box<[f32]> { } } -impl From> for Box<[f64]> { +impl From> for Box<[f64]> { /// Get internal sample data as boxed slice of *f64*. #[allow(unsafe_code)] - fn from(audio: Audio) -> Self { - let mut frames: Vec> = audio.frames.into(); - let capacity = frames.len() * size_of::>() / 8; + fn from(audio: Audio) -> Self { + let mut frames: Vec> = audio.frames.into(); + let capacity = frames.len() * size_of::>() / 8; let buffer: Box<[f64]> = unsafe { let ptr = frames.as_mut_ptr() as *mut f64; Box::from_raw(from_raw_parts_mut(ptr, capacity)) diff --git a/src/chan.rs b/src/chan.rs deleted file mode 100644 index 8c7af68..0000000 --- a/src/chan.rs +++ /dev/null @@ -1,762 +0,0 @@ -//! Audio channels (left, right, etc.). Each channel contains a single sample. -//! -//! An audio [`Frame`](crate::frame::Frame) is used to group multiple channels. - -use core::{ - fmt::Debug, - ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign}, -}; - -#[cfg(not(test))] -use crate::math::Libm; -use crate::private::Sealed; - -/// Component of a speaker configuration, such as *front left*, *lfe*, *etc*. -pub trait Channel: - Copy - + Clone - + Debug - + Default - + From - + PartialOrd - + Add - + AddAssign - + Sub - + SubAssign - + Mul - + MulAssign - + Neg - + From - + From - + From - + From - + Into - + Into - + Into - + Into - + Sealed - + Unpin - + Sized - + 'static -{ - /// Minimum value (*negative one*) - const MIN: Self; - - /// Mid value (*zero/silence*) - const MID: Self; - - /// Maximum value (*one*) - const MAX: Self; - - /// Convert to `f32` - fn to_f32(self) -> f32; - - /// Linear interpolation - #[inline(always)] - fn lerp(self, rhs: Self, t: Self) -> Self { - self + t * (rhs - self) - } -} - -/// 16-bit sample [`Channel`]. -#[derive(Clone, Copy, Debug, Default, PartialEq, PartialOrd)] -#[repr(transparent)] -pub struct Ch16(i16); - -impl Channel for Ch16 { - const MAX: Ch16 = Ch16(32_767); - const MID: Ch16 = Ch16(0); - const MIN: Ch16 = Ch16(-32_768); - - #[inline(always)] - fn to_f32(self) -> f32 { - const MULTIPLIER: f32 = 1.0 / 32_767.5; - (f32::from(self.0) + 0.5) * MULTIPLIER - } -} - -impl Ch16 { - /// Create a new 16-bit [`Channel`] value. - #[inline(always)] - pub const fn new(value: i16) -> Self { - Self(value) - } -} - -impl From for Ch16 { - #[inline(always)] - fn from(value: f32) -> Self { - Self::new((value.clamp(-1.0, 1.0) * 32_767.5).floor() as i16) - } -} - -impl From for Ch16 { - #[inline(always)] - fn from(ch: Ch24) -> Self { - Self::new(ch.0) - } -} - -impl From for Ch16 { - #[inline(always)] - fn from(ch: Ch32) -> Self { - Self::from(ch.0) - } -} - -impl From for Ch16 { - #[inline(always)] - fn from(ch: Ch64) -> Self { - Self::from(ch.0 as f32) - } -} - -impl From for i16 { - #[inline(always)] - fn from(ch: Ch16) -> i16 { - ch.0 - } -} - -impl> Add for Ch16 { - type Output = Self; - - #[inline(always)] - fn add(self, rhs: R) -> Self { - Self::new(i16::from(self).saturating_add(i16::from(rhs.into()))) - } -} - -impl> Sub for Ch16 { - type Output = Self; - - #[inline(always)] - fn sub(self, rhs: R) -> Self { - Self::new(i16::from(self).saturating_sub(i16::from(rhs.into()))) - } -} - -impl> Mul for Ch16 { - type Output = Self; - - #[inline(always)] - fn mul(self, rhs: R) -> Self { - let l = i32::from(self.0); - let r = i32::from(rhs.into().0); - let v = (l * r) / 32_767; - Self::new(v.clamp(-32_768, 32_767) as i16) - } -} - -impl Neg for Ch16 { - type Output = Ch16; - - #[inline(always)] - fn neg(self) -> Self { - Self::new((u16::MAX - i16::from(self) as u16) as i16) - } -} - -/// 24-bit sample [`Channel`]. -#[derive(Clone, Copy, Debug, Default, PartialEq, PartialOrd)] -#[repr(C, packed)] -pub struct Ch24(i16, u8); - -impl Channel for Ch24 { - const MAX: Ch24 = Ch24::new(8_388_607); - const MID: Ch24 = Ch24::new(0); - const MIN: Ch24 = Ch24::new(-8_388_608); - - #[inline(always)] - fn to_f32(self) -> f32 { - const MULTIPLIER: f32 = 1.0 / 8_388_607.5; - (i32::from(self) as f32 + 0.5) * MULTIPLIER - } -} - -impl Ch24 { - /// Create a new 24-bit [`Channel`] value. - #[inline(always)] - pub const fn new(value: i32) -> Self { - let value = if value < -8_388_608 { - -8_388_608 - } else if value > 8_388_607 { - 8_388_607 - } else { - value - }; - Self((value >> 8) as i16, value as u8) - } -} - -impl From for Ch24 { - #[inline(always)] - fn from(value: f32) -> Self { - Self::new((value.clamp(-1.0, 1.0) * 8_388_607.5).floor() as i32) - } -} - -impl From for Ch24 { - #[inline(always)] - fn from(ch: Ch16) -> Self { - Self(i16::from(ch), (i16::from(ch) >> 8) as u8 ^ 0b1000_0000) - } -} - -impl From for Ch24 { - #[inline(always)] - fn from(ch: Ch32) -> Self { - Self::from(ch.0) - } -} - -impl From for Ch24 { - #[inline(always)] - fn from(ch: Ch64) -> Self { - Self::from(ch.0 as f32) - } -} - -impl From for i32 { - #[inline(always)] - fn from(ch: Ch24) -> i32 { - ((ch.0 as i32) << 8) | ch.1 as i32 - } -} - -impl> Add for Ch24 { - type Output = Self; - - #[inline(always)] - fn add(self, rhs: R) -> Self { - Self::new(i32::from(self) + i32::from(rhs.into())) - } -} - -impl> Sub for Ch24 { - type Output = Self; - - #[inline(always)] - fn sub(self, rhs: R) -> Self { - Self::new(i32::from(self) - i32::from(rhs.into())) - } -} - -impl> Mul for Ch24 { - type Output = Self; - - #[inline(always)] - fn mul(self, rhs: R) -> Self { - let l: i64 = i32::from(self).into(); - let r: i64 = i32::from(rhs.into()).into(); - let v = (l * r) / 8_388_607; - Self::new(v.clamp(-8_388_608, 8_388_607) as i32) - } -} - -impl Neg for Ch24 { - type Output = Ch24; - - #[inline(always)] - fn neg(self) -> Self { - Self::new((u32::MAX - i32::from(self) as u32) as i32) - } -} - -/// 32-bit sample [`Channel`]. -#[derive(Clone, Copy, Debug, Default, PartialEq, PartialOrd)] -#[repr(transparent)] -pub struct Ch32(f32); - -impl Channel for Ch32 { - const MAX: Ch32 = Ch32(1.0); - const MID: Ch32 = Ch32(0.0); - const MIN: Ch32 = Ch32(-1.0); - - #[inline(always)] - fn to_f32(self) -> f32 { - self.0 - } -} - -impl Ch32 { - /// Create a new 32-bit [`Channel`] value. - #[inline(always)] - pub const fn new(value: f32) -> Self { - Self(value) - } -} - -impl From for Ch32 { - #[inline(always)] - fn from(value: f32) -> Self { - Self::new(value) - } -} - -impl From for Ch32 { - #[inline(always)] - fn from(ch: Ch16) -> Self { - Self::new(ch.to_f32()) - } -} - -impl From for Ch32 { - #[inline(always)] - fn from(ch: Ch24) -> Self { - Self::new(ch.to_f32()) - } -} - -impl From for Ch32 { - #[inline(always)] - fn from(ch: Ch64) -> Self { - Self::new(ch.to_f32()) - } -} - -impl From for f32 { - #[inline(always)] - fn from(ch: Ch32) -> f32 { - ch.0 - } -} - -impl> Add for Ch32 { - type Output = Self; - - #[inline(always)] - fn add(self, rhs: R) -> Self { - Self::new(f32::from(self) + f32::from(rhs.into())) - } -} - -impl> Sub for Ch32 { - type Output = Self; - - #[inline(always)] - fn sub(self, rhs: R) -> Self { - Self::new(f32::from(self) - f32::from(rhs.into())) - } -} - -impl> Mul for Ch32 { - type Output = Self; - - #[inline(always)] - fn mul(self, rhs: R) -> Self { - Self::new(f32::from(self) * f32::from(rhs.into())) - } -} - -impl Neg for Ch32 { - type Output = Ch32; - - #[inline(always)] - fn neg(self) -> Self { - Self(-f32::from(self)) - } -} - -/// 64-bit sample [`Channel`]. -#[derive(Clone, Copy, Debug, Default, PartialEq, PartialOrd)] -#[repr(transparent)] -pub struct Ch64(f64); - -impl Channel for Ch64 { - const MAX: Ch64 = Ch64(1.0); - const MID: Ch64 = Ch64(0.0); - const MIN: Ch64 = Ch64(-1.0); - - #[inline(always)] - fn to_f32(self) -> f32 { - self.0 as f32 - } -} - -impl Ch64 { - /// Create a new 64-bit [`Channel`] value. - #[inline(always)] - pub const fn new(value: f64) -> Self { - Self(value) - } -} - -impl From for Ch64 { - #[inline(always)] - fn from(value: f32) -> Self { - Self::new(value as f64) - } -} - -impl From for Ch64 { - #[inline(always)] - fn from(ch: Ch16) -> Self { - Self::new(ch.to_f32() as f64) - } -} - -impl From for Ch64 { - #[inline(always)] - fn from(ch: Ch24) -> Self { - Self::new(ch.to_f32() as f64) - } -} - -impl From for Ch64 { - #[inline(always)] - fn from(ch: Ch32) -> Self { - Self::new(ch.0 as f64) - } -} - -impl From for f64 { - #[inline(always)] - fn from(ch: Ch64) -> f64 { - ch.0 - } -} - -impl> Add for Ch64 { - type Output = Self; - - #[inline(always)] - fn add(self, rhs: R) -> Self { - Self::new(self.0 + rhs.into().0) - } -} - -impl> Sub for Ch64 { - type Output = Self; - - #[inline(always)] - fn sub(self, rhs: R) -> Self { - Self::new(self.0 - rhs.into().0) - } -} - -impl> Mul for Ch64 { - type Output = Self; - - #[inline(always)] - fn mul(self, rhs: R) -> Self { - Self::new(self.0 * rhs.into().0) - } -} - -impl Neg for Ch64 { - type Output = Ch64; - - #[inline(always)] - fn neg(self) -> Self { - Self(-self.0) - } -} - -impl AddAssign for Ch16 { - #[inline(always)] - fn add_assign(&mut self, rhs: Self) { - *self = *self + rhs; - } -} - -impl AddAssign for Ch24 { - #[inline(always)] - fn add_assign(&mut self, rhs: Self) { - *self = *self + rhs; - } -} - -impl AddAssign for Ch32 { - #[inline(always)] - fn add_assign(&mut self, rhs: Self) { - *self = *self + rhs; - } -} - -impl AddAssign for Ch64 { - #[inline(always)] - fn add_assign(&mut self, rhs: Self) { - *self = *self + rhs; - } -} - -impl SubAssign for Ch16 { - #[inline(always)] - fn sub_assign(&mut self, rhs: Self) { - *self = *self - rhs; - } -} - -impl SubAssign for Ch24 { - #[inline(always)] - fn sub_assign(&mut self, rhs: Self) { - *self = *self - rhs; - } -} - -impl SubAssign for Ch32 { - #[inline(always)] - fn sub_assign(&mut self, rhs: Self) { - *self = *self - rhs; - } -} - -impl SubAssign for Ch64 { - #[inline(always)] - fn sub_assign(&mut self, rhs: Self) { - *self = *self - rhs; - } -} - -impl MulAssign for Ch16 { - #[inline(always)] - fn mul_assign(&mut self, rhs: Self) { - *self = *self * rhs; - } -} - -impl MulAssign for Ch24 { - #[inline(always)] - fn mul_assign(&mut self, rhs: Self) { - *self = *self * rhs; - } -} - -impl MulAssign for Ch32 { - #[inline(always)] - fn mul_assign(&mut self, rhs: Self) { - *self = *self * rhs; - } -} - -impl MulAssign for Ch64 { - #[inline(always)] - fn mul_assign(&mut self, rhs: Self) { - *self = *self * rhs; - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn ch16() { - assert_eq!(-1.0, Ch16::MIN.to_f32()); - assert_eq!(0.000015259022, Ch16::MID.to_f32()); - assert_eq!(1.0, Ch16::MAX.to_f32()); - - assert_eq!(Ch16::MIN, Ch16::from(Ch16::MIN.to_f32())); - assert_eq!(Ch16::MID, Ch16::from(Ch16::MID.to_f32())); - assert_eq!(Ch16::MAX, Ch16::from(Ch16::MAX.to_f32())); - } - - #[test] - fn ch16_roundtrip() { - assert_eq!(-32768, i16::from(Ch16::MIN)); - assert_eq!(0, i16::from(Ch16::MID)); - assert_eq!(32767, i16::from(Ch16::MAX)); - - assert_eq!(Ch16::MIN, Ch16::new(i16::from(Ch16::MIN))); - assert_eq!(Ch16::MID, Ch16::new(i16::from(Ch16::MID))); - assert_eq!(Ch16::MAX, Ch16::new(i16::from(Ch16::MAX))); - } - - #[test] - fn ch24() { - assert_eq!(-1.0, Ch24::MIN.to_f32()); - assert_eq!(0.00000005960465, Ch24::MID.to_f32()); - assert_eq!(1.0, Ch24::MAX.to_f32()); - - assert_eq!(Ch24::MIN, Ch24::from(Ch24::MIN.to_f32())); - assert_eq!(Ch24::MID, Ch24::from(Ch24::MID.to_f32())); - assert_eq!(Ch24::MAX, Ch24::from(Ch24::MAX.to_f32())); - } - - #[test] - fn ch24_roundtrip() { - assert_eq!(-8388608, i32::from(Ch24::MIN)); - assert_eq!(0, i32::from(Ch24::MID)); - assert_eq!(8388607, i32::from(Ch24::MAX)); - - assert_eq!(Ch24::MIN, Ch24::new(i32::from(Ch24::MIN))); - assert_eq!(Ch24::MID, Ch24::new(i32::from(Ch24::MID))); - assert_eq!(Ch24::MAX, Ch24::new(i32::from(Ch24::MAX))); - } - - #[test] - fn ch32() { - assert_eq!(-1.0, Ch32::MIN.to_f32()); - assert_eq!(0.0, Ch32::MID.to_f32()); - assert_eq!(1.0, Ch32::MAX.to_f32()); - - assert_eq!(Ch32::MIN, Ch32::from(Ch32::MIN.to_f32())); - assert_eq!(Ch32::MID, Ch32::from(Ch32::MID.to_f32())); - assert_eq!(Ch32::MAX, Ch32::from(Ch32::MAX.to_f32())); - } - - #[test] - fn ch64() { - assert_eq!(-1.0, Ch64::MIN.to_f32()); - assert_eq!(0.0, Ch64::MID.to_f32()); - assert_eq!(1.0, Ch64::MAX.to_f32()); - - assert_eq!(Ch64::MIN, Ch64::from(Ch64::MIN.to_f32())); - assert_eq!(Ch64::MID, Ch64::from(Ch64::MID.to_f32())); - assert_eq!(Ch64::MAX, Ch64::from(Ch64::MAX.to_f32())); - } - - #[test] - fn ch16_to_ch24() { - assert_eq!(Ch24::MIN, Ch24::from(Ch16::MIN)); - assert_eq!(Ch24::new(128), Ch24::from(Ch16::MID)); - assert_eq!(Ch24::MAX, Ch24::from(Ch16::MAX)); - } - - #[test] - fn ch24_to_ch16() { - assert_eq!(Ch16::MIN, Ch16::from(Ch24::MIN)); - assert_eq!(Ch16::MID, Ch16::from(Ch24::MID)); - assert_eq!(Ch16::MAX, Ch16::from(Ch24::MAX)); - } - - #[test] - fn ch16_arith() { - // Test addition - assert_eq!(Ch16::new(-1), Ch16::new(-32768) + Ch16::new(32767)); - assert_eq!(Ch16::new(8192), Ch16::new(-8192) + Ch16::new(16384)); - assert_eq!(Ch16::MAX, Ch16::MID + Ch16::MAX); - assert_eq!(Ch16::MIN, Ch16::new(-16384) + Ch16::new(-16384)); - // Test subtraction - assert_eq!(Ch16::new(0), Ch16::new(-32768) - Ch16::new(-32768)); - assert_eq!(Ch16::new(0), Ch16::new(32767) - Ch16::new(32767)); - assert_eq!(Ch16::new(-32767), Ch16::new(0) - Ch16::new(32767)); - // Test multiplication - assert_eq!(Ch16::new(0), Ch16::new(0) * Ch16::new(32767)); - assert_eq!(Ch16::new(32767), Ch16::new(32767) * Ch16::new(32767)); - assert_eq!(Ch16::new(-32768), Ch16::new(32767) * Ch16::new(-32768)); - assert_eq!(Ch16::new(-32768), Ch16::new(-32768) * Ch16::new(32767)); - assert_eq!(Ch16::new(32767), Ch16::new(-32768) * Ch16::new(-32768)); - assert_eq!(Ch16::new(-16384), Ch16::new(32767) * Ch16::new(-16384)); - // Test negation - assert_eq!(Ch16::MIN, -Ch16::MAX); - assert_eq!(Ch16::MAX, -Ch16::MIN); - assert_eq!(Ch16::new(-1), -Ch16::new(0)); - assert_eq!(Ch16::new(0), -Ch16::new(-1)); - } - - #[test] - fn ch24_arith() { - // Test addition - assert_eq!(Ch24::new(-1), Ch24::new(-8388608) + Ch24::new(8388607)); - assert_eq!( - Ch24::new(2097152), - Ch24::new(-2097152) + Ch24::new(4194304) - ); - assert_eq!(Ch24::MAX, Ch24::MID + Ch24::MAX); - assert_eq!(Ch24::MIN, Ch24::new(-4194304) + Ch24::new(-4194304)); - // Test subtraction - assert_eq!(Ch24::new(0), Ch24::new(-8388608) - Ch24::new(-8388608)); - assert_eq!(Ch24::new(0), Ch24::new(8388607) - Ch24::new(8388607)); - assert_eq!(Ch24::new(-8388607), Ch24::new(0) - Ch24::new(8388607)); - // Test multiplication - assert_eq!(Ch24::new(0), Ch24::new(0) * Ch24::new(8388607)); - assert_eq!(Ch24::new(8388607), Ch24::new(8388607) * Ch24::new(8388607)); - assert_eq!( - Ch24::new(-8388608), - Ch24::new(8388607) * Ch24::new(-8388608) - ); - assert_eq!( - Ch24::new(-8388608), - Ch24::new(-8388608) * Ch24::new(8388607) - ); - assert_eq!( - Ch24::new(8388607), - Ch24::new(-8388608) * Ch24::new(-8388608) - ); - assert_eq!( - Ch24::new(-4194304), - Ch24::new(8388607) * Ch24::new(-4194304) - ); - // Test negation - assert_eq!(Ch24::MIN, -Ch24::MAX); - assert_eq!(Ch24::MAX, -Ch24::MIN); - assert_eq!(Ch24::new(-1), -Ch24::new(0)); - assert_eq!(Ch24::new(0), -Ch24::new(-1)); - } - - #[test] - fn ch32_arith() { - // Test addition - assert_eq!(Ch32::new(0.0), Ch32::new(-1.0) + Ch32::new(1.0)); - assert_eq!(Ch32::new(0.25), Ch32::new(-0.25) + Ch32::new(0.5)); - assert_eq!(Ch32::new(1.0), Ch32::new(0.0) + Ch32::new(1.0)); - assert_eq!(Ch32::new(-1.0), Ch32::new(-0.5) + Ch32::new(-0.5)); - // Test subtraction - assert_eq!(Ch32::new(0.0), Ch32::new(-1.0) - Ch32::new(-1.0)); - assert_eq!(Ch32::new(0.0), Ch32::new(1.0) - Ch32::new(1.0)); - assert_eq!(Ch32::new(-1.0), Ch32::new(0.0) - Ch32::new(1.0)); - // Test multiplication - assert_eq!(Ch32::new(0.0), Ch32::new(0.0) * Ch32::new(1.0)); - assert_eq!(Ch32::new(1.0), Ch32::new(1.0) * Ch32::new(1.0)); - assert_eq!(Ch32::new(-1.0), Ch32::new(1.0) * Ch32::new(-1.0)); - assert_eq!(Ch32::new(1.0), Ch32::new(-1.0) * Ch32::new(-1.0)); - assert_eq!(Ch32::new(-0.5), Ch32::new(1.0) * Ch32::new(-0.5)); - // Test negation - assert_eq!(Ch32::MIN, -Ch32::MAX); - assert_eq!(Ch32::MAX, -Ch32::MIN); - assert_eq!(Ch32::new(0.0), -Ch32::new(0.0)); - } - - #[test] - fn ch64_arith() { - // Test addition - assert_eq!(Ch64::new(0.0), Ch64::new(-1.0) + Ch64::new(1.0)); - assert_eq!(Ch64::new(0.25), Ch64::new(-0.25) + Ch64::new(0.5)); - assert_eq!(Ch64::new(1.0), Ch64::new(0.0) + Ch64::new(1.0)); - assert_eq!(Ch64::new(-1.0), Ch64::new(-0.5) + Ch64::new(-0.5)); - // Test subtraction - assert_eq!(Ch64::new(0.0), Ch64::new(-1.0) - Ch64::new(-1.0)); - assert_eq!(Ch64::new(0.0), Ch64::new(1.0) - Ch64::new(1.0)); - assert_eq!(Ch64::new(-1.0), Ch64::new(0.0) - Ch64::new(1.0)); - // Test multiplication - assert_eq!(Ch64::new(0.0), Ch64::new(0.0) * Ch64::new(1.0)); - assert_eq!(Ch64::new(1.0), Ch64::new(1.0) * Ch64::new(1.0)); - assert_eq!(Ch64::new(-1.0), Ch64::new(1.0) * Ch64::new(-1.0)); - assert_eq!(Ch64::new(1.0), Ch64::new(-1.0) * Ch64::new(-1.0)); - assert_eq!(Ch64::new(-0.5), Ch64::new(1.0) * Ch64::new(-0.5)); - // Test negation - assert_eq!(Ch64::MIN, -Ch64::MAX); - assert_eq!(Ch64::MAX, -Ch64::MIN); - assert_eq!(Ch64::new(0.0), -Ch64::new(0.0)); - } - - #[test] - fn ch16_saturation() { - assert_eq!(Ch16::MAX, Ch16::new(24576) + Ch16::new(16384)); - assert_eq!(Ch16::MIN, Ch16::new(-16384) + Ch16::new(-24576)); - assert_eq!(Ch16::MIN, Ch16::new(-16384) - Ch16::new(24576)); - } - - #[test] - fn ch24_saturation() { - assert_eq!(Ch24::MAX, Ch24::new(6291456) + Ch24::new(4194304)); - assert_eq!(Ch24::MIN, Ch24::new(-4194304) + Ch24::new(-6291456)); - assert_eq!(Ch24::MIN, Ch24::new(-4194304) - Ch24::new(6291456)); - } - - #[test] - fn ch32_unsaturation() { - assert_eq!(Ch32::new(1.25), Ch32::new(0.75) + Ch32::new(0.5)); - assert_eq!(Ch32::new(-1.25), Ch32::new(-0.5) + Ch32::new(-0.75)); - assert_eq!(Ch32::new(-1.25), Ch32::new(-0.5) - Ch32::new(0.75)); - } - - #[test] - fn ch64_unsaturation() { - assert_eq!(Ch64::new(1.25), Ch64::new(0.75) + Ch64::new(0.5)); - assert_eq!(Ch64::new(-1.25), Ch64::new(-0.5) + Ch64::new(-0.75)); - assert_eq!(Ch64::new(-1.25), Ch64::new(-0.5) - Ch64::new(0.75)); - } -} diff --git a/src/frame.rs b/src/frame.rs index 186489a..eb46c32 100644 --- a/src/frame.rs +++ b/src/frame.rs @@ -6,33 +6,31 @@ use core::{ ops::{Add, Mul, Neg, Sub}, }; -use crate::chan::Channel; +use crate::samp::Sample; #[cfg(not(test))] use crate::math::Libm; -/// Frame - A number of interleaved sample [channel]s. -/// -/// [channel]: crate::chan::Channel +/// Frame - A number of interleaved [`Sample`]s #[repr(transparent)] #[derive(Copy, Clone, Debug, PartialEq)] -pub struct Frame([Chan; CH]); +pub struct Frame([Samp; CH]); -impl Default for Frame { +impl Default for Frame { fn default() -> Self { - Frame([Chan::default(); CH]) + Frame([Samp::default(); CH]) } } -impl Frame { - /// Get a mutable slice of the channels in this frame. +impl Frame { + /// Get a mutable slice of the samples in this frame. #[inline(always)] - pub fn channels_mut(&mut self) -> &mut [Chan; CH] { + pub fn samples_mut(&mut self) -> &mut [Samp; CH] { &mut self.0 } - /// Get a slice of the channels in this frame. + /// Get a slice of the samples in this frame. #[inline(always)] - pub fn channels(&self) -> &[Chan; CH] { + pub fn samples(&self) -> &[Samp; CH] { &self.0 } @@ -41,7 +39,7 @@ impl Frame { /// 1.0/0.0 is straight ahead, 0.25 is right, 0.5 is back, and 0.75 is left. /// The algorithm used is "Constant Power Panning". #[inline(always)] - pub fn pan>(self, channel: C, angle: f32) -> Self { + pub fn pan>(self, channel: C, angle: f32) -> Self { match CH { 1 => self.pan_1(channel.into(), angle.rem_euclid(1.0)), 2 => self.pan_2(channel.into(), angle.rem_euclid(1.0)), @@ -74,7 +72,7 @@ impl Frame { /// Convert an audio Frame to another format. #[inline(always)] - pub fn to, const N: usize>(self) -> Frame { + pub fn to, const N: usize>(self) -> Frame { match CH { 1 => self.to_1(), 2 => self.to_2(), @@ -89,7 +87,7 @@ impl Frame { } #[inline(always)] - fn pan_1(mut self, chan: Chan, _x: f32) -> Self { + fn pan_1(mut self, chan: Samp, _x: f32) -> Self { const MONO: usize = 0; self.0[MONO] += chan; @@ -98,7 +96,7 @@ impl Frame { } #[inline(always)] - fn pan_2(mut self, chan: Chan, x: f32) -> Self { + fn pan_2(mut self, chan: Samp, x: f32) -> Self { const LEFT: usize = 0; const RIGHT: usize = 1; @@ -112,7 +110,7 @@ impl Frame { } #[inline(always)] - fn pan_3(mut self, chan: Chan, x: f32) -> Self { + fn pan_3(mut self, chan: Samp, x: f32) -> Self { const LEFT: usize = 0; const RIGHT: usize = 1; const CENTER: usize = 2; @@ -149,7 +147,7 @@ impl Frame { } #[inline(always)] - fn pan_4(mut self, chan: Chan, x: f32) -> Self { + fn pan_4(mut self, chan: Samp, x: f32) -> Self { const FRONT_L: usize = 0; const FRONT_R: usize = 1; const SURROUND_L: usize = 2; @@ -187,7 +185,7 @@ impl Frame { } #[inline(always)] - fn pan_5(mut self, chan: Chan, x: f32) -> Self { + fn pan_5(mut self, chan: Samp, x: f32) -> Self { const FRONT_L: usize = 0; const FRONT_R: usize = 1; const FRONT: usize = 2; @@ -231,7 +229,7 @@ impl Frame { } #[inline(always)] - fn pan_6(mut self, chan: Chan, x: f32) -> Self { + fn pan_6(mut self, chan: Samp, x: f32) -> Self { const FRONT_L: usize = 0; const FRONT_R: usize = 1; const FRONT: usize = 2; @@ -276,7 +274,7 @@ impl Frame { } #[inline(always)] - fn pan_7(mut self, chan: Chan, x: f32) -> Self { + fn pan_7(mut self, chan: Samp, x: f32) -> Self { const FRONT_L: usize = 0; const FRONT_R: usize = 1; const FRONT: usize = 2; @@ -328,7 +326,7 @@ impl Frame { } #[inline(always)] - fn pan_8(mut self, chan: Chan, x: f32) -> Self { + fn pan_8(mut self, chan: Samp, x: f32) -> Self { const FRONT_L: usize = 0; const FRONT_R: usize = 1; const FRONT: usize = 2; @@ -387,7 +385,7 @@ impl Frame { } #[inline(always)] - fn to_1, const N: usize>(self) -> Frame { + fn to_1, const N: usize>(self) -> Frame { const MONO: usize = 0; let mut frame = Frame::::default(); @@ -402,7 +400,7 @@ impl Frame { } #[inline(always)] - fn to_2, const N: usize>(self) -> Frame { + fn to_2, const N: usize>(self) -> Frame { const LEFT: usize = 0; const RIGHT: usize = 1; @@ -421,7 +419,7 @@ impl Frame { } #[inline(always)] - fn to_3, const N: usize>(self) -> Frame { + fn to_3, const N: usize>(self) -> Frame { const LEFT: usize = 0; const RIGHT: usize = 1; const CENTER: usize = 2; @@ -460,7 +458,7 @@ impl Frame { } #[inline(always)] - fn to_4, const N: usize>(self) -> Frame { + fn to_4, const N: usize>(self) -> Frame { const FRONT_L: usize = 0; const FRONT_R: usize = 1; const SURROUND_L: usize = 2; @@ -481,7 +479,7 @@ impl Frame { } #[inline(always)] - fn to_5, const N: usize>(self) -> Frame { + fn to_5, const N: usize>(self) -> Frame { const FRONT_L: usize = 0; const FRONT_R: usize = 1; const FRONT: usize = 2; @@ -505,7 +503,7 @@ impl Frame { } #[inline(always)] - fn to_6, const N: usize>(self) -> Frame { + fn to_6, const N: usize>(self) -> Frame { const FRONT_L: usize = 0; const FRONT_R: usize = 1; const FRONT: usize = 2; @@ -538,7 +536,7 @@ impl Frame { } #[inline(always)] - fn to_7, const N: usize>(self) -> Frame { + fn to_7, const N: usize>(self) -> Frame { const FRONT_L: usize = 0; const FRONT_R: usize = 1; const FRONT: usize = 2; @@ -574,7 +572,7 @@ impl Frame { } #[inline(always)] - fn to_8, const N: usize>(self) -> Frame { + fn to_8, const N: usize>(self) -> Frame { const FRONT_L: usize = 0; const FRONT_R: usize = 1; const FRONT: usize = 2; @@ -613,101 +611,101 @@ impl Frame { } } -impl Frame { +impl Frame { /// Create a new mono interleaved audio frame from channel(s). #[inline(always)] - pub fn new(mono: Chan) -> Self { + pub fn new(mono: Samp) -> Self { Self([mono]) } } -impl Frame { +impl Frame { /// Create a new stereo interleaved audio frame from channel(s). #[inline(always)] - pub fn new(left: Chan, right: Chan) -> Self { + pub fn new(left: Samp, right: Samp) -> Self { Self([left, right]) } } -impl Frame { +impl Frame { /// Create a new surround 3.0 interleaved audio frame from channel(s). #[inline(always)] - pub fn new(left: Chan, right: Chan, center: Chan) -> Self { + pub fn new(left: Samp, right: Samp, center: Samp) -> Self { Self([left, right, center]) } } -impl Frame { +impl Frame { /// Create a new surround 4.0 interleaved audio frame from channel(s). #[inline(always)] pub fn new( - left: Chan, - right: Chan, - back_left: Chan, - back_right: Chan, + left: Samp, + right: Samp, + back_left: Samp, + back_right: Samp, ) -> Self { Self([left, right, back_left, back_right]) } } -impl Frame { +impl Frame { /// Create a new surround 5.0 interleaved audio frame from channel(s). #[inline(always)] pub fn new( - left: Chan, - right: Chan, - center: Chan, - back_left: Chan, - back_right: Chan, + left: Samp, + right: Samp, + center: Samp, + back_left: Samp, + back_right: Samp, ) -> Self { Self([left, right, center, back_left, back_right]) } } -impl Frame { +impl Frame { /// Create a new surround 5.1 interleaved audio frame from channel(s). #[inline(always)] pub fn new( - left: Chan, - right: Chan, - center: Chan, - lfe: Chan, - back_left: Chan, - back_right: Chan, + left: Samp, + right: Samp, + center: Samp, + lfe: Samp, + back_left: Samp, + back_right: Samp, ) -> Self { Self([left, right, center, lfe, back_left, back_right]) } } -impl Frame { +impl Frame { /// Create a new surround 6.1 interleaved audio frame from channel(s). #[inline(always)] pub fn new( - left: Chan, - right: Chan, - center: Chan, - lfe: Chan, - back: Chan, - side_left: Chan, - side_right: Chan, + left: Samp, + right: Samp, + center: Samp, + lfe: Samp, + back: Samp, + side_left: Samp, + side_right: Samp, ) -> Self { Self([left, right, center, lfe, back, side_left, side_right]) } } -impl Frame { +impl Frame { /// Create a new surround 7.1 interleaved audio frame from channel(s). #[inline(always)] #[allow(clippy::too_many_arguments)] pub fn new( - left: Chan, - right: Chan, - center: Chan, - lfe: Chan, - back_left: Chan, - back_right: Chan, - side_left: Chan, - side_right: Chan, + left: Samp, + right: Samp, + center: Samp, + lfe: Samp, + back_left: Samp, + back_right: Samp, + side_left: Samp, + side_right: Samp, ) -> Self { Self([ left, right, center, lfe, back_left, back_right, side_left, @@ -716,13 +714,13 @@ impl Frame { } } -impl From for Frame { +impl From for Frame { fn from(rhs: f32) -> Self { - Frame([Chan::from(rhs); CH]) + Frame([Samp::from(rhs); CH]) } } -impl Add for Frame { +impl Add for Frame { type Output = Self; #[inline(always)] @@ -734,7 +732,7 @@ impl Add for Frame { } } -impl Sub for Frame { +impl Sub for Frame { type Output = Self; #[inline(always)] @@ -746,7 +744,7 @@ impl Sub for Frame { } } -impl Mul for Frame { +impl Mul for Frame { type Output = Self; #[inline(always)] @@ -758,7 +756,7 @@ impl Mul for Frame { } } -impl Neg for Frame { +impl Neg for Frame { type Output = Self; #[inline(always)] diff --git a/src/lib.rs b/src/lib.rs index ebfab19..dac3e91 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -33,11 +33,13 @@ //! //! ## 8-Bit Sawtooth Wave Example //! ```rust -//! use fon::chan::{Ch16, Ch32}; -//! use fon::pos::Mono; -//! use fon::Audio; +//! use fon::{ +//! pos::Mono, +//! samp::{Samp16, Samp32}, +//! Audio, +//! }; //! -//! let mut a = Audio::::with_silence(48_000, 256); +//! let mut a = Audio::::with_silence(48_000, 256); //! let mut counter = 0.0; //! for f in a.iter_mut() { //! f[Mono] = counter.into(); @@ -45,14 +47,14 @@ //! counter %= 1.0; //! } //! -//! let mut audio = Audio::::with_audio(48_000, &a); +//! let mut audio = Audio::::with_audio(48_000, &a); //! ``` //! //! [audio buffer]: crate::Audio -//! [16-bit Signed Integer PCM]: crate::chan::Ch16 -//! [24-bit Signed Integer PCM]: crate::chan::Ch24 -//! [32-bit Float PCM]: crate::chan::Ch32 -//! [64-bit Float PCM]: crate::chan::Ch64 +//! [16-bit Signed Integer PCM]: crate::samp::Samp16 +//! [24-bit Signed Integer PCM]: crate::samp::Samp24 +//! [32-bit Float PCM]: crate::samp::Samp32 +//! [64-bit Float PCM]: crate::samp::Samp64 //! [operations]: crate::ops //! [this MDN article]: https://developer.mozilla.org/en-US/docs/Web/Media/Formats/Audio_concepts //! [Mono]: crate::pos::Mono @@ -101,8 +103,7 @@ mod private; mod sink; mod stream; -pub mod chan; - +pub mod samp; pub mod pos; pub use audio::{Audio, AudioSink}; diff --git a/src/pos.rs b/src/pos.rs index ff1c6af..963ece5 100644 --- a/src/pos.rs +++ b/src/pos.rs @@ -2,7 +2,7 @@ use core::ops::{Index, IndexMut}; -use crate::{chan::Channel, frame::Frame}; +use crate::{samp::Sample, frame::Frame}; /// All directions /// - Mono @@ -96,520 +96,520 @@ pub struct BackR; //////////////////////////////////////////////////////////// -impl Index for Frame { - type Output = Chan; +impl Index for Frame { + type Output = Samp; fn index(&self, _: Mono) -> &Self::Output { - &self.channels()[0] + &self.samples()[0] } } -impl IndexMut for Frame { +impl IndexMut for Frame { fn index_mut(&mut self, _: Mono) -> &mut Self::Output { - &mut self.channels_mut()[0] + &mut self.samples_mut()[0] } } //////////////////////////////////////////////////////////// -impl Index for Frame { - type Output = Chan; +impl Index for Frame { + type Output = Samp; fn index(&self, _: Left) -> &Self::Output { - &self.channels()[0] + &self.samples()[0] } } -impl IndexMut for Frame { +impl IndexMut for Frame { fn index_mut(&mut self, _: Left) -> &mut Self::Output { - &mut self.channels_mut()[0] + &mut self.samples_mut()[0] } } -impl Index for Frame { - type Output = Chan; +impl Index for Frame { + type Output = Samp; fn index(&self, _: Right) -> &Self::Output { - &self.channels()[1] + &self.samples()[1] } } -impl IndexMut for Frame { +impl IndexMut for Frame { fn index_mut(&mut self, _: Right) -> &mut Self::Output { - &mut self.channels_mut()[1] + &mut self.samples_mut()[1] } } //////////////////////////////////////////////////////////// -impl Index for Frame { - type Output = Chan; +impl Index for Frame { + type Output = Samp; fn index(&self, _: Left) -> &Self::Output { - &self.channels()[0] + &self.samples()[0] } } -impl IndexMut for Frame { +impl IndexMut for Frame { fn index_mut(&mut self, _: Left) -> &mut Self::Output { - &mut self.channels_mut()[0] + &mut self.samples_mut()[0] } } -impl Index for Frame { - type Output = Chan; +impl Index for Frame { + type Output = Samp; fn index(&self, _: Right) -> &Self::Output { - &self.channels()[1] + &self.samples()[1] } } -impl IndexMut for Frame { +impl IndexMut for Frame { fn index_mut(&mut self, _: Right) -> &mut Self::Output { - &mut self.channels_mut()[1] + &mut self.samples_mut()[1] } } -impl Index
for Frame { - type Output = Chan; +impl Index
for Frame { + type Output = Samp; fn index(&self, _: Center) -> &Self::Output { - &self.channels()[2] + &self.samples()[2] } } -impl IndexMut
for Frame { +impl IndexMut
for Frame { fn index_mut(&mut self, _: Center) -> &mut Self::Output { - &mut self.channels_mut()[2] + &mut self.samples_mut()[2] } } //////////////////////////////////////////////////////////// -impl Index for Frame { - type Output = Chan; +impl Index for Frame { + type Output = Samp; fn index(&self, _: FrontL) -> &Self::Output { - &self.channels()[0] + &self.samples()[0] } } -impl IndexMut for Frame { +impl IndexMut for Frame { fn index_mut(&mut self, _: FrontL) -> &mut Self::Output { - &mut self.channels_mut()[0] + &mut self.samples_mut()[0] } } -impl Index for Frame { - type Output = Chan; +impl Index for Frame { + type Output = Samp; fn index(&self, _: FrontR) -> &Self::Output { - &self.channels()[1] + &self.samples()[1] } } -impl IndexMut for Frame { +impl IndexMut for Frame { fn index_mut(&mut self, _: FrontR) -> &mut Self::Output { - &mut self.channels_mut()[1] + &mut self.samples_mut()[1] } } -impl Index for Frame { - type Output = Chan; +impl Index for Frame { + type Output = Samp; fn index(&self, _: SurroundL) -> &Self::Output { - &self.channels()[2] + &self.samples()[2] } } -impl IndexMut for Frame { +impl IndexMut for Frame { fn index_mut(&mut self, _: SurroundL) -> &mut Self::Output { - &mut self.channels_mut()[2] + &mut self.samples_mut()[2] } } -impl Index for Frame { - type Output = Chan; +impl Index for Frame { + type Output = Samp; fn index(&self, _: SurroundR) -> &Self::Output { - &self.channels()[3] + &self.samples()[3] } } -impl IndexMut for Frame { +impl IndexMut for Frame { fn index_mut(&mut self, _: SurroundR) -> &mut Self::Output { - &mut self.channels_mut()[3] + &mut self.samples_mut()[3] } } //////////////////////////////////////////////////////////// -impl Index for Frame { - type Output = Chan; +impl Index for Frame { + type Output = Samp; fn index(&self, _: FrontL) -> &Self::Output { - &self.channels()[0] + &self.samples()[0] } } -impl IndexMut for Frame { +impl IndexMut for Frame { fn index_mut(&mut self, _: FrontL) -> &mut Self::Output { - &mut self.channels_mut()[0] + &mut self.samples_mut()[0] } } -impl Index for Frame { - type Output = Chan; +impl Index for Frame { + type Output = Samp; fn index(&self, _: FrontR) -> &Self::Output { - &self.channels()[1] + &self.samples()[1] } } -impl IndexMut for Frame { +impl IndexMut for Frame { fn index_mut(&mut self, _: FrontR) -> &mut Self::Output { - &mut self.channels_mut()[1] + &mut self.samples_mut()[1] } } -impl Index for Frame { - type Output = Chan; +impl Index for Frame { + type Output = Samp; fn index(&self, _: Front) -> &Self::Output { - &self.channels()[2] + &self.samples()[2] } } -impl IndexMut for Frame { +impl IndexMut for Frame { fn index_mut(&mut self, _: Front) -> &mut Self::Output { - &mut self.channels_mut()[2] + &mut self.samples_mut()[2] } } -impl Index for Frame { - type Output = Chan; +impl Index for Frame { + type Output = Samp; fn index(&self, _: SurroundL) -> &Self::Output { - &self.channels()[3] + &self.samples()[3] } } -impl IndexMut for Frame { +impl IndexMut for Frame { fn index_mut(&mut self, _: SurroundL) -> &mut Self::Output { - &mut self.channels_mut()[3] + &mut self.samples_mut()[3] } } -impl Index for Frame { - type Output = Chan; +impl Index for Frame { + type Output = Samp; fn index(&self, _: SurroundR) -> &Self::Output { - &self.channels()[4] + &self.samples()[4] } } -impl IndexMut for Frame { +impl IndexMut for Frame { fn index_mut(&mut self, _: SurroundR) -> &mut Self::Output { - &mut self.channels_mut()[4] + &mut self.samples_mut()[4] } } //////////////////////////////////////////////////////////// -impl Index for Frame { - type Output = Chan; +impl Index for Frame { + type Output = Samp; fn index(&self, _: FrontL) -> &Self::Output { - &self.channels()[0] + &self.samples()[0] } } -impl IndexMut for Frame { +impl IndexMut for Frame { fn index_mut(&mut self, _: FrontL) -> &mut Self::Output { - &mut self.channels_mut()[0] + &mut self.samples_mut()[0] } } -impl Index for Frame { - type Output = Chan; +impl Index for Frame { + type Output = Samp; fn index(&self, _: FrontR) -> &Self::Output { - &self.channels()[1] + &self.samples()[1] } } -impl IndexMut for Frame { +impl IndexMut for Frame { fn index_mut(&mut self, _: FrontR) -> &mut Self::Output { - &mut self.channels_mut()[1] + &mut self.samples_mut()[1] } } -impl Index for Frame { - type Output = Chan; +impl Index for Frame { + type Output = Samp; fn index(&self, _: Front) -> &Self::Output { - &self.channels()[2] + &self.samples()[2] } } -impl IndexMut for Frame { +impl IndexMut for Frame { fn index_mut(&mut self, _: Front) -> &mut Self::Output { - &mut self.channels_mut()[2] + &mut self.samples_mut()[2] } } -impl Index for Frame { - type Output = Chan; +impl Index for Frame { + type Output = Samp; fn index(&self, _: Lfe) -> &Self::Output { - &self.channels()[3] + &self.samples()[3] } } -impl IndexMut for Frame { +impl IndexMut for Frame { fn index_mut(&mut self, _: Lfe) -> &mut Self::Output { - &mut self.channels_mut()[3] + &mut self.samples_mut()[3] } } -impl Index for Frame { - type Output = Chan; +impl Index for Frame { + type Output = Samp; fn index(&self, _: SurroundL) -> &Self::Output { - &self.channels()[4] + &self.samples()[4] } } -impl IndexMut for Frame { +impl IndexMut for Frame { fn index_mut(&mut self, _: SurroundL) -> &mut Self::Output { - &mut self.channels_mut()[4] + &mut self.samples_mut()[4] } } -impl Index for Frame { - type Output = Chan; +impl Index for Frame { + type Output = Samp; fn index(&self, _: SurroundR) -> &Self::Output { - &self.channels()[5] + &self.samples()[5] } } -impl IndexMut for Frame { +impl IndexMut for Frame { fn index_mut(&mut self, _: SurroundR) -> &mut Self::Output { - &mut self.channels_mut()[5] + &mut self.samples_mut()[5] } } //////////////////////////////////////////////////////////// -impl Index for Frame { - type Output = Chan; +impl Index for Frame { + type Output = Samp; fn index(&self, _: FrontL) -> &Self::Output { - &self.channels()[0] + &self.samples()[0] } } -impl IndexMut for Frame { +impl IndexMut for Frame { fn index_mut(&mut self, _: FrontL) -> &mut Self::Output { - &mut self.channels_mut()[0] + &mut self.samples_mut()[0] } } -impl Index for Frame { - type Output = Chan; +impl Index for Frame { + type Output = Samp; fn index(&self, _: FrontR) -> &Self::Output { - &self.channels()[1] + &self.samples()[1] } } -impl IndexMut for Frame { +impl IndexMut for Frame { fn index_mut(&mut self, _: FrontR) -> &mut Self::Output { - &mut self.channels_mut()[1] + &mut self.samples_mut()[1] } } -impl Index for Frame { - type Output = Chan; +impl Index for Frame { + type Output = Samp; fn index(&self, _: Front) -> &Self::Output { - &self.channels()[2] + &self.samples()[2] } } -impl IndexMut for Frame { +impl IndexMut for Frame { fn index_mut(&mut self, _: Front) -> &mut Self::Output { - &mut self.channels_mut()[2] + &mut self.samples_mut()[2] } } -impl Index for Frame { - type Output = Chan; +impl Index for Frame { + type Output = Samp; fn index(&self, _: Lfe) -> &Self::Output { - &self.channels()[3] + &self.samples()[3] } } -impl IndexMut for Frame { +impl IndexMut for Frame { fn index_mut(&mut self, _: Lfe) -> &mut Self::Output { - &mut self.channels_mut()[3] + &mut self.samples_mut()[3] } } -impl Index for Frame { - type Output = Chan; +impl Index for Frame { + type Output = Samp; fn index(&self, _: Back) -> &Self::Output { - &self.channels()[4] + &self.samples()[4] } } -impl IndexMut for Frame { +impl IndexMut for Frame { fn index_mut(&mut self, _: Back) -> &mut Self::Output { - &mut self.channels_mut()[4] + &mut self.samples_mut()[4] } } -impl Index for Frame { - type Output = Chan; +impl Index for Frame { + type Output = Samp; fn index(&self, _: Left) -> &Self::Output { - &self.channels()[5] + &self.samples()[5] } } -impl IndexMut for Frame { +impl IndexMut for Frame { fn index_mut(&mut self, _: Left) -> &mut Self::Output { - &mut self.channels_mut()[5] + &mut self.samples_mut()[5] } } -impl Index for Frame { - type Output = Chan; +impl Index for Frame { + type Output = Samp; fn index(&self, _: Right) -> &Self::Output { - &self.channels()[6] + &self.samples()[6] } } -impl IndexMut for Frame { +impl IndexMut for Frame { fn index_mut(&mut self, _: Right) -> &mut Self::Output { - &mut self.channels_mut()[6] + &mut self.samples_mut()[6] } } //////////////////////////////////////////////////////////// -impl Index for Frame { - type Output = Chan; +impl Index for Frame { + type Output = Samp; fn index(&self, _: FrontL) -> &Self::Output { - &self.channels()[0] + &self.samples()[0] } } -impl IndexMut for Frame { +impl IndexMut for Frame { fn index_mut(&mut self, _: FrontL) -> &mut Self::Output { - &mut self.channels_mut()[0] + &mut self.samples_mut()[0] } } -impl Index for Frame { - type Output = Chan; +impl Index for Frame { + type Output = Samp; fn index(&self, _: FrontR) -> &Self::Output { - &self.channels()[1] + &self.samples()[1] } } -impl IndexMut for Frame { +impl IndexMut for Frame { fn index_mut(&mut self, _: FrontR) -> &mut Self::Output { - &mut self.channels_mut()[1] + &mut self.samples_mut()[1] } } -impl Index for Frame { - type Output = Chan; +impl Index for Frame { + type Output = Samp; fn index(&self, _: Front) -> &Self::Output { - &self.channels()[2] + &self.samples()[2] } } -impl IndexMut for Frame { +impl IndexMut for Frame { fn index_mut(&mut self, _: Front) -> &mut Self::Output { - &mut self.channels_mut()[2] + &mut self.samples_mut()[2] } } -impl Index for Frame { - type Output = Chan; +impl Index for Frame { + type Output = Samp; fn index(&self, _: Lfe) -> &Self::Output { - &self.channels()[3] + &self.samples()[3] } } -impl IndexMut for Frame { +impl IndexMut for Frame { fn index_mut(&mut self, _: Lfe) -> &mut Self::Output { - &mut self.channels_mut()[3] + &mut self.samples_mut()[3] } } -impl Index for Frame { - type Output = Chan; +impl Index for Frame { + type Output = Samp; fn index(&self, _: BackL) -> &Self::Output { - &self.channels()[4] + &self.samples()[4] } } -impl IndexMut for Frame { +impl IndexMut for Frame { fn index_mut(&mut self, _: BackL) -> &mut Self::Output { - &mut self.channels_mut()[4] + &mut self.samples_mut()[4] } } -impl Index for Frame { - type Output = Chan; +impl Index for Frame { + type Output = Samp; fn index(&self, _: BackR) -> &Self::Output { - &self.channels()[5] + &self.samples()[5] } } -impl IndexMut for Frame { +impl IndexMut for Frame { fn index_mut(&mut self, _: BackR) -> &mut Self::Output { - &mut self.channels_mut()[5] + &mut self.samples_mut()[5] } } -impl Index for Frame { - type Output = Chan; +impl Index for Frame { + type Output = Samp; fn index(&self, _: Left) -> &Self::Output { - &self.channels()[6] + &self.samples()[6] } } -impl IndexMut for Frame { +impl IndexMut for Frame { fn index_mut(&mut self, _: Left) -> &mut Self::Output { - &mut self.channels_mut()[6] + &mut self.samples_mut()[6] } } -impl Index for Frame { - type Output = Chan; +impl Index for Frame { + type Output = Samp; fn index(&self, _: Right) -> &Self::Output { - &self.channels()[7] + &self.samples()[7] } } -impl IndexMut for Frame { +impl IndexMut for Frame { fn index_mut(&mut self, _: Right) -> &mut Self::Output { - &mut self.channels_mut()[7] + &mut self.samples_mut()[7] } } diff --git a/src/private.rs b/src/private.rs index 10cb664..84ef3f3 100644 --- a/src/private.rs +++ b/src/private.rs @@ -1,7 +1,7 @@ -use crate::chan::{Ch16, Ch24, Ch32, Ch64}; +use crate::samp::{Samp16, Samp24, Samp32, Samp64}; pub trait Sealed {} -impl Sealed for Ch16 {} -impl Sealed for Ch24 {} -impl Sealed for Ch32 {} -impl Sealed for Ch64 {} +impl Sealed for Samp16 {} +impl Sealed for Samp24 {} +impl Sealed for Samp32 {} +impl Sealed for Samp64 {} diff --git a/src/samp.rs b/src/samp.rs new file mode 100644 index 0000000..b331aba --- /dev/null +++ b/src/samp.rs @@ -0,0 +1,762 @@ +//! Audio channels (left, right, etc.). Each channel contains a single sample. +//! +//! An audio [`Frame`](crate::frame::Frame) is used to group multiple channels. + +use core::{ + fmt::Debug, + ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign}, +}; + +#[cfg(not(test))] +use crate::math::Libm; +use crate::private::Sealed; + +/// Component of a speaker configuration, such as *front left*, *lfe*, *etc*. +pub trait Sample: + Copy + + Clone + + Debug + + Default + + From + + PartialOrd + + Add + + AddAssign + + Sub + + SubAssign + + Mul + + MulAssign + + Neg + + From + + From + + From + + From + + Into + + Into + + Into + + Into + + Sealed + + Unpin + + Sized + + 'static +{ + /// Minimum value (*negative one*) + const MIN: Self; + + /// Mid value (*zero/silence*) + const MID: Self; + + /// Maximum value (*one*) + const MAX: Self; + + /// Convert to `f32` + fn to_f32(self) -> f32; + + /// Linear interpolation + #[inline(always)] + fn lerp(self, rhs: Self, t: Self) -> Self { + self + t * (rhs - self) + } +} + +/// 16-bit sample [`Sample`]. +#[derive(Clone, Copy, Debug, Default, PartialEq, PartialOrd)] +#[repr(transparent)] +pub struct Samp16(i16); + +impl Sample for Samp16 { + const MAX: Samp16 = Samp16(32_767); + const MID: Samp16 = Samp16(0); + const MIN: Samp16 = Samp16(-32_768); + + #[inline(always)] + fn to_f32(self) -> f32 { + const MULTIPLIER: f32 = 1.0 / 32_767.5; + (f32::from(self.0) + 0.5) * MULTIPLIER + } +} + +impl Samp16 { + /// Create a new 16-bit [`Sample`] value. + #[inline(always)] + pub const fn new(value: i16) -> Self { + Self(value) + } +} + +impl From for Samp16 { + #[inline(always)] + fn from(value: f32) -> Self { + Self::new((value.clamp(-1.0, 1.0) * 32_767.5).floor() as i16) + } +} + +impl From for Samp16 { + #[inline(always)] + fn from(ch: Samp24) -> Self { + Self::new(ch.0) + } +} + +impl From for Samp16 { + #[inline(always)] + fn from(ch: Samp32) -> Self { + Self::from(ch.0) + } +} + +impl From for Samp16 { + #[inline(always)] + fn from(ch: Samp64) -> Self { + Self::from(ch.0 as f32) + } +} + +impl From for i16 { + #[inline(always)] + fn from(ch: Samp16) -> i16 { + ch.0 + } +} + +impl> Add for Samp16 { + type Output = Self; + + #[inline(always)] + fn add(self, rhs: R) -> Self { + Self::new(i16::from(self).saturating_add(i16::from(rhs.into()))) + } +} + +impl> Sub for Samp16 { + type Output = Self; + + #[inline(always)] + fn sub(self, rhs: R) -> Self { + Self::new(i16::from(self).saturating_sub(i16::from(rhs.into()))) + } +} + +impl> Mul for Samp16 { + type Output = Self; + + #[inline(always)] + fn mul(self, rhs: R) -> Self { + let l = i32::from(self.0); + let r = i32::from(rhs.into().0); + let v = (l * r) / 32_767; + Self::new(v.clamp(-32_768, 32_767) as i16) + } +} + +impl Neg for Samp16 { + type Output = Samp16; + + #[inline(always)] + fn neg(self) -> Self { + Self::new((u16::MAX - i16::from(self) as u16) as i16) + } +} + +/// 24-bit sample [`Sample`]. +#[derive(Clone, Copy, Debug, Default, PartialEq, PartialOrd)] +#[repr(C, packed)] +pub struct Samp24(i16, u8); + +impl Sample for Samp24 { + const MAX: Samp24 = Samp24::new(8_388_607); + const MID: Samp24 = Samp24::new(0); + const MIN: Samp24 = Samp24::new(-8_388_608); + + #[inline(always)] + fn to_f32(self) -> f32 { + const MULTIPLIER: f32 = 1.0 / 8_388_607.5; + (i32::from(self) as f32 + 0.5) * MULTIPLIER + } +} + +impl Samp24 { + /// Create a new 24-bit [`Sample`] value. + #[inline(always)] + pub const fn new(value: i32) -> Self { + let value = if value < -8_388_608 { + -8_388_608 + } else if value > 8_388_607 { + 8_388_607 + } else { + value + }; + Self((value >> 8) as i16, value as u8) + } +} + +impl From for Samp24 { + #[inline(always)] + fn from(value: f32) -> Self { + Self::new((value.clamp(-1.0, 1.0) * 8_388_607.5).floor() as i32) + } +} + +impl From for Samp24 { + #[inline(always)] + fn from(ch: Samp16) -> Self { + Self(i16::from(ch), (i16::from(ch) >> 8) as u8 ^ 0b1000_0000) + } +} + +impl From for Samp24 { + #[inline(always)] + fn from(ch: Samp32) -> Self { + Self::from(ch.0) + } +} + +impl From for Samp24 { + #[inline(always)] + fn from(ch: Samp64) -> Self { + Self::from(ch.0 as f32) + } +} + +impl From for i32 { + #[inline(always)] + fn from(ch: Samp24) -> i32 { + ((ch.0 as i32) << 8) | ch.1 as i32 + } +} + +impl> Add for Samp24 { + type Output = Self; + + #[inline(always)] + fn add(self, rhs: R) -> Self { + Self::new(i32::from(self) + i32::from(rhs.into())) + } +} + +impl> Sub for Samp24 { + type Output = Self; + + #[inline(always)] + fn sub(self, rhs: R) -> Self { + Self::new(i32::from(self) - i32::from(rhs.into())) + } +} + +impl> Mul for Samp24 { + type Output = Self; + + #[inline(always)] + fn mul(self, rhs: R) -> Self { + let l: i64 = i32::from(self).into(); + let r: i64 = i32::from(rhs.into()).into(); + let v = (l * r) / 8_388_607; + Self::new(v.clamp(-8_388_608, 8_388_607) as i32) + } +} + +impl Neg for Samp24 { + type Output = Samp24; + + #[inline(always)] + fn neg(self) -> Self { + Self::new((u32::MAX - i32::from(self) as u32) as i32) + } +} + +/// 32-bit sample [`Sample`]. +#[derive(Clone, Copy, Debug, Default, PartialEq, PartialOrd)] +#[repr(transparent)] +pub struct Samp32(f32); + +impl Sample for Samp32 { + const MAX: Samp32 = Samp32(1.0); + const MID: Samp32 = Samp32(0.0); + const MIN: Samp32 = Samp32(-1.0); + + #[inline(always)] + fn to_f32(self) -> f32 { + self.0 + } +} + +impl Samp32 { + /// Create a new 32-bit [`Sample`] value. + #[inline(always)] + pub const fn new(value: f32) -> Self { + Self(value) + } +} + +impl From for Samp32 { + #[inline(always)] + fn from(value: f32) -> Self { + Self::new(value) + } +} + +impl From for Samp32 { + #[inline(always)] + fn from(ch: Samp16) -> Self { + Self::new(ch.to_f32()) + } +} + +impl From for Samp32 { + #[inline(always)] + fn from(ch: Samp24) -> Self { + Self::new(ch.to_f32()) + } +} + +impl From for Samp32 { + #[inline(always)] + fn from(ch: Samp64) -> Self { + Self::new(ch.to_f32()) + } +} + +impl From for f32 { + #[inline(always)] + fn from(ch: Samp32) -> f32 { + ch.0 + } +} + +impl> Add for Samp32 { + type Output = Self; + + #[inline(always)] + fn add(self, rhs: R) -> Self { + Self::new(f32::from(self) + f32::from(rhs.into())) + } +} + +impl> Sub for Samp32 { + type Output = Self; + + #[inline(always)] + fn sub(self, rhs: R) -> Self { + Self::new(f32::from(self) - f32::from(rhs.into())) + } +} + +impl> Mul for Samp32 { + type Output = Self; + + #[inline(always)] + fn mul(self, rhs: R) -> Self { + Self::new(f32::from(self) * f32::from(rhs.into())) + } +} + +impl Neg for Samp32 { + type Output = Samp32; + + #[inline(always)] + fn neg(self) -> Self { + Self(-f32::from(self)) + } +} + +/// 64-bit sample [`Sample`]. +#[derive(Clone, Copy, Debug, Default, PartialEq, PartialOrd)] +#[repr(transparent)] +pub struct Samp64(f64); + +impl Sample for Samp64 { + const MAX: Samp64 = Samp64(1.0); + const MID: Samp64 = Samp64(0.0); + const MIN: Samp64 = Samp64(-1.0); + + #[inline(always)] + fn to_f32(self) -> f32 { + self.0 as f32 + } +} + +impl Samp64 { + /// Create a new 64-bit [`Sample`] value. + #[inline(always)] + pub const fn new(value: f64) -> Self { + Self(value) + } +} + +impl From for Samp64 { + #[inline(always)] + fn from(value: f32) -> Self { + Self::new(value as f64) + } +} + +impl From for Samp64 { + #[inline(always)] + fn from(ch: Samp16) -> Self { + Self::new(ch.to_f32() as f64) + } +} + +impl From for Samp64 { + #[inline(always)] + fn from(ch: Samp24) -> Self { + Self::new(ch.to_f32() as f64) + } +} + +impl From for Samp64 { + #[inline(always)] + fn from(ch: Samp32) -> Self { + Self::new(ch.0 as f64) + } +} + +impl From for f64 { + #[inline(always)] + fn from(ch: Samp64) -> f64 { + ch.0 + } +} + +impl> Add for Samp64 { + type Output = Self; + + #[inline(always)] + fn add(self, rhs: R) -> Self { + Self::new(self.0 + rhs.into().0) + } +} + +impl> Sub for Samp64 { + type Output = Self; + + #[inline(always)] + fn sub(self, rhs: R) -> Self { + Self::new(self.0 - rhs.into().0) + } +} + +impl> Mul for Samp64 { + type Output = Self; + + #[inline(always)] + fn mul(self, rhs: R) -> Self { + Self::new(self.0 * rhs.into().0) + } +} + +impl Neg for Samp64 { + type Output = Samp64; + + #[inline(always)] + fn neg(self) -> Self { + Self(-self.0) + } +} + +impl AddAssign for Samp16 { + #[inline(always)] + fn add_assign(&mut self, rhs: Self) { + *self = *self + rhs; + } +} + +impl AddAssign for Samp24 { + #[inline(always)] + fn add_assign(&mut self, rhs: Self) { + *self = *self + rhs; + } +} + +impl AddAssign for Samp32 { + #[inline(always)] + fn add_assign(&mut self, rhs: Self) { + *self = *self + rhs; + } +} + +impl AddAssign for Samp64 { + #[inline(always)] + fn add_assign(&mut self, rhs: Self) { + *self = *self + rhs; + } +} + +impl SubAssign for Samp16 { + #[inline(always)] + fn sub_assign(&mut self, rhs: Self) { + *self = *self - rhs; + } +} + +impl SubAssign for Samp24 { + #[inline(always)] + fn sub_assign(&mut self, rhs: Self) { + *self = *self - rhs; + } +} + +impl SubAssign for Samp32 { + #[inline(always)] + fn sub_assign(&mut self, rhs: Self) { + *self = *self - rhs; + } +} + +impl SubAssign for Samp64 { + #[inline(always)] + fn sub_assign(&mut self, rhs: Self) { + *self = *self - rhs; + } +} + +impl MulAssign for Samp16 { + #[inline(always)] + fn mul_assign(&mut self, rhs: Self) { + *self = *self * rhs; + } +} + +impl MulAssign for Samp24 { + #[inline(always)] + fn mul_assign(&mut self, rhs: Self) { + *self = *self * rhs; + } +} + +impl MulAssign for Samp32 { + #[inline(always)] + fn mul_assign(&mut self, rhs: Self) { + *self = *self * rhs; + } +} + +impl MulAssign for Samp64 { + #[inline(always)] + fn mul_assign(&mut self, rhs: Self) { + *self = *self * rhs; + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn ch16() { + assert_eq!(-1.0, Samp16::MIN.to_f32()); + assert_eq!(0.000015259022, Samp16::MID.to_f32()); + assert_eq!(1.0, Samp16::MAX.to_f32()); + + assert_eq!(Samp16::MIN, Samp16::from(Samp16::MIN.to_f32())); + assert_eq!(Samp16::MID, Samp16::from(Samp16::MID.to_f32())); + assert_eq!(Samp16::MAX, Samp16::from(Samp16::MAX.to_f32())); + } + + #[test] + fn ch16_roundtrip() { + assert_eq!(-32768, i16::from(Samp16::MIN)); + assert_eq!(0, i16::from(Samp16::MID)); + assert_eq!(32767, i16::from(Samp16::MAX)); + + assert_eq!(Samp16::MIN, Samp16::new(i16::from(Samp16::MIN))); + assert_eq!(Samp16::MID, Samp16::new(i16::from(Samp16::MID))); + assert_eq!(Samp16::MAX, Samp16::new(i16::from(Samp16::MAX))); + } + + #[test] + fn ch24() { + assert_eq!(-1.0, Samp24::MIN.to_f32()); + assert_eq!(0.00000005960465, Samp24::MID.to_f32()); + assert_eq!(1.0, Samp24::MAX.to_f32()); + + assert_eq!(Samp24::MIN, Samp24::from(Samp24::MIN.to_f32())); + assert_eq!(Samp24::MID, Samp24::from(Samp24::MID.to_f32())); + assert_eq!(Samp24::MAX, Samp24::from(Samp24::MAX.to_f32())); + } + + #[test] + fn ch24_roundtrip() { + assert_eq!(-8388608, i32::from(Samp24::MIN)); + assert_eq!(0, i32::from(Samp24::MID)); + assert_eq!(8388607, i32::from(Samp24::MAX)); + + assert_eq!(Samp24::MIN, Samp24::new(i32::from(Samp24::MIN))); + assert_eq!(Samp24::MID, Samp24::new(i32::from(Samp24::MID))); + assert_eq!(Samp24::MAX, Samp24::new(i32::from(Samp24::MAX))); + } + + #[test] + fn ch32() { + assert_eq!(-1.0, Samp32::MIN.to_f32()); + assert_eq!(0.0, Samp32::MID.to_f32()); + assert_eq!(1.0, Samp32::MAX.to_f32()); + + assert_eq!(Samp32::MIN, Samp32::from(Samp32::MIN.to_f32())); + assert_eq!(Samp32::MID, Samp32::from(Samp32::MID.to_f32())); + assert_eq!(Samp32::MAX, Samp32::from(Samp32::MAX.to_f32())); + } + + #[test] + fn ch64() { + assert_eq!(-1.0, Samp64::MIN.to_f32()); + assert_eq!(0.0, Samp64::MID.to_f32()); + assert_eq!(1.0, Samp64::MAX.to_f32()); + + assert_eq!(Samp64::MIN, Samp64::from(Samp64::MIN.to_f32())); + assert_eq!(Samp64::MID, Samp64::from(Samp64::MID.to_f32())); + assert_eq!(Samp64::MAX, Samp64::from(Samp64::MAX.to_f32())); + } + + #[test] + fn ch16_to_ch24() { + assert_eq!(Samp24::MIN, Samp24::from(Samp16::MIN)); + assert_eq!(Samp24::new(128), Samp24::from(Samp16::MID)); + assert_eq!(Samp24::MAX, Samp24::from(Samp16::MAX)); + } + + #[test] + fn ch24_to_ch16() { + assert_eq!(Samp16::MIN, Samp16::from(Samp24::MIN)); + assert_eq!(Samp16::MID, Samp16::from(Samp24::MID)); + assert_eq!(Samp16::MAX, Samp16::from(Samp24::MAX)); + } + + #[test] + fn ch16_arith() { + // Test addition + assert_eq!(Samp16::new(-1), Samp16::new(-32768) + Samp16::new(32767)); + assert_eq!(Samp16::new(8192), Samp16::new(-8192) + Samp16::new(16384)); + assert_eq!(Samp16::MAX, Samp16::MID + Samp16::MAX); + assert_eq!(Samp16::MIN, Samp16::new(-16384) + Samp16::new(-16384)); + // Test subtraction + assert_eq!(Samp16::new(0), Samp16::new(-32768) - Samp16::new(-32768)); + assert_eq!(Samp16::new(0), Samp16::new(32767) - Samp16::new(32767)); + assert_eq!(Samp16::new(-32767), Samp16::new(0) - Samp16::new(32767)); + // Test multiplication + assert_eq!(Samp16::new(0), Samp16::new(0) * Samp16::new(32767)); + assert_eq!(Samp16::new(32767), Samp16::new(32767) * Samp16::new(32767)); + assert_eq!(Samp16::new(-32768), Samp16::new(32767) * Samp16::new(-32768)); + assert_eq!(Samp16::new(-32768), Samp16::new(-32768) * Samp16::new(32767)); + assert_eq!(Samp16::new(32767), Samp16::new(-32768) * Samp16::new(-32768)); + assert_eq!(Samp16::new(-16384), Samp16::new(32767) * Samp16::new(-16384)); + // Test negation + assert_eq!(Samp16::MIN, -Samp16::MAX); + assert_eq!(Samp16::MAX, -Samp16::MIN); + assert_eq!(Samp16::new(-1), -Samp16::new(0)); + assert_eq!(Samp16::new(0), -Samp16::new(-1)); + } + + #[test] + fn ch24_arith() { + // Test addition + assert_eq!(Samp24::new(-1), Samp24::new(-8388608) + Samp24::new(8388607)); + assert_eq!( + Samp24::new(2097152), + Samp24::new(-2097152) + Samp24::new(4194304) + ); + assert_eq!(Samp24::MAX, Samp24::MID + Samp24::MAX); + assert_eq!(Samp24::MIN, Samp24::new(-4194304) + Samp24::new(-4194304)); + // Test subtraction + assert_eq!(Samp24::new(0), Samp24::new(-8388608) - Samp24::new(-8388608)); + assert_eq!(Samp24::new(0), Samp24::new(8388607) - Samp24::new(8388607)); + assert_eq!(Samp24::new(-8388607), Samp24::new(0) - Samp24::new(8388607)); + // Test multiplication + assert_eq!(Samp24::new(0), Samp24::new(0) * Samp24::new(8388607)); + assert_eq!(Samp24::new(8388607), Samp24::new(8388607) * Samp24::new(8388607)); + assert_eq!( + Samp24::new(-8388608), + Samp24::new(8388607) * Samp24::new(-8388608) + ); + assert_eq!( + Samp24::new(-8388608), + Samp24::new(-8388608) * Samp24::new(8388607) + ); + assert_eq!( + Samp24::new(8388607), + Samp24::new(-8388608) * Samp24::new(-8388608) + ); + assert_eq!( + Samp24::new(-4194304), + Samp24::new(8388607) * Samp24::new(-4194304) + ); + // Test negation + assert_eq!(Samp24::MIN, -Samp24::MAX); + assert_eq!(Samp24::MAX, -Samp24::MIN); + assert_eq!(Samp24::new(-1), -Samp24::new(0)); + assert_eq!(Samp24::new(0), -Samp24::new(-1)); + } + + #[test] + fn ch32_arith() { + // Test addition + assert_eq!(Samp32::new(0.0), Samp32::new(-1.0) + Samp32::new(1.0)); + assert_eq!(Samp32::new(0.25), Samp32::new(-0.25) + Samp32::new(0.5)); + assert_eq!(Samp32::new(1.0), Samp32::new(0.0) + Samp32::new(1.0)); + assert_eq!(Samp32::new(-1.0), Samp32::new(-0.5) + Samp32::new(-0.5)); + // Test subtraction + assert_eq!(Samp32::new(0.0), Samp32::new(-1.0) - Samp32::new(-1.0)); + assert_eq!(Samp32::new(0.0), Samp32::new(1.0) - Samp32::new(1.0)); + assert_eq!(Samp32::new(-1.0), Samp32::new(0.0) - Samp32::new(1.0)); + // Test multiplication + assert_eq!(Samp32::new(0.0), Samp32::new(0.0) * Samp32::new(1.0)); + assert_eq!(Samp32::new(1.0), Samp32::new(1.0) * Samp32::new(1.0)); + assert_eq!(Samp32::new(-1.0), Samp32::new(1.0) * Samp32::new(-1.0)); + assert_eq!(Samp32::new(1.0), Samp32::new(-1.0) * Samp32::new(-1.0)); + assert_eq!(Samp32::new(-0.5), Samp32::new(1.0) * Samp32::new(-0.5)); + // Test negation + assert_eq!(Samp32::MIN, -Samp32::MAX); + assert_eq!(Samp32::MAX, -Samp32::MIN); + assert_eq!(Samp32::new(0.0), -Samp32::new(0.0)); + } + + #[test] + fn ch64_arith() { + // Test addition + assert_eq!(Samp64::new(0.0), Samp64::new(-1.0) + Samp64::new(1.0)); + assert_eq!(Samp64::new(0.25), Samp64::new(-0.25) + Samp64::new(0.5)); + assert_eq!(Samp64::new(1.0), Samp64::new(0.0) + Samp64::new(1.0)); + assert_eq!(Samp64::new(-1.0), Samp64::new(-0.5) + Samp64::new(-0.5)); + // Test subtraction + assert_eq!(Samp64::new(0.0), Samp64::new(-1.0) - Samp64::new(-1.0)); + assert_eq!(Samp64::new(0.0), Samp64::new(1.0) - Samp64::new(1.0)); + assert_eq!(Samp64::new(-1.0), Samp64::new(0.0) - Samp64::new(1.0)); + // Test multiplication + assert_eq!(Samp64::new(0.0), Samp64::new(0.0) * Samp64::new(1.0)); + assert_eq!(Samp64::new(1.0), Samp64::new(1.0) * Samp64::new(1.0)); + assert_eq!(Samp64::new(-1.0), Samp64::new(1.0) * Samp64::new(-1.0)); + assert_eq!(Samp64::new(1.0), Samp64::new(-1.0) * Samp64::new(-1.0)); + assert_eq!(Samp64::new(-0.5), Samp64::new(1.0) * Samp64::new(-0.5)); + // Test negation + assert_eq!(Samp64::MIN, -Samp64::MAX); + assert_eq!(Samp64::MAX, -Samp64::MIN); + assert_eq!(Samp64::new(0.0), -Samp64::new(0.0)); + } + + #[test] + fn ch16_saturation() { + assert_eq!(Samp16::MAX, Samp16::new(24576) + Samp16::new(16384)); + assert_eq!(Samp16::MIN, Samp16::new(-16384) + Samp16::new(-24576)); + assert_eq!(Samp16::MIN, Samp16::new(-16384) - Samp16::new(24576)); + } + + #[test] + fn ch24_saturation() { + assert_eq!(Samp24::MAX, Samp24::new(6291456) + Samp24::new(4194304)); + assert_eq!(Samp24::MIN, Samp24::new(-4194304) + Samp24::new(-6291456)); + assert_eq!(Samp24::MIN, Samp24::new(-4194304) - Samp24::new(6291456)); + } + + #[test] + fn ch32_unsaturation() { + assert_eq!(Samp32::new(1.25), Samp32::new(0.75) + Samp32::new(0.5)); + assert_eq!(Samp32::new(-1.25), Samp32::new(-0.5) + Samp32::new(-0.75)); + assert_eq!(Samp32::new(-1.25), Samp32::new(-0.5) - Samp32::new(0.75)); + } + + #[test] + fn ch64_unsaturation() { + assert_eq!(Samp64::new(1.25), Samp64::new(0.75) + Samp64::new(0.5)); + assert_eq!(Samp64::new(-1.25), Samp64::new(-0.5) + Samp64::new(-0.75)); + assert_eq!(Samp64::new(-1.25), Samp64::new(-0.5) - Samp64::new(0.75)); + } +} diff --git a/src/sink.rs b/src/sink.rs index 8119eff..954b77f 100644 --- a/src/sink.rs +++ b/src/sink.rs @@ -1,9 +1,9 @@ use core::{fmt::Debug, num::NonZeroU32}; -use crate::{chan::Channel, Frame}; +use crate::{samp::Sample, Frame}; /// Audio sink - a type that consumes audio samples. -pub trait Sink: Debug { +pub trait Sink: Debug { /// Get the sample rate of the sink in hertz. fn sample_rate(&self) -> NonZeroU32; @@ -17,7 +17,7 @@ pub trait Sink: Debug { /// **Warning**: if used incorrectly, this method may introduce audio /// aliasing. To avoid that, make sure the sample rate of the frames from /// the iterator matches exactly the sample rate of the sink. - fn sink_with(&mut self, iter: &mut dyn Iterator>); + fn sink_with(&mut self, iter: &mut dyn Iterator>); /// Check if the sink is empty (length of zero). fn is_empty(&self) -> bool { @@ -28,24 +28,24 @@ pub trait Sink: Debug { /// Sink that converts to a different audio format before passing to another /// [`Sink`](crate::Sink). #[derive(Debug)] -pub struct SinkTo +pub struct SinkTo where - Chan: Channel + From, - C: Channel, - S: Sink, + Samp: Sample + From, + S: Sample, + K: Sink, { - sink: S, - _phantom: core::marker::PhantomData<(Chan, C)>, + sink: K, + _phantom: core::marker::PhantomData (Samp, S)>, } -impl SinkTo +impl SinkTo where - Chan: Channel + From, - C: Channel, - S: Sink, + Samp: Sample + From, + S: Sample, + K: Sink, { /// Convert an arbitrary `Sink` type to a different format. - pub fn new(sink: S) -> Self { + pub fn new(sink: K) -> Self { Self { sink, _phantom: core::marker::PhantomData, @@ -54,12 +54,12 @@ where } #[allow(single_use_lifetimes)] -impl Sink - for &mut SinkTo +impl Sink + for &mut SinkTo where - Chan: Channel + From, - C: Channel, - S: Sink, + Samp: Sample + From, + S: Sample, + K: Sink, { /// Get the sample rate of the sink in hertz. fn sample_rate(&self) -> NonZeroU32 { @@ -78,18 +78,18 @@ where /// **Warning**: if used incorrectly, this method may introduce audio /// aliasing. To avoid that, make sure the sample rate of the frames from /// the iterator matches exactly the sample rate of the sink. - fn sink_with(&mut self, iter: &mut dyn Iterator>) { + fn sink_with(&mut self, iter: &mut dyn Iterator>) { self.sink.sink_with(&mut iter.map(Frame::to)) } } #[allow(single_use_lifetimes)] -impl Sink - for SinkTo +impl Sink + for SinkTo where - Chan: Channel + From, - C: Channel, - S: Sink, + Samp: Sample + From, + S: Sample, + K: Sink, { /// Get the sample rate of the sink in hertz. fn sample_rate(&self) -> NonZeroU32 { @@ -108,7 +108,7 @@ where /// **Warning**: if used incorrectly, this method may introduce audio /// aliasing. To avoid that, make sure the sample rate of the frames from /// the iterator matches exactly the sample rate of the sink. - fn sink_with(&mut self, iter: &mut dyn Iterator>) { + fn sink_with(&mut self, iter: &mut dyn Iterator>) { self.sink.sink_with(&mut iter.map(Frame::to)) } } diff --git a/src/stream.rs b/src/stream.rs index 055c4ec..4ed8fd0 100644 --- a/src/stream.rs +++ b/src/stream.rs @@ -2,7 +2,7 @@ use alloc::vec::Vec; use core::{mem, num::NonZeroU32}; use crate::{ - chan::{Ch32, Channel}, + samp::{Samp32, Sample}, frame::Frame, Audio, Sink, }; @@ -30,8 +30,8 @@ pub struct Stream { input_sample_rate: Option, /// Simplified ratio of input รท output samples. ratio: (u32, u32), - /// Channel data. - channels: [Resampler32; 8], + /// Sample data. + samples: [Resampler32; 8], /// Calculated input latency for resampler. input_latency: u32, } @@ -44,7 +44,7 @@ impl Stream { output_sample_rate: target_hz, input_sample_rate: None, ratio: (0, 1), - channels: [ + samples: [ Default::default(), Default::default(), Default::default(), @@ -67,7 +67,7 @@ impl Stream { // Handle sample rate change, if needed. if NonZeroU32::new(hz.get()) != self.input_sample_rate { // Prepare each channel for sample rate change - for ch in self.channels.iter_mut() { + for ch in self.samples.iter_mut() { // Store fractional sample data. let v = ch.state.samp_frac_num; ch.state.samp_frac_num = speex::_muldiv(v, den, self.ratio.1); @@ -85,22 +85,22 @@ impl Stream { } /// Flush audio to sink and end stream. - pub fn flush(mut self, sink: S) + pub fn flush(mut self, sink: K) where - Ch: Channel, - S: Sink, + S: Sample, + K: Sink, { - if self.channels[0].state.started == 0 { + if self.samples[0].state.started == 0 { return; } // Generate silence. for chan in 0..CH { - self.channels[chan].input.clear(); + self.samples[chan].input.clear(); } for _ in 0..self.input_latency { for chan in 0..CH { - self.channels[chan].input.push(0.0); + self.samples[chan].input.push(0.0); } } @@ -113,18 +113,18 @@ impl Stream { /// If the sink gets full, then no more audio will be written. If there is /// not enough audio then the sink chooses whether or not to fill the rest /// of it's buffer with silence. - pub fn pipe(&mut self, audio: &Audio, mut sink: S) + pub fn pipe(&mut self, audio: &Audio, mut sink: K) where - Chan: Channel, - Ch: Channel + From, - S: Sink, - Ch32: From, + Samp: Sample, + S: Sample + From, + K: Sink, + Samp32: From, { // Make sure that the sample rates match. assert_eq!(sink.sample_rate().get(), self.output_sample_rate); // If sample rates match, do a copy (faster than resampling). - if self.channels[0].state.started == 0 + if self.samples[0].state.started == 0 && sink.sample_rate() == audio.sample_rate() { sink.sink_with(&mut audio.iter().cloned().map(|x| x.to())); @@ -138,7 +138,7 @@ impl Stream { } // First, de-interleave input audio data into f32 buffer. - let converted = Audio::::with_frames( + let converted = Audio::::with_frames( audio.sample_rate().get(), audio .as_slice() @@ -147,41 +147,41 @@ impl Stream { .collect::>(), ); for chan in 0..CH { - self.channels[chan].input.clear(); + self.samples[chan].input.clear(); } for frame in converted.iter() { for chan in 0..CH { - self.channels[chan] + self.samples[chan] .input - .push(frame.channels()[chan].to_f32()); + .push(frame.samples()[chan].to_f32()); } } - // Next, allocate space for output channels and resample. + // Next, allocate space for output samples and resample. self.resample_audio(sink); } - fn resample_audio(&mut self, mut sink: S) + fn resample_audio(&mut self, mut sink: K) where - Ch: Channel, - S: Sink, + S: Sample, + K: Sink, { // If no input samples, skip doing the work. - if self.channels[0].input.is_empty() { + if self.samples[0].input.is_empty() { return; } let mut out = u32::MAX; - // Allocate space for output channels and resample + // Allocate space for output samples and resample for chan in 0..CH { - self.channels[chan].output.resize(sink.len(), 0.0); + self.samples[chan].output.resize(sink.len(), 0.0); // FIXME: Remove length parameters, return number of output samples. - self.channels[chan].state.process_float( - self.channels[chan].input.as_slice(), - &mut (self.channels[chan].input.len() as u32), - self.channels[chan].output.as_mut_slice(), + self.samples[chan].state.process_float( + self.samples[chan].input.as_slice(), + &mut (self.samples[chan].input.len() as u32), + self.samples[chan].output.as_mut_slice(), &mut out, self.ratio.1, ); @@ -189,10 +189,10 @@ impl Stream { // Then, re-interleave the samples back. sink.sink_with(&mut (0..out as usize).map(|i| { - let mut out_frame = Frame::::default(); + let mut out_frame = Frame::::default(); for chan in 0..CH { - out_frame.channels_mut()[chan] = - Ch::from(self.channels[chan].output[i]); + out_frame.samples_mut()[chan] = + S::from(self.samples[chan].output[i]); } out_frame }));