use super::bits::BitReader;
use super::error::{Error, Result};
use super::swb::{long_offsets, short_offsets};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub enum WindowSequence {
OnlyLong = 0,
LongStart = 1,
EightShort = 2,
LongStop = 3,
}
impl WindowSequence {
fn from_bits(bits: u8) -> Self {
match bits & 3 {
0 => Self::OnlyLong,
1 => Self::LongStart,
2 => Self::EightShort,
_ => Self::LongStop,
}
}
#[must_use]
pub fn is_eight_short(self) -> bool {
matches!(self, Self::EightShort)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub enum WindowShape {
Sine = 0,
Kbd = 1,
}
impl WindowShape {
fn from_bit(bit: bool) -> Self {
if bit { Self::Kbd } else { Self::Sine }
}
}
#[derive(Debug, Clone, Copy)]
pub struct IcsInfo {
pub window_sequence: WindowSequence,
pub window_shape: WindowShape,
pub max_sfb: u8,
pub num_windows: u8,
pub num_window_groups: u8,
pub window_group_length: [u8; 8],
pub num_swb: u8,
}
impl IcsInfo {
pub fn parse(br: &mut BitReader<'_>, fs_index: u8, common_window: bool) -> Result<Self> {
let _reserved = br.read_bit()?;
let window_sequence = WindowSequence::from_bits(br.read(2)? as u8);
let window_shape = WindowShape::from_bit(br.read_bit()?);
let (max_sfb, grouping) = if window_sequence.is_eight_short() {
(br.read(4)? as u8, Some(br.read(7)? as u8))
} else {
let max_sfb = br.read(6)? as u8;
let predictor_data_present = br.read_bit()?;
if predictor_data_present {
return Err(Error::Format("predictor/LTP on LC stream"));
}
let _ = common_window;
(max_sfb, None)
};
let (num_windows, num_window_groups, window_group_length) =
grouping_of(window_sequence, grouping);
let offsets = if window_sequence.is_eight_short() {
short_offsets(fs_index)?
} else {
long_offsets(fs_index)?
};
let num_swb = offsets.len().saturating_sub(1) as u8;
if max_sfb as usize > num_swb as usize {
return Err(Error::IcsInfoInvalid);
}
Ok(IcsInfo {
window_sequence,
window_shape,
max_sfb,
num_windows,
num_window_groups,
window_group_length,
num_swb,
})
}
#[must_use]
pub fn window_len(&self) -> usize {
if self.window_sequence.is_eight_short() {
super::swb::SHORT_WINDOW_LEN
} else {
super::swb::LONG_WINDOW_LEN
}
}
}
fn grouping_of(seq: WindowSequence, grouping: Option<u8>) -> (u8, u8, [u8; 8]) {
if !seq.is_eight_short() {
let mut lens = [0u8; 8];
lens[0] = 1;
return (1, 1, lens);
}
let gbits = grouping.unwrap_or(0);
let mut lens = [0u8; 8];
lens[0] = 1;
let mut groups = 1u8;
for i in 1..8 {
if (gbits >> (6 - (i - 1))) & 1 == 1 {
lens[(groups - 1) as usize] += 1;
} else {
lens[groups as usize] = 1;
groups += 1;
}
}
(8, groups, lens)
}