use crate::bitstream::BitstreamReader;
use crate::fixedpoint::*;
use crate::tables::*;
const MAX_SUBBANDS: usize = 14;
const SAMPLES_PER_SUBBAND: usize = 20;
pub const FRAME_SIZE: usize = 320;
const NOISE_GAINS: [i16; 3] = [0x16a1, 0x2000, 0x5a82];
pub struct DecoderState {
pub bitrate: u16,
pub bits_per_frame: i16,
pub encoded_frame_size: i16,
pub num_subbands: i16,
pub prng_state: [i16; 4],
pub synth_memory: [i16; 320],
pub filterbank_memory: [i16; 640],
}
impl DecoderState {
pub fn new(bitrate: u16) -> Result<Self, u32> {
let (validated, err) = if bitrate < 4800 || bitrate > 32000 {
(16000u16, 8u32)
} else {
let snapped = ((bitrate as u32 + 400) / 800 * 800) as u16;
if snapped != bitrate {
(snapped, 8)
} else {
(bitrate, 0)
}
};
let bits_per_frame = (validated as i32 / 50) as i16;
let encoded_frame_size = (validated as i32 / 800) as i16;
let num_subbands = if validated >= 16000 {
14
} else if validated >= 12000 {
12
} else if validated >= 9600 {
10
} else {
8
};
let state = DecoderState {
bitrate: validated,
bits_per_frame,
encoded_frame_size,
num_subbands,
prng_state: [1, 1, 1, 1],
synth_memory: [0; 320],
filterbank_memory: [0; 640],
};
if err != 0 {
Err(err)
} else {
Ok(state)
}
}
pub fn decode_frame_to_subbands(
&mut self,
input: &[i16],
output: &mut [i16; FRAME_SIZE],
) -> i16 {
let mut bs = BitstreamReader::new(input, self.bits_per_frame);
let mut scale_param: i16 = 0;
self.decode_frame_params(&mut bs, output, &mut scale_param);
scale_param
}
fn decode_frame_params(
&mut self,
bs: &mut BitstreamReader,
output: &mut [i16; FRAME_SIZE],
scale_param: &mut i16,
) {
let ns = self.num_subbands as usize;
let total_samples = ns * SAMPLES_PER_SUBBAND;
let mut gains = [0i16; MAX_SUBBANDS];
let mut scale_factors = [0i16; MAX_SUBBANDS];
self.decode_gains(bs, ns, &mut scale_factors, &mut gains, scale_param);
let frame_param = bs.read_bits(4);
bs.total_bits_remaining = sub(bs.total_bits_remaining, 4);
let mut alloc = [0i16; MAX_SUBBANDS];
let mut scratch = [0i16; 32];
let remaining = bs.total_bits_remaining;
compute_bit_alloc_for_frame(
remaining,
self.num_subbands,
&gains[..ns],
&mut alloc[..ns],
&mut scratch,
);
increment_allocation_bins(frame_param, &mut alloc, &scratch);
self.decode_subframes(bs, ns, &scale_factors, &mut alloc, output);
for s in output[total_samples..FRAME_SIZE].iter_mut() {
*s = 0;
}
}
fn decode_gains(
&self,
bs: &mut BitstreamReader,
num_subbands: usize,
scale_factors_out: &mut [i16; MAX_SUBBANDS],
gains_out: &mut [i16; MAX_SUBBANDS],
scale_param: &mut i16,
) {
let initial_index = bs.read_bits(5);
bs.total_bits_remaining = sub(bs.total_bits_remaining, 5);
let initial_gain = sub(initial_index, 7);
let mut differentials = [0i16; MAX_SUBBANDS];
if num_subbands > 1 {
let mut tree_base: usize = 23;
for d in 0..(num_subbands - 1) {
let mut node: i16 = 0;
loop {
bs.read_bit();
let entry = node as usize + tree_base;
node = if bs.last_bit == 0 {
GAIN_HUFFMAN_TREE[entry][0]
} else {
GAIN_HUFFMAN_TREE[entry][1]
};
bs.total_bits_remaining = sub(bs.total_bits_remaining, 1);
if node <= 0 {
break;
}
}
differentials[d] = negate(node);
tree_base += 23;
}
}
gains_out[0] = initial_gain;
for i in 0..(num_subbands - 1) {
let sum = l_add(gains_out[i] as i32, differentials[i] as i32);
let sum2 = l_add(sum, -12);
gains_out[i + 1] = extract_l(sum2);
}
let mut total_cost: i16 = 0;
let mut max_eff_gain: i16 = 0;
for i in 0..num_subbands {
let eff = l_add(gains_out[i] as i32, 0x18);
let eff_i16 = extract_l(eff);
let diff = sub(eff_i16, max_eff_gain);
if diff > 0 {
max_eff_gain = eff_i16;
}
total_cost = add(total_cost, SCALE_FACTOR_BITS[eff_i16 as usize]);
}
let mut sp: i16 = 9;
let mut cost_check = sub(total_cost, 8);
let mut gain_check = sub(max_eff_gain, 0x1c);
loop {
if cost_check < 0 && gain_check < 1 {
break;
}
sp = sub(sp, 1);
total_cost = shr(total_cost, 1);
max_eff_gain = sub(max_eff_gain, 2);
cost_check = sub(total_cost, 8);
gain_check = sub(max_eff_gain, 0x1c);
if sp < 0 {
break;
}
}
*scale_param = sp;
let offset = (sp * 2 + 0x18) as i16;
for i in 0..num_subbands {
let idx = l_add(gains_out[i] as i32, offset as i32);
let idx_i16 = extract_l(idx);
scale_factors_out[i] = SCALE_FACTOR_BITS[idx_i16 as usize];
}
}
fn decode_subframes(
&mut self,
bs: &mut BitstreamReader,
num_subbands: usize,
scale_factors: &[i16; MAX_SUBBANDS],
alloc: &mut [i16; MAX_SUBBANDS],
output: &mut [i16; FRAME_SIZE],
) {
let mut error = false;
for sb in 0..num_subbands {
let step = alloc[sb];
let scale = scale_factors[sb];
let out_base = sb * SAMPLES_PER_SUBBAND;
for k in 0..SAMPLES_PER_SUBBAND {
output[out_base + k] = 0;
}
if sub(step, 7) < 0 && !error {
let tree = codebook_tree(step);
let num_subframes = QUANT_NUM_COEFF[step as usize];
let num_levels = QUANT_LEVELS_M1[step as usize];
if num_subframes >= 1 {
let mut out_pos = out_base;
let mut sf = 0i16;
'subframe_loop: while sf < num_subframes {
if bs.total_bits_remaining < 1 {
error = true;
self.set_error_state(sb, num_subbands, alloc);
break;
}
let mut node: i16 = 0;
loop {
if bs.total_bits_remaining < 1 {
error = true;
self.set_error_state(sb, num_subbands, alloc);
for k in 0..SAMPLES_PER_SUBBAND {
output[out_base + k] = 0;
}
break 'subframe_loop;
}
bs.read_bit();
let child = if bs.last_bit == 0 {
tree[(node as usize) * 2]
} else {
tree[(node as usize) * 2 + 1]
};
node = child;
bs.total_bits_remaining =
sub(bs.total_bits_remaining, 1);
if child <= 0 {
break;
}
}
if error {
break;
}
let symbol = negate(node);
let mut digits = [0i16; 6];
let num_nonzero = inverse_quantize(symbol, &mut digits, step);
if sub(bs.total_bits_remaining, num_nonzero) < 0 {
error = true;
self.set_error_state(sb, num_subbands, alloc);
for k in 0..SAMPLES_PER_SUBBAND {
output[out_base + k] = 0;
}
break;
}
let mut sign_bits: i16 = 0;
let mut sign_mask: i16 = 0;
if num_nonzero != 0 {
for _ in 0..num_nonzero {
bs.read_bit();
sign_bits = add(shl(sign_bits, 1), bs.last_bit);
bs.total_bits_remaining =
sub(bs.total_bits_remaining, 1);
}
sign_mask = shl(1, sub(num_nonzero, 1));
}
if num_levels > 0 {
for j in 0..(num_levels as usize) {
let recon =
QUANT_RECON_LEVELS[step as usize][digits[j] as usize];
let product = l_mult0(scale, recon);
let shifted = l_shr(product, 12);
let mut sample = extract_l(shifted);
if sample != 0 {
if (sign_mask as u16 & sign_bits as u16) == 0 {
sample = negate(sample);
}
sign_mask = shr(sign_mask, 1);
}
output[out_pos] = sample;
out_pos += 1;
}
}
sf += 1;
}
}
} else if error {
alloc[sb] = 7;
}
let current_step = alloc[sb];
if current_step == 5 || current_step == 6 {
let gain_idx = (current_step - 5) as usize;
let noise_level = mult(scale, NOISE_GAINS[gain_idx]);
let neg_noise = negate(noise_level);
let mut prng_val = noise_prng(&mut self.prng_state);
for k in 0..10 {
let pos = out_base + k;
if output[pos] == 0 {
output[pos] = if (prng_val as u16 & 1) != 0 {
noise_level
} else {
neg_noise
};
prng_val = shr(prng_val, 1);
}
}
prng_val = noise_prng(&mut self.prng_state);
for k in 10..20 {
let pos = out_base + k;
if output[pos] == 0 {
output[pos] = if (prng_val as u16 & 1) != 0 {
noise_level
} else {
neg_noise
};
prng_val = shr(prng_val, 1);
}
}
}
if current_step == 7 {
let gain_idx = (current_step - 5) as usize; let noise_level = mult(scale, NOISE_GAINS[gain_idx]);
let neg_noise = negate(noise_level);
let mut prng_val = noise_prng(&mut self.prng_state);
for k in 0..10 {
let pos = out_base + k;
output[pos] = if (prng_val as u16 & 1) != 0 {
noise_level
} else {
neg_noise
};
prng_val = shr(prng_val, 1);
}
prng_val = noise_prng(&mut self.prng_state);
for k in 10..20 {
let pos = out_base + k;
output[pos] = if (prng_val as u16 & 1) != 0 {
noise_level
} else {
neg_noise
};
prng_val = shr(prng_val, 1);
}
}
}
if error {
bs.total_bits_remaining = sub(bs.total_bits_remaining, 1);
}
}
fn set_error_state(&self, current_sb: usize, num_subbands: usize, alloc: &mut [i16; MAX_SUBBANDS]) {
let next_sb = current_sb + 1;
if next_sb < num_subbands {
for i in next_sb..num_subbands {
alloc[i] = 7;
}
}
alloc[current_sb] = 7;
}
}
pub(crate) fn compute_bit_alloc_for_frame(
remaining_bits: i16,
num_subbands: i16,
gains: &[i16],
alloc: &mut [i16],
scratch: &mut [i16],
) {
let budget = if sub(remaining_bits, 0x140) > 0 {
let excess = sub(remaining_bits, 0x140);
let scaled = l_mult0(excess, 5);
let reduced = shr(extract_l(scaled), 3);
add(reduced, 0x140)
} else {
remaining_bits
};
let threshold = search_threshold(gains, num_subbands, budget);
compute_allocation(alloc, gains, num_subbands, threshold);
optimize_allocation(alloc, scratch, gains, budget, num_subbands, 16, threshold);
}
pub(crate) fn search_threshold(gains: &[i16], num_subbands: i16, budget: i16) -> i16 {
let ns = num_subbands as usize;
let mut thresh: i16 = -32;
let mut step: i16 = 32;
loop {
let candidate = add(thresh, step);
let mut local_alloc = [0i16; MAX_SUBBANDS];
for i in 0..ns {
let diff = sub(candidate, gains[i]);
let mut q = shr(diff, 1);
if q < 0 {
q = 0;
}
if sub(q, 7) > 0 {
q = sub(8, 1);
}
local_alloc[i] = q;
}
let mut cost: i16 = 0;
for i in 0..ns {
cost = add(cost, BIT_ALLOC_COST[local_alloc[i] as usize]);
}
let target = sub(budget, 0x20);
let slack = sub(cost, target);
if slack >= 0 {
thresh = candidate;
}
step = shr(step, 1);
if step <= 0 {
break;
}
}
thresh
}
pub(crate) fn compute_allocation(alloc: &mut [i16], gains: &[i16], num_subbands: i16, threshold: i16) {
for i in 0..(num_subbands as usize) {
let diff = sub(threshold, gains[i]);
let mut q = shr(diff, 1);
if q < 0 {
q = 0;
}
if sub(q, 7) > 0 {
q = sub(8, 1);
}
alloc[i] = q;
}
}
pub(crate) fn optimize_allocation(
alloc: &mut [i16],
scratch: &mut [i16],
gains: &[i16],
budget: i16,
num_subbands: i16,
num_iterations: i16,
threshold: i16,
) {
let ns = num_subbands as usize;
let mut inc_cost: i16 = 0;
for i in 0..ns {
inc_cost = add(inc_cost, BIT_ALLOC_COST[alloc[i] as usize]);
}
let mut dec_alloc = [0i16; MAX_SUBBANDS];
let mut inc_alloc = [0i16; MAX_SUBBANDS];
for i in 0..ns {
dec_alloc[i] = alloc[i];
inc_alloc[i] = alloc[i];
}
let mut dec_cost = inc_cost;
let max_iter = num_iterations - 1;
let mut low_idx = num_iterations;
let mut high_idx = num_iterations;
let mut swap_log = [0i16; 32];
for _ in 0..max_iter {
let total = add(dec_cost, inc_cost);
let doubled_budget = shl(budget, 1);
let balance = sub(total, doubled_budget);
if balance < 1 {
let mut best_idx: i16 = 0;
let mut best_metric: i16 = 99;
let mut idx: i16 = 0;
for i in 0..ns {
if dec_alloc[i] > 0 {
let step_x2 = shl(dec_alloc[i], 1);
let diff = sub(threshold, gains[i]);
let metric = sub(diff, step_x2);
let cmp = sub(metric, best_metric);
if cmp < 0 {
best_idx = idx;
best_metric = metric;
}
}
idx += 1;
}
low_idx = sub(low_idx, 1);
swap_log[low_idx as usize] = best_idx;
let old_step = dec_alloc[best_idx as usize];
dec_cost = sub(dec_cost, BIT_ALLOC_COST[old_step as usize]);
dec_alloc[best_idx as usize] = sub(old_step, 1);
let new_step = dec_alloc[best_idx as usize];
dec_cost = add(dec_cost, BIT_ALLOC_COST[new_step as usize]);
} else {
let mut best_idx: i16 = 0;
let mut best_metric: i16 = -99;
let mut idx = sub(num_subbands, 1);
while idx >= 0 {
let i = idx as usize;
if sub(inc_alloc[i], 7) < 0 {
let step_x2 = shl(inc_alloc[i], 1);
let diff = sub(threshold, gains[i]);
let metric = sub(diff, step_x2);
let cmp = sub(metric, best_metric);
if cmp > 0 {
best_metric = metric;
best_idx = idx;
}
}
idx -= 1;
}
swap_log[high_idx as usize] = best_idx;
high_idx = add(high_idx, 1);
let old_step = inc_alloc[best_idx as usize];
if sub(old_step, 7) < 0 {
inc_cost = sub(inc_cost, BIT_ALLOC_COST[old_step as usize]);
inc_alloc[best_idx as usize] = add(old_step, 1);
let new_step = inc_alloc[best_idx as usize];
inc_cost = add(inc_cost, BIT_ALLOC_COST[new_step as usize]);
}
}
}
for i in 0..ns {
alloc[i] = dec_alloc[i];
}
let mut out_idx: i16 = 0;
let mut log_idx = low_idx;
while out_idx < max_iter {
scratch[out_idx as usize] = swap_log[log_idx as usize];
log_idx += 1;
out_idx += 1;
}
}
pub(crate) fn increment_allocation_bins(count: i16, alloc: &mut [i16], scratch: &[i16]) {
let mut remaining = count;
let mut idx = 0usize;
while remaining > 0 {
let subband = scratch[idx] as usize;
alloc[subband] = add(alloc[subband], 1);
idx += 1;
remaining = sub(remaining, 1);
}
}
fn noise_prng(state: &mut [i16; 4]) -> i16 {
let sum = l_add(state[0] as i32, state[3] as i32);
let mut val = extract_l(sum);
if (val as u16) & 0x8000 != 0 {
val = add(val, 1);
}
state[3] = state[2];
state[2] = state[1];
state[1] = state[0];
state[0] = val;
val
}
fn inverse_quantize(symbol: i16, digits: &mut [i16], step: i16) -> i16 {
let si = step as usize;
let mut nonzero: i16 = 0;
let divisor = add(QUANT_INV_STEP[si], 1);
let step_size = QUANT_STEP_SIZE[si];
let num_digits = sub(QUANT_LEVELS_M1[si], 1);
if num_digits >= 0 {
let count = (num_digits + 1) as usize;
let mut val = symbol;
for j in (0..count).rev() {
let quotient = mult(val, step_size);
let product = l_mult0(quotient, divisor);
let prod_lo = extract_l(product);
let remainder = sub(val, prod_lo);
digits[j] = remainder;
if remainder != 0 {
nonzero = add(nonzero, 1);
}
val = quotient;
}
return nonzero;
}
0
}
fn codebook_tree(step: i16) -> &'static [i16] {
match step {
0 => &CODEBOOK_TREE_0,
1 => &CODEBOOK_TREE_1,
2 => &CODEBOOK_TREE_2,
3 => &CODEBOOK_TREE_3,
4 => &CODEBOOK_TREE_4,
5 => &CODEBOOK_TREE_5,
6 => &CODEBOOK_TREE_6,
_ => &CODEBOOK_TREE_0,
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_decoder_init() {
let dec = DecoderState::new(16000).unwrap();
assert_eq!(dec.bits_per_frame, 320);
assert_eq!(dec.encoded_frame_size, 20);
assert_eq!(dec.num_subbands, 14);
}
#[test]
fn test_decoder_init_snap() {
let result = DecoderState::new(16400);
assert!(result.is_err());
}
#[test]
fn test_decoder_init_subbands() {
assert_eq!(DecoderState::new(8000).unwrap().num_subbands, 8);
assert_eq!(DecoderState::new(9600).unwrap().num_subbands, 10);
assert_eq!(DecoderState::new(12000).unwrap().num_subbands, 12);
assert_eq!(DecoderState::new(16000).unwrap().num_subbands, 14);
}
#[test]
fn test_noise_prng() {
let mut state: [i16; 4] = [1, 1, 1, 1];
let v1 = noise_prng(&mut state);
assert_eq!(v1, 2);
assert_eq!(state, [2, 1, 1, 1]);
let v2 = noise_prng(&mut state);
assert_eq!(v2, 3);
assert_eq!(state, [3, 2, 1, 1]);
}
#[test]
fn test_inverse_quantize_step0() {
let mut digits = [0i16; 6];
let nz = inverse_quantize(5, &mut digits, 0);
assert_eq!(digits[1], 5);
assert_eq!(digits[0], 0);
assert_eq!(nz, 1);
}
#[test]
fn test_compute_allocation() {
let gains = [10i16, 8, 6, 4, 2, 0, -2, -4];
let mut alloc = [0i16; 8];
compute_allocation(&mut alloc, &gains, 8, 10);
assert_eq!(alloc[0], 0); assert_eq!(alloc[7], 7); }
}