use super::Stroke;
use crate::error::{Error, ParseError};
use crate::formats::predictor;
pub const BLOCK_WORDS: usize = 511;
pub const OVERLAP: usize = 64;
pub const RATE: u32 = 35_002;
pub const MAX_ORDER: usize = predictor::MAX_ORDER;
pub const MIN_WIDTH: u8 = 1;
pub const MAX_WIDTH: u8 = 16;
pub fn block_frames(width: u8, block_bytes: usize, channels: usize) -> usize {
8 * (block_bytes - 2) / (usize::from(width) * channels)
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Audio {
pub lanes: Vec<Vec<i16>>,
pub tail: Vec<Vec<i16>>,
pub clipped: usize,
pub overlap_checked: usize,
}
impl Audio {
pub fn frames(&self) -> usize {
self.lanes.first().map_or(0, Vec::len)
}
pub fn seconds(&self) -> f64 {
self.frames() as f64 / f64::from(RATE)
}
pub fn interleaved(&self) -> Vec<i16> {
let frames = self.frames();
let mut out = Vec::with_capacity(frames * self.lanes.len());
for frame in 0..frames {
out.extend(self.lanes.iter().map(|c| c[frame]));
}
out
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct BlockHeader {
pub width: u8,
pub order: u8,
pub attenuation: u8,
}
impl BlockHeader {
fn read(word: u16) -> BlockHeader {
BlockHeader {
width: (word & 0x1f) as u8,
order: ((word >> 5) & 7) as u8,
attenuation: (word >> 8) as u8,
}
}
fn frames(self, block_bytes: usize, channels: usize) -> usize {
block_frames(self.width, block_bytes, channels)
}
}
struct Fields<'a> {
words: &'a [u8],
next: usize,
reservoir: u64,
held: u32,
}
impl<'a> Fields<'a> {
fn new(words: &'a [u8]) -> Fields<'a> {
Fields {
words,
next: 0,
reservoir: 0,
held: 0,
}
}
fn take(&mut self, width: u8) -> Option<i32> {
while self.held < u32::from(width) {
let at = self.next * 2;
let word = u16::from_be_bytes(self.words.get(at..at + 2)?.try_into().unwrap());
self.reservoir |= u64::from(word) << self.held;
self.held += 16;
self.next += 1;
}
let value = (self.reservoir & ((1u64 << width) - 1)) as i64;
self.reservoir >>= width;
self.held -= u32::from(width);
let sign = 1i64 << (width - 1);
Some(((value ^ sign) - sign) as i32)
}
}
pub fn decode(stroke: &Stroke<'_>, channels: u16) -> Result<Audio, Error> {
if !(1..=2).contains(&channels) {
return Err(ParseError::OutOfBounds {
value: format!("{channels} channels"),
bound: "1 or 2, which is what a library states".into(),
}
.into());
}
let channels = usize::from(channels);
let block_bytes = BLOCK_WORDS * 2 * channels;
let audio = stroke.audio();
let blocks = usize::from(stroke.blocks());
if audio.len() != blocks * block_bytes {
return Err(ParseError::AssertFail(format!(
"the stroke spans {} bytes where {blocks} blocks hold {}",
audio.len(),
blocks * block_bytes
))
.into());
}
let frames = usize::try_from(stroke.frames()).map_err(|_| ParseError::OutOfBounds {
value: format!("{} frames", stroke.frames()),
bound: "a frame count that fits this platform's address space".into(),
})?;
let most = blocks * (block_frames(MIN_WIDTH, block_bytes, channels) - OVERLAP);
if frames > most {
return Err(ParseError::AssertFail(format!(
"the blocks own at most {most} frames where the record states {frames}"
))
.into());
}
let mut out: Vec<Vec<i16>> = Vec::with_capacity(channels);
for _ in 0..channels {
let mut channel = Vec::new();
channel
.try_reserve_exact(frames)
.map_err(|_| ParseError::OutOfBounds {
value: format!("{frames} frames"),
bound: "an allocation that fits memory".into(),
})?;
out.push(channel);
}
let seeds = stroke.seeds();
let mut history = [[0i64; MAX_ORDER]; 2];
for (state, seeds) in history.iter_mut().zip(&seeds) {
for (j, slot) in state.iter_mut().enumerate() {
*slot = i64::from(seeds[MAX_ORDER - 1 - j]);
}
}
let mut clipped = 0;
let mut overlap_checked = 0;
let mut tail: Vec<Vec<i32>> = Vec::new();
let mut block = vec![vec![0i32; 0]; channels];
for index in 0..blocks {
let raw = &audio[index * block_bytes..(index + 1) * block_bytes];
let header = BlockHeader::read(u16::from_be_bytes([raw[0], raw[1]]));
if !(MIN_WIDTH..=MAX_WIDTH).contains(&header.width) || usize::from(header.order) > MAX_ORDER
{
return Err(ParseError::OutOfBounds {
value: format!(
"block {index}: width {} order {}",
header.width, header.order
),
bound: format!(
"a width of {MIN_WIDTH} to {MAX_WIDTH} and an order of at most {MAX_ORDER}"
),
}
.into());
}
let block_frames = header.frames(block_bytes, channels);
if block_frames < OVERLAP + MAX_ORDER {
return Err(ParseError::AssertFail(format!(
"block {index} holds {block_frames} frames, too few for the {OVERLAP} it \
repeats from the block before plus the {MAX_ORDER} the next one seeds from"
))
.into());
}
let owned = block_frames - OVERLAP;
let mut fields = Fields::new(&raw[2..]);
let order = usize::from(header.order);
for channel in block.iter_mut() {
channel.clear();
channel.reserve(block_frames);
}
for _ in 0..block_frames {
for (channel, state) in block.iter_mut().zip(history.iter_mut()) {
let residual = fields.take(header.width).ok_or_else(|| {
ParseError::AssertFail(format!(
"block {index} runs out of words before its {block_frames} frames"
))
})?;
let value = predictor::predict(state, order, i64::from(residual));
channel.push(value.clamp(i64::from(i32::MIN), i64::from(i32::MAX)) as i32);
}
}
if !tail.is_empty() {
for (channel, (decoded, expected)) in block.iter().zip(&tail).enumerate() {
if decoded[..OVERLAP] != expected[..] {
let at = decoded[..OVERLAP]
.iter()
.zip(expected)
.position(|(a, b)| a != b)
.unwrap_or(0);
return Err(ParseError::AssertFail(format!(
"block {index} channel {channel} repeats frame {at} as {} where the \
block before decoded {}",
decoded[at], expected[at]
))
.into());
}
overlap_checked += OVERLAP;
}
}
tail = block.iter().map(|c| c[owned..].to_vec()).collect();
for (state, decoded) in history.iter_mut().zip(&block) {
for (j, slot) in state.iter_mut().enumerate() {
*slot = i64::from(decoded[owned - 1 - j]);
}
}
for (channel, decoded) in out.iter_mut().zip(&block) {
for &sample in &decoded[..owned] {
let narrow = sample.clamp(i32::from(i16::MIN), i32::from(i16::MAX)) as i16;
if i32::from(narrow) != sample {
clipped += 1;
}
channel.push(narrow);
}
}
}
let decoded = out.first().map_or(0, Vec::len);
if decoded != frames {
return Err(ParseError::AssertFail(format!(
"the blocks own {decoded} frames where the record states {frames}"
))
.into());
}
let mut narrowed = Vec::with_capacity(channels);
for channel in &tail {
narrowed.push(
channel
.iter()
.map(|&sample| {
let narrow = sample.clamp(i32::from(i16::MIN), i32::from(i16::MAX)) as i16;
clipped += usize::from(i32::from(narrow) != sample);
narrow
})
.collect(),
);
}
Ok(Audio {
lanes: out,
tail: narrowed,
clipped,
overlap_checked,
})
}
#[cfg(test)]
mod tests {
use super::super::{RECORD, REC_BLOCKS, REC_FRAMES, REC_SEEDS};
use super::*;
fn block(width: u8, order: u8, channels: usize, residuals: &[i32]) -> Vec<u8> {
let block_bytes = BLOCK_WORDS * 2 * channels;
let mut out = Vec::with_capacity(block_bytes);
out.extend_from_slice(&(u16::from(width) | (u16::from(order) << 5)).to_be_bytes());
let mut reservoir: u64 = 0;
let mut held = 0u32;
for &value in residuals {
let masked = (value as i64 as u64) & ((1u64 << width) - 1);
reservoir |= masked << held;
held += u32::from(width);
while held >= 16 {
out.extend_from_slice(&((reservoir & 0xffff) as u16).to_be_bytes());
reservoir >>= 16;
held -= 16;
}
}
if held > 0 {
out.extend_from_slice(&((reservoir & 0xffff) as u16).to_be_bytes());
}
out.resize(block_bytes, 0);
out
}
fn stroke<'a>(audio: &'a [u8], frames: u32, blocks: u16, seeds: [i16; 4]) -> Stroke<'a> {
let mut record = [0u8; RECORD];
record[REC_FRAMES..REC_FRAMES + 4].copy_from_slice(&frames.to_be_bytes());
record[REC_BLOCKS..REC_BLOCKS + 2].copy_from_slice(&blocks.to_be_bytes());
for (i, &seed) in seeds.iter().enumerate() {
let at = REC_SEEDS + i * 2;
record[at..at + 2].copy_from_slice(&seed.to_be_bytes());
}
Stroke {
root: 0,
record,
audio: std::borrow::Cow::Borrowed(audio),
}
}
fn frames_per_block(width: u8, channels: usize) -> usize {
block_frames(width, BLOCK_WORDS * 2 * channels, channels)
}
#[test]
fn order_zero_states_the_samples_outright() {
let frames = frames_per_block(8, 1);
let residuals: Vec<i32> = (0..frames).map(|i| (i % 61) as i32 - 30).collect();
let audio = block(8, 0, 1, &residuals);
let decoded = decode(&stroke(&audio, (frames - OVERLAP) as u32, 1, [0; 4]), 1).unwrap();
assert_eq!(decoded.frames(), frames - OVERLAP);
assert_eq!(&decoded.lanes[0][..4], &[-30, -29, -28, -27]);
assert_eq!(decoded.clipped, 0);
}
#[test]
fn order_one_integrates_from_the_records_newest_seed() {
let frames = frames_per_block(6, 1);
let audio = block(6, 1, 1, &vec![3i32; frames]);
let decoded = decode(
&stroke(&audio, (frames - OVERLAP) as u32, 1, [0, 0, 0, 100]),
1,
)
.unwrap();
assert_eq!(&decoded.lanes[0][..4], &[103, 106, 109, 112]);
}
#[test]
fn a_width_the_header_cannot_carry_is_refused() {
let audio = vec![0u8; BLOCK_WORDS * 2];
let error = decode(&stroke(&audio, 1, 1, [0; 4]), 1)
.unwrap_err()
.to_string();
assert!(error.contains("width 0"), "{error}");
}
#[test]
fn a_frame_count_the_blocks_do_not_own_is_refused() {
let audio = block(8, 0, 1, &[0i32; 16]);
let error = decode(&stroke(&audio, 7, 1, [0; 4]), 1)
.unwrap_err()
.to_string();
assert!(error.contains("the record states 7"), "{error}");
}
#[test]
fn a_frame_count_larger_than_the_blocks_can_hold_is_refused_before_reserving() {
let audio = block(8, 0, 1, &[0i32; 16]);
let error = decode(&stroke(&audio, u32::MAX, 1, [0; 4]), 1)
.unwrap_err()
.to_string();
assert!(error.contains("the blocks own at most"), "{error}");
assert!(
error.contains(&format!("the record states {}", u32::MAX)),
"{error}"
);
}
#[test]
fn a_channel_count_no_library_states_is_refused() {
let audio = block(8, 0, 1, &[0i32; 16]);
let error = decode(&stroke(&audio, 1, 1, [0; 4]), 0)
.unwrap_err()
.to_string();
assert!(error.contains("1 or 2"), "{error}");
}
#[test]
fn a_span_shorter_than_its_block_count_is_refused() {
let audio = block(8, 0, 1, &[0i32; 16]);
let error = decode(&stroke(&audio, 1, 2, [0; 4]), 1)
.unwrap_err()
.to_string();
assert!(error.contains("2 blocks hold"), "{error}");
}
#[test]
fn a_block_that_does_not_repeat_the_one_before_is_refused() {
let frames = frames_per_block(8, 1);
let first: Vec<i32> = (0..frames).map(|i| (i % 7) as i32).collect();
let mut audio = block(8, 0, 1, &first);
audio.extend(block(8, 0, 1, &vec![0i32; frames]));
let error = decode(&stroke(&audio, 2 * (frames - OVERLAP) as u32, 2, [0; 4]), 1)
.unwrap_err()
.to_string();
assert!(error.contains("repeats frame"), "{error}");
}
#[test]
fn a_block_repeating_the_one_before_decodes_and_emits_it_once() {
let frames = frames_per_block(8, 1);
let owned = frames - OVERLAP;
let first: Vec<i32> = (0..frames).map(|i| (i % 7) as i32).collect();
let mut second = vec![0i32; frames];
second[..OVERLAP].copy_from_slice(&first[owned..]);
let mut audio = block(8, 0, 1, &first);
audio.extend(block(8, 0, 1, &second));
let decoded = decode(&stroke(&audio, 2 * owned as u32, 2, [0; 4]), 1).unwrap();
assert_eq!(decoded.frames(), 2 * owned);
assert_eq!(decoded.overlap_checked, OVERLAP);
let repeated: Vec<i16> = first[owned..].iter().map(|&v| v as i16).collect();
assert_eq!(&decoded.lanes[0][owned..owned + OVERLAP], &repeated[..]);
assert_eq!(decoded.lanes[0][owned + OVERLAP], 0);
}
#[test]
fn a_stereo_block_alternates_channels_field_by_field() {
let frames = frames_per_block(8, 2);
let residuals: Vec<i32> = (0..frames * 2)
.map(|i| if i % 2 == 0 { 10 } else { -10 })
.collect();
let audio = block(8, 0, 2, &residuals);
let decoded = decode(&stroke(&audio, (frames - OVERLAP) as u32, 1, [0; 4]), 2).unwrap();
assert_eq!(decoded.lanes.len(), 2);
assert!(decoded.lanes[0].iter().all(|&s| s == 10));
assert!(decoded.lanes[1].iter().all(|&s| s == -10));
assert_eq!(decoded.interleaved()[..4], [10, -10, 10, -10]);
}
}