use std::sync::OnceLock;
use super::smpl_tables_blob::tables::Region as SmplMemRegion;
pub(crate) use super::smpl_tables_blob::tables::HeapWindow as SmplMem;
static SMPL_MEM: OnceLock<SmplMem> = OnceLock::new();
#[cfg(test)]
pub(crate) fn parse_smpl_mem_json(s: &str) -> SmplMem {
#[derive(serde::Deserialize)]
struct RawRegion {
base: u32,
b64: String,
}
#[derive(serde::Deserialize)]
struct Raw {
regions: Vec<RawRegion>,
g_cc: u32,
g_nrg: u32,
g_pitch: u32,
clk: u32,
}
use base64::Engine;
let raw: Raw = serde_json::from_str(s).expect("smpl_cc_blob.json must parse");
let engine = base64::engine::general_purpose::STANDARD;
let regions = raw
.regions
.into_iter()
.map(|r| SmplMemRegion {
base: r.base,
data: engine.decode(r.b64).expect("smpl_cc_blob region b64"),
})
.collect();
SmplMem {
regions,
g_cc: raw.g_cc,
g_nrg: raw.g_nrg,
g_pitch: raw.g_pitch,
g_clk: raw.clk,
}
}
const G_CLK: u32 = 0xb9f9a8;
const G_PITCH: u32 = 0xb9d378;
const PCFG: u32 = G_CLK.wrapping_add(0x5704);
const HDR_CONTOUR_MAP: u32 = 0xe7c10;
const HDR_LAG_CDF: u32 = 0xbaa7b0;
const HDR_FRAC_BASE: u32 = 0xbaa9be;
const HDR_DELTA_CDF: u32 = 0xbab13e;
const HDR_UNUSED: [u32; 3] = [0xe7d20, 0xe7ef0, 0xe8096];
const DELTA_BOUNDS_ADDR: u32 = 0xe7ef0;
const NUM_CONTOURS: usize = 217;
fn build_smpl_mem() -> SmplMem {
let seed: super::smpl_pitch_seed::PitchSeed =
super::smpl_tables_blob::load_blob_buffa(include_bytes!("testdata/pitch_seed.bin"));
let w = seed.build_contour_window();
let mut regions = Vec::with_capacity(6);
let push = |regions: &mut Vec<SmplMemRegion>, base: u32, data: Vec<u8>| {
regions.push(SmplMemRegion { base, data });
};
let mut r0 = Vec::with_capacity(NUM_CONTOURS * 0x44 + 4 + 32);
for (lags, seglens) in &w.records {
let sc = lags.len();
for i in 0..8 {
r0.extend_from_slice(&(*lags.get(i).unwrap_or(&0) as i32).to_le_bytes());
}
for i in 0..8 {
r0.extend_from_slice(&(*seglens.get(i).unwrap_or(&0) as i32).to_le_bytes());
}
r0.extend_from_slice(&(sc as i32).to_le_bytes());
}
r0.extend_from_slice(&187u32.to_le_bytes());
for h in [
NUM_CONTOURS as u32,
HDR_CONTOUR_MAP,
HDR_LAG_CDF,
HDR_FRAC_BASE,
HDR_UNUSED[0],
HDR_UNUSED[1],
HDR_UNUSED[2],
HDR_DELTA_CDF,
] {
r0.extend_from_slice(&h.to_le_bytes());
}
push(&mut regions, PCFG.wrapping_add(0x1d38), r0);
let u16_bytes =
|v: &[u32]| -> Vec<u8> { v.iter().flat_map(|&x| (x as u16).to_le_bytes()).collect() };
push(&mut regions, HDR_LAG_CDF, u16_bytes(&w.lag_cdf));
let frac: Vec<u32> = w.frac_cmfs.iter().flatten().copied().collect();
push(&mut regions, HDR_FRAC_BASE, u16_bytes(&frac));
let delta: Vec<u32> = w.delta_cmfs.iter().flatten().copied().collect();
push(&mut regions, HDR_DELTA_CDF, u16_bytes(&delta));
push(&mut regions, HDR_CONTOUR_MAP, w.contour_map.clone());
let mut bounds: Vec<u8> = w
.firstblock_range
.iter()
.flat_map(|&[lo, hi]| [lo as u8, hi as u8])
.collect();
bounds.extend_from_slice(&[0, 0]);
push(&mut regions, DELTA_BOUNDS_ADDR, bounds);
SmplMem {
regions,
g_cc: 0,
g_nrg: 0,
g_pitch: G_PITCH,
g_clk: G_CLK,
}
}
pub(crate) fn load_smpl_mem() -> &'static SmplMem {
SMPL_MEM.get_or_init(build_smpl_mem)
}
impl SmplMem {
fn region_for(&self, addr: u32, n: usize) -> Option<(&[u8], usize)> {
for r in &self.regions {
if addr >= r.base && (addr - r.base) as usize + n <= r.data.len() {
return Some((&r.data, (addr - r.base) as usize));
}
}
None
}
pub(crate) fn u8(&self, addr: u32) -> u8 {
self.region_for(addr, 1).map_or(0, |(d, off)| d[off])
}
pub(crate) fn u16(&self, addr: u32) -> u16 {
self.region_for(addr, 2)
.map_or(0, |(d, off)| u16::from_le_bytes([d[off], d[off + 1]]))
}
pub(crate) fn i16(&self, addr: u32) -> i16 {
self.u16(addr) as i16
}
pub(crate) fn u32(&self, addr: u32) -> u32 {
self.region_for(addr, 4).map_or(0, |(d, off)| {
u32::from_le_bytes([d[off], d[off + 1], d[off + 2], d[off + 3]])
})
}
pub(crate) fn i32(&self, addr: u32) -> i32 {
self.u32(addr) as i32
}
pub(crate) fn cdf_at(&self, addr: u32, n: usize) -> Vec<u16> {
(0..n)
.map(|i| self.u16(addr.wrapping_add((i as u32) * 2)))
.collect()
}
pub(crate) fn cdf_bytes(&self, addr: u32, n: usize) -> Option<&[u8]> {
let (data, off) = self.region_for(addr, n * 2)?;
Some(&data[off..off + n * 2])
}
}
#[cfg(test)]
pub(crate) fn try_load_full_heap() -> Option<SmplMem> {
let s = std::fs::read_to_string("src/voip/mlow/testdata/smpl_cc_blob.json").ok()?;
Some(parse_smpl_mem_json(&s))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn pitch_contour_window_complete_vs_heap() {
let Some(full) = try_load_full_heap() else {
println!("smpl_cc_blob.json absent; skipping completeness gate");
return;
};
let window = load_smpl_mem();
let gclk = full.g_clk;
let pcfg = gclk.wrapping_add(0x5704);
let chk_u8 = |a: u32| assert_eq!(window.u8(a), full.u8(a), "u8 miss @ {a:#x}");
let chk_u32 = |a: u32| assert_eq!(window.u32(a), full.u32(a), "u32 miss @ {a:#x}");
let chk_cdf = |a: u32, n: usize| {
assert_eq!(window.cdf_at(a, n), full.cdf_at(a, n), "cdf miss @ {a:#x}")
};
for off in [22240u32, 22244, 22248, 22252, 22268] {
chk_u32(pcfg.wrapping_add(off));
}
let num_contours = full.u32(pcfg.wrapping_add(22240)) as i32;
let contour_map = full.u32(pcfg.wrapping_add(22244));
let lag_cdf = full.u32(pcfg.wrapping_add(22248));
let frac_base = full.u32(pcfg.wrapping_add(22252));
let delta_cdf = full.u32(pcfg.wrapping_add(22268));
chk_cdf(lag_cdf, (num_contours + 1).max(0) as usize);
for di in 0..10u32 {
let lo = full.u8(0xe7ef0u32.wrapping_add(di * 2)) as i32;
let hi = full.u8(0xe7ef0u32.wrapping_add(di * 2 + 1)) as i32;
chk_u8(0xe7ef0u32.wrapping_add(di * 2));
chk_u8(0xe7ef0u32.wrapping_add(di * 2 + 1));
let r_n = (hi - lo) + 2;
if r_n >= 2 {
chk_cdf(lag_cdf.wrapping_add((lo as u32) * 2), r_n as usize);
}
}
let mut max_prev = 0i32;
for c in 0..num_contours {
let ctr_base = pcfg.wrapping_add((c as u32) * 0x44);
let sc = full.i32(ctr_base.wrapping_add(0x1d78)).max(1);
for s in 0..sc {
max_prev = max_prev.max(full.i32(ctr_base.wrapping_add(0x1d38) + (s as u32) * 4));
}
}
for prev in 0..=max_prev {
chk_cdf(delta_cdf.wrapping_add((prev as u32) * 20), 10);
}
for i in 0..217u32 {
chk_u8(contour_map.wrapping_add(i));
}
for c in 0..num_contours {
let ctr_base = pcfg.wrapping_add((c as u32) * 0x44);
let sc = full.i32(ctr_base.wrapping_add(0x1d78));
chk_u32(ctr_base.wrapping_add(0x1d78));
chk_u32(ctr_base.wrapping_add(0x1d38)); chk_u32(ctr_base.wrapping_add(0x1d58)); for s in 0..sc.max(0) {
chk_u32(ctr_base.wrapping_add(0x1d38) + (s as u32) * 4);
chk_u32(ctr_base.wrapping_add(0x1d58) + (s as u32) * 4);
}
for seg_sel in 0..3u32 {
let frac_seg_base = frac_base.wrapping_add(seg_sel * 0x280);
for nl2 in 0..0x40i32 {
let off = frac_seg_base
.wrapping_add((nl2 * 2) as u32)
.wrapping_add(0xfe);
chk_cdf(off, 65);
}
}
}
}
}