Skip to main content

mcelp/
preprocess.rs

1//! Encoder input conditioning.
2//!
3//! The encoder takes 320 mu-law samples, expands them to linear and runs them
4//! through a second-order high-pass that removes DC and the lowest part of the
5//! band before any analysis happens.
6
7use crate::fixed::{acc, hi, sat, shift, trunc32};
8
9/// Samples per frame.
10pub use crate::FRAME;
11/// Samples per half-frame, which is the unit the analysis works on.
12pub use crate::HALF;
13
14/// Expand one mu-law byte to linear.
15///
16/// A plain table lookup, against the same table the reference uses.
17pub fn ulaw_to_linear(sample: u8) -> i16 {
18    crate::tables::ULAW_TO_LINEAR[sample as usize]
19}
20
21/// State of the input high-pass filter.
22#[derive(Clone, Copy, Default)]
23pub struct Highpass {
24    /// The two previous outputs, kept at full 32-bit precision.
25    output: [i64; 2],
26    /// The two previous inputs.
27    input: [i16; 2],
28}
29
30impl Highpass {
31    /// Filter one half-frame in place.
32    ///
33    /// `y[n] = 8 * (a1 y[n-1] + a2 y[n-2] + b0 x[n] + b1 x[n-1] + b2 x[n-2])`,
34    /// where the recursive part is evaluated against the undamaged 32-bit
35    /// history rather than the rounded output.
36    pub fn run(&mut self, block: &mut [i16]) {
37        let c = &crate::tables::INPUT_HIGHPASS[..5];
38        for sample in block.iter_mut() {
39            let x = *sample;
40            let mut a = acc(recursive(self.output[0], c[0]) + recursive(self.output[1], c[1]));
41            a = acc(a + (x as i64) * (c[2] as i64) * 2);
42            a = acc(a + (self.input[0] as i64) * (c[3] as i64) * 2);
43            a = acc(a + (self.input[1] as i64) * (c[4] as i64) * 2);
44            a = sat(shift(a, 3));
45
46            self.input[1] = self.input[0];
47            self.input[0] = x;
48            self.output[1] = self.output[0];
49            self.output[0] = trunc32(a);
50
51            // The rounding add saturates, so a sample that overshoots full scale
52            // clips there instead of wrapping round to the opposite rail.
53            *sample = hi(sat(acc(a + 32768)));
54        }
55    }
56}
57
58/// One recursive tap: a 32x16 product built from the halves of the state, the
59/// low half being pre-shifted so the two partial products line up.
60fn recursive(state: i64, coef: i16) -> i64 {
61    let low = ((state as i16 as u16) >> 1) as i64;
62    let partial = shift(acc(low * (coef as i64) * 2), -16);
63    acc(shift(partial, 1) + (hi(state) as i64) * (coef as i64) * 2)
64}