Skip to main content

nord_format/formats/npno/
codec.rs

1//! The stroke codec: one recorded note's blocks back into samples.
2//!
3//! A stroke's audio is [`Stroke::blocks`](super::Stroke::blocks) back-to-back
4//! blocks of [`BLOCK_WORDS`] × 2 × channels bytes. Each opens with one big-endian
5//! u16 header and then carries big-endian u16 words of packed residuals:
6//!
7//! ```text
8//! bits 0..4   the residual field width in bits
9//! bits 5..7   the backward-difference order, 0..=4
10//! bits 8..15  a per-block attenuation statistic, in dB against a full scale of
11//!             8192; nothing here reads it, and it is not a gain to apply
12//! ```
13//!
14//! ⚠️ **The packing is low-bit-first.** Append each big-endian word to the high end
15//! of a reservoir and take fields from its low bits, so global bit `b` is bit
16//! `b % 16` of word `b / 16` counting that word's least significant bit as bit 0.
17//! Fields are two's complement, they cross word boundaries freely, and on a stereo
18//! stroke consecutive fields alternate channels. Reading the residuals
19//! most-significant-bit first is structurally plausible and reconstructs no signal.
20//!
21//! The recurrence is the finite-difference predictor
22//! [`nsmp`](crate::formats::nsmp::codec) uses, per channel:
23//!
24//! ```text
25//! x[n] = r[n] − Σ_{j=1..order} (−1)^j C(order, j) · x[n−j]
26//! ```
27//!
28//! seeded from the four samples the stroke's record carries, oldest first.
29//!
30//! A block holds `⌊8 · (block bytes − 2) / (width · channels)⌋` frames, of which
31//! the **last [`OVERLAP`] repeat as the first frames of the next block**. Only the
32//! frames before that repeat are emitted, and the history carried into the next
33//! block is the four samples immediately before it rather than the four at the
34//! physical block end. Their sum is the frame count the record states, and the
35//! repeat is bit-exact — [`decode`] checks both and refuses a stroke that fails
36//! either. The last block has no next block to repeat into, so its own final
37//! [`OVERLAP`] frames sit past the stroke's end; [`Audio::tail`] carries them.
38//!
39//! The packing and the predictor: Inferred from specimens; not confirmed on
40//! hardware. Nothing here is played, only reconstructed. Confirmed on hardware.
41//! The frames play at [`RATE`], and a stroke owns the whole
42//! `blocks × BLOCK_WORDS × 2 × channels` bytes the container gives it — a library
43//! whose spans were moved at that size still plays.
44
45use super::Stroke;
46use crate::error::{Error, ParseError};
47use crate::formats::predictor;
48
49/// u16 words in one block, per channel, the header included.
50pub const BLOCK_WORDS: usize = 511;
51
52/// Frames a block repeats from the one before it. Never emitted.
53pub const OVERLAP: usize = 64;
54
55/// Frames per second per channel. Confirmed on hardware.
56pub const RATE: u32 = 35_002;
57
58/// Highest backward-difference order a block header can ask for.
59pub const MAX_ORDER: usize = predictor::MAX_ORDER;
60
61/// Narrowest residual field a block header can express.
62pub const MIN_WIDTH: u8 = 1;
63
64/// Widths a block header can express. A field wider than a reservoir top-up is
65/// refused rather than read across an unbounded number of words.
66pub const MAX_WIDTH: u8 = 16;
67
68/// Frames a block of `width` carries, the [`OVERLAP`] it repeats included. A wider
69/// block is a shorter one, so the width and the frame count are one choice.
70pub fn block_frames(width: u8, block_bytes: usize, channels: usize) -> usize {
71    8 * (block_bytes - 2) / (usize::from(width) * channels)
72}
73
74/// Decoded audio for one stroke.
75#[derive(Debug, Clone, PartialEq, Eq)]
76pub struct Audio {
77    /// One vector per channel, each [`Audio::frames`] long.
78    pub lanes: Vec<Vec<i16>>,
79    /// The [`OVERLAP`] frames per channel the last block carries past the stroke's
80    /// end. The stroke does not own them and nothing plays them; they are here
81    /// because coding that block again needs them.
82    pub tail: Vec<Vec<i16>>,
83    /// Samples the reconstruction put outside `i16` and that were saturated. A non-zero
84    /// count means the stroke is not what this codec describes. Inferred from
85    /// specimens; not confirmed on hardware.
86    pub clipped: usize,
87    /// Repeated samples compared against the block before, all of which matched.
88    pub overlap_checked: usize,
89}
90
91impl Audio {
92    /// Samples per channel.
93    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    /// The frames interleaved by channel, which is what a WAV wants.
102    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/// What one block's header states.
113#[derive(Debug, Clone, Copy, PartialEq, Eq)]
114pub struct BlockHeader {
115    pub width: u8,
116    pub order: u8,
117    /// Attenuation in dB against a full scale of 8192 — a statistic the encoder
118    /// recorded, not a gain the decoder applies.
119    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    /// Frames this block carries, the overlap included.
132    fn frames(self, block_bytes: usize, channels: usize) -> usize {
133        block_frames(self.width, block_bytes, channels)
134    }
135}
136
137/// Residual fields, low-bit-first out of a block's big-endian u16 words.
138struct 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
171/// Decode one stroke, checking the block overlap and the record's frame count.
172///
173/// `channels` is the library's — 1 or 2, and any other count is refused — and
174/// `stroke.audio()` must be the whole span.
175pub 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    // The narrowest field a header can declare is the longest block, so this is the
201    // most frames the span can own whatever its headers say.
202    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        // The record states the seeds oldest first; the recurrence wants the most
225        // recent sample at index 0.
226        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        // The frames before the repeat have to cover it and still leave the four
253        // the next block's predictor continues from.
254        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        // The history the next block continues from sits before the repeat, not at
301        // the physical end of this one.
302        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    /// Packs `frames × channels` residuals the way a block carries them: a header
355    /// word, then `width`-bit two's-complement fields low-bit-first into
356    /// big-endian u16 words.
357    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    /// The record fields [`decode`] reads, over a span the caller built.
381    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    /// Frames one block of `width` holds, the overlap included.
397    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    /// The record states its frame count in bytes the file carries, so the blocks the
443    /// stroke holds bound it before anything is reserved to hold them.
444    #[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        // The next block must open with the previous block's last OVERLAP frames;
480        // this one opens with zeros.
481        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        // The repeat is emitted once, by the block that repeats it, so the two
502        // blocks' frames run on continuously.
503        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}