use crate::{AudioSamples, AudioTypeConversion, CastInto, ConvertTo, traits::StandardSample};
impl<T> AudioTypeConversion for AudioSamples<'_, T>
where
T: StandardSample,
{
type Sample = T;
#[inline]
fn to_format<O>(&self) -> AudioSamples<'static, O>
where
T: ConvertTo<O>,
O: StandardSample,
{
self.map_into(T::convert_to)
}
#[inline]
fn to_type<O>(self) -> AudioSamples<'static, O>
where
T: ConvertTo<O>,
O: StandardSample,
{
self.map_into(T::convert_to)
}
#[inline]
fn cast_as<O>(&self) -> AudioSamples<'static, O>
where
T: CastInto<O> + ConvertTo<O>,
O: StandardSample,
{
self.map_into(T::cast_into)
}
#[inline]
fn cast_to<O>(self) -> AudioSamples<'static, O>
where
T: CastInto<O> + ConvertTo<O>,
O: StandardSample,
{
self.map_into(T::cast_into)
}
}
#[cfg(test)]
mod tests {
use std::num::NonZeroUsize;
use super::*;
use crate::{channels, sample_rate};
use approx_eq::assert_approx_eq;
use ndarray::array;
#[test]
fn test_mono_f32_to_i16_conversion() {
let data = array![0.5f32, -0.3, 0.0, 1.0, -1.0];
let audio_f32 = AudioSamples::new_mono(data, sample_rate!(44100)).unwrap();
let audio_i16 = audio_f32.to_format::<i16>();
assert_eq!(audio_i16.sample_rate(), sample_rate!(44100));
assert_eq!(audio_i16.num_channels(), channels!(1));
assert_eq!(
audio_i16.samples_per_channel(),
NonZeroUsize::new(5).unwrap()
);
let converted_data = audio_i16;
assert!(
(converted_data[0] - 16383).abs() <= 1,
"Expected ~16383±1, got {}",
converted_data[0]
);
assert_eq!(converted_data[2], 0); assert_eq!(converted_data[3], 32767); assert!(
converted_data[4] <= -32767,
"Expected <= -32767, got {}",
converted_data[4]
);
}
#[test]
fn test_multi_channel_i16_to_f32_conversion() {
let data = array![[16384i16, 32767, 0], [-16384, -32768, 8192]];
let audio_i16 = AudioSamples::new_multi_channel(data, sample_rate!(48000)).unwrap();
let audio_f32 = audio_i16.to_format::<f32>();
assert_eq!(audio_f32.sample_rate(), sample_rate!(48000));
assert_eq!(audio_f32.num_channels(), channels!(2));
assert_eq!(
audio_f32.samples_per_channel(),
NonZeroUsize::new(3).unwrap()
);
let converted_data = audio_f32;
assert_approx_eq!(converted_data[[0, 0]] as f64, 0.5, 1e-4); assert_approx_eq!(converted_data[[0, 1]] as f64, 1.0, 1e-4); assert_approx_eq!(converted_data[[0, 2]] as f64, 0.0, 1e-10); assert_approx_eq!(converted_data[[1, 0]] as f64, -0.5, 1e-4); assert_approx_eq!(converted_data[[1, 1]] as f64, -1.0, 1e-4); assert_approx_eq!(converted_data[[1, 2]] as f64, 0.25, 1e-4); }
#[test]
fn test_consuming_conversion() {
let data = array![0.1f32, 0.2, 0.3];
let audio_f32 = AudioSamples::new_mono(data, sample_rate!(44100)).unwrap();
let audio_i16 = audio_f32.to_type::<i16>();
assert_eq!(audio_i16.num_channels(), channels!(1));
assert_eq!(
audio_i16.samples_per_channel(),
NonZeroUsize::new(3).unwrap()
);
let converted_data = audio_i16;
assert_eq!(converted_data[0], 3276); assert_eq!(converted_data[1], 6553); assert_eq!(converted_data[2], 9830); }
#[test]
fn test_convenience_methods() {
let data = array![100i16, -200, 300];
let audio_i16 = AudioSamples::new_mono(data, sample_rate!(44100)).unwrap();
let audio_f32 = audio_i16.as_f32();
let audio_f64 = audio_i16.as_f64();
let audio_i32 = audio_i16.as_i32();
assert_eq!(audio_f32.num_channels(), channels!(1));
assert_eq!(audio_f64.num_channels(), channels!(1));
assert_eq!(audio_i32.num_channels(), channels!(1));
assert_eq!(audio_f32.sample_rate(), sample_rate!(44100));
assert_eq!(audio_f64.sample_rate(), sample_rate!(44100));
assert_eq!(audio_i32.sample_rate(), sample_rate!(44100));
}
#[test]
fn test_round_trip_conversion() {
let original_data = array![0.123f32, -0.456, 0.789, -0.999, 0.0];
let audio_original =
AudioSamples::new_mono(original_data.clone(), sample_rate!(44100)).unwrap();
let audio_i16 = audio_original.to_format::<i16>();
let audio_round_trip = audio_i16.to_format::<f32>();
assert_eq!(audio_round_trip.num_channels(), channels!(1));
assert_eq!(
audio_round_trip.samples_per_channel(),
NonZeroUsize::new(5).unwrap()
);
assert_eq!(audio_round_trip.sample_rate(), sample_rate!(44100));
let round_trip_data = audio_round_trip.as_mono().unwrap();
for (original, round_trip) in original_data.iter().zip(round_trip_data.iter()) {
assert_approx_eq!(*original as f64, *round_trip as f64, 5e-4); }
}
#[test]
fn test_edge_cases() {
let data = array![f32::MAX, f32::MIN, 0.0f32];
let audio_f32 = AudioSamples::new_mono(data, sample_rate!(44100)).unwrap();
let audio_i16 = audio_f32.to_format::<i16>();
let converted_data = audio_i16.as_mono().unwrap();
assert_eq!(converted_data[0], i16::MAX);
assert_eq!(converted_data[1], -32767i16);
assert_eq!(converted_data[2], 0);
}
}