//! 8-bit µ-law to 16-bit linear decode table -- ITU-T G.711 (1972, reaffirmed 2000).
//!
//! The table is computed at compile time by [`mulaw_to_linear`], a `const fn`
//! that encodes the standard piecewise-linear decoding formula. The 256-entry
//! table fits in L1; the table lookup is the decode fast path -- no branchy
//! segment arithmetic at decode call time.
//!
//! # The µ-law decode formula (ITU-T G.711 reference, teachable-moment)
//!
//! µ-law bytes are stored bit-inverted on the wire (the encoder finishes with
//! a bitwise XOR mask, see `mulaw_encode_table.rs`). The decoder's first move
//! is therefore `let toggled = !u;` -- undo the encoder's terminal inversion
//! and recover the raw exponent/mantissa/sign bits.
//!
//! After toggling:
//!   * bit 7 (MSB) = 1  --> original PCM was NEGATIVE.
//!   * bits 6..4        --> 3-bit segment exponent (0..7); larger = louder.
//!   * bits 3..0        --> 4-bit mantissa (offset within segment).
//!
//! The biased magnitude is reconstructed as
//!   `t = ((mantissa << 3) + BIAS) << exponent`  (BIAS = 0x84 = 132),
//! then the reference decoder applies a final sign-aware adjustment:
//!   * positive --> return `t - BIAS`
//!   * negative --> return `BIAS - t`
//!
//! This BIAS add/subtract on both sides of the encode/decode is the companding
//! "compression mid-tread" property: zero PCM in, zero PCM out (silent input
//! encodes to 0xFF, decodes back to 0). The asymmetry `BIAS - t` for the
//! negative branch is what gives µ-law its slightly larger dynamic range on
//! the negative side (one extra notch below zero that the positive side lacks).
//!
//! # Why NOT a `g711` crate dep
//!
//! The codec has been standard since 1972 and is ~30 lines of table-driven
//! code. Pulling a dependency for a constant-mapping table violates the FOB
//! hygiene rule (ADR-0008 -- link mature OSS only when the complexity is
//! non-trivial; this is neither). It's also learner-facing: this file
//! TEACHES the telephony history, which earns the project's "learns Rust
//! from this codebase" goal a real win.

/// Decode bias per ITU-T G.711 §2.2 (the Sun Microsystems reference impl uses
/// bias = 0x84 = 132 for both decode and encode; the magic number traces
/// directly to the µ-law segment boundary at `BIAS << exponent`, which keeps
/// segment 0's t-value range `[BIAS, BIAS + 0x70)` exactly proportional to
/// the µ-law quantization step).
const BIAS: i32 = 0x84;

/// Convert one 8-bit µ-law byte to a 16-bit linear PCM sample.
///
/// Generated at compile time so the [`MULAW_TO_LINEAR`] table is a `static`
/// array -- no runtime cost beyond the L1 cache for the 256-byte lookup.
///
/// # Algorithm
///
/// Mirrors the ITU-T G.711 reference decoder (Sun Microsystems variant,
/// public domain). See the module-level docs for the formula walkthrough.
const fn mulaw_to_linear(u: u8) -> i16 {
    // Undo the encoder's terminal bitwise XOR mask (0xFF for positive,
    // 0x7F for negative). NOT is wholesale inversion -- recovers the raw
    // sign | exponent | mantissa bits the encoder assembled pre-XOR.
    let toggled = !u;

    // After NOT: MSB = 1 iff the original PCM sample was NEGATIVE.
    let is_negative = (toggled & 0x80) != 0;

    let exponent = ((toggled >> 4) & 0x07) as i32;
    let mantissa = (toggled & 0x0F) as i32;

    // Reconstruct the biased magnitude: `((mant << 3) + BIAS) << exp`.
    // The `<< 3` aligns the 4-bit mantissa to the segment's 8-sample step;
    // the `+ BIAS` shifts every segment's range up by BIAS so the lowest
    // segment (exp=0) covers `[BIAS, BIAS + 0x70)` (the µ-law near-zero band).
    let t = ((mantissa << 3) + BIAS) << exponent;

    // Sign-aware final adjustment -- the reference decoder does NOT just
    // subtract the bias from `t` symmetrically: the negative branch inverts
    // the subtraction (`BIAS - t`), preserving the µ-law "mid-tread" zero.
    // With this, an input of zero PCM decodes back through `mulaw_to_linear`
    // (the encoder maps 0 -> 0xFF) and yields zero, not BIAS.
    if is_negative {
        (BIAS - t) as i16
    } else {
        (t - BIAS) as i16
    }
}

/// 256-entry µ-law decode table (one slot per possible 8-bit byte).
///
/// `#[rustfmt::skip]` keeps rustfmt from reflowing the const-eval initializer
/// (a `while` loop initializing 256 entries) -- the canonical idiom for
/// compile-time table generation in stable Rust (no `const_for` needed).
#[rustfmt::skip]
pub static MULAW_TO_LINEAR: [i16; 256] = {
    let mut t = [0i16; 256];
    let mut i = 0;
    while i < 256 {
        t[i] = mulaw_to_linear(i as u8);
        i += 1;
    }
    t
};
