#![allow(unused)]
use std::num::NonZeroU32;
use non_empty_slice::{NonEmptySlice, NonEmptyVec, non_empty_vec};
#[cfg(feature = "simd")]
use wide::f32x8;
use crate::{AudioSample, AudioSampleError, AudioSampleResult, ConvertTo, ParameterError};
#[cfg(feature = "simd")]
#[inline]
pub fn convert_f32_to_i16_simd(input: &[f32], output: &mut [i16]) -> AudioSampleResult<()> {
if input.len() != output.len() {
return Err(AudioSampleError::Parameter(ParameterError::invalid_value(
"slice_lengths",
"Input and output slices must have same length",
)));
}
let chunks = input.len() / 8;
let remainder = input.len() % 8;
for i in 0..chunks {
let start_idx = i * 8;
let f32_vec = f32x8::from([
input[start_idx],
input[start_idx + 1],
input[start_idx + 2],
input[start_idx + 3],
input[start_idx + 4],
input[start_idx + 5],
input[start_idx + 6],
input[start_idx + 7],
]);
let clamped = f32_vec.max(f32x8::splat(-1.0)).min(f32x8::splat(1.0));
let as_array = clamped.to_array();
for (j, &v) in as_array.iter().enumerate() {
let scaled = if v < 0.0 { v * 32768.0 } else { v * 32767.0 };
let rounded = scaled.round();
let clamped = rounded.clamp(i16::MIN as f32, i16::MAX as f32);
output[start_idx + j] = clamped as i16;
}
}
let start_remainder = chunks * 8;
for i in 0..remainder {
let v = input[start_remainder + i].clamp(-1.0, 1.0);
let scaled = if v < 0.0 { v * 32768.0 } else { v * 32767.0 };
let rounded = scaled.round();
output[start_remainder + i] = rounded.clamp(i16::MIN as f32, i16::MAX as f32) as i16;
}
Ok(())
}
#[cfg(feature = "simd")]
#[inline]
pub fn convert_i16_to_f32_simd(input: &[i16], output: &mut [f32]) -> AudioSampleResult<()> {
if input.len() != output.len() {
return Err(AudioSampleError::Parameter(ParameterError::invalid_value(
"slice_lengths",
"Input and output slices must have same length",
)));
}
let chunks = input.len() / 8;
let remainder = input.len() % 8;
for i in 0..chunks {
let start_idx = i * 8;
let f32_values = f32x8::from([
input[start_idx] as f32,
input[start_idx + 1] as f32,
input[start_idx + 2] as f32,
input[start_idx + 3] as f32,
input[start_idx + 4] as f32,
input[start_idx + 5] as f32,
input[start_idx + 6] as f32,
input[start_idx + 7] as f32,
]);
let as_array = f32_values.to_array();
for (j, &v) in as_array.iter().enumerate() {
output[start_idx + j] = if v < 0.0 { v / 32768.0 } else { v / 32767.0 };
}
}
let start_remainder = chunks * 8;
for i in 0..remainder {
let v = input[start_remainder + i] as f32;
output[start_remainder + i] = if v < 0.0 { v / 32768.0 } else { v / 32767.0 };
}
Ok(())
}
#[cfg(feature = "simd")]
#[inline]
pub fn convert_f32_to_i32_simd(input: &[f32], output: &mut [i32]) -> AudioSampleResult<()> {
if input.len() != output.len() {
return Err(AudioSampleError::Parameter(ParameterError::invalid_value(
"slice_lengths",
"Input and output slices must have same length",
)));
}
let chunks = input.len() / 8;
let remainder = input.len() % 8;
for i in 0..chunks {
let start_idx = i * 8;
let f32_vec = f32x8::from([
input[start_idx],
input[start_idx + 1],
input[start_idx + 2],
input[start_idx + 3],
input[start_idx + 4],
input[start_idx + 5],
input[start_idx + 6],
input[start_idx + 7],
]);
let clamped = f32_vec.max(f32x8::splat(-1.0)).min(f32x8::splat(1.0));
let as_array = clamped.to_array();
for (j, &v) in as_array.iter().enumerate() {
let scaled = if v < 0.0 {
v * 2147483648.0
} else {
v * 2147483647.0
};
let rounded = scaled.round();
let clamped = rounded.clamp(i32::MIN as f32, i32::MAX as f32);
output[start_idx + j] = clamped as i32;
}
}
let start_remainder = chunks * 8;
for i in 0..remainder {
let v = input[start_remainder + i].clamp(-1.0, 1.0);
let scaled = if v < 0.0 {
v * 2147483648.0
} else {
v * 2147483647.0
};
let rounded = scaled.round();
output[start_remainder + i] = rounded.clamp(i32::MIN as f32, i32::MAX as f32) as i32;
}
Ok(())
}
#[cfg(feature = "simd")]
#[inline]
pub fn convert_simd<T, U>(input: &[T], output: &mut [U]) -> AudioSampleResult<()>
where
T: AudioSample + ConvertTo<U>,
U: AudioSample,
{
use std::any::TypeId;
if TypeId::of::<T>() == TypeId::of::<f32>() && TypeId::of::<U>() == TypeId::of::<i16>() {
let input =
unsafe { std::slice::from_raw_parts(input.as_ptr() as *const f32, input.len()) };
let output = unsafe {
std::slice::from_raw_parts_mut(output.as_mut_ptr() as *mut i16, output.len())
};
return convert_f32_to_i16_simd(input, output);
}
if TypeId::of::<T>() == TypeId::of::<i16>() && TypeId::of::<U>() == TypeId::of::<f32>() {
let input =
unsafe { std::slice::from_raw_parts(input.as_ptr() as *const i16, input.len()) };
let output = unsafe {
std::slice::from_raw_parts_mut(output.as_mut_ptr() as *mut f32, output.len())
};
return convert_i16_to_f32_simd(input, output);
}
if TypeId::of::<T>() == TypeId::of::<f32>() && TypeId::of::<U>() == TypeId::of::<i32>() {
let input =
unsafe { std::slice::from_raw_parts(input.as_ptr() as *const f32, input.len()) };
let output = unsafe {
std::slice::from_raw_parts_mut(output.as_mut_ptr() as *mut i32, output.len())
};
return convert_f32_to_i32_simd(input, output);
}
for (i, o) in input.iter().zip(output.iter_mut()) {
*o = i.convert_to();
}
Ok(())
}
#[inline]
pub fn convert_scalar_unrolled<T, U>(input: &[T], output: &mut [U]) -> AudioSampleResult<()>
where
T: AudioSample + ConvertTo<U>,
U: AudioSample,
{
if input.len() != output.len() {
return Err(AudioSampleError::Parameter(ParameterError::invalid_value(
"slice_lengths",
"Input and output slices must have same length",
)));
}
let chunks = input.len() / 4;
let remainder = input.len() % 4;
for i in 0..chunks {
let base = i * 4;
output[base] = input[base].convert_to();
output[base + 1] = input[base + 1].convert_to();
output[base + 2] = input[base + 2].convert_to();
output[base + 3] = input[base + 3].convert_to();
}
let start_remainder = chunks * 4;
for i in 0..remainder {
output[start_remainder + i] = input[start_remainder + i].convert_to();
}
Ok(())
}
#[inline]
pub fn convert<T, U>(input: &[T], output: &mut [U]) -> AudioSampleResult<()>
where
T: AudioSample + ConvertTo<U>,
U: AudioSample,
{
#[cfg(feature = "simd")]
{
convert_simd(input, output)
}
#[cfg(not(feature = "simd"))]
{
convert_scalar_unrolled(input, output)
}
}
#[inline]
pub fn deinterleave_stereo<T: AudioSample>(
interleaved: &[T],
output: &mut [T],
) -> AudioSampleResult<()> {
if interleaved.len() != output.len() {
return Err(AudioSampleError::Parameter(ParameterError::invalid_value(
"slice_lengths",
"Input and output slices must have same length",
)));
}
if !interleaved.len().is_multiple_of(2) {
return Err(AudioSampleError::Parameter(ParameterError::invalid_value(
"interleaved_length",
"Interleaved stereo data must have even length",
)));
}
#[cfg(feature = "simd")]
{
Ok(deinterleave_stereo_simd(interleaved, output))
}
#[cfg(not(feature = "simd"))]
{
deinterleave_stereo_scalar(interleaved, output);
Ok(())
}
}
#[inline]
fn deinterleave_stereo_scalar<T: AudioSample>(interleaved: &[T], output: &mut [T]) {
let frames = interleaved.len() / 2;
let (left_out, right_out) = output.split_at_mut(frames);
let chunks = frames / 4;
let remainder = frames % 4;
for i in 0..chunks {
let base_frame = i * 4;
let base_interleaved = base_frame * 2;
left_out[base_frame] = interleaved[base_interleaved];
right_out[base_frame] = interleaved[base_interleaved + 1];
left_out[base_frame + 1] = interleaved[base_interleaved + 2];
right_out[base_frame + 1] = interleaved[base_interleaved + 3];
left_out[base_frame + 2] = interleaved[base_interleaved + 4];
right_out[base_frame + 2] = interleaved[base_interleaved + 5];
left_out[base_frame + 3] = interleaved[base_interleaved + 6];
right_out[base_frame + 3] = interleaved[base_interleaved + 7];
}
let start = chunks * 4;
for i in 0..remainder {
let frame_idx = start + i;
let interleaved_idx = frame_idx * 2;
left_out[frame_idx] = interleaved[interleaved_idx];
right_out[frame_idx] = interleaved[interleaved_idx + 1];
}
}
#[cfg(feature = "simd")]
fn deinterleave_stereo_simd<T: AudioSample>(interleaved: &[T], output: &mut [T]) {
use std::any::TypeId;
if TypeId::of::<T>() == TypeId::of::<f32>() {
let interleaved = unsafe {
std::slice::from_raw_parts(interleaved.as_ptr() as *const f32, interleaved.len())
};
let output = unsafe {
std::slice::from_raw_parts_mut(output.as_mut_ptr() as *mut f32, output.len())
};
return deinterleave_stereo_f32_simd(interleaved, output);
}
deinterleave_stereo_scalar(interleaved, output)
}
#[cfg(feature = "simd")]
fn deinterleave_stereo_f32_simd(interleaved: &[f32], output: &mut [f32]) {
let frames = interleaved.len() / 2;
let (left_out, right_out) = output.split_at_mut(frames);
let simd_chunks = frames / 4;
let remainder_start = simd_chunks * 4;
for i in 0..simd_chunks {
let base_frame = i * 4;
let base_interleaved = base_frame * 2;
let v = f32x8::from([
interleaved[base_interleaved],
interleaved[base_interleaved + 1],
interleaved[base_interleaved + 2],
interleaved[base_interleaved + 3],
interleaved[base_interleaved + 4],
interleaved[base_interleaved + 5],
interleaved[base_interleaved + 6],
interleaved[base_interleaved + 7],
]);
let arr = v.to_array();
left_out[base_frame] = arr[0];
left_out[base_frame + 1] = arr[2];
left_out[base_frame + 2] = arr[4];
left_out[base_frame + 3] = arr[6];
right_out[base_frame] = arr[1];
right_out[base_frame + 1] = arr[3];
right_out[base_frame + 2] = arr[5];
right_out[base_frame + 3] = arr[7];
}
for i in remainder_start..frames {
let interleaved_idx = i * 2;
left_out[i] = interleaved[interleaved_idx];
right_out[i] = interleaved[interleaved_idx + 1];
}
}
#[inline]
pub fn deinterleave_multi<T: AudioSample>(
interleaved: &NonEmptySlice<T>,
output: &mut NonEmptySlice<T>,
num_channels: NonZeroU32,
) -> AudioSampleResult<()> {
if interleaved.len() != output.len() {
return Err(AudioSampleError::Parameter(ParameterError::invalid_value(
"slice_lengths",
"Input and output slices must have same length",
)));
}
if !interleaved
.len()
.get()
.is_multiple_of(num_channels.get() as usize)
{
return Err(AudioSampleError::Parameter(ParameterError::invalid_value(
"interleaved_length",
"Interleaved data length must be divisible by channel count",
)));
}
if num_channels.get() == 2 {
return deinterleave_stereo(interleaved, output);
}
deinterleave_multi_scalar(interleaved, output, num_channels);
Ok(())
}
fn deinterleave_multi_scalar<T: AudioSample>(
interleaved: &NonEmptySlice<T>,
output: &mut NonEmptySlice<T>,
num_channels: NonZeroU32,
) {
let frames = interleaved.len().get() / num_channels.get() as usize;
for ch in 0..num_channels.get() as usize {
let out_start = ch * frames;
let out_slice = &mut output[out_start..out_start + frames];
for frame in 0..frames {
out_slice[frame] = interleaved[frame * num_channels.get() as usize + ch];
}
}
}
#[inline]
pub fn interleave_stereo<T: AudioSample>(planar: &[T], output: &mut [T]) -> AudioSampleResult<()> {
if planar.len() != output.len() {
return Err(AudioSampleError::Parameter(ParameterError::invalid_value(
"slice_lengths",
"Input and output slices must have same length",
)));
}
if !planar.len().is_multiple_of(2) {
return Err(AudioSampleError::Parameter(ParameterError::invalid_value(
"planar_length",
"Planar stereo data must have even length",
)));
}
#[cfg(feature = "simd")]
{
Ok(interleave_stereo_simd(planar, output))
}
#[cfg(not(feature = "simd"))]
{
interleave_stereo_scalar(planar, output);
Ok(())
}
}
#[inline]
fn interleave_stereo_scalar<T: AudioSample>(planar: &[T], output: &mut [T]) {
let frames = planar.len() / 2;
let (left_in, right_in) = planar.split_at(frames);
let chunks = frames / 4;
let remainder = frames % 4;
for i in 0..chunks {
let base_frame = i * 4;
let base_interleaved = base_frame * 2;
output[base_interleaved] = left_in[base_frame];
output[base_interleaved + 1] = right_in[base_frame];
output[base_interleaved + 2] = left_in[base_frame + 1];
output[base_interleaved + 3] = right_in[base_frame + 1];
output[base_interleaved + 4] = left_in[base_frame + 2];
output[base_interleaved + 5] = right_in[base_frame + 2];
output[base_interleaved + 6] = left_in[base_frame + 3];
output[base_interleaved + 7] = right_in[base_frame + 3];
}
let start = chunks * 4;
for i in 0..remainder {
let frame_idx = start + i;
let interleaved_idx = frame_idx * 2;
output[interleaved_idx] = left_in[frame_idx];
output[interleaved_idx + 1] = right_in[frame_idx];
}
}
#[cfg(feature = "simd")]
fn interleave_stereo_simd<T: AudioSample>(planar: &[T], output: &mut [T]) {
use std::any::TypeId;
if TypeId::of::<T>() == TypeId::of::<f32>() {
let planar =
unsafe { std::slice::from_raw_parts(planar.as_ptr() as *const f32, planar.len()) };
let output = unsafe {
std::slice::from_raw_parts_mut(output.as_mut_ptr() as *mut f32, output.len())
};
return interleave_stereo_f32_simd(planar, output);
}
interleave_stereo_scalar(planar, output)
}
#[cfg(feature = "simd")]
fn interleave_stereo_f32_simd(planar: &[f32], output: &mut [f32]) {
let frames = planar.len() / 2;
let (left_in, right_in) = planar.split_at(frames);
let simd_chunks = frames / 4;
let remainder_start = simd_chunks * 4;
for i in 0..simd_chunks {
let base_frame = i * 4;
let base_interleaved = base_frame * 2;
let l0 = left_in[base_frame];
let l1 = left_in[base_frame + 1];
let l2 = left_in[base_frame + 2];
let l3 = left_in[base_frame + 3];
let r0 = right_in[base_frame];
let r1 = right_in[base_frame + 1];
let r2 = right_in[base_frame + 2];
let r3 = right_in[base_frame + 3];
let interleaved = f32x8::from([l0, r0, l1, r1, l2, r2, l3, r3]);
let arr = interleaved.to_array();
output[base_interleaved] = arr[0];
output[base_interleaved + 1] = arr[1];
output[base_interleaved + 2] = arr[2];
output[base_interleaved + 3] = arr[3];
output[base_interleaved + 4] = arr[4];
output[base_interleaved + 5] = arr[5];
output[base_interleaved + 6] = arr[6];
output[base_interleaved + 7] = arr[7];
}
for i in remainder_start..frames {
let interleaved_idx = i * 2;
output[interleaved_idx] = left_in[i];
output[interleaved_idx + 1] = right_in[i];
}
}
#[inline]
pub fn interleave_multi<T: AudioSample>(
planar: &NonEmptySlice<T>,
output: &mut NonEmptySlice<T>,
num_channels: NonZeroU32,
) -> AudioSampleResult<()> {
if planar.len() != output.len() {
return Err(AudioSampleError::Parameter(ParameterError::invalid_value(
"slice_lengths",
"Input and output slices must have same length",
)));
}
if !planar
.len()
.get()
.is_multiple_of(num_channels.get() as usize)
{
return Err(AudioSampleError::Parameter(ParameterError::invalid_value(
"planar_length",
"Planar data length must be divisible by channel count",
)));
}
if num_channels.get() == 2 {
return interleave_stereo(planar, output);
}
interleave_multi_scalar(planar, output, num_channels);
Ok(())
}
fn interleave_multi_scalar<T: AudioSample>(
planar: &NonEmptySlice<T>,
output: &mut NonEmptySlice<T>,
num_channels: NonZeroU32,
) {
let frames = planar.len().get() / num_channels.get() as usize;
for frame in 0..frames {
let out_base = frame * num_channels.get() as usize;
for ch in 0..num_channels.get() as usize {
let in_idx = ch * frames + frame;
output[out_base + ch] = planar[in_idx];
}
}
}
#[inline]
pub fn deinterleave_stereo_vec<T: AudioSample>(
interleaved: &NonEmptyVec<T>,
) -> AudioSampleResult<NonEmptyVec<T>> {
if !interleaved.len().get().is_multiple_of(2) {
return Err(AudioSampleError::Parameter(ParameterError::invalid_value(
"interleaved_length",
"Interleaved stereo data must have even length",
)));
}
let mut output = non_empty_vec![T::default(); interleaved.len()];
deinterleave_stereo(interleaved, &mut output)?;
Ok(output)
}
#[inline]
pub fn deinterleave_multi_vec<T: AudioSample>(
interleaved: &NonEmptySlice<T>,
num_channels: NonZeroU32,
) -> AudioSampleResult<NonEmptyVec<T>> {
if !interleaved
.len()
.get()
.is_multiple_of(num_channels.get() as usize)
{
return Err(AudioSampleError::Parameter(ParameterError::invalid_value(
"interleaved_length",
"Interleaved data length must be divisible by channel count",
)));
}
let mut output = non_empty_vec![T::default(); interleaved.len()];
deinterleave_multi(interleaved, &mut output, num_channels)?;
Ok(output)
}
#[inline]
pub fn interleave_stereo_vec<T: AudioSample>(
planar: &NonEmptyVec<T>,
) -> AudioSampleResult<NonEmptyVec<T>> {
if !planar.len().get().is_multiple_of(2) {
return Err(AudioSampleError::Parameter(ParameterError::invalid_value(
"planar_length",
"Planar stereo data must have even length",
)));
}
let mut output = non_empty_vec![T::default(); planar.len()];
interleave_stereo(planar, &mut output)?;
Ok(output)
}
#[inline]
pub fn interleave_multi_vec<T: AudioSample>(
planar: &NonEmptyVec<T>,
num_channels: NonZeroU32,
) -> AudioSampleResult<NonEmptyVec<T>> {
if !planar
.len()
.get()
.is_multiple_of(num_channels.get() as usize)
{
return Err(AudioSampleError::Parameter(ParameterError::invalid_value(
"planar_length",
"Planar data length must be divisible by channel count",
)));
}
let mut output = non_empty_vec![T::default(); planar.len()];
interleave_multi(planar, &mut output, num_channels)?;
Ok(output)
}
#[cfg(test)]
mod tests {
use non_empty_iter::TryIntoNonEmptyIterator;
use super::*;
#[test]
fn test_scalar_conversion() {
let _input = non_empty_vec![0.5f32, -0.3, 0.8, 1.0, -1.0];
let mut _output = non_empty_vec![0i16; crate::nzu!(5)];
#[cfg(not(feature = "simd"))]
{
convert_scalar_unrolled(&_input, &mut _output).unwrap();
let expected0: i16 = 0.5f32.convert_to();
let expected1: i16 = (-0.3f32).convert_to();
let expected4: i16 = (-1.0f32).convert_to();
assert_eq!(_output[0], expected0);
assert_eq!(_output[1], expected1);
assert_eq!(_output[4], expected4);
}
}
#[cfg(feature = "simd")]
#[test]
fn test_simd_f32_to_i16_conversion() {
let input = non_empty_vec![0.5f32, -0.3, 0.8, 1.0, -1.0, 0.0, 0.1, -0.1, 0.25];
let mut output = non_empty_vec![0i16; 9];
convert_f32_to_i16_simd(&input, &mut output).unwrap();
let expected0: i16 = input[0].convert_to();
let expected1: i16 = input[1].convert_to();
let expected8: i16 = input[8].convert_to();
assert_eq!(output[0], expected0);
assert_eq!(output[1], expected1);
assert_eq!(output[8], expected8); }
#[cfg(feature = "simd")]
#[test]
fn test_simd_i16_to_f32_conversion() {
let input = non_empty_vec![16383i16, -9830, 26214, 32767, -32768, 0, 3276, -3276];
let mut output = non_empty_vec![0.0f32; 8];
convert_i16_to_f32_simd(&input, &mut output).unwrap();
use approx_eq::assert_approx_eq;
let expected0: f32 = input[0].convert_to();
let expected1: f32 = input[1].convert_to();
let expected3: f32 = input[3].convert_to();
assert_approx_eq!(output[0] as f64, expected0 as f64, 1e-5);
assert_approx_eq!(output[1] as f64, expected1 as f64, 1e-5);
assert_approx_eq!(output[3] as f64, expected3 as f64, 1e-5);
}
#[test]
fn test_optimized_conversion_dispatch() {
let input = non_empty_vec![0.5f32, -0.3, 0.8];
let mut output = non_empty_vec![0i16; crate::nzu!(3)];
convert(&input, &mut output).unwrap();
assert_eq!(output.len().get(), 3);
let expected0: i16 = input[0].convert_to();
assert_eq!(output[0], expected0);
}
#[test]
fn test_deinterleave_stereo_f32() {
let interleaved = vec![0.1f32, 0.5, 0.2, 0.6, 0.3, 0.7, 0.4, 0.8];
let mut output = vec![0.0f32; 8];
deinterleave_stereo(&interleaved, &mut output).unwrap();
assert_eq!(output[0], 0.1); assert_eq!(output[1], 0.2); assert_eq!(output[2], 0.3); assert_eq!(output[3], 0.4); assert_eq!(output[4], 0.5); assert_eq!(output[5], 0.6); assert_eq!(output[6], 0.7); assert_eq!(output[7], 0.8); }
#[test]
fn test_deinterleave_stereo_i16() {
let interleaved = vec![100i16, 200, 300, 400, 500, 600];
let mut output = vec![0i16; 6];
deinterleave_stereo(&interleaved, &mut output).unwrap();
assert_eq!(output[0], 100); assert_eq!(output[1], 300); assert_eq!(output[2], 500); assert_eq!(output[3], 200); assert_eq!(output[4], 400); assert_eq!(output[5], 600); }
#[test]
fn test_deinterleave_stereo_remainder() {
let interleaved = vec![1.0f32, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0];
let mut output = vec![0.0f32; 10];
deinterleave_stereo(&interleaved, &mut output).unwrap();
assert_eq!(&output[0..5], &[1.0, 3.0, 5.0, 7.0, 9.0]);
assert_eq!(&output[5..10], &[2.0, 4.0, 6.0, 8.0, 10.0]);
}
#[test]
fn test_deinterleave_multi_3ch() {
let interleaved = non_empty_vec![1.0f32, 2.0, 3.0, 4.0, 5.0, 6.0];
let mut output = non_empty_vec![0.0f32; crate::nzu!(6)];
deinterleave_multi(&interleaved, &mut output, NonZeroU32::new(3).unwrap());
assert_eq!(output[0], 1.0); assert_eq!(output[1], 4.0); assert_eq!(output[2], 2.0); assert_eq!(output[3], 5.0); assert_eq!(output[4], 3.0); assert_eq!(output[5], 6.0); }
#[test]
fn test_deinterleave_multi_6ch() {
let interleaved: Vec<f32> = (1..=12).map(|x| x as f32).collect();
let interleaved = NonEmptyVec::new(interleaved).unwrap();
let mut output = non_empty_vec![0.0f32; crate::nzu!(12)];
deinterleave_multi(&interleaved, &mut output, NonZeroU32::new(6).unwrap()).unwrap();
assert_eq!(&output[0..2], &[1.0, 7.0]); assert_eq!(&output[2..4], &[2.0, 8.0]); assert_eq!(&output[4..6], &[3.0, 9.0]); assert_eq!(&output[6..8], &[4.0, 10.0]); assert_eq!(&output[8..10], &[5.0, 11.0]); assert_eq!(&output[10..12], &[6.0, 12.0]); }
#[test]
fn test_interleave_stereo_f32() {
let planar = non_empty_vec![0.1f32, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8];
let mut output = non_empty_vec![0.0f32; crate::nzu!(8)];
interleave_stereo(&planar, &mut output).unwrap();
assert_eq!(output[0], 0.1); assert_eq!(output[1], 0.5); assert_eq!(output[2], 0.2); assert_eq!(output[3], 0.6); assert_eq!(output[4], 0.3); assert_eq!(output[5], 0.7); assert_eq!(output[6], 0.4); assert_eq!(output[7], 0.8); }
#[test]
fn test_interleave_stereo_i16() {
let planar = non_empty_vec![100i16, 300, 500, 200, 400, 600];
let mut output = non_empty_vec![0i16; crate::nzu!(6)];
interleave_stereo(&planar, &mut output).unwrap();
assert_eq!(output[0], 100); assert_eq!(output[1], 200); assert_eq!(output[2], 300); assert_eq!(output[3], 400); assert_eq!(output[4], 500); assert_eq!(output[5], 600); }
#[test]
fn test_interleave_multi_3ch() {
let planar = non_empty_vec![1.0f32, 4.0, 2.0, 5.0, 3.0, 6.0];
let mut output = non_empty_vec![0.0f32; crate::nzu!(6)];
interleave_multi(&planar, &mut output, NonZeroU32::new(3).unwrap()).unwrap();
assert_eq!(output[0], 1.0); assert_eq!(output[1], 2.0); assert_eq!(output[2], 3.0); assert_eq!(output[3], 4.0); assert_eq!(output[4], 5.0); assert_eq!(output[5], 6.0); }
#[test]
fn test_stereo_roundtrip_f32() {
let original = vec![1.0f32, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0];
let mut deinterleaved = vec![0.0f32; 8];
let mut reinterleaved = vec![0.0f32; 8];
deinterleave_stereo(&original, &mut deinterleaved).unwrap();
interleave_stereo(&deinterleaved, &mut reinterleaved).unwrap();
assert_eq!(original, reinterleaved);
}
#[test]
fn test_stereo_roundtrip_i16() {
let original: Vec<i16> = (1..=16).map(|x| x as i16 * 100).collect();
let mut deinterleaved = vec![0i16; 16];
let mut reinterleaved = vec![0i16; 16];
deinterleave_stereo(&original, &mut deinterleaved).unwrap();
interleave_stereo(&deinterleaved, &mut reinterleaved).unwrap();
assert_eq!(original, reinterleaved);
}
#[test]
fn test_multi_roundtrip_6ch() {
let original: Vec<f32> = (1..=60).map(|x| x as f32).collect(); let original = NonEmptyVec::new(original).unwrap();
let mut deinterleaved = non_empty_vec![0.0f32; crate::nzu!(60)];
let mut reinterleaved = non_empty_vec![0.0f32; crate::nzu!(60)];
let num_channels = NonZeroU32::new(6).unwrap();
deinterleave_multi(&original, &mut deinterleaved, num_channels).unwrap();
interleave_multi(&deinterleaved, &mut reinterleaved, num_channels).unwrap();
assert_eq!(original, reinterleaved);
}
#[test]
fn test_deinterleave_stereo_vec_fn() {
let interleaved = non_empty_vec![1.0f32, 2.0, 3.0, 4.0];
let planar = deinterleave_stereo_vec(&interleaved).unwrap();
assert_eq!(planar, non_empty_vec![1.0, 3.0, 2.0, 4.0]);
}
#[test]
fn test_interleave_stereo_vec_fn() {
let planar = non_empty_vec![1.0f32, 3.0, 2.0, 4.0];
let interleaved = interleave_stereo_vec(&planar).unwrap();
assert_eq!(interleaved, non_empty_vec![1.0, 2.0, 3.0, 4.0]);
}
#[test]
fn test_deinterleave_stereo_length_mismatch() {
let interleaved = non_empty_vec![1.0f32, 2.0, 3.0, 4.0];
let mut output = non_empty_vec![0.0f32; crate::nzu!(2)];
let result = deinterleave_stereo(&interleaved, &mut output);
assert!(result.is_err());
}
#[test]
fn test_deinterleave_stereo_odd_length() {
let interleaved = non_empty_vec![1.0f32, 2.0, 3.0]; let mut output = non_empty_vec![0.0f32; crate::nzu!(3)];
let result = deinterleave_stereo(&interleaved, &mut output);
assert!(result.is_err());
}
#[test]
fn test_deinterleave_multi_not_divisible() {
let interleaved = non_empty_vec![1.0f32, 2.0, 3.0, 4.0, 5.0]; let mut output = non_empty_vec![0.0f32; crate::nzu!(5)];
let result = deinterleave_multi(&interleaved, &mut output, NonZeroU32::new(3).unwrap());
assert!(result.is_err());
}
}