1use super::Stroke;
46use crate::error::{Error, ParseError};
47use crate::formats::predictor;
48
49pub const BLOCK_WORDS: usize = 511;
51
52pub const OVERLAP: usize = 64;
54
55pub const RATE: u32 = 35_002;
57
58pub const MAX_ORDER: usize = predictor::MAX_ORDER;
60
61pub const MIN_WIDTH: u8 = 1;
63
64pub const MAX_WIDTH: u8 = 16;
67
68pub fn block_frames(width: u8, block_bytes: usize, channels: usize) -> usize {
71 8 * (block_bytes - 2) / (usize::from(width) * channels)
72}
73
74#[derive(Debug, Clone, PartialEq, Eq)]
76pub struct Audio {
77 pub lanes: Vec<Vec<i16>>,
79 pub tail: Vec<Vec<i16>>,
83 pub clipped: usize,
87 pub overlap_checked: usize,
89}
90
91impl Audio {
92 pub fn frames(&self) -> usize {
94 self.lanes.first().map_or(0, Vec::len)
95 }
96
97 pub fn seconds(&self) -> f64 {
98 self.frames() as f64 / f64::from(RATE)
99 }
100
101 pub fn interleaved(&self) -> Vec<i16> {
103 let frames = self.frames();
104 let mut out = Vec::with_capacity(frames * self.lanes.len());
105 for frame in 0..frames {
106 out.extend(self.lanes.iter().map(|c| c[frame]));
107 }
108 out
109 }
110}
111
112#[derive(Debug, Clone, Copy, PartialEq, Eq)]
114pub struct BlockHeader {
115 pub width: u8,
116 pub order: u8,
117 pub attenuation: u8,
120}
121
122impl BlockHeader {
123 fn read(word: u16) -> BlockHeader {
124 BlockHeader {
125 width: (word & 0x1f) as u8,
126 order: ((word >> 5) & 7) as u8,
127 attenuation: (word >> 8) as u8,
128 }
129 }
130
131 fn frames(self, block_bytes: usize, channels: usize) -> usize {
133 block_frames(self.width, block_bytes, channels)
134 }
135}
136
137struct Fields<'a> {
139 words: &'a [u8],
140 next: usize,
141 reservoir: u64,
142 held: u32,
143}
144
145impl<'a> Fields<'a> {
146 fn new(words: &'a [u8]) -> Fields<'a> {
147 Fields {
148 words,
149 next: 0,
150 reservoir: 0,
151 held: 0,
152 }
153 }
154
155 fn take(&mut self, width: u8) -> Option<i32> {
156 while self.held < u32::from(width) {
157 let at = self.next * 2;
158 let word = u16::from_be_bytes(self.words.get(at..at + 2)?.try_into().unwrap());
159 self.reservoir |= u64::from(word) << self.held;
160 self.held += 16;
161 self.next += 1;
162 }
163 let value = (self.reservoir & ((1u64 << width) - 1)) as i64;
164 self.reservoir >>= width;
165 self.held -= u32::from(width);
166 let sign = 1i64 << (width - 1);
167 Some(((value ^ sign) - sign) as i32)
168 }
169}
170
171pub fn decode(stroke: &Stroke<'_>, channels: u16) -> Result<Audio, Error> {
176 if !(1..=2).contains(&channels) {
177 return Err(ParseError::OutOfBounds {
178 value: format!("{channels} channels"),
179 bound: "1 or 2, which is what a library states".into(),
180 }
181 .into());
182 }
183 let channels = usize::from(channels);
184 let block_bytes = BLOCK_WORDS * 2 * channels;
185 let audio = stroke.audio();
186 let blocks = usize::from(stroke.blocks());
187 if audio.len() != blocks * block_bytes {
188 return Err(ParseError::AssertFail(format!(
189 "the stroke spans {} bytes where {blocks} blocks hold {}",
190 audio.len(),
191 blocks * block_bytes
192 ))
193 .into());
194 }
195
196 let frames = usize::try_from(stroke.frames()).map_err(|_| ParseError::OutOfBounds {
197 value: format!("{} frames", stroke.frames()),
198 bound: "a frame count that fits this platform's address space".into(),
199 })?;
200 let most = blocks * (block_frames(MIN_WIDTH, block_bytes, channels) - OVERLAP);
203 if frames > most {
204 return Err(ParseError::AssertFail(format!(
205 "the blocks own at most {most} frames where the record states {frames}"
206 ))
207 .into());
208 }
209 let mut out: Vec<Vec<i16>> = Vec::with_capacity(channels);
210 for _ in 0..channels {
211 let mut channel = Vec::new();
212 channel
213 .try_reserve_exact(frames)
214 .map_err(|_| ParseError::OutOfBounds {
215 value: format!("{frames} frames"),
216 bound: "an allocation that fits memory".into(),
217 })?;
218 out.push(channel);
219 }
220
221 let seeds = stroke.seeds();
222 let mut history = [[0i64; MAX_ORDER]; 2];
223 for (state, seeds) in history.iter_mut().zip(&seeds) {
224 for (j, slot) in state.iter_mut().enumerate() {
227 *slot = i64::from(seeds[MAX_ORDER - 1 - j]);
228 }
229 }
230
231 let mut clipped = 0;
232 let mut overlap_checked = 0;
233 let mut tail: Vec<Vec<i32>> = Vec::new();
234 let mut block = vec![vec![0i32; 0]; channels];
235 for index in 0..blocks {
236 let raw = &audio[index * block_bytes..(index + 1) * block_bytes];
237 let header = BlockHeader::read(u16::from_be_bytes([raw[0], raw[1]]));
238 if !(MIN_WIDTH..=MAX_WIDTH).contains(&header.width) || usize::from(header.order) > MAX_ORDER
239 {
240 return Err(ParseError::OutOfBounds {
241 value: format!(
242 "block {index}: width {} order {}",
243 header.width, header.order
244 ),
245 bound: format!(
246 "a width of {MIN_WIDTH} to {MAX_WIDTH} and an order of at most {MAX_ORDER}"
247 ),
248 }
249 .into());
250 }
251 let block_frames = header.frames(block_bytes, channels);
252 if block_frames < OVERLAP + MAX_ORDER {
255 return Err(ParseError::AssertFail(format!(
256 "block {index} holds {block_frames} frames, too few for the {OVERLAP} it \
257 repeats from the block before plus the {MAX_ORDER} the next one seeds from"
258 ))
259 .into());
260 }
261 let owned = block_frames - OVERLAP;
262
263 let mut fields = Fields::new(&raw[2..]);
264 let order = usize::from(header.order);
265 for channel in block.iter_mut() {
266 channel.clear();
267 channel.reserve(block_frames);
268 }
269 for _ in 0..block_frames {
270 for (channel, state) in block.iter_mut().zip(history.iter_mut()) {
271 let residual = fields.take(header.width).ok_or_else(|| {
272 ParseError::AssertFail(format!(
273 "block {index} runs out of words before its {block_frames} frames"
274 ))
275 })?;
276 let value = predictor::predict(state, order, i64::from(residual));
277 channel.push(value.clamp(i64::from(i32::MIN), i64::from(i32::MAX)) as i32);
278 }
279 }
280
281 if !tail.is_empty() {
282 for (channel, (decoded, expected)) in block.iter().zip(&tail).enumerate() {
283 if decoded[..OVERLAP] != expected[..] {
284 let at = decoded[..OVERLAP]
285 .iter()
286 .zip(expected)
287 .position(|(a, b)| a != b)
288 .unwrap_or(0);
289 return Err(ParseError::AssertFail(format!(
290 "block {index} channel {channel} repeats frame {at} as {} where the \
291 block before decoded {}",
292 decoded[at], expected[at]
293 ))
294 .into());
295 }
296 overlap_checked += OVERLAP;
297 }
298 }
299 tail = block.iter().map(|c| c[owned..].to_vec()).collect();
300 for (state, decoded) in history.iter_mut().zip(&block) {
303 for (j, slot) in state.iter_mut().enumerate() {
304 *slot = i64::from(decoded[owned - 1 - j]);
305 }
306 }
307
308 for (channel, decoded) in out.iter_mut().zip(&block) {
309 for &sample in &decoded[..owned] {
310 let narrow = sample.clamp(i32::from(i16::MIN), i32::from(i16::MAX)) as i16;
311 if i32::from(narrow) != sample {
312 clipped += 1;
313 }
314 channel.push(narrow);
315 }
316 }
317 }
318
319 let decoded = out.first().map_or(0, Vec::len);
320 if decoded != frames {
321 return Err(ParseError::AssertFail(format!(
322 "the blocks own {decoded} frames where the record states {frames}"
323 ))
324 .into());
325 }
326
327 let mut narrowed = Vec::with_capacity(channels);
328 for channel in &tail {
329 narrowed.push(
330 channel
331 .iter()
332 .map(|&sample| {
333 let narrow = sample.clamp(i32::from(i16::MIN), i32::from(i16::MAX)) as i16;
334 clipped += usize::from(i32::from(narrow) != sample);
335 narrow
336 })
337 .collect(),
338 );
339 }
340
341 Ok(Audio {
342 lanes: out,
343 tail: narrowed,
344 clipped,
345 overlap_checked,
346 })
347}
348
349#[cfg(test)]
350mod tests {
351 use super::super::{RECORD, REC_BLOCKS, REC_FRAMES, REC_SEEDS};
352 use super::*;
353
354 fn block(width: u8, order: u8, channels: usize, residuals: &[i32]) -> Vec<u8> {
358 let block_bytes = BLOCK_WORDS * 2 * channels;
359 let mut out = Vec::with_capacity(block_bytes);
360 out.extend_from_slice(&(u16::from(width) | (u16::from(order) << 5)).to_be_bytes());
361 let mut reservoir: u64 = 0;
362 let mut held = 0u32;
363 for &value in residuals {
364 let masked = (value as i64 as u64) & ((1u64 << width) - 1);
365 reservoir |= masked << held;
366 held += u32::from(width);
367 while held >= 16 {
368 out.extend_from_slice(&((reservoir & 0xffff) as u16).to_be_bytes());
369 reservoir >>= 16;
370 held -= 16;
371 }
372 }
373 if held > 0 {
374 out.extend_from_slice(&((reservoir & 0xffff) as u16).to_be_bytes());
375 }
376 out.resize(block_bytes, 0);
377 out
378 }
379
380 fn stroke<'a>(audio: &'a [u8], frames: u32, blocks: u16, seeds: [i16; 4]) -> Stroke<'a> {
382 let mut record = [0u8; RECORD];
383 record[REC_FRAMES..REC_FRAMES + 4].copy_from_slice(&frames.to_be_bytes());
384 record[REC_BLOCKS..REC_BLOCKS + 2].copy_from_slice(&blocks.to_be_bytes());
385 for (i, &seed) in seeds.iter().enumerate() {
386 let at = REC_SEEDS + i * 2;
387 record[at..at + 2].copy_from_slice(&seed.to_be_bytes());
388 }
389 Stroke {
390 root: 0,
391 record,
392 audio: std::borrow::Cow::Borrowed(audio),
393 }
394 }
395
396 fn frames_per_block(width: u8, channels: usize) -> usize {
398 block_frames(width, BLOCK_WORDS * 2 * channels, channels)
399 }
400
401 #[test]
402 fn order_zero_states_the_samples_outright() {
403 let frames = frames_per_block(8, 1);
404 let residuals: Vec<i32> = (0..frames).map(|i| (i % 61) as i32 - 30).collect();
405 let audio = block(8, 0, 1, &residuals);
406 let decoded = decode(&stroke(&audio, (frames - OVERLAP) as u32, 1, [0; 4]), 1).unwrap();
407 assert_eq!(decoded.frames(), frames - OVERLAP);
408 assert_eq!(&decoded.lanes[0][..4], &[-30, -29, -28, -27]);
409 assert_eq!(decoded.clipped, 0);
410 }
411
412 #[test]
413 fn order_one_integrates_from_the_records_newest_seed() {
414 let frames = frames_per_block(6, 1);
415 let audio = block(6, 1, 1, &vec![3i32; frames]);
416 let decoded = decode(
417 &stroke(&audio, (frames - OVERLAP) as u32, 1, [0, 0, 0, 100]),
418 1,
419 )
420 .unwrap();
421 assert_eq!(&decoded.lanes[0][..4], &[103, 106, 109, 112]);
422 }
423
424 #[test]
425 fn a_width_the_header_cannot_carry_is_refused() {
426 let audio = vec![0u8; BLOCK_WORDS * 2];
427 let error = decode(&stroke(&audio, 1, 1, [0; 4]), 1)
428 .unwrap_err()
429 .to_string();
430 assert!(error.contains("width 0"), "{error}");
431 }
432
433 #[test]
434 fn a_frame_count_the_blocks_do_not_own_is_refused() {
435 let audio = block(8, 0, 1, &[0i32; 16]);
436 let error = decode(&stroke(&audio, 7, 1, [0; 4]), 1)
437 .unwrap_err()
438 .to_string();
439 assert!(error.contains("the record states 7"), "{error}");
440 }
441
442 #[test]
445 fn a_frame_count_larger_than_the_blocks_can_hold_is_refused_before_reserving() {
446 let audio = block(8, 0, 1, &[0i32; 16]);
447 let error = decode(&stroke(&audio, u32::MAX, 1, [0; 4]), 1)
448 .unwrap_err()
449 .to_string();
450 assert!(error.contains("the blocks own at most"), "{error}");
451 assert!(
452 error.contains(&format!("the record states {}", u32::MAX)),
453 "{error}"
454 );
455 }
456
457 #[test]
458 fn a_channel_count_no_library_states_is_refused() {
459 let audio = block(8, 0, 1, &[0i32; 16]);
460 let error = decode(&stroke(&audio, 1, 1, [0; 4]), 0)
461 .unwrap_err()
462 .to_string();
463 assert!(error.contains("1 or 2"), "{error}");
464 }
465
466 #[test]
467 fn a_span_shorter_than_its_block_count_is_refused() {
468 let audio = block(8, 0, 1, &[0i32; 16]);
469 let error = decode(&stroke(&audio, 1, 2, [0; 4]), 1)
470 .unwrap_err()
471 .to_string();
472 assert!(error.contains("2 blocks hold"), "{error}");
473 }
474
475 #[test]
476 fn a_block_that_does_not_repeat_the_one_before_is_refused() {
477 let frames = frames_per_block(8, 1);
478 let first: Vec<i32> = (0..frames).map(|i| (i % 7) as i32).collect();
479 let mut audio = block(8, 0, 1, &first);
482 audio.extend(block(8, 0, 1, &vec![0i32; frames]));
483 let error = decode(&stroke(&audio, 2 * (frames - OVERLAP) as u32, 2, [0; 4]), 1)
484 .unwrap_err()
485 .to_string();
486 assert!(error.contains("repeats frame"), "{error}");
487 }
488
489 #[test]
490 fn a_block_repeating_the_one_before_decodes_and_emits_it_once() {
491 let frames = frames_per_block(8, 1);
492 let owned = frames - OVERLAP;
493 let first: Vec<i32> = (0..frames).map(|i| (i % 7) as i32).collect();
494 let mut second = vec![0i32; frames];
495 second[..OVERLAP].copy_from_slice(&first[owned..]);
496 let mut audio = block(8, 0, 1, &first);
497 audio.extend(block(8, 0, 1, &second));
498 let decoded = decode(&stroke(&audio, 2 * owned as u32, 2, [0; 4]), 1).unwrap();
499 assert_eq!(decoded.frames(), 2 * owned);
500 assert_eq!(decoded.overlap_checked, OVERLAP);
501 let repeated: Vec<i16> = first[owned..].iter().map(|&v| v as i16).collect();
504 assert_eq!(&decoded.lanes[0][owned..owned + OVERLAP], &repeated[..]);
505 assert_eq!(decoded.lanes[0][owned + OVERLAP], 0);
506 }
507
508 #[test]
509 fn a_stereo_block_alternates_channels_field_by_field() {
510 let frames = frames_per_block(8, 2);
511 let residuals: Vec<i32> = (0..frames * 2)
512 .map(|i| if i % 2 == 0 { 10 } else { -10 })
513 .collect();
514 let audio = block(8, 0, 2, &residuals);
515 let decoded = decode(&stroke(&audio, (frames - OVERLAP) as u32, 1, [0; 4]), 2).unwrap();
516 assert_eq!(decoded.lanes.len(), 2);
517 assert!(decoded.lanes[0].iter().all(|&s| s == 10));
518 assert!(decoded.lanes[1].iter().all(|&s| s == -10));
519 assert_eq!(decoded.interleaved()[..4], [10, -10, 10, -10]);
520 }
521}