use oxideav_core::bits::{BitReader, BitWriter};
use crate::swb_offset::{long_window_offsets_family, short_window_offsets_family, FrameFamily};
use crate::{Error, Result};
pub const EIGHT_SHORT_SEQUENCE: u8 = 2;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub enum WindowSequence {
OnlyLong = 0,
LongStart = 1,
EightShort = 2,
LongStop = 3,
}
impl WindowSequence {
pub fn from_bits(bits: u8) -> Self {
match bits & 0b11 {
0 => WindowSequence::OnlyLong,
1 => WindowSequence::LongStart,
2 => WindowSequence::EightShort,
_ => WindowSequence::LongStop,
}
}
pub fn is_eight_short(self) -> bool {
matches!(self, WindowSequence::EightShort)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub enum WindowShape {
Sine = 0,
Kbd = 1,
}
impl WindowShape {
pub fn from_bit(bit: bool) -> Self {
if bit {
WindowShape::Kbd
} else {
WindowShape::Sine
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct PredictorData {
pub reset: bool,
pub reset_group_number: Option<u8>,
pub prediction_used: Vec<bool>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct LtpData {
pub lag_update: Option<bool>,
pub lag: Option<u16>,
pub coef: u8,
pub long_used: Vec<bool>,
pub short: Option<Vec<LtpShortWindow>>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct LtpShortWindow {
pub used: bool,
pub lag_present: bool,
pub lag: i8,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum LtpEdition {
#[default]
Iso2009,
Iso2001,
}
pub const MAX_LTP_LONG_SFB: usize = 40;
pub const SHORT_WINDOWS_PER_FRAME: usize = 8;
pub const PRED_SFB_MAX: [u8; 12] = [33, 33, 38, 40, 40, 40, 41, 41, 37, 37, 37, 34];
pub const NUM_SWB_LONG_WINDOW: [u8; 12] = [41, 41, 47, 49, 49, 51, 47, 47, 43, 43, 43, 40];
pub const NUM_SWB_SHORT_WINDOW: [u8; 12] = [12, 12, 12, 14, 14, 14, 15, 15, 15, 15, 15, 15];
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct IcsInfo {
pub family: FrameFamily,
pub ics_reserved_bit: bool,
pub window_sequence: WindowSequence,
pub window_shape: WindowShape,
pub max_sfb: u8,
pub scale_factor_grouping: Option<u8>,
pub predictor_data_present: bool,
pub predictor_data: Option<PredictorData>,
pub ltp_data_present: bool,
pub ltp_data: Option<LtpData>,
pub ltp_data_present_pair: Option<bool>,
pub ltp_data_pair: Option<LtpData>,
pub num_windows: u8,
pub num_window_groups: u8,
pub window_group_length: Vec<u8>,
pub num_swb: u8,
}
impl IcsInfo {
pub fn parse(
reader: &mut BitReader<'_>,
audio_object_type: u8,
sampling_frequency_index: u8,
common_window: bool,
) -> Result<Self> {
Self::parse_family(
reader,
FrameFamily::Lc1024,
audio_object_type,
sampling_frequency_index,
common_window,
)
}
pub fn parse_family(
reader: &mut BitReader<'_>,
family: FrameFamily,
audio_object_type: u8,
sampling_frequency_index: u8,
common_window: bool,
) -> Result<Self> {
let fs_index = sampling_frequency_index as usize;
if fs_index >= NUM_SWB_LONG_WINDOW.len() {
return Err(Error::IcsInfoUnsupportedSampleRateIndex(
sampling_frequency_index,
));
}
let ics_reserved_bit = read_bit(reader)?;
let window_sequence_bits = read_u8(reader, 2)?;
let window_sequence = WindowSequence::from_bits(window_sequence_bits);
let window_shape = WindowShape::from_bit(read_bit(reader)?);
if family.is_ld() && window_sequence != WindowSequence::OnlyLong {
return Err(Error::LdShortWindow);
}
let mut scale_factor_grouping = None;
let mut predictor_data_present = false;
let mut predictor_data = None;
let mut ltp_data_present = false;
let mut ltp_data = None;
let mut ltp_data_present_pair = None;
let mut ltp_data_pair = None;
let max_sfb;
if window_sequence.is_eight_short() {
max_sfb = read_u8(reader, 4)?;
scale_factor_grouping = Some(read_u8(reader, 7)?);
} else {
max_sfb = read_u8(reader, 6)?;
predictor_data_present = read_bit(reader)?;
if predictor_data_present {
if audio_object_type == 1 {
let reset = read_bit(reader)?;
let reset_group_number = if reset {
Some(read_u8(reader, 5)?)
} else {
None
};
let pred_sfb_max = PRED_SFB_MAX[fs_index] as u16;
let n = core::cmp::min(max_sfb as u16, pred_sfb_max) as usize;
let mut prediction_used = Vec::with_capacity(n);
for _ in 0..n {
prediction_used.push(read_bit(reader)?);
}
predictor_data = Some(PredictorData {
reset,
reset_group_number,
prediction_used,
});
} else {
ltp_data_present = read_bit(reader)?;
if ltp_data_present {
ltp_data = Some(parse_ltp_data(
reader,
audio_object_type,
window_sequence,
max_sfb,
)?);
}
if common_window {
let pair_flag = read_bit(reader)?;
ltp_data_present_pair = Some(pair_flag);
if pair_flag {
ltp_data_pair = Some(parse_ltp_data(
reader,
audio_object_type,
window_sequence,
max_sfb,
)?);
}
}
}
} else if common_window && audio_object_type != 1 {
}
}
let (num_windows, num_window_groups, window_group_length, num_swb) =
derive_window_grouping_family(
family,
window_sequence,
scale_factor_grouping,
sampling_frequency_index,
)?;
Ok(IcsInfo {
family,
ics_reserved_bit,
window_sequence,
window_shape,
max_sfb,
scale_factor_grouping,
predictor_data_present,
predictor_data,
ltp_data_present,
ltp_data,
ltp_data_present_pair,
ltp_data_pair,
num_windows,
num_window_groups,
window_group_length,
num_swb,
})
}
pub fn window_len(&self) -> Result<usize> {
if self.window_sequence.is_eight_short() {
self.family.short_window_len().ok_or(Error::LdShortWindow)
} else {
Ok(self.family.frame_len())
}
}
pub fn swb_offsets(&self, fs_index: u8) -> Result<&'static [u16]> {
if self.window_sequence.is_eight_short() {
short_window_offsets_family(self.family, fs_index)
} else {
long_window_offsets_family(self.family, fs_index)
}
}
pub fn write(
&self,
writer: &mut BitWriter,
audio_object_type: u8,
sampling_frequency_index: u8,
common_window: bool,
) -> Result<()> {
let fs_index = sampling_frequency_index as usize;
if fs_index >= NUM_SWB_LONG_WINDOW.len() {
return Err(Error::IcsInfoEncodeInvalid);
}
if self.family.is_ld() && self.window_sequence != WindowSequence::OnlyLong {
return Err(Error::IcsInfoEncodeInvalid);
}
writer.write_bit(self.ics_reserved_bit);
writer.write_u32(self.window_sequence as u32 & 0b11, 2);
writer.write_u32(self.window_shape as u32 & 0b1, 1);
if self.window_sequence.is_eight_short() {
if self.max_sfb > 0x0f {
return Err(Error::IcsInfoEncodeInvalid);
}
let mask = self
.scale_factor_grouping
.ok_or(Error::IcsInfoEncodeInvalid)?;
if mask > 0x7f {
return Err(Error::IcsInfoEncodeInvalid);
}
if self.predictor_data_present
|| self.predictor_data.is_some()
|| self.ltp_data_present
|| self.ltp_data.is_some()
|| self.ltp_data_present_pair.is_some()
|| self.ltp_data_pair.is_some()
{
return Err(Error::IcsInfoEncodeInvalid);
}
writer.write_u32(self.max_sfb as u32, 4);
writer.write_u32(mask as u32, 7);
} else {
if self.max_sfb > 0x3f {
return Err(Error::IcsInfoEncodeInvalid);
}
if self.scale_factor_grouping.is_some() {
return Err(Error::IcsInfoEncodeInvalid);
}
writer.write_u32(self.max_sfb as u32, 6);
writer.write_bit(self.predictor_data_present);
if self.predictor_data_present {
if audio_object_type == 1 {
if self.ltp_data_present
|| self.ltp_data.is_some()
|| self.ltp_data_present_pair.is_some()
|| self.ltp_data_pair.is_some()
{
return Err(Error::IcsInfoEncodeInvalid);
}
let pd = self
.predictor_data
.as_ref()
.ok_or(Error::IcsInfoEncodeInvalid)?;
if pd.reset != pd.reset_group_number.is_some() {
return Err(Error::IcsInfoEncodeInvalid);
}
let pred_sfb_max = PRED_SFB_MAX[fs_index] as u16;
let expected = core::cmp::min(self.max_sfb as u16, pred_sfb_max) as usize;
if pd.prediction_used.len() != expected {
return Err(Error::IcsInfoEncodeInvalid);
}
writer.write_bit(pd.reset);
if let Some(g) = pd.reset_group_number {
if g > 0x1f {
return Err(Error::IcsInfoEncodeInvalid);
}
writer.write_u32(g as u32, 5);
}
for &b in &pd.prediction_used {
writer.write_bit(b);
}
} else {
if self.predictor_data.is_some() {
return Err(Error::IcsInfoEncodeInvalid);
}
writer.write_bit(self.ltp_data_present);
if self.ltp_data_present {
let ltp = self.ltp_data.as_ref().ok_or(Error::IcsInfoEncodeInvalid)?;
write_ltp_data(
writer,
ltp,
audio_object_type,
self.window_sequence,
self.max_sfb,
)?;
} else if self.ltp_data.is_some() {
return Err(Error::IcsInfoEncodeInvalid);
}
if common_window {
let pair_flag = self
.ltp_data_present_pair
.ok_or(Error::IcsInfoEncodeInvalid)?;
writer.write_bit(pair_flag);
if pair_flag {
let ltp2 = self
.ltp_data_pair
.as_ref()
.ok_or(Error::IcsInfoEncodeInvalid)?;
write_ltp_data(
writer,
ltp2,
audio_object_type,
self.window_sequence,
self.max_sfb,
)?;
} else if self.ltp_data_pair.is_some() {
return Err(Error::IcsInfoEncodeInvalid);
}
} else if self.ltp_data_present_pair.is_some() || self.ltp_data_pair.is_some() {
return Err(Error::IcsInfoEncodeInvalid);
}
}
} else {
if self.predictor_data.is_some()
|| self.ltp_data_present
|| self.ltp_data.is_some()
|| self.ltp_data_present_pair.is_some()
|| self.ltp_data_pair.is_some()
{
return Err(Error::IcsInfoEncodeInvalid);
}
}
}
Ok(())
}
}
pub fn parse_ltp_data(
reader: &mut BitReader<'_>,
audio_object_type: u8,
window_sequence: WindowSequence,
max_sfb: u8,
) -> Result<LtpData> {
parse_ltp_data_edition(
reader,
audio_object_type,
window_sequence,
max_sfb,
LtpEdition::Iso2009,
)
}
pub fn parse_ltp_data_edition(
reader: &mut BitReader<'_>,
audio_object_type: u8,
window_sequence: WindowSequence,
max_sfb: u8,
edition: LtpEdition,
) -> Result<LtpData> {
if audio_object_type == 23 {
let lag_update = read_bit(reader)?;
let lag = if lag_update {
Some(read_u16(reader, 10)?)
} else {
None
};
let coef = read_u8(reader, 3)?;
let n = core::cmp::min(max_sfb as usize, MAX_LTP_LONG_SFB);
let mut long_used = Vec::with_capacity(n);
for _ in 0..n {
long_used.push(read_bit(reader)?);
}
Ok(LtpData {
lag_update: Some(lag_update),
lag,
coef,
long_used,
short: None,
})
} else {
let lag = read_u16(reader, 11)?;
let coef = read_u8(reader, 3)?;
let mut short = None;
let long_used = if window_sequence.is_eight_short() {
if edition == LtpEdition::Iso2001 {
let mut v = Vec::with_capacity(SHORT_WINDOWS_PER_FRAME);
for _ in 0..SHORT_WINDOWS_PER_FRAME {
let used = read_bit(reader)?;
let (lag_present, lag) = if used {
let lag_present = read_bit(reader)?;
let lag = if lag_present {
let raw = read_u8(reader, 4)?;
((raw << 4) as i8) >> 4
} else {
0
};
(lag_present, lag)
} else {
(false, 0)
};
v.push(LtpShortWindow {
used,
lag_present,
lag,
});
}
short = Some(v);
}
Vec::new()
} else {
let n = core::cmp::min(max_sfb as usize, MAX_LTP_LONG_SFB);
let mut v = Vec::with_capacity(n);
for _ in 0..n {
v.push(read_bit(reader)?);
}
v
};
Ok(LtpData {
lag_update: None,
lag: Some(lag),
coef,
long_used,
short,
})
}
}
pub fn write_ltp_data(
writer: &mut BitWriter,
ltp: &LtpData,
audio_object_type: u8,
window_sequence: WindowSequence,
max_sfb: u8,
) -> Result<()> {
write_ltp_data_edition(
writer,
ltp,
audio_object_type,
window_sequence,
max_sfb,
LtpEdition::Iso2009,
)
}
pub fn write_ltp_data_edition(
writer: &mut BitWriter,
ltp: &LtpData,
audio_object_type: u8,
window_sequence: WindowSequence,
max_sfb: u8,
edition: LtpEdition,
) -> Result<()> {
if ltp.coef > 0x07 {
return Err(Error::IcsInfoEncodeInvalid);
}
let short_branch = audio_object_type != 23
&& window_sequence.is_eight_short()
&& edition == LtpEdition::Iso2001;
if !short_branch && ltp.short.is_some() {
return Err(Error::IcsInfoEncodeInvalid);
}
if audio_object_type == 23 {
let lag_update = ltp.lag_update.ok_or(Error::IcsInfoEncodeInvalid)?;
writer.write_bit(lag_update);
if lag_update {
let lag = ltp.lag.ok_or(Error::IcsInfoEncodeInvalid)?;
if lag > 0x3ff {
return Err(Error::IcsInfoEncodeInvalid);
}
writer.write_u32(lag as u32, 10);
} else if ltp.lag.is_some() {
return Err(Error::IcsInfoEncodeInvalid);
}
writer.write_u32(ltp.coef as u32, 3);
let expected = core::cmp::min(max_sfb as usize, MAX_LTP_LONG_SFB);
if ltp.long_used.len() != expected {
return Err(Error::IcsInfoEncodeInvalid);
}
for &b in <p.long_used {
writer.write_bit(b);
}
} else {
if ltp.lag_update.is_some() {
return Err(Error::IcsInfoEncodeInvalid);
}
let lag = ltp.lag.ok_or(Error::IcsInfoEncodeInvalid)?;
if lag > 0x7ff {
return Err(Error::IcsInfoEncodeInvalid);
}
writer.write_u32(lag as u32, 11);
writer.write_u32(ltp.coef as u32, 3);
if window_sequence.is_eight_short() {
if !ltp.long_used.is_empty() {
return Err(Error::IcsInfoEncodeInvalid);
}
if edition == LtpEdition::Iso2001 {
let short = ltp.short.as_ref().ok_or(Error::IcsInfoEncodeInvalid)?;
if short.len() != SHORT_WINDOWS_PER_FRAME {
return Err(Error::IcsInfoEncodeInvalid);
}
for w in short {
if !w.used && (w.lag_present || w.lag != 0) {
return Err(Error::IcsInfoEncodeInvalid);
}
if !w.lag_present && w.lag != 0 {
return Err(Error::IcsInfoEncodeInvalid);
}
if !(-8..=7).contains(&w.lag) {
return Err(Error::IcsInfoEncodeInvalid);
}
writer.write_bit(w.used);
if w.used {
writer.write_bit(w.lag_present);
if w.lag_present {
writer.write_u32((w.lag as u32) & 0x0f, 4);
}
}
}
}
} else {
let expected = core::cmp::min(max_sfb as usize, MAX_LTP_LONG_SFB);
if ltp.long_used.len() != expected {
return Err(Error::IcsInfoEncodeInvalid);
}
for &b in <p.long_used {
writer.write_bit(b);
}
}
}
Ok(())
}
pub fn derive_window_grouping(
window_sequence: WindowSequence,
scale_factor_grouping: Option<u8>,
fs_index: usize,
) -> (u8, u8, Vec<u8>, u8) {
if !window_sequence.is_eight_short() {
return (1, 1, vec![1], NUM_SWB_LONG_WINDOW[fs_index]);
}
derive_short_grouping(scale_factor_grouping, NUM_SWB_SHORT_WINDOW[fs_index])
}
pub fn derive_window_grouping_family(
family: FrameFamily,
window_sequence: WindowSequence,
scale_factor_grouping: Option<u8>,
fs_index: u8,
) -> Result<(u8, u8, Vec<u8>, u8)> {
if !window_sequence.is_eight_short() {
let num_swb = (long_window_offsets_family(family, fs_index)?.len() - 1) as u8;
return Ok((1, 1, vec![1], num_swb));
}
let num_swb = (short_window_offsets_family(family, fs_index)?.len() - 1) as u8;
Ok(derive_short_grouping(scale_factor_grouping, num_swb))
}
fn derive_short_grouping(scale_factor_grouping: Option<u8>, num_swb: u8) -> (u8, u8, Vec<u8>, u8) {
let mask = scale_factor_grouping.unwrap_or(0);
let mut groups: Vec<u8> = vec![1];
for i in 0..7u32 {
let bit = (mask >> (6 - i as u8)) & 1;
if bit == 0 {
groups.push(1);
} else {
let last = groups.last_mut().expect("at least one group");
*last += 1;
}
}
let num_window_groups = groups.len() as u8;
(8, num_window_groups, groups, num_swb)
}
fn read_u8(reader: &mut BitReader<'_>, n: u32) -> Result<u8> {
debug_assert!(n <= 8);
Ok(reader.read_u32(n).map_err(|_| Error::UnexpectedEnd)? as u8)
}
fn read_u16(reader: &mut BitReader<'_>, n: u32) -> Result<u16> {
debug_assert!(n <= 16);
Ok(reader.read_u32(n).map_err(|_| Error::UnexpectedEnd)? as u16)
}
fn read_bit(reader: &mut BitReader<'_>) -> Result<bool> {
reader.read_bit().map_err(|_| Error::UnexpectedEnd)
}