mirror of
https://github.com/storytold/craft-libs.git
synced 2026-11-07 12:13:20 +00:00
craft-audio: review fixes, round 11 (#442)
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 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
afdc045e94
commit
1a9f579a07
@@ -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
|
||||
})
|
||||
|
||||
@@ -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<i32> = 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<i32> = 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<u8> {
|
||||
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);
|
||||
|
||||
@@ -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 }
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user