#[cfg(feature = "wav")]
mod wav_reference {
const REF_16BIT_MONO: &[u8] = include_bytes!("reference/ref_44100_16bit_mono.wav");
const REF_24BIT_MONO: &[u8] = include_bytes!("reference/ref_48000_24bit_mono.wav");
const REF_16BIT_STEREO: &[u8] = include_bytes!("reference/ref_44100_16bit_stereo.wav");
const REF_F32_MONO: &[u8] = include_bytes!("reference/ref_44100_f32_mono.wav");
#[test]
fn wav_16bit_mono_format() {
let (info, samples) = shravan::wav::decode(REF_16BIT_MONO).unwrap();
assert_eq!(info.format, shravan::AudioFormat::Wav);
assert_eq!(info.sample_rate, 44100);
assert_eq!(info.channels, 1);
assert_eq!(info.bit_depth, 16);
assert_eq!(samples.len(), 4410); assert!(samples.iter().all(|s| s.is_finite()));
assert!(samples.iter().all(|s| s.abs() <= 1.0));
let rms = rms(&samples);
assert!(rms > 0.05, "RMS {rms} too low for a sine wave");
assert!(rms < 0.9, "RMS {rms} too high");
}
#[test]
fn wav_24bit_mono_format() {
let (info, samples) = shravan::wav::decode(REF_24BIT_MONO).unwrap();
assert_eq!(info.sample_rate, 48000);
assert_eq!(info.bit_depth, 24);
assert_eq!(samples.len(), 4800); let rms = rms(&samples);
assert!(rms > 0.05 && rms < 0.9, "RMS {rms} out of range");
}
#[test]
fn wav_16bit_stereo_format() {
let (info, samples) = shravan::wav::decode(REF_16BIT_STEREO).unwrap();
assert_eq!(info.channels, 2);
assert_eq!(samples.len(), 8820); }
#[test]
fn wav_f32_mono_format() {
let (info, samples) = shravan::wav::decode(REF_F32_MONO).unwrap();
assert_eq!(info.bit_depth, 32);
assert_eq!(samples.len(), 4410);
let rms = rms(&samples);
assert!(rms > 0.05 && rms < 0.9, "RMS {rms} out of range");
}
#[test]
fn wav_cross_format_consistency() {
let (_, samples_16) = shravan::wav::decode(REF_16BIT_MONO).unwrap();
let (_, samples_f32) = shravan::wav::decode(REF_F32_MONO).unwrap();
assert_eq!(samples_16.len(), samples_f32.len());
let max_diff: f32 = samples_16
.iter()
.zip(samples_f32.iter())
.map(|(a, b)| (a - b).abs())
.fold(0.0f32, f32::max);
assert!(
max_diff < 0.001,
"Max diff between 16-bit and f32: {max_diff}"
);
}
#[cfg(all(feature = "wav", feature = "pcm"))]
#[test]
fn wav_encode_decode_matches_reference() {
let (info, original) = shravan::wav::decode(REF_16BIT_MONO).unwrap();
let re_encoded = shravan::wav::encode(
&original,
info.sample_rate,
info.channels,
shravan::pcm::PcmFormat::I16,
)
.unwrap();
let (_, re_decoded) = shravan::wav::decode(&re_encoded).unwrap();
assert_eq!(original.len(), re_decoded.len());
for (a, b) in original.iter().zip(re_decoded.iter()) {
assert!((a - b).abs() < 0.001, "Re-encode mismatch: {a} vs {b}");
}
}
fn rms(samples: &[f32]) -> f32 {
let sum: f64 = samples.iter().map(|&s| (s as f64) * (s as f64)).sum();
libm::sqrt(sum / samples.len() as f64) as f32
}
}
#[cfg(feature = "flac")]
mod flac_reference {
const REF_16BIT_MONO: &[u8] = include_bytes!("reference/ref_44100_16bit_mono.flac");
const REF_24BIT_MONO: &[u8] = include_bytes!("reference/ref_48000_24bit_mono.flac");
const REF_16BIT_STEREO: &[u8] = include_bytes!("reference/ref_44100_16bit_stereo.flac");
#[test]
fn flac_16bit_mono_format() {
let (info, samples) = shravan::flac::decode(REF_16BIT_MONO).unwrap();
assert_eq!(info.format, shravan::AudioFormat::Flac);
assert_eq!(info.sample_rate, 44100);
assert_eq!(info.channels, 1);
assert_eq!(info.bit_depth, 16);
assert_eq!(samples.len(), 4410);
assert!(samples.iter().all(|s| s.is_finite()));
let rms = rms(&samples);
assert!(rms > 0.05 && rms < 0.9, "RMS {rms} out of range");
}
#[test]
fn flac_24bit_mono_format() {
let (info, samples) = shravan::flac::decode(REF_24BIT_MONO).unwrap();
assert_eq!(info.sample_rate, 48000);
assert_eq!(info.bit_depth, 24);
assert_eq!(samples.len(), 4800);
let rms = rms(&samples);
assert!(rms > 0.05 && rms < 0.9, "RMS {rms} out of range");
}
#[test]
fn flac_16bit_stereo_format() {
let (info, samples) = shravan::flac::decode(REF_16BIT_STEREO).unwrap();
assert_eq!(info.channels, 2);
assert_eq!(samples.len(), 8820);
}
#[test]
fn flac_wav_cross_decode_consistency() {
let wav_data = include_bytes!("reference/ref_44100_16bit_mono.wav");
let (_, wav_samples) = shravan::wav::decode(wav_data).unwrap();
let (_, flac_samples) = shravan::flac::decode(REF_16BIT_MONO).unwrap();
assert_eq!(wav_samples.len(), flac_samples.len());
let max_diff: f32 = wav_samples
.iter()
.zip(flac_samples.iter())
.map(|(a, b)| (a - b).abs())
.fold(0.0f32, f32::max);
assert!(max_diff < 0.0001, "WAV vs FLAC max diff: {max_diff}");
}
#[cfg(feature = "flac")]
#[test]
fn flac_encode_decode_roundtrip_vs_reference() {
let (info, original) = shravan::flac::decode(REF_16BIT_MONO).unwrap();
let re_encoded = shravan::flac::encode(
&original,
info.sample_rate,
info.channels,
info.bit_depth as u8,
)
.unwrap();
let (_, re_decoded) = shravan::flac::decode(&re_encoded).unwrap();
assert_eq!(original.len(), re_decoded.len());
let max_diff: f32 = original
.iter()
.zip(re_decoded.iter())
.map(|(a, b)| (a - b).abs())
.fold(0.0f32, f32::max);
assert!(
max_diff < 0.0001,
"FLAC re-encode roundtrip max diff: {max_diff}"
);
}
fn rms(samples: &[f32]) -> f32 {
let sum: f64 = samples.iter().map(|&s| (s as f64) * (s as f64)).sum();
libm::sqrt(sum / samples.len() as f64) as f32
}
}
#[cfg(feature = "aiff")]
mod aiff_reference {
const REF_16BIT_MONO: &[u8] = include_bytes!("reference/ref_44100_16bit_mono.aiff");
#[test]
fn aiff_16bit_mono_format() {
let (info, samples) = shravan::aiff::decode(REF_16BIT_MONO).unwrap();
assert_eq!(info.format, shravan::AudioFormat::Aiff);
assert_eq!(info.sample_rate, 44100);
assert_eq!(info.channels, 1);
assert_eq!(info.bit_depth, 16);
assert_eq!(samples.len(), 4410);
let rms = rms(&samples);
assert!(rms > 0.05 && rms < 0.9, "RMS {rms} out of range");
}
#[test]
fn aiff_wav_cross_decode_consistency() {
let wav_data = include_bytes!("reference/ref_44100_16bit_mono.wav");
let (_, wav_samples) = shravan::wav::decode(wav_data).unwrap();
let (_, aiff_samples) = shravan::aiff::decode(REF_16BIT_MONO).unwrap();
assert_eq!(wav_samples.len(), aiff_samples.len());
let max_diff: f32 = wav_samples
.iter()
.zip(aiff_samples.iter())
.map(|(a, b)| (a - b).abs())
.fold(0.0f32, f32::max);
assert!(max_diff < 0.0001, "WAV vs AIFF max diff: {max_diff}");
}
fn rms(samples: &[f32]) -> f32 {
let sum: f64 = samples.iter().map(|&s| (s as f64) * (s as f64)).sum();
libm::sqrt(sum / samples.len() as f64) as f32
}
}
#[cfg(feature = "wav")]
#[test]
fn codec_open_reference_wav() {
let data = include_bytes!("reference/ref_44100_16bit_mono.wav");
let (info, samples) = shravan::codec::open(data).unwrap();
assert_eq!(info.format, shravan::AudioFormat::Wav);
assert_eq!(samples.len(), 4410);
}
#[cfg(feature = "flac")]
#[test]
fn codec_open_reference_flac() {
let data = include_bytes!("reference/ref_44100_16bit_mono.flac");
let (info, samples) = shravan::codec::open(data).unwrap();
assert_eq!(info.format, shravan::AudioFormat::Flac);
assert_eq!(samples.len(), 4410);
}
#[cfg(feature = "aiff")]
#[test]
fn codec_open_reference_aiff() {
let data = include_bytes!("reference/ref_44100_16bit_mono.aiff");
let (info, samples) = shravan::codec::open(data).unwrap();
assert_eq!(info.format, shravan::AudioFormat::Aiff);
assert_eq!(samples.len(), 4410);
}