Skip to content

Commit

Permalink
add i24 tests
Browse files Browse the repository at this point in the history
rename 24bit impl
  • Loading branch information
julientregoat committed Dec 7, 2020
1 parent 3bd0e90 commit 161e690
Show file tree
Hide file tree
Showing 2 changed files with 110 additions and 41 deletions.
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ pub use platform::{
available_hosts, default_host, host_from_id, Device, Devices, Host, HostId, Stream,
SupportedInputConfigs, SupportedOutputConfigs, ALL_HOSTS,
};
pub use samples_formats::{Sample, SampleFormat, Padded24};
pub use samples_formats::{Sample, SampleFormat, Unpacked24};
use std::convert::TryInto;
use std::ops::{Div, Mul};
use std::time::Duration;
Expand Down
149 changes: 109 additions & 40 deletions src/samples_formats.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::mem;
use std::{mem, ops::Deref};

/// Format that each sample has.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
Expand Down Expand Up @@ -39,7 +39,7 @@ pub unsafe trait Sample: Copy + Clone {
/// Converts this sample into a standard i16 sample.
fn to_i16(&self) -> i16;
/// Converts this sample into a 24 bit integer stored in an i32.
fn to_i24(&self) -> Padded24;
fn to_i24(&self) -> Unpacked24;
/// Converts this sample into a standard i32 sample.
fn to_i32(&self) -> i32;

Expand Down Expand Up @@ -71,7 +71,7 @@ unsafe impl Sample for u16 {
}
}

