use crate::range_decoder::RangeDecoder;
use crate::silk_frame::SignalType;
use crate::Error;
pub const SILK_MAX_SUBFRAMES: usize = 4;
const GAIN_MSB_ICDF_INACTIVE: &[u8] = &[224, 112, 44, 15, 3, 2, 1, 0];
const GAIN_MSB_ICDF_UNVOICED: &[u8] = &[254, 237, 192, 132, 70, 23, 4, 0];
const GAIN_MSB_ICDF_VOICED: &[u8] = &[255, 252, 226, 155, 61, 11, 2, 0];
const GAIN_LSB_ICDF: &[u8] = &[224, 192, 160, 128, 96, 64, 32, 0];
const GAIN_DELTA_ICDF: &[u8] = &[
250, 245, 234, 203, 71, 50, 42, 38, 35, 33, 31, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18,
17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0,
];
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct SubframeGainsConfig {
pub signal_type: SignalType,
pub num_subframes: u8,
pub first_subframe_is_independent: bool,
pub previous_log_gain: Option<u8>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct SubframeGain {
pub log_gain: u8,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct SubframeGains {
gains: [SubframeGain; SILK_MAX_SUBFRAMES],
len: u8,
}
impl SubframeGains {
pub fn decode(rd: &mut RangeDecoder<'_>, cfg: SubframeGainsConfig) -> Result<Self, Error> {
if cfg.num_subframes != 2 && cfg.num_subframes != 4 {
return Err(Error::MalformedPacket);
}
let num = cfg.num_subframes as usize;
let mut gains = [SubframeGain { log_gain: 0 }; SILK_MAX_SUBFRAMES];
let mut prev: Option<u8> = cfg.previous_log_gain;
for (k, slot) in gains.iter_mut().enumerate().take(num) {
let is_independent = k == 0 && cfg.first_subframe_is_independent;
let log_gain = if is_independent {
Self::decode_independent(rd, cfg.signal_type, prev)
} else {
let p = match prev {
Some(v) => v,
None => return Err(Error::MalformedPacket),
};
Self::decode_delta(rd, p)
};
*slot = SubframeGain { log_gain };
prev = Some(log_gain);
if rd.has_error() {
return Err(Error::MalformedPacket);
}
}
Ok(Self {
gains,
len: cfg.num_subframes,
})
}
pub fn len(&self) -> usize {
self.len as usize
}
pub fn is_empty(&self) -> bool {
self.len == 0
}
pub fn as_slice(&self) -> &[SubframeGain] {
&self.gains[..self.len()]
}
pub fn last_log_gain(&self) -> u8 {
self.gains[self.len() - 1].log_gain
}
pub fn dequant_q16(&self) -> [u32; SILK_MAX_SUBFRAMES] {
let mut out = [0u32; SILK_MAX_SUBFRAMES];
for (slot, gain) in out.iter_mut().zip(self.gains.iter()).take(self.len()) {
*slot = crate::silk_log2lin::silk_gains_dequant(gain.log_gain);
}
out
}
fn icdf_for_signal_type(signal_type: SignalType) -> &'static [u8] {
match signal_type {
SignalType::Inactive => GAIN_MSB_ICDF_INACTIVE,
SignalType::Unvoiced => GAIN_MSB_ICDF_UNVOICED,
SignalType::Voiced => GAIN_MSB_ICDF_VOICED,
}
}
fn decode_independent(
rd: &mut RangeDecoder<'_>,
signal_type: SignalType,
previous_log_gain: Option<u8>,
) -> u8 {
let msb = rd.dec_icdf(Self::icdf_for_signal_type(signal_type), 8) as u8;
let lsb = rd.dec_icdf(GAIN_LSB_ICDF, 8) as u8;
let gain_index = (msb << 3) | (lsb & 0x07);
match previous_log_gain {
Some(prev) => gain_index.max(prev.saturating_sub(16)),
None => gain_index,
}
}
fn decode_delta(rd: &mut RangeDecoder<'_>, previous_log_gain: u8) -> u8 {
let delta = rd.dec_icdf(GAIN_DELTA_ICDF, 8) as i32;
let prev = previous_log_gain as i32;
let a = 2 * delta - 16;
let b = prev + delta - 4;
let inner = a.max(b);
inner.clamp(0, 63) as u8
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn gain_msb_inactive_pdf_sums_to_256() {
let pdf = [32u32, 112, 68, 29, 12, 1, 1, 1];
assert_eq!(pdf.iter().sum::<u32>(), 256);
assert_eq!(GAIN_MSB_ICDF_INACTIVE.len(), pdf.len());
for w in GAIN_MSB_ICDF_INACTIVE.windows(2) {
assert!(w[0] > w[1] || (w[0] == 0 && w[1] == 0));
}
assert_eq!(*GAIN_MSB_ICDF_INACTIVE.last().unwrap(), 0);
}
#[test]
fn gain_msb_unvoiced_pdf_sums_to_256() {
let pdf = [2u32, 17, 45, 60, 62, 47, 19, 4];
assert_eq!(pdf.iter().sum::<u32>(), 256);
assert_eq!(
GAIN_MSB_ICDF_UNVOICED,
&[254u8, 237, 192, 132, 70, 23, 4, 0]
);
}
#[test]
fn gain_msb_voiced_pdf_sums_to_256() {
let pdf = [1u32, 3, 26, 71, 94, 50, 9, 2];
assert_eq!(pdf.iter().sum::<u32>(), 256);
assert_eq!(GAIN_MSB_ICDF_VOICED, &[255u8, 252, 226, 155, 61, 11, 2, 0]);
}
#[test]
fn gain_lsb_pdf_is_uniform_eight() {
assert_eq!(GAIN_LSB_ICDF, &[224u8, 192, 160, 128, 96, 64, 32, 0]);
}
#[test]
fn gain_delta_pdf_sums_to_256() {
let pdf: [u32; 41] = [
6, 5, 11, 31, 132, 21, 8, 4, 3, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
];
assert_eq!(pdf.iter().sum::<u32>(), 256);
assert_eq!(GAIN_DELTA_ICDF.len(), pdf.len());
assert_eq!(*GAIN_DELTA_ICDF.last().unwrap(), 0);
for w in GAIN_DELTA_ICDF.windows(2) {
assert!(w[0] >= w[1]);
}
}
#[test]
fn gain_delta_first_cell_matches_pdf() {
assert_eq!(GAIN_DELTA_ICDF[0], 250);
assert_eq!(GAIN_DELTA_ICDF[3], 203);
assert_eq!(GAIN_DELTA_ICDF[4], 71);
}
#[test]
fn clamp_independent_with_no_previous_returns_raw_index() {
let buf = [0x55u8, 0xAA, 0x33, 0xCC, 0x7F, 0x80, 0x12, 0x34];
let mut rd1 = RangeDecoder::new(&buf);
let mut rd2 = RangeDecoder::new(&buf);
let msb = rd1.dec_icdf(GAIN_MSB_ICDF_INACTIVE, 8) as u8;
let lsb = rd1.dec_icdf(GAIN_LSB_ICDF, 8) as u8;
let expected_gain = (msb << 3) | (lsb & 0x07);
let got = SubframeGains::decode_independent(&mut rd2, SignalType::Inactive, None);
assert_eq!(got, expected_gain);
assert!(got < 64);
}
#[test]
fn clamp_independent_with_low_previous_keeps_raw_index() {
let buf = [0x42u8, 0x18, 0xC3, 0x7F, 0x55, 0xAA, 0x33, 0xCC];
let mut rd1 = RangeDecoder::new(&buf);
let mut rd2 = RangeDecoder::new(&buf);
let msb = rd1.dec_icdf(GAIN_MSB_ICDF_VOICED, 8) as u8;
let lsb = rd1.dec_icdf(GAIN_LSB_ICDF, 8) as u8;
let raw = (msb << 3) | (lsb & 0x07);
let got = SubframeGains::decode_independent(&mut rd2, SignalType::Voiced, Some(0));
assert_eq!(got, raw);
}
#[test]
fn clamp_independent_with_high_previous_raises_index() {
let buf = [0x00u8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
let mut rd = RangeDecoder::new(&buf);
let got = SubframeGains::decode_independent(&mut rd, SignalType::Inactive, Some(60));
assert!(got >= 44, "got={got}");
assert!(got <= 63, "got={got}");
}
#[test]
fn clamp_independent_previous_saturates_at_zero() {
let buf = [0x55u8, 0xAA, 0x33, 0xCC, 0x7F, 0x80];
let mut rd1 = RangeDecoder::new(&buf);
let mut rd2 = RangeDecoder::new(&buf);
let msb = rd1.dec_icdf(GAIN_MSB_ICDF_UNVOICED, 8) as u8;
let lsb = rd1.dec_icdf(GAIN_LSB_ICDF, 8) as u8;
let raw = (msb << 3) | (lsb & 0x07);
let got = SubframeGains::decode_independent(&mut rd2, SignalType::Unvoiced, Some(15));
assert_eq!(got, raw);
}
#[test]
fn delta_path_clamps_to_0_63() {
let buf = [0x77u8, 0x33, 0x11, 0xAA, 0xDE, 0xAD, 0xBE, 0xEF, 0x55];
for prev in [0u8, 1, 10, 31, 32, 50, 60, 63] {
let mut rd = RangeDecoder::new(&buf);
let g = SubframeGains::decode_delta(&mut rd, prev);
assert!(g <= 63, "prev={prev}, g={g}");
}
}
#[test]
fn delta_path_formula_consistency() {
let buf = [0x12u8, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0];
let mut rd1 = RangeDecoder::new(&buf);
let mut rd2 = RangeDecoder::new(&buf);
let delta = rd1.dec_icdf(GAIN_DELTA_ICDF, 8) as i32;
let prev = 30u8;
let expected = {
let a = 2 * delta - 16;
let b = prev as i32 + delta - 4;
a.max(b).clamp(0, 63) as u8
};
let got = SubframeGains::decode_delta(&mut rd2, prev);
assert_eq!(got, expected, "delta={delta}");
}
fn fresh_buf() -> [u8; 24] {
[
0xC3, 0x18, 0x42, 0x7F, 0x55, 0xAA, 0x33, 0xCC, 0x77, 0x33, 0x11, 0xAA, 0xDE, 0xAD,
0xBE, 0xEF, 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
]
}
#[test]
fn full_decode_inactive_four_subframes_first_independent() {
let buf = fresh_buf();
let mut rd = RangeDecoder::new(&buf);
let cfg = SubframeGainsConfig {
signal_type: SignalType::Inactive,
num_subframes: 4,
first_subframe_is_independent: true,
previous_log_gain: None,
};
let gains = SubframeGains::decode(&mut rd, cfg).expect("decode must succeed");
assert_eq!(gains.len(), 4);
for g in gains.as_slice() {
assert!(g.log_gain <= 63);
}
assert!(gains.as_slice()[0].log_gain <= 63);
}
#[test]
fn full_decode_unvoiced_two_subframes_first_delta() {
let buf = fresh_buf();
let mut rd = RangeDecoder::new(&buf);
let cfg = SubframeGainsConfig {
signal_type: SignalType::Unvoiced,
num_subframes: 2,
first_subframe_is_independent: false,
previous_log_gain: Some(40),
};
let gains = SubframeGains::decode(&mut rd, cfg).expect("decode must succeed");
assert_eq!(gains.len(), 2);
for g in gains.as_slice() {
assert!(g.log_gain <= 63);
}
}
#[test]
fn full_decode_voiced_four_subframes_first_independent_with_prev() {
let buf = fresh_buf();
let mut rd = RangeDecoder::new(&buf);
let cfg = SubframeGainsConfig {
signal_type: SignalType::Voiced,
num_subframes: 4,
first_subframe_is_independent: true,
previous_log_gain: Some(50),
};
let gains = SubframeGains::decode(&mut rd, cfg).expect("decode must succeed");
assert_eq!(gains.len(), 4);
assert!(
gains.as_slice()[0].log_gain >= 34,
"first gain={}",
gains.as_slice()[0].log_gain
);
for g in gains.as_slice() {
assert!(g.log_gain <= 63);
}
}
#[test]
fn full_decode_first_delta_without_prev_is_rejected() {
let buf = fresh_buf();
let mut rd = RangeDecoder::new(&buf);
let cfg = SubframeGainsConfig {
signal_type: SignalType::Voiced,
num_subframes: 4,
first_subframe_is_independent: false,
previous_log_gain: None,
};
let err = SubframeGains::decode(&mut rd, cfg).unwrap_err();
assert_eq!(err, Error::MalformedPacket);
}
#[test]
fn full_decode_invalid_subframe_count_is_rejected() {
let buf = fresh_buf();
for bad in [0u8, 1, 3, 5, 8, 255] {
let mut rd = RangeDecoder::new(&buf);
let cfg = SubframeGainsConfig {
signal_type: SignalType::Voiced,
num_subframes: bad,
first_subframe_is_independent: true,
previous_log_gain: None,
};
let err = SubframeGains::decode(&mut rd, cfg).unwrap_err();
assert_eq!(err, Error::MalformedPacket, "bad num_subframes={bad}");
}
}
#[test]
fn last_log_gain_matches_last_subframe() {
let buf = fresh_buf();
let mut rd = RangeDecoder::new(&buf);
let cfg = SubframeGainsConfig {
signal_type: SignalType::Voiced,
num_subframes: 4,
first_subframe_is_independent: true,
previous_log_gain: None,
};
let gains = SubframeGains::decode(&mut rd, cfg).expect("decode must succeed");
assert_eq!(gains.last_log_gain(), gains.as_slice()[3].log_gain);
}
#[test]
fn delta_after_independent_chain_consistency() {
let buf = fresh_buf();
let mut rd_manual = RangeDecoder::new(&buf);
let msb = rd_manual.dec_icdf(GAIN_MSB_ICDF_VOICED, 8) as u8;
let lsb = rd_manual.dec_icdf(GAIN_LSB_ICDF, 8) as u8;
let g0 = (msb << 3) | (lsb & 0x07); let mut prev = g0;
let mut chain = [g0, 0, 0, 0];
for slot in &mut chain[1..] {
let delta = rd_manual.dec_icdf(GAIN_DELTA_ICDF, 8) as i32;
let a = 2 * delta - 16;
let b = prev as i32 + delta - 4;
let g = a.max(b).clamp(0, 63) as u8;
*slot = g;
prev = g;
}
let mut rd = RangeDecoder::new(&buf);
let cfg = SubframeGainsConfig {
signal_type: SignalType::Voiced,
num_subframes: 4,
first_subframe_is_independent: true,
previous_log_gain: None,
};
let gains = SubframeGains::decode(&mut rd, cfg).expect("decode must succeed");
for (k, expected) in chain.iter().enumerate() {
assert_eq!(
gains.as_slice()[k].log_gain,
*expected,
"subframe {} mismatch: got {}, expected {}",
k,
gains.as_slice()[k].log_gain,
*expected
);
}
}
#[test]
fn dequant_q16_zeroes_trailing_slots_for_two_subframe_frame() {
let mut bytes = vec![0u8; 16];
bytes[0] = 0x40;
let mut rd = RangeDecoder::new(&bytes);
let cfg = SubframeGainsConfig {
signal_type: SignalType::Inactive,
num_subframes: 2,
first_subframe_is_independent: true,
previous_log_gain: None,
};
let gains = SubframeGains::decode(&mut rd, cfg).expect("decode must succeed");
let q16 = gains.dequant_q16();
for (k, val) in q16.iter().enumerate().take(gains.len()) {
assert!(
(81_920..=1_686_110_208).contains(val),
"subframe {} gain_Q16 {} outside spec range",
k,
val
);
}
for (k, val) in q16.iter().enumerate().skip(gains.len()) {
assert_eq!(*val, 0, "slot {} expected zero, got {}", k, val);
}
}
#[test]
fn dequant_q16_matches_per_subframe_call() {
let mut bytes = vec![0u8; 16];
bytes[0] = 0xFF;
let mut rd = RangeDecoder::new(&bytes);
let cfg = SubframeGainsConfig {
signal_type: SignalType::Voiced,
num_subframes: 4,
first_subframe_is_independent: true,
previous_log_gain: None,
};
let gains = SubframeGains::decode(&mut rd, cfg).expect("decode must succeed");
let array = gains.dequant_q16();
for (k, val) in array.iter().enumerate().take(gains.len()) {
let log_gain = gains.as_slice()[k].log_gain;
let expected = crate::silk_log2lin::silk_gains_dequant(log_gain);
assert_eq!(*val, expected, "subframe {} mismatch", k);
}
}
#[test]
fn signal_type_routes_to_correct_icdf() {
assert_eq!(
SubframeGains::icdf_for_signal_type(SignalType::Inactive),
GAIN_MSB_ICDF_INACTIVE
);
assert_eq!(
SubframeGains::icdf_for_signal_type(SignalType::Unvoiced),
GAIN_MSB_ICDF_UNVOICED
);
assert_eq!(
SubframeGains::icdf_for_signal_type(SignalType::Voiced),
GAIN_MSB_ICDF_VOICED
);
}
}