X-Git-Url: https://git.nihav.org/?a=blobdiff_plain;f=nihav-llaudio%2Fsrc%2Fcodecs%2Fapepred.rs;fp=nihav-llaudio%2Fsrc%2Fcodecs%2Fapepred.rs;h=6aad207199f595b6aab30ac6a25a1a16b71f76c4;hb=87927c5732b39bb23209486bed8d7bb7fc56b92e;hp=0000000000000000000000000000000000000000;hpb=640b1eb06b5c5e0678bc35d2e2e297e4b3bda540;p=nihav.git diff --git a/nihav-llaudio/src/codecs/apepred.rs b/nihav-llaudio/src/codecs/apepred.rs new file mode 100644 index 0000000..6aad207 --- /dev/null +++ b/nihav-llaudio/src/codecs/apepred.rs @@ -0,0 +1,472 @@ +const HISTORY_SIZE: usize = 512; + +fn val2sign(val: i32) -> i32 { + if val > 0 { + -1 + } else if val < 0 { + 1 + } else { + 0 + } +} + +pub struct OldFilt { + version: u16, + compression: u16, +} + +pub struct NewFilt { + version: u16, + filters: [NFilterContext; 3], + lfilt: LastFilterContext, + rfilt: LastFilterContext, +} + +#[allow(clippy::large_enum_variant)] +pub enum FilterMode { + Old(OldFilt), + New(NewFilt), + None, +} + +impl FilterMode { + pub fn new(version: u16, compression: u16) -> Self { + if version < 3930 { + FilterMode::Old(OldFilt::new(version, compression)) + } else { + FilterMode::New(NewFilt::new(version, compression)) + } + } + pub fn filter_mono(&mut self, l: &mut [i32]) { + match *self { + FilterMode::Old(ref mut ofilt) => ofilt.filter(l), + FilterMode::New(ref mut nfilt) => nfilt.filter_mono(l), + FilterMode::None => unreachable!(), + }; + } + pub fn filter_stereo(&mut self, l: &mut [i32], r: &mut [i32]) { + match *self { + FilterMode::Old(ref mut ofilt) => { + ofilt.filter(l); + ofilt.filter(r); + for (l, r) in l.iter_mut().zip(r.iter_mut()) { + let new_l = *l - *r / 2; + let new_r = *r + new_l; + *l = new_l; + *r = new_r; + } + }, + FilterMode::New(ref mut nfilt) => { + nfilt.filter_stereo(l, r); + for (l, r) in l.iter_mut().zip(r.iter_mut()) { + let new_l = *r - *l / 2; + let new_r = *l + new_l; + *l = new_l; + *r = new_r; + } + }, + FilterMode::None => unreachable!(), + }; + } +} + +const NEW_FILTER_PARAMS: [[(u8, u8); 3]; 5] = [ + [ (0, 0), ( 0, 0), ( 0, 0) ], + [ (1, 11), ( 0, 0), ( 0, 0) ], + [ (4, 11), ( 0, 0), ( 0, 0) ], + [ (2, 10), (16, 13), ( 0, 0) ], + [ (1, 11), (16, 13), (80, 15) ], +]; + +#[derive(Clone,Default)] +struct NFilterContext { + buf: Vec, + coeffs: Vec, + order: usize, + bits: u8, + avg: i32, + new: bool, +} + +impl NFilterContext { + fn new(ord16: u8, bits: u8, new: bool) -> Self { + let order = ord16 as usize * 16; + Self { + buf: if order > 0 { vec![0; order * 2 + HISTORY_SIZE] } else { Vec::new() }, + coeffs: vec![0; order], + order, + bits, + avg: 0, + new, + } + } + fn reset(&mut self) { + for el in self.buf[..self.order * 2].iter_mut() { *el = 0; } + for el in self.coeffs.iter_mut() { *el = 0; } + self.avg = 0; + } + fn apply(&mut self, dst: &mut [i32]) { + if self.order == 0 { return; } + let mut adapt_pos = self.order; + let mut delay_pos = self.order * 2; + for el in dst.iter_mut() { + let mut sum = 0i32; + for (i, coef) in self.coeffs.iter_mut().enumerate() { + sum += *coef * self.buf[delay_pos - self.order + i]; + if *el < 0 { + *coef += self.buf[adapt_pos - self.order + i]; + } else if *el > 0 { + *coef -= self.buf[adapt_pos - self.order + i]; + } + } + let pred = (sum + (1 << (self.bits - 1))) >> self.bits; + let val = *el + pred; + *el = val; + self.buf[delay_pos] = val.min(32767).max(-32768); + if self.new { + let aval = val.abs(); + let sign = val2sign(val); + self.buf[adapt_pos] = if aval == 0 { + 0 + } else if aval <= self.avg * 4 / 3 { + sign * 8 + } else if aval <= self.avg * 3 { + sign * 16 + } else { + sign * 32 + }; + self.avg += (aval - self.avg) / 16; + self.buf[adapt_pos - 1] >>= 1; + self.buf[adapt_pos - 2] >>= 1; + self.buf[adapt_pos - 8] >>= 1; + } else { + self.buf[adapt_pos] = 4 * val2sign(val); + self.buf[adapt_pos - 4] >>= 1; + self.buf[adapt_pos - 8] >>= 1; + } + delay_pos += 1; + adapt_pos += 1; + if delay_pos == HISTORY_SIZE + self.order * 2 { + delay_pos = self.order * 2; + adapt_pos = self.order; + for i in 0..self.order * 2 { + self.buf[i] = self.buf[HISTORY_SIZE + i]; + } + } + } + } +} + +#[derive(Clone,Copy,Default)] +struct LastFilterContext { + last_a: i32, + filter_a: i32, + filter_b: i32, + coeffs_a: [i32; 4], + coeffs_b: [i32; 5], + delay_a: [i32; 4], + adapt_a: [i32; 4], + delay_b: [i32; 5], + adapt_b: [i32; 5], +} + +impl LastFilterContext { + fn init(&mut self) { + const COEFFS_A_NEW: [i32; 4] = [360, 317, -109, 98]; + + self.filter_a = 0; + self.filter_b = 0; + self.coeffs_a = COEFFS_A_NEW; + self.coeffs_b = [0; 5]; + self.last_a = 0; + self.delay_a = [0; 4]; + self.adapt_a = [0; 4]; + self.delay_b = [0; 5]; + self.adapt_b = [0; 5]; + } + fn predict_a(&mut self) -> i32 { + for i in (0..3).rev() { + self.delay_a[i + 1] = self.delay_a[i]; + self.adapt_a[i + 1] = self.adapt_a[i]; + } + self.delay_a[0] = self.last_a; + self.delay_a[1] = self.last_a - self.delay_a[1]; + self.adapt_a[0] = val2sign(self.delay_a[0]); + self.adapt_a[1] = val2sign(self.delay_a[1]); + + self.delay_a[0] * self.coeffs_a[0] + + self.delay_a[1] * self.coeffs_a[1] + + self.delay_a[2] * self.coeffs_a[2] + + self.delay_a[3] * self.coeffs_a[3] + } + fn predict_b(&mut self, other_a: i32) -> i32 { + for i in (0..4).rev() { + self.delay_b[i + 1] = self.delay_b[i]; + self.adapt_b[i + 1] = self.adapt_b[i]; + } + self.delay_b[0] = other_a - ((self.filter_b * 31) >> 5); + self.delay_b[1] = self.delay_b[0] - self.delay_b[1]; + self.adapt_b[0] = val2sign(self.delay_b[0]); + self.adapt_b[1] = val2sign(self.delay_b[1]); + + self.filter_b = other_a; + + (self.delay_b[0] * self.coeffs_b[0] + + self.delay_b[1] * self.coeffs_b[1] + + self.delay_b[2] * self.coeffs_b[2] + + self.delay_b[3] * self.coeffs_b[3] + + self.delay_b[4] * self.coeffs_b[4]) >> 1 + } + fn update_a(&mut self, pred: i32, diff: i32) -> i32 { + self.last_a = diff + (pred >> 10); + let sign = val2sign(diff); + for i in 0..4 { + self.coeffs_a[i] += self.adapt_a[i] * sign; + } + self.filter_a = self.last_a + ((self.filter_a * 31) >> 5); + + self.filter_a + } + fn update_b(&mut self, diff: i32) { + let sign = val2sign(diff); + for i in 0..5 { + self.coeffs_b[i] += self.adapt_b[i] * sign; + } + } + fn predict_3930(&mut self, diff: i32) -> i32 { + for i in (0..3).rev() { + self.delay_a[i + 1] = self.delay_a[i]; + } + self.delay_a[0] = self.last_a; + let d0 = self.delay_a[0]; + let d1 = self.delay_a[0] - self.delay_a[1]; + let d2 = self.delay_a[1] - self.delay_a[2]; + let d3 = self.delay_a[2] - self.delay_a[3]; + + let pred = (self.coeffs_a[0] * d0 + + self.coeffs_a[1] * d1 + + self.coeffs_a[2] * d2 + + self.coeffs_a[3] * d3) >> 9; + self.last_a = diff + pred; + self.filter_a = self.last_a + ((self.filter_a * 31) >> 5); + + let sign = val2sign(diff); + self.coeffs_a[0] += if d0 < 0 { sign } else { -sign }; + self.coeffs_a[1] += if d1 < 0 { sign } else { -sign }; + self.coeffs_a[2] += if d2 < 0 { sign } else { -sign }; + self.coeffs_a[3] += if d3 < 0 { sign } else { -sign }; + + self.filter_a + } +} + +impl NewFilt { + fn new(version: u16, compression: u16) -> Self { + let cidx = (compression / 1000) as usize - 1; + let mut obj = Self { + version, + filters: [NFilterContext::default(), NFilterContext::default(), NFilterContext::default()], + lfilt: LastFilterContext::default(), + rfilt: LastFilterContext::default(), + }; + obj.version = version; + let new = version >= 3980; + for i in 0..3 { + let (ord16, bits) = NEW_FILTER_PARAMS[cidx][i]; + obj.filters[i] = NFilterContext::new(ord16, bits, new); + } + obj + } + fn filter_mono(&mut self, dst: &mut [i32]) { + for filt in self.filters.iter_mut() { + filt.reset(); + filt.apply(dst); + } + self.lfilt.init(); + if self.version >= 3950 { + for el in dst.iter_mut() { + let pred = self.lfilt.predict_a(); + *el = self.lfilt.update_a(pred, *el); + } + } else { + for el in dst.iter_mut() { + *el = self.lfilt.predict_3930(*el); + } + } + } + fn filter_stereo(&mut self, l: &mut [i32], r: &mut [i32]) { + for filt in self.filters.iter_mut() { + filt.reset(); + filt.apply(l); + filt.reset(); + filt.apply(r); + } + self.lfilt.init(); + self.rfilt.init(); + if self.version >= 3950 { + for (l, r) in l.iter_mut().zip(r.iter_mut()) { + let mut pred = self.lfilt.predict_a(); + pred += self.lfilt.predict_b(self.rfilt.filter_a); + let new_l = self.lfilt.update_a(pred, *l); + self.lfilt.update_b(*l); + *l = new_l; + + let mut pred = self.rfilt.predict_a(); + pred += self.rfilt.predict_b(self.lfilt.filter_a); + let new_r = self.rfilt.update_a(pred, *r); + self.rfilt.update_b(*r); + *r = new_r; + } + } else { + for (l, r) in l.iter_mut().zip(r.iter_mut()) { + let new_l = self.lfilt.predict_3930(*r); + let new_r = self.rfilt.predict_3930(*l); + *l = new_l; + *r = new_r; + } + } + } +} + +impl OldFilt { + fn new(version: u16, compression: u16) -> Self { + Self { + version, compression + } + } + fn filter(&mut self, dst: &mut [i32]) { + match self.compression { + 1000 => { + Self::filter_fast(dst); + }, + 2000 => { + Self::filter_normal(dst, 4, 10); + }, + 3000 => { + Self::filter_high(dst, 16, 9); + Self::filter_normal(dst, 16, 10); + }, + 4000 => { + if self.version < 3830 { + Self::filter_high(dst, 128, 11); + Self::filter_normal(dst, 128, 10); + } else { + Self::filter_extra_high(dst); + Self::filter_high(dst, 256, 12); + Self::filter_normal(dst, 256, 11); + } + }, + _ => unreachable!(), + }; + } + fn filter_fast(dst: &mut [i32]) { + const COEFF_A_FAST: i32 = 375; + + if dst.len() <= 3 { + return; + } + let mut delay = [dst[1], dst[0]]; + let mut last = dst[2]; + let mut filter = dst[2]; + let mut weight = COEFF_A_FAST; + for el in dst[3..].iter_mut() { + delay[1] = delay[0]; + delay[0] = last; + let pred = delay[0] * 2 - delay[1]; + last = *el + ((pred * weight) >> 9); + if (*el ^ pred) > 0 { + weight += 1; + } else { + weight -= 1; + } + filter += last; + *el = filter; + } + } + fn filter_normal(dst: &mut [i32], start: usize, shift: u8) { + const COEFFS_A_NORMAL: [i32; 3] = [64, 115, 64]; + const COEFFS_B_NORMAL: [i32; 2] = [740, 0]; + + let mut last = 0; + let mut coeffs_a = COEFFS_A_NORMAL; + let mut coeffs_b = COEFFS_B_NORMAL; + let mut filter_a = 0; + let mut filter_b = 0; + let mut delay_a = [0; 3]; + let mut delay_b = [0; 2]; + + for (i, el) in dst.iter_mut().enumerate() { + delay_a[2] = delay_a[1]; delay_a[1] = delay_a[0]; delay_a[0] = last; + delay_b[1] = delay_b[0]; delay_b[0] = filter_b; + if i < start { + let val = *el + filter_a; + last = *el; + filter_b = *el; + filter_a = val; + *el = val; + continue; + } + let a0 = delay_a[0] + (delay_a[2] - delay_a[1]) * 8; + let a1 = (delay_a[0] - delay_a[1]) * 2; + let a2 = delay_a[0]; + let b0 = delay_b[0] * 2 - delay_b[1]; + let b1 = delay_b[0]; + + let pred_a = a0 * coeffs_a[0] + a1 * coeffs_a[1] + a2 * coeffs_a[2]; + let pred_b = b0 * coeffs_b[0] - b1 * coeffs_b[1]; + + let sign = val2sign(*el); + coeffs_a[0] += (((a0 >> 30) & 2) - 1) * sign; + coeffs_a[1] += (((a1 >> 28) & 8) - 4) * sign; + coeffs_a[2] += (((a2 >> 28) & 8) - 4) * sign; + last = *el + (pred_a >> 11); + + let sign = val2sign(last); + coeffs_b[0] += (((b0 >> 29) & 4) - 2) * sign; + coeffs_b[1] -= (((b1 >> 30) & 2) - 1) * sign; + + filter_b = last + (pred_b >> shift); + filter_a = filter_b + ((filter_a * 31) >> 5); + + *el = filter_a; + } + } + fn filter_high(dst: &mut [i32], order: usize, shift: u8) { + let mut coeffs = [0i32; 256]; + let mut delay = [0i32; 256]; + if dst.len() <= order { + return; + } + delay[..order].copy_from_slice(&dst[..order]); + for el in dst[order..].iter_mut() { + let sign = val2sign(*el); + let mut sum = 0; + for i in 0..order { + sum += delay[i] * coeffs[i]; + coeffs[i] -= (((delay[i] >> 30) & 2) - 1) * sign; + } + *el -= sum >> shift; + for i in 0..order-1 { + delay[i] = delay[i + 1]; + } + delay[order - 1] = *el; + } + } + fn filter_extra_high(dst: &mut [i32]) { + let mut coeffs = [0i32; 8]; + let mut delay = [0i32; 8]; + for el in dst[256..].iter_mut() { + let sign = val2sign(*el); + let mut sum = 0; + for i in 0..8 { + sum += delay[i] * coeffs[i]; + coeffs[i] -= (((delay[i] >> 30) & 2) - 1) * sign; + } + for i in (0..7).rev() { + delay[i + 1] = delay[i]; + } + delay[0] = *el; + *el -= sum >> 9; + } + } +}