use crate::core::fixed::tables::{pow2_frac_q16_16, sin_pi_ratio_q30};
pub(crate) const EXP_ROM: [u16; 256] = {
let mut t = [0u16; 256];
let mut lo = 0usize;
while lo < 256 {
let p = pow2_frac_q16_16((768 - 3 * lo) as u32);
t[lo] = ((p + 64) >> 7) as u16;
lo += 1;
}
t
};
pub(crate) const LOGSIN_ROM: [u16; 256] = {
let mut t = [0u16; 256];
let mut i = 0u32;
while i < 256 {
let mut s = sin_pi_ratio_q30(2 * i + 1, 1024);
let mut hi: u16 = 0;
let half: i64 = 1i64 << 29;
while s < half {
s <<= 1;
hi += 1;
}
let target = (((s * 1024) + (1i64 << 29)) >> 30) as i32;
let mut best_lo = 0u16;
let mut best_d = i32::MAX;
let mut lo = 0usize;
while lo < 256 {
let diff = EXP_ROM[lo] as i32 - target;
let d = if diff < 0 { -diff } else { diff };
if d < best_d {
best_d = d;
best_lo = lo as u16;
}
lo += 1;
}
t[i as usize] = 256 * hi + best_lo;
i += 1;
}
t
};
#[rustfmt::skip]
pub(crate) const MUL: [u32; 16] = [1, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 20, 24, 24, 30, 30];
#[rustfmt::skip]
pub(crate) const KSL: [u16; 16] = [0, 32, 40, 45, 48, 51, 53, 55, 56, 58, 59, 60, 61, 62, 63, 64];
pub(crate) const KSL_SHIFT: [u8; 4] = [8, 1, 2, 0];
#[cfg(test)]
mod tests {
use super::*;
use alloc::vec::Vec;
#[rustfmt::skip]
const CANON_LOGSIN: [u16; 256] = [
2137, 1731, 1543, 1419, 1326, 1252, 1190, 1137, 1091, 1050, 1013, 979, 949, 920, 894, 869,
846, 825, 804, 785, 767, 749, 732, 717, 701, 687, 672, 659, 646, 633, 621, 609,
598, 587, 576, 566, 556, 546, 536, 527, 518, 509, 501, 492, 484, 476, 468, 461,
453, 446, 439, 432, 425, 418, 411, 405, 399, 392, 386, 380, 375, 369, 363, 358,
352, 347, 341, 336, 331, 326, 321, 316, 311, 307, 302, 297, 293, 289, 284, 280,
276, 271, 267, 263, 259, 255, 251, 248, 244, 240, 236, 233, 229, 226, 222, 219,
215, 212, 209, 205, 202, 199, 196, 193, 190, 187, 184, 181, 178, 175, 172, 169,
167, 164, 161, 159, 156, 153, 151, 148, 146, 143, 141, 138, 136, 134, 131, 129,
127, 125, 122, 120, 118, 116, 114, 112, 110, 108, 106, 104, 102, 100, 98, 96,
94, 92, 91, 89, 87, 85, 83, 82, 80, 78, 77, 75, 74, 72, 70, 69,
67, 66, 64, 63, 62, 60, 59, 57, 56, 55, 53, 52, 51, 49, 48, 47,
46, 45, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, 30,
29, 28, 27, 26, 25, 24, 23, 23, 22, 21, 20, 20, 19, 18, 17, 17,
16, 15, 15, 14, 13, 13, 12, 12, 11, 10, 10, 9, 9, 8, 8, 7,
7, 7, 6, 6, 5, 5, 5, 4, 4, 4, 3, 3, 3, 2, 2, 2,
2, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,
];
#[test]
fn generated_tables_match_canonical() {
assert_eq!(EXP_ROM[0], 1024);
assert!((512..=514).contains(&EXP_ROM[255]));
for i in 0..256 {
let d = (LOGSIN_ROM[i] as i32 - CANON_LOGSIN[i] as i32).abs();
assert!(
d <= 1,
"LOGSIN[{i}] = {} vs {}",
LOGSIN_ROM[i],
CANON_LOGSIN[i]
);
}
}
fn full_sine(phase1024: u32) -> i32 {
let quad = (phase1024 >> 8) & 3;
let mut idx = (phase1024 & 0xFF) as usize;
if quad & 1 != 0 {
idx = 255 - idx;
}
let att = LOGSIN_ROM[idx] as u32;
let mag = (EXP_ROM[(att & 0xFF) as usize] >> (att >> 8)) as i32;
if quad & 2 != 0 {
-mag
} else {
mag
}
}
#[test]
fn tables_reconstruct_full_sine() {
assert_eq!(full_sine(256), 1024);
assert_eq!(full_sine(768), -1024);
let vals: Vec<i32> = (0..1024).map(full_sine).collect();
assert_eq!(*vals.iter().max().unwrap(), 1024);
assert_eq!(*vals.iter().min().unwrap(), -1024);
for p in 1..256 {
assert!(full_sine(p) >= full_sine(p - 1));
}
}
}