From afdc045e94b5dd30fd7204c7f9b8e91bef5ff960 Mon Sep 17 00:00:00 2001 From: alehel Date: Wed, 4 Nov 2026 06:30:29 +0100 Subject: [PATCH] craft-audio: review fixes, round 10 (#442) Tests only; each was confirmed to fail on a mutated encoder. - Every sample rate code in the frame header table. - Signals that reach the Rice parameter and LPC shift limits, where a value past the limit gives a file decoders refuse. - ENCODE_EXTENSIONS lists flac. Co-Authored-By: Claude Opus 5.5 --- crates/audio/src/write/flac/frame.rs | 8 ++++++++ crates/audio/src/write/flac/oracle_tests.rs | 20 ++++++++++++++++++++ crates/audio/tests/audio/encode_format.rs | 1 + 3 files changed, 29 insertions(+) diff --git a/crates/audio/src/write/flac/frame.rs b/crates/audio/src/write/flac/frame.rs index 72528c5b..593807ea 100644 --- a/crates/audio/src/write/flac/frame.rs +++ b/crates/audio/src/write/flac/frame.rs @@ -231,6 +231,14 @@ mod tests { assert_eq!([8, 12, 16, 20, 24, 32].map(sample_size_code), [1, 2, 4, 5, 6, 0]); } + #[test] + fn sample_rates_in_the_table_have_their_codes() { + let table = [88_200, 176_400, 192_000, 8_000, 16_000, 22_050, 24_000, 32_000, 44_100, 48_000, 96_000]; + for (rate, code) in table.into_iter().zip(1..) { + assert_eq!(sample_rate_code(rate), (code, None), "{rate}"); + } + } + #[test] fn sample_rates_outside_the_table_are_named_in_the_header() { assert_eq!(sample_rate_code(48_000), (10, None)); diff --git a/crates/audio/src/write/flac/oracle_tests.rs b/crates/audio/src/write/flac/oracle_tests.rs index 6645b26f..2ac0a853 100644 --- a/crates/audio/src/write/flac/oracle_tests.rs +++ b/crates/audio/src/write/flac/oracle_tests.rs @@ -342,3 +342,23 @@ fn a_full_scale_click_at_32_bits_is_still_predicted() { let Some(size) = round_trip("click-32", &planar, EncoderConfig::new(48_000, 1, 32), 4096) else { return }; assert!(size < 4_096 * 4 / 2, "{size}"); } + +/// Signals that reach the format's limits, which a decoder refuses when they are passed: a Rice +/// parameter of 31 is the escape code, and an LPC shift above 15 reads as negative. +#[test] +fn rice_parameter_and_lpc_shift_stay_in_range() { + let mut r = Rng(71); + let bursts: Vec = + (0..9_000).map(|i| if i % 1024 < 128 { if i % 2 == 0 { i32::MAX } else { -i32::MAX } } else { (r.next() * 100.0) as i32 }).collect(); + if round_trip("limit-rice", &[bursts], EncoderConfig::new(48_000, 1, 32), 4096).is_none() { + return; + } + let mut y = 0.0; + let correlated: Vec = (0..9_000) + .map(|_| { + y = 0.24 * y + r.next() * 8000.0; + y as i32 + }) + .collect(); + round_trip("limit-shift", &[correlated], EncoderConfig::new(48_000, 1, 16), 4096); +} diff --git a/crates/audio/tests/audio/encode_format.rs b/crates/audio/tests/audio/encode_format.rs index fb47652c..30b99268 100644 --- a/crates/audio/tests/audio/encode_format.rs +++ b/crates/audio/tests/audio/encode_format.rs @@ -10,6 +10,7 @@ fn only_formats_the_encoder_writes_are_named() { assert_eq!(encode_format_for("BWF"), Some(EncodeFormat::Wav)); assert_eq!(encode_format_for(".aifc"), Some(EncodeFormat::Aiff)); assert_eq!(encode_format_for("flac"), Some(EncodeFormat::Flac)); + assert!(craft_audio::ENCODE_EXTENSIONS.contains(&"flac")); for name in craft_audio::ENCODE_EXTENSIONS { assert!(encode_format_for(name).is_some(), "{name}"); }