From 1a9f579a07b4a9fbb148a98f52f86bf4f0bfe9dc Mon Sep 17 00:00:00 2001 From: alehel Date: Wed, 4 Nov 2026 06:50:56 +0100 Subject: [PATCH] craft-audio: review fixes, round 11 (#442) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit No change in output: the 74 oracle test streams are byte-identical. - The Wasted case is handled in one function, without the unreachable arm and the wrapper round 8 added. - The bitstream writer uses predict::fold, the tested copy, not its own. - STREAMINFO's MD5 may be 0 (RFC 9639 §8.2), so the comment no longer says the RFC requires it. Co-Authored-By: Claude Opus 5.5 --- crates/audio/src/write/flac/encoder.rs | 2 +- crates/audio/src/write/flac/frame.rs | 20 +++++++------------- crates/audio/src/write/flac/predict.rs | 2 +- 3 files changed, 9 insertions(+), 15 deletions(-) diff --git a/crates/audio/src/write/flac/encoder.rs b/crates/audio/src/write/flac/encoder.rs index c401c746..2e01c62d 100644 --- a/crates/audio/src/write/flac/encoder.rs +++ b/crates/audio/src/write/flac/encoder.rs @@ -81,7 +81,7 @@ impl Encoder { total_samples: 0, min_frame: 0, max_frame: 0, - // RFC 9639 requires an MD5 signature of the unencoded audio in STREAMINFO; this is an + // STREAMINFO holds an MD5 signature of the unencoded audio (RFC 9639 §8.2); this is an // integrity checksum, not a password hash or a security boundary. md5: super::md5::Md5::default(), // NOSONAR }) diff --git a/crates/audio/src/write/flac/frame.rs b/crates/audio/src/write/flac/frame.rs index 593807ea..34756ca0 100644 --- a/crates/audio/src/write/flac/frame.rs +++ b/crates/audio/src/write/flac/frame.rs @@ -106,7 +106,7 @@ fn write_residual(w: &mut BitWriter, residual: &Residual, r: &[i64], block: usiz w.write_bits(u32::from(k), if wide { 5 } else { 4 }); let n = if p == 0 { len.saturating_sub(order) } else { len }; for &v in r.get(start..start + n).unwrap_or_default() { - let u = if v >= 0 { (v as u64) << 1 } else { ((-v - 1) as u64) << 1 | 1 }; + let u = super::predict::fold(v); let mut q = u >> k; while q >= 32 { w.write_bits(0, 32); @@ -119,16 +119,8 @@ fn write_residual(w: &mut BitWriter, residual: &Residual, r: &[i64], block: usiz } } -fn write_subframe(w: &mut BitWriter, x: &[i32], sub: &Subframe, bps: u8) { - if let Subframe::Wasted { bits, coded } = sub { - let shifted: Vec = x.iter().map(|&v| v >> bits).collect(); - return write_coded(w, &shifted, coded, bps - bits, *bits); - } - write_coded(w, x, sub, bps, 0); -} - /// Subframe header (§9.2.1) and body of samples already without their `wasted` low bits. -fn write_coded(w: &mut BitWriter, x: &[i32], sub: &Subframe, bps: u8, wasted: u8) { +fn write_subframe(w: &mut BitWriter, x: &[i32], sub: &Subframe, bps: u8, wasted: u8) { let b = u32::from(bps); let sample = |w: &mut BitWriter, v: i32| w.write_bits(v as u32, b); // the flag, then the count minus 1 in unary @@ -166,8 +158,10 @@ fn write_coded(w: &mut BitWriter, x: &[i32], sub: &Subframe, bps: u8, wasted: u8 let r = super::predict::lpc_residual(x, coefs, *shift).unwrap_or_default(); write_residual(w, residual, &r, x.len(), o); } - // `choose` does not nest them - Subframe::Wasted { coded, .. } => write_coded(w, x, coded, bps, wasted), + Subframe::Wasted { bits, coded } => { + let shifted: Vec = x.iter().map(|&v| v >> bits).collect(); + write_subframe(w, &shifted, coded, bps - bits, *bits); + } } } @@ -196,7 +190,7 @@ pub fn write(spec: &FrameSpec) -> Vec { let mut w = BitWriter::new(); w.write_bytes(&h); for (x, sub, bps) in spec.channels { - write_subframe(&mut w, x, sub, *bps); + write_subframe(&mut w, x, sub, *bps, 0); } let mut out = w.finish(); let crc = crc16(&out); diff --git a/crates/audio/src/write/flac/predict.rs b/crates/audio/src/write/flac/predict.rs index 983dbd4a..7a99464e 100644 --- a/crates/audio/src/write/flac/predict.rs +++ b/crates/audio/src/write/flac/predict.rs @@ -45,7 +45,7 @@ pub enum Subframe { } /// Folded residual: 0, -1, 1, -2, 2 … → 0, 1, 2, 3, 4 …. -fn fold(r: i64) -> u64 { +pub(super) fn fold(r: i64) -> u64 { if r >= 0 { (r as u64) << 1 } else { ((-r - 1) as u64) << 1 | 1 } }