fn to_i24(&self) -> Padded24 {
fn to_i24(&self) -> Unpacked24 {
self.to_f32().to_i24()
}

Expand Down Expand Up @@ -116,7 +116,7 @@ unsafe impl Sample for i16 {
}

#[inline]
fn to_i24(&self) -> Padded24 {
fn to_i24(&self) -> Unpacked24 {
self.to_f32().to_i24()
}

Expand Down Expand Up @@ -160,14 +160,14 @@ unsafe impl Sample for f32 {

/// This function inherently returns a lossy value due to scaling.
#[inline]
fn to_i24(&self) -> Padded24 {
fn to_i24(&self) -> Unpacked24 {
let result: f32;
if self.is_sign_positive() {
result = self * Padded24::MAX as f32;
result = self * Unpacked24::MAX as f32;
} else {
result = self.abs() * Padded24::MIN as f32;
result = self.abs() * Unpacked24::MIN as f32;
}
Padded24(result.round() as i32)
Unpacked24(result.round() as i32)
}

#[inline]
Expand All @@ -188,16 +188,16 @@ unsafe impl Sample for f32 {
}
}

#[derive(Copy, Clone)]
pub struct Padded24(i32);
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct Unpacked24(i32);

impl Padded24 {
impl Unpacked24 {
const MAX: i32 = 8_388_607;
const MIN: i32 = -8_388_608;

// assumes i24 has been correctly parsed already
pub fn new(val: i32) -> Self {
Padded24(val)
Unpacked24(val)
}

pub fn from_be_bytes(b: [u8; 3]) -> Self {
Expand All @@ -209,7 +209,7 @@ impl Padded24 {
extra_byte = u8::MAX;
}

Padded24(i32::from_be_bytes([extra_byte, b[0], b[1], b[2]]))
Unpacked24(i32::from_be_bytes([extra_byte, b[0], b[1], b[2]]))
}

pub fn to_be_bytes(&self) -> [u8; 3] {
Expand All @@ -231,7 +231,7 @@ impl Padded24 {
extra_byte = u8::MAX;
}

Padded24(i32::from_le_bytes([b[0], b[1], b[2], extra_byte]))
Unpacked24(i32::from_le_bytes([b[0], b[1], b[2], extra_byte]))
}

pub fn to_le_bytes(&self) -> [u8; 3] {
Expand All @@ -245,7 +245,37 @@ impl Padded24 {
}
}

unsafe impl Sample for Padded24 {
impl PartialEq<i8> for Unpacked24 {
fn eq(&self, other: &i8) -> bool {
*other as i32 == self.0
}
}

impl PartialEq<i16> for Unpacked24 {
fn eq(&self, other: &i16) -> bool {
*other as i32 == self.0
}
}

impl PartialEq<i32> for Unpacked24 {
fn eq(&self, other: &i32) -> bool {
*other == self.0
}
}

impl PartialEq<u8> for Unpacked24 {
fn eq(&self, other: &u8) -> bool {
*other as i32 == self.0
}
}

impl PartialEq<u16> for Unpacked24 {
fn eq(&self, other: &u16) -> bool {
*other as i32 == self.0
}
}

unsafe impl Sample for Unpacked24 {
const FORMAT: SampleFormat = SampleFormat::I24;

#[inline]
Expand All @@ -270,7 +300,7 @@ unsafe impl Sample for Padded24 {
}

#[inline]
fn to_i24(&self) -> Padded24 {
fn to_i24(&self) -> Unpacked24 {
*self
}

Expand Down Expand Up @@ -315,7 +345,7 @@ unsafe impl Sample for i32 {

/// This function inherently returns a lossy value due to scaling.
#[inline]
fn to_i24(&self) -> Padded24 {
fn to_i24(&self) -> Unpacked24 {
self.to_f32().to_i24()
}

Expand All @@ -333,60 +363,65 @@ unsafe impl Sample for i32 {
}
}

// TODO add _to_i24 tests
#[cfg(test)]
mod test {
use super::{Padded24, Sample};
use super::{Sample, Unpacked24};

#[test]
fn i24_to_i16() {
assert_eq!(Padded24::new(Padded24::MAX).to_i16(), std::i16::MAX);
assert_eq!(Padded24::new(Padded24::MIN / 2).to_i16(), std::i16::MIN / 2);
assert_eq!(Padded24::new(Padded24::MIN).to_i16(), std::i16::MIN);
assert_eq!(Padded24::new(0).to_i16(), 0);
assert_eq!(Unpacked24::new(Unpacked24::MAX).to_i16(), std::i16::MAX);
assert_eq!(
Unpacked24::new(Unpacked24::MIN / 2).to_i16(),
std::i16::MIN / 2
);
assert_eq!(Unpacked24::new(Unpacked24::MIN).to_i16(), std::i16::MIN);
assert_eq!(Unpacked24::new(0).to_i16(), 0);
}

#[test]
fn i24_to_i24() {
// let max = Padded24::new(Padded24::MAX);
// let min = Padded24::new(Padded24::MIN);

// assert_eq!(max.to_i16(), std::i16::MAX);
// assert_eq!((std::i32::MIN / 2).to_i16(), std::i16::MIN / 2);
// assert_eq!(std::i32::MIN.to_i16(), std::i16::MIN);
// assert_eq!(0i32.to_i16(), 0);
assert_eq!(Unpacked24::new(Unpacked24::MAX).to_i24(), Unpacked24::MAX);
assert_eq!(
Unpacked24::new(Unpacked24::MIN / 2).to_i24(),
Unpacked24::MIN / 2
);
assert_eq!(Unpacked24::new(Unpacked24::MIN).to_i24(), Unpacked24::MIN);
assert_eq!(Unpacked24::new(0).to_i24(), 0i32);
}

#[test]
fn i24_to_i32() {
assert_eq!(Padded24::new(Padded24::MAX).to_i32(), std::i32::MAX);
assert_eq!(Padded24::new(Padded24::MIN / 2).to_i32(), std::i32::MIN / 2);
assert_eq!(Padded24::new(Padded24::MIN).to_i32(), std::i32::MIN);
assert_eq!(Padded24::new(0).to_i32(), 0);
assert_eq!(Unpacked24::new(Unpacked24::MAX).to_i32(), std::i32::MAX);
assert_eq!(
Unpacked24::new(Unpacked24::MIN / 2).to_i32(),
std::i32::MIN / 2
);
assert_eq!(Unpacked24::new(Unpacked24::MIN).to_i32(), std::i32::MIN);
assert_eq!(Unpacked24::new(0).to_i32(), 0);
}

#[test]
fn i24_to_u16() {
assert_eq!(Padded24::new(Padded24::MAX).to_u16(), std::u16::MAX);
assert_eq!(Unpacked24::new(Unpacked24::MAX).to_u16(), std::u16::MAX);
// half of the int max will be 3/4 of the uint max
assert_eq!(
Padded24::new(Padded24::MAX / 2).to_u16(),
Unpacked24::new(Unpacked24::MAX / 2).to_u16(),
(std::u16::MAX as f32 / 4.0 * 3.0).round() as u16
);
assert_eq!(Padded24::new(Padded24::MIN).to_u16(), std::u16::MIN);
assert_eq!(Unpacked24::new(Unpacked24::MIN).to_u16(), std::u16::MIN);
}

#[test]
fn i24_to_f32() {
let max = Padded24::new(Padded24::MAX);
let min = Padded24::new(Padded24::MIN);
let max = Unpacked24::new(Unpacked24::MAX);
let min = Unpacked24::new(Unpacked24::MIN);

assert_eq!(max.to_f32(), 1.0f32);
assert_eq!(max.to_f32() / 8.0, 0.125f32);
assert_eq!(max.to_f32() / -16.0, -0.0625f32);
assert_eq!(max.to_f32() / -4.0, -0.25f32);
assert_eq!(min.to_f32(), -1.0f32);
assert_eq!(Padded24::new(0).to_f32(), 0f32);
assert_eq!(Unpacked24::new(0).to_f32(), 0f32);
}

#[test]
Expand All @@ -397,6 +432,14 @@ mod test {
assert_eq!(0i32.to_i16(), 0);
}

#[test]
fn i32_to_i24() {
assert_eq!(std::i32::MAX.to_i24(), Unpacked24::MAX);
assert_eq!((std::i32::MIN / 2).to_i24(), Unpacked24::MIN / 2);
assert_eq!(std::i32::MIN.to_i24(), Unpacked24::MIN);
assert_eq!(0i32.to_i24(), Unpacked24::new(0));
}

#[test]
fn i32_to_i32() {
assert_eq!(std::i32::MAX.to_i32(), std::i32::MAX);
Expand Down Expand Up @@ -429,6 +472,12 @@ mod test {
assert_eq!(32767i16.to_i16(), 32767);
assert_eq!((-32768i16).to_i16(), -32768);
}
#[test]
fn i16_to_i24() {
assert_eq!(0i16.to_i24(), 0i32);
assert_eq!(i16::MIN.to_i24(), Unpacked24::MIN);
assert_eq!(i16::MAX.to_i24(), Unpacked24::MAX);
}

#[test]
fn i16_to_i32() {
Expand Down Expand Up @@ -462,6 +511,14 @@ mod test {
assert_eq!(0u16.to_i16(), -32768);
}

#[test]
fn u16_to_i24() {
assert_eq!(u16::MAX.to_i24(), Unpacked24::MAX);
assert_eq!(u16::MIN.to_i24(), Unpacked24::MIN);
assert_eq!(32768u16.to_i24(), 0i32);
assert_eq!(16384u16.to_i24(), Unpacked24::MIN / 2);
}

#[test]
fn u16_to_i32() {
assert_eq!(((std::u16::MAX as f32 / 2.0).round() as u16).to_i32(), 0);
Expand Down Expand Up @@ -492,6 +549,18 @@ mod test {
assert_eq!((-1.0f32).to_i16(), ::std::i16::MIN);
}

#[test]
fn f32_to_i24() {
assert_eq!(1.0f32.to_i24(), Unpacked24::MAX);
assert_eq!(
(0.5f32).to_i24(),
(Unpacked24::MAX as f32 / 2.0).round() as i32
);
assert_eq!(0.0f32.to_i24(), 0i32);
assert_eq!((-0.5f32).to_i24(), Unpacked24::MIN / 2);
assert_eq!((-1.0f32).to_i24(), Unpacked24::MIN);
}

#[test]
fn f32_to_i32() {
assert_eq!(1.0f32.to_i32(), std::i32::MAX);
Expand Down

0 comments on commit 161e690

Please sign in to comment.