use crate::common::{complex::Scaler, config::Lc3Config};
use super::side_info::LongTermPostFilterInfo;
pub struct PacketLossConcealment<'a> {
spec_lines_last_good: &'a mut [Scaler],
num_lost_frames: usize,
alpha: Scaler,
plc_seed: usize,
ne: usize,
}
impl<'a> PacketLossConcealment<'a> {
pub fn new(ne: usize, scaler_buf: &'a mut [Scaler]) -> (Self, &'a mut [Scaler]) {
let (spec_lines_last_good, scaler_buf) = scaler_buf.split_at_mut(ne);
(
Self {
spec_lines_last_good,
plc_seed: 24607,
num_lost_frames: 0,
alpha: 1.0,
ne,
},
scaler_buf,
)
}
pub const fn calc_working_buffer_length(config: &Lc3Config) -> usize {
config.ne
}
pub fn save(&mut self, spec_lines: &[Scaler]) {
self.num_lost_frames = 0;
self.alpha = 1.0;
self.spec_lines_last_good[..self.ne].copy_from_slice(&spec_lines[..self.ne]);
}
pub fn load_into(&mut self, spec_lines: &mut [Scaler]) -> LongTermPostFilterInfo {
if self.num_lost_frames >= 4 {
self.alpha *= if self.num_lost_frames < 8 { 0.9 } else { 0.85 };
}
self.num_lost_frames += 1;
for (current, last_good) in spec_lines.iter_mut().zip(self.spec_lines_last_good.iter()) {
self.plc_seed = (16831 + self.plc_seed * 12821) & 0xFFFF;
*current = if self.plc_seed < 0x8000 {
last_good * self.alpha
} else {
last_good * -self.alpha
};
}
LongTermPostFilterInfo {
is_active: false,
pitch_index: 0,
pitch_present: false,
}
}
}
#[cfg(test)]
mod tests {
extern crate std;
use super::*;
#[test]
fn save_and_load() {
let mut spec_lines = [-2268.137, 7869.9785, 15884.984, 9776.979];
let mut scaler_buf = [0.; 4];
let (mut packet_loss, _) = PacketLossConcealment::new(spec_lines.len(), &mut scaler_buf);
packet_loss.save(&spec_lines);
packet_loss.load_into(&mut spec_lines);
packet_loss.load_into(&mut spec_lines);
packet_loss.load_into(&mut spec_lines);
let spec_lines_expected = [2268.137, 7869.9785, -15884.984, -9776.979];
assert_eq!(spec_lines, spec_lines_expected);
}
}