#![allow(dead_code)]
pub mod json;
pub mod sha256;
use std::io::Cursor;
use json::Json;
use wav_codec::{SampleFormat, WavReader, WavSpec};
pub use sha256::sha256_hex;
pub fn manifest() -> Json {
json::parse(include_str!("../conformance-vectors.json"))
}
pub fn vectors() -> Vec<Json> {
manifest().field("vectors").as_array().to_vec()
}
pub fn vector(id: &str) -> Json {
vectors()
.into_iter()
.find(|v| v.field("id").as_str() == id)
.unwrap_or_else(|| panic!("no vector {}", id))
}
pub fn fixture_path(rel: &str) -> String {
format!("{}/tests/{}", env!("CARGO_MANIFEST_DIR"), rel)
}
pub fn fixture_bytes(v: &Json) -> Vec<u8> {
let rel = v.field("file").as_str();
let bytes = if v.field("kind").as_str() == "perf" {
perf_fixture()
} else {
std::fs::read(fixture_path(rel)).unwrap_or_else(|e| panic!("read {}: {}", rel, e))
};
assert_eq!(
bytes.len() as u64,
v.field("len").as_u64(),
"{} length",
rel
);
assert_eq!(
sha256_hex(&bytes),
v.field("sha256").as_str(),
"{} sha256",
rel
);
bytes
}
pub fn open(bytes: &[u8]) -> wav_codec::Result<WavReader<Cursor<&[u8]>>> {
WavReader::new(Cursor::new(bytes))
}
pub fn expected_spec(v: &Json) -> WavSpec {
let s = v.field("spec");
WavSpec {
channels: s.field("channels").as_u64() as u16,
sample_rate: s.field("sample_rate").as_u64() as u32,
bits_per_sample: s.field("bits_per_sample").as_u64() as u16,
sample_format: match s.field("sample_format").as_str() {
"int" => SampleFormat::Int,
"float" => SampleFormat::Float,
other => panic!("unknown sample_format {}", other),
},
}
}
#[derive(Clone, Debug, PartialEq)]
pub enum Expected {
I8(Vec<i8>),
I16(Vec<i16>),
I32(Vec<i32>),
F32(Vec<u32>),
F64(Vec<u64>),
}
impl Expected {
pub fn len(&self) -> usize {
match self {
Expected::I8(v) => v.len(),
Expected::I16(v) => v.len(),
Expected::I32(v) => v.len(),
Expected::F32(v) => v.len(),
Expected::F64(v) => v.len(),
}
}
}
pub fn expected_samples(v: &Json) -> Option<Expected> {
let e = v.get("expect")?;
if let Some(a) = e.get("samples_u8") {
let out = a
.as_array()
.iter()
.map(|x| (x.as_i64() - 128) as i8)
.collect();
return Some(Expected::I8(out));
}
if let Some(a) = e.get("samples_i16") {
return Some(Expected::I16(
a.as_array().iter().map(|x| x.as_i64() as i16).collect(),
));
}
if let Some(a) = e.get("samples_i32") {
return Some(Expected::I32(
a.as_array().iter().map(|x| x.as_i64() as i32).collect(),
));
}
if let Some(a) = e.get("samples_f32_lebits") {
return Some(Expected::F32(
a.as_array()
.iter()
.map(|x| u32::from_le_bytes(hex_bytes(x.as_str()).try_into().unwrap()))
.collect(),
));
}
if let Some(a) = e.get("samples_f64_lebits") {
return Some(Expected::F64(
a.as_array()
.iter()
.map(|x| u64::from_le_bytes(hex_bytes(x.as_str()).try_into().unwrap()))
.collect(),
));
}
None
}
pub fn hex_bytes(hex: &str) -> Vec<u8> {
(0..hex.len())
.step_by(2)
.map(|i| u8::from_str_radix(&hex[i..i + 2], 16).unwrap())
.collect()
}
pub const PERF_FRAMES: usize = 44100 * 30;
pub struct PerfLcg {
state: u32,
}
impl PerfLcg {
pub fn new() -> Self {
PerfLcg { state: 0 }
}
pub fn next_frame(&mut self) -> (i16, i16) {
self.state = self.state.wrapping_mul(1_103_515_245).wrapping_add(12_345) & 0x7FFF_FFFF;
let l = (self.state & 0xFFFF) as i32 - 32_768;
let r = ((self.state >> 15) & 0xFFFF) as i32 - 32_768;
(l as i16, r as i16)
}
}
impl Default for PerfLcg {
fn default() -> Self {
Self::new()
}
}
pub fn perf_fixture() -> Vec<u8> {
let data_len = (PERF_FRAMES * 4) as u32;
let mut out = Vec::with_capacity(44 + PERF_FRAMES * 4);
out.extend_from_slice(b"RIFF");
out.extend_from_slice(&(36 + data_len).to_le_bytes());
out.extend_from_slice(b"WAVEfmt ");
out.extend_from_slice(&16u32.to_le_bytes());
out.extend_from_slice(&1u16.to_le_bytes());
out.extend_from_slice(&2u16.to_le_bytes());
out.extend_from_slice(&44_100u32.to_le_bytes());
out.extend_from_slice(&176_400u32.to_le_bytes());
out.extend_from_slice(&4u16.to_le_bytes());
out.extend_from_slice(&16u16.to_le_bytes());
out.extend_from_slice(b"data");
out.extend_from_slice(&data_len.to_le_bytes());
let mut lcg = PerfLcg::new();
for _ in 0..PERF_FRAMES {
let (l, r) = lcg.next_frame();
out.extend_from_slice(&l.to_le_bytes());
out.extend_from_slice(&r.to_le_bytes());
}
out
}
pub fn checksum(samples: impl IntoIterator<Item = i16>) -> u64 {
let mut h: u64 = 0xcbf2_9ce4_8422_2325;
for s in samples {
h ^= s as u16 as u64;
h = h.wrapping_mul(0x0000_0100_0000_01b3);
}
h
}
pub fn perf_expected_checksum() -> u64 {
let mut lcg = PerfLcg::new();
checksum((0..PERF_FRAMES).flat_map(|_| {
let (l, r) = lcg.next_frame();
[l, r]
}))
}