use crate::md5::Md5;
pub(crate) fn bytes_per_sample(bits_per_sample: u8) -> usize {
(bits_per_sample as usize).div_ceil(8)
}
pub(crate) fn md5_of_samples(samples: &[Vec<i32>], bits_per_sample: u8) -> [u8; 16] {
let bps_bytes = bytes_per_sample(bits_per_sample);
let frames = samples.first().map_or(0, |c| c.len());
let mut hasher = Md5::new();
let mut buf = [0u8; 4];
for i in 0..frames {
for channel in samples {
let word = channel[i] as u32;
buf.copy_from_slice(&word.to_le_bytes());
hasher.update(&buf[..bps_bytes]);
}
}
hasher.finalize()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn bytes_per_sample_rounds_up() {
assert_eq!(bytes_per_sample(8), 1);
assert_eq!(bytes_per_sample(12), 2);
assert_eq!(bytes_per_sample(16), 2);
assert_eq!(bytes_per_sample(20), 3);
assert_eq!(bytes_per_sample(24), 3);
assert_eq!(bytes_per_sample(32), 4);
}
#[test]
fn negative_samples_use_twos_complement_low_bytes() {
let md5 = md5_of_samples(&[vec![-1i32]], 16);
let reference = crate::md5::digest(&[0xFF, 0xFF]);
assert_eq!(md5, reference);
}
#[test]
fn interleaves_channels() {
let md5 = md5_of_samples(&[vec![1i32], vec![2i32]], 16);
let reference = crate::md5::digest(&[0x01, 0x00, 0x02, 0x00]);
assert_eq!(md5, reference);
}
}