use std::sync::OnceLock;
use crate::frame::{BlockType, GranuleSideInfo, GRANULE_LINES};
use crate::header::FrameHeader;
use super::psychoacoustic::PsyResult;
pub const MAX_LEVEL: i32 = 8206;
pub const QUANT_BIAS: f64 = 0.0946;
pub fn requant_magnitude(level: i32) -> f64 {
static T: OnceLock<Vec<f64>> = OnceLock::new();
let t = T.get_or_init(|| {
(0..=MAX_LEVEL as usize)
.map(|i| (i as f64).powf(4.0 / 3.0))
.collect()
});
let a = level.unsigned_abs() as usize;
t.get(a)
.copied()
.unwrap_or_else(|| (a as f64).powf(4.0 / 3.0))
}
pub fn quantize_level(xr: f64) -> i32 {
level_from(xr.abs().powf(0.75))
}
#[inline]
pub(crate) fn level_from(powered: f64) -> i32 {
let m = powered - QUANT_BIAS;
m.round().clamp(0.0, MAX_LEVEL as f64) as i32
}
pub fn xrpow(freq: &[f32; GRANULE_LINES]) -> [f64; GRANULE_LINES] {
let mut p = [0f64; GRANULE_LINES];
if xrpow_use_powf() {
for (pi, &f) in p.iter_mut().zip(freq.iter()) {
*pi = (f.abs() as f64).powf(0.75); }
} else {
for (pi, &f) in p.iter_mut().zip(freq.iter()) {
let a = f.abs() as f64;
*pi = (a * a.sqrt()).sqrt();
}
}
p
}
fn xrpow_use_powf() -> bool {
static USE_POWF: OnceLock<bool> = OnceLock::new();
*USE_POWF.get_or_init(|| {
std::env::var("RFF_MP3_XRPOW")
.map(|v| v == "powf")
.unwrap_or(false)
})
}
#[derive(Debug, Clone)]
pub struct QuantizedGranule {
pub coeffs: [i32; GRANULE_LINES],
pub side: GranuleSideInfo,
pub scalefactors: [u8; 39],
}
impl Default for QuantizedGranule {
fn default() -> Self {
QuantizedGranule {
coeffs: [0; GRANULE_LINES],
side: GranuleSideInfo::default(),
scalefactors: [0; 39],
}
}
}
const MAX_UNCLIPPED: i32 = 8191;
const SF_MULT: f64 = 0.5;
const MAX_SF: u8 = 15;
const MAX_OUTER: usize = 24;
fn quantize_with_sf(
header: &FrameHeader,
freq: &[f32; GRANULE_LINES],
xrp: &[f64; GRANULE_LINES],
gain: i32,
sf: &[u8; 22],
) -> [i32; GRANULE_LINES] {
let off = crate::tables::sfb_long_offsets(header.sample_rate);
let base = -0.25 * (gain - 210) as f64;
let mut coeffs = [0i32; GRANULE_LINES];
for b in 0..22 {
let s = if b < 21 { sf[b] } else { 0 } as f64; let step = 2f64.powf(0.75 * (base + SF_MULT * s));
let (lo, hi) = (off[b] as usize, (off[b + 1] as usize).min(GRANULE_LINES));
for i in lo..hi {
let mag = level_from(xrp[i] * step);
coeffs[i] = if freq[i] < 0.0 { -mag } else { mag };
}
}
coeffs
}
fn band_noise(
header: &FrameHeader,
freq: &[f32; GRANULE_LINES],
coeffs: &[i32; GRANULE_LINES],
gain: i32,
sf: &[u8; 22],
) -> [f32; 21] {
let off = crate::tables::sfb_long_offsets(header.sample_rate);
let mut noise = [0f32; 21];
for (b, n) in noise.iter_mut().enumerate() {
let scale = 2f64.powf(0.25 * (gain - 210) as f64 - SF_MULT * sf[b] as f64);
let (lo, hi) = (off[b] as usize, (off[b + 1] as usize).min(GRANULE_LINES));
let mut e = 0f64;
for i in lo..hi {
let xr = coeffs[i].signum() as f64 * requant_magnitude(coeffs[i]) * scale;
let d = freq[i] as f64 - xr;
e += d * d;
}
*n = e as f32;
}
noise
}
fn bits_for(v: u8) -> u8 {
if v == 0 {
0
} else {
(8 - v.leading_zeros()) as u8
}
}
fn choose_compress(sf: &[u8; 22]) -> (u16, usize) {
let max1 = sf[0..11].iter().copied().max().unwrap_or(0);
let max2 = sf[11..21].iter().copied().max().unwrap_or(0);
let (need1, need2) = (bits_for(max1), bits_for(max2));
for (idx, &(slen1, slen2)) in crate::tables::SCALEFAC_COMPRESS_V1.iter().enumerate() {
if slen1 >= need1 && slen2 >= need2 {
return (idx as u16, 11 * slen1 as usize + 10 * slen2 as usize);
}
}
(15, 11 * 4 + 10 * 3)
}
fn huff_cost(
header: &FrameHeader,
coeffs: &[i32; GRANULE_LINES],
block_type: BlockType,
) -> (GranuleSideInfo, usize) {
super::huffman::select(header, coeffs, block_type)
}
struct InnerResult {
gain: i32,
coeffs: [i32; GRANULE_LINES],
side: GranuleSideInfo,
}
fn inner_gain(
header: &FrameHeader,
freq: &[f32; GRANULE_LINES],
xrp: &[f64; GRANULE_LINES],
sf: &[u8; 22],
huff_budget: usize,
block_type: BlockType,
) -> (i32, Option<InnerResult>) {
let mut cached: Option<InnerResult> = None;
let (mut lo, mut hi) = (0i32, 255i32);
while lo < hi {
let mid = (lo + hi) / 2;
let coeffs = quantize_with_sf(header, freq, xrp, mid, sf);
let fits = coeffs.iter().all(|&c| c.abs() <= MAX_UNCLIPPED) && {
let (side, bits) = huff_cost(header, &coeffs, block_type);
let fits = bits <= huff_budget;
if fits {
cached = Some(InnerResult {
gain: mid,
coeffs,
side,
});
}
fits
};
if fits {
hi = mid;
} else {
lo = mid + 1;
}
}
let cached = cached.filter(|c| c.gain == lo);
(lo, cached)
}
pub fn loops(
header: &FrameHeader,
freq: &[f32; GRANULE_LINES],
psy: &PsyResult,
bit_budget: usize,
block_type: BlockType,
) -> QuantizedGranule {
let mut sf = [0u8; 22];
let mut best: Option<(f32, QuantizedGranule)> = None;
let mut best_iter = 0usize;
let xrp = xrpow(freq);
for outer in 0..MAX_OUTER {
let (compress, sf_bits) = choose_compress(&sf);
let huff_budget = bit_budget.saturating_sub(sf_bits);
let (gain, inner) = inner_gain(header, freq, &xrp, &sf, huff_budget, block_type);
let (coeffs, mut side) = match inner {
Some(r) => (r.coeffs, r.side),
None => {
let coeffs = quantize_with_sf(header, freq, &xrp, gain, &sf);
let (side, _) = huff_cost(header, &coeffs, block_type);
(coeffs, side)
}
};
side.global_gain = gain as u8;
side.scalefac_compress = compress;
let mut scalefactors = [0u8; 39];
scalefactors[..22].copy_from_slice(&sf);
let granule = QuantizedGranule {
coeffs,
side,
scalefactors,
};
let noise = band_noise(header, freq, &granule.coeffs, gain, &sf);
let mut peak_nmr = f32::NEG_INFINITY;
let mut worst: Option<usize> = None;
let mut worst_nmr = f32::NEG_INFINITY;
for (b, &n) in noise.iter().enumerate() {
let nmr = n / psy.thresholds[b].max(1e-20);
peak_nmr = peak_nmr.max(nmr);
if n > psy.thresholds[b] && sf[b] < MAX_SF && nmr > worst_nmr {
worst_nmr = nmr;
worst = Some(b);
}
}
if best.as_ref().is_none_or(|(bn, _)| peak_nmr < *bn) {
best = Some((peak_nmr, granule));
best_iter = outer;
}
match worst {
Some(b) => sf[b] += 1, None => break, }
}
super::prof::OUTER_TOTAL.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
if best_iter == 0 {
super::prof::OUTER_KEPT0.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
}
best.expect("at least one iteration runs").1
}
fn nonclip_floor(
header: &FrameHeader,
freq: &[f32; GRANULE_LINES],
xrp: &[f64; GRANULE_LINES],
) -> i32 {
let flat = [0u8; 22];
let ok = |g: i32| {
quantize_with_sf(header, freq, xrp, g, &flat)
.iter()
.all(|&c| c.abs() <= MAX_UNCLIPPED)
};
let (mut lo, mut hi) = (0i32, 255i32);
while lo < hi {
let mid = (lo + hi) / 2;
if ok(mid) {
hi = mid;
} else {
lo = mid + 1;
}
}
lo
}
pub fn loops_vbr(
header: &FrameHeader,
freq: &[f32; GRANULE_LINES],
psy: &PsyResult,
target_nmr: f32,
block_type: BlockType,
) -> QuantizedGranule {
let flat = [0u8; 22];
let xrp = xrpow(freq);
let peak = |g: i32| {
let coeffs = quantize_with_sf(header, freq, &xrp, g, &flat);
let noise = band_noise(header, freq, &coeffs, g, &flat);
noise
.iter()
.enumerate()
.map(|(b, &n)| n / psy.thresholds[b].max(1e-20))
.fold(0f32, f32::max)
};
let (mut lo, mut hi) = (0i32, 255i32);
while lo < hi {
let mid = (lo + hi + 1) / 2;
if peak(mid) <= target_nmr {
lo = mid;
} else {
hi = mid - 1;
}
}
let gain = lo.max(nonclip_floor(header, freq, &xrp));
let mut sf = [0u8; 22];
for _ in 0..MAX_OUTER {
let coeffs = quantize_with_sf(header, freq, &xrp, gain, &sf);
let noise = band_noise(header, freq, &coeffs, gain, &sf);
let mut worst = None;
let mut worst_nmr = f32::NEG_INFINITY;
for (b, &n) in noise.iter().enumerate() {
let nmr = n / psy.thresholds[b].max(1e-20);
if n > psy.thresholds[b] && sf[b] < MAX_SF && nmr > worst_nmr {
worst_nmr = nmr;
worst = Some(b);
}
}
match worst {
Some(b) => sf[b] += 1,
None => break,
}
}
let coeffs = quantize_with_sf(header, freq, &xrp, gain, &sf);
let (compress, _) = choose_compress(&sf);
let (mut side, _) = super::huffman::select(header, &coeffs, block_type);
side.global_gain = gain as u8;
side.scalefac_compress = compress;
let mut scalefactors = [0u8; 39];
scalefactors[..22].copy_from_slice(&sf);
QuantizedGranule {
coeffs,
side,
scalefactors,
}
}
#[cfg(test)]
mod c2_tests {
use super::*;
use crate::decode::scalefactors::ScaleFactors;
use crate::frame::ChannelMode;
use crate::header::MpegVersion;
fn hdr() -> FrameHeader {
FrameHeader {
version: MpegVersion::V1,
crc_protected: false,
bitrate_kbps: 128,
sample_rate: 44100,
padding: false,
channel_mode: ChannelMode::Mono,
copyright: false,
original: true,
emphasis: 0,
}
}
#[test]
fn xrpow_path_matches_powf_reference() {
let header = hdr();
let mut s = 0xABCD_1234u32;
let mut total = 0usize;
let mut diffs = 0usize;
for trial in 0..40 {
let mut freq = [0f32; GRANULE_LINES];
for f in freq.iter_mut() {
s = s.wrapping_mul(1_664_525).wrapping_add(1_013_904_223);
*f = ((s >> 8) as f32 / (1u32 << 24) as f32 - 0.5) * 2.0 * 1000.0;
}
let xrp = xrpow(&freq);
let off = crate::tables::sfb_long_offsets(header.sample_rate);
for &gain in &[120i32, 180, 210, 230] {
let mut sf = [0u8; 22];
for (b, sfb) in sf.iter_mut().enumerate() {
*sfb = ((trial + b) % 4) as u8;
}
let got = quantize_with_sf(&header, &freq, &xrp, gain, &sf);
let base = -0.25 * (gain - 210) as f64;
for b in 0..22 {
let sv = if b < 21 { sf[b] } else { 0 } as f64;
let scale_inv = 2f64.powf(base + SF_MULT * sv);
let (lo, hi) = (off[b] as usize, (off[b + 1] as usize).min(GRANULE_LINES));
for i in lo..hi {
let mag = quantize_level(freq[i].abs() as f64 * scale_inv);
let want = if freq[i] < 0.0 { -mag } else { mag };
total += 1;
if got[i] != want {
assert!(
(got[i] - want).abs() <= 1,
"line {i}: table {} vs powf {want} (gain {gain})",
got[i]
);
diffs += 1;
}
}
}
}
}
assert!(
diffs * 1000 < total,
"too many xrpow/powf mismatches: {diffs}/{total}"
);
eprintln!("[A1] xrpow vs powf: {diffs}/{total} off-by-one (ULP) lines");
}
#[test]
fn spectrum_roundtrip_through_quantizer() {
let header = hdr();
let mut freq = [0f32; GRANULE_LINES];
freq[40] = 5.0;
freq[41] = -3.0;
freq[100] = 1.2;
freq[200] = 0.6;
let psy = PsyResult::default();
let q = loops(&header, &freq, &psy, 100_000, BlockType::Long); eprintln!(
"[C2dbg] gain={} part2_3={} nz_coeffs={}",
q.side.global_gain,
q.side.part2_3_length,
q.coeffs.iter().filter(|&&c| c != 0).count()
);
let mut sf = ScaleFactors::default();
sf.long.copy_from_slice(&q.scalefactors[..22]);
let mut out = [0f32; GRANULE_LINES];
let nz = q.coeffs.iter().rposition(|&c| c != 0).map_or(0, |i| i + 1);
crate::decode::requantize::apply(&header, &q.side, &sf, &q.coeffs, nz, &mut out);
let mut maxerr = 0f32;
for i in 0..GRANULE_LINES {
maxerr = maxerr.max((out[i] - freq[i]).abs());
}
eprintln!(
"[C2dbg] requant maxerr={maxerr} out[40]={} out[41]={}",
out[40], out[41]
);
assert!(maxerr < 0.2, "spectrum round-trip error {maxerr}");
}
}
#[cfg(test)]
mod q6_tests {
use super::*;
use crate::frame::{BlockType, ChannelMode, GranuleSideInfo};
use crate::header::MpegVersion;
fn hdr() -> FrameHeader {
FrameHeader {
version: MpegVersion::V1,
crc_protected: false,
bitrate_kbps: 128,
sample_rate: 44100,
padding: false,
channel_mode: ChannelMode::Mono,
copyright: false,
original: true,
emphasis: 0,
}
}
fn peak_nmr_db(
header: &FrameHeader,
freq: &[f32; GRANULE_LINES],
g: &QuantizedGranule,
thresholds: &[f32; 22],
) -> f32 {
let mut sf = [0u8; 22];
sf.copy_from_slice(&g.scalefactors[..22]);
let noise = band_noise(header, freq, &g.coeffs, g.side.global_gain as i32, &sf);
let mut peak = f32::NEG_INFINITY;
for (b, &n) in noise.iter().enumerate() {
peak = peak.max(10.0 * (n / thresholds[b].max(1e-20)).log10());
}
peak
}
#[test]
fn distortion_loop_beats_flat_on_a_complex_signal() {
let header = hdr();
let sr = 44100.0;
let pcm: Vec<f32> = (0..1152)
.map(|i| {
let t = i as f32 / sr;
0.35 * (2.0 * std::f32::consts::PI * 600.0 * t).sin()
+ 0.2 * (2.0 * std::f32::consts::PI * 5200.0 * t).sin()
})
.collect();
let psy = super::super::psychoacoustic::analyze(&pcm, 44100);
let mut fifo = [0f32; 512];
let sub = super::super::filterbank::analyze(&pcm, &mut fifo);
let mut overlap = [0f32; GRANULE_LINES];
let mut freq = super::super::mdct::forward(&sub, BlockType::Long, &mut overlap);
super::super::antialias::expand(&GranuleSideInfo::default(), &mut freq);
let budget = 1600;
let flat = PsyResult {
thresholds: [f32::MAX; 22], ..psy.clone()
};
let shaped = loops(&header, &freq, &psy, budget, BlockType::Long);
let plain = loops(&header, &freq, &flat, budget, BlockType::Long);
let nmr_shaped = peak_nmr_db(&header, &freq, &shaped, &psy.thresholds);
let nmr_plain = peak_nmr_db(&header, &freq, &plain, &psy.thresholds);
eprintln!("[Q6] peak NMR: shaped {nmr_shaped:.1} dB vs flat {nmr_plain:.1} dB");
assert!(
nmr_shaped <= nmr_plain + 0.01,
"psymodel shaping must not worsen peak NMR: {nmr_shaped} vs {nmr_plain}"
);
}
}
#[cfg(test)]
mod n4_tests {
use super::*;
#[test]
fn requant_magnitude_matches_power_law() {
for level in [0, 1, 2, 3, 17, 255, 1024, MAX_LEVEL] {
let expect = (level as f64).powf(4.0 / 3.0);
assert!((requant_magnitude(level) - expect).abs() < 1e-9);
}
assert_eq!(requant_magnitude(-3), requant_magnitude(3));
}
#[test]
fn forward_inverse_round_trip_on_the_lattice() {
for level in 0..=MAX_LEVEL {
let xr = requant_magnitude(level);
assert_eq!(
quantize_level(xr),
level,
"round-trip failed at level {level} (xr={xr})"
);
}
}
#[test]
fn quantizer_clamps_and_zeroes() {
assert_eq!(quantize_level(0.0), 0);
assert_eq!(quantize_level(0.3), 0);
assert_eq!(quantize_level(1.0e9), MAX_LEVEL);
}
#[test]
fn level_from_matches_guarded() {
let guarded = |powered: f64| -> i32 {
let m = powered - QUANT_BIAS;
if m <= 0.0 {
0
} else {
(m.round() as i32).clamp(0, MAX_LEVEL)
}
};
let mut p = -1.0f64;
while p < 9000.0 {
assert_eq!(level_from(p), guarded(p), "level_from mismatch at {p}");
p += 0.013; }
for n in 0..50 {
let mid = n as f64 + 0.5 + QUANT_BIAS;
assert_eq!(level_from(mid), guarded(mid), "midpoint {mid}");
}
for &p in &[f64::from(0), 1e9, MAX_LEVEL as f64 + 5.0] {
assert_eq!(level_from(p), guarded(p));
}
}
}