use crate::analysis::BINS;
use crate::bands::{self, BANDS};
use crate::fixed::{acc, hi, sat, shift};
use crate::vad::{self, Features, Frame};
pub const WARMUP: i16 = 11;
pub fn unnormalise(magnitude: &[i16; BINS], headroom: i16) -> [i16; BINS] {
let mut out = [0i16; BINS];
for (o, &m) in out.iter_mut().zip(magnitude.iter()) {
*o = hi(sat(shift(acc((m as i64) << 16), -(headroom as i32))));
}
out
}
pub fn features(
spectrum: &[i16; BINS],
fast: &[i64; BANDS],
slow: &[i64; BANDS],
voicing: i16,
) -> Frame {
let levels = bands::levels(spectrum);
let summary = bands::summary(&levels);
let mut frame = Frame {
summary,
voicing,
..Frame::default()
};
for (i, energies) in [fast, slow].into_iter().enumerate() {
let tracked = bands::tracked_levels(energies);
let excess = bands::excess(&levels, &tracked);
frame.reference[i] = Features {
tracked: bands::summary(&tracked),
excess_sum: vad::excess_sum(&excess),
difference: bands::summary_difference(summary, bands::summary(&tracked)),
variance: bands::snr_statistics(&excess).1,
};
}
frame
}
use crate::noise::NoiseEstimate;
use crate::shaping::{self, HOP, Levels, Overlap, SPAN, Scale, Smoother};
use crate::vad::{Decision, Vad};
use crate::weights::{self, Depths, Mix, Shaping};
pub struct Suppressor {
warmup: i16,
detector: Vad,
fast: NoiseEstimate,
slow: NoiseEstimate,
levels: Levels,
depths: Depths,
shaping: Shaping,
scale: Scale,
smoother: Smoother,
overlap: Overlap,
}
struct FloorShape {
scale: [i16; BANDS],
weight: [i16; BANDS],
overall_level: i16,
summary_level: i16,
}
struct FloorLevels {
band: [i16; BANDS],
overall: i16,
summary: i16,
}
struct FloorBands {
depth: [i64; BANDS],
weight: [i16; BANDS],
mix: [i64; BANDS],
}
impl FloorBands {
fn new(levels: &FloorLevels, decision: Decision) -> Self {
let (depth, weight) = weights::depths(levels.summary);
let (mix, _) = Mix::run(
&levels.band,
levels.summary,
levels.overall,
decision.score,
decision.active,
);
Self { depth, weight, mix }
}
}
impl Default for Suppressor {
fn default() -> Self {
Suppressor {
warmup: WARMUP,
detector: Vad::default(),
fast: NoiseEstimate::fast(),
slow: NoiseEstimate::slow(),
levels: Levels::default(),
depths: Depths::default(),
shaping: Shaping::default(),
scale: Scale::default(),
smoother: Smoother::default(),
overlap: Overlap::default(),
}
}
}
impl Suppressor {
fn decide(&mut self, magnitude: &[i16; BINS], headroom: i16, voicing: i16) -> Decision {
if self.warmup >= 0 {
self.warmup -= 1;
Decision {
active: false,
fast: false,
score: -4,
}
} else {
let scaled = unnormalise(magnitude, headroom);
let frame = features(&scaled, &self.fast.energy, &self.slow.energy, voicing);
self.detector.run(&frame)
}
}
fn floor_levels(&mut self, magnitude: &[i16; BINS], headroom: i16, score: i16) -> FloorLevels {
let overall = weights::overall_level(&self.fast.energy);
let (band, summary) = self
.levels
.run(magnitude, &self.slow.energy, score, headroom);
FloorLevels {
band,
overall,
summary,
}
}
fn refine_floor_shape(&mut self, levels: &FloorLevels, decision: Decision) -> FloorShape {
let mut bands = FloorBands::new(levels, decision);
self.depths.refine(
&mut bands.depth,
&mut bands.mix,
&self.fast.energy,
&levels.band,
&bands.weight,
decision.active,
);
let (band_weight, mut band_scale) = self.shaping.finish(
&mut bands.mix,
&levels.band,
levels.overall,
levels.summary,
decision.active,
);
self.scale.smooth(&mut band_scale, decision.active);
FloorShape {
scale: band_scale,
weight: band_weight,
overall_level: levels.overall,
summary_level: levels.summary,
}
}
fn floor_shape(
&mut self,
magnitude: &[i16; BINS],
headroom: i16,
decision: Decision,
) -> FloorShape {
let levels = self.floor_levels(magnitude, headroom, decision.score);
self.refine_floor_shape(&levels, decision)
}
fn noise_floor(
&mut self,
magnitude: &[i16; BINS],
headroom: i16,
decision: Decision,
) -> [i16; BINS] {
self.fast.update(magnitude, headroom, decision.fast);
self.slow.update(magnitude, headroom, decision.active);
let shape = self.floor_shape(magnitude, headroom, decision);
shaping::noise_floor(
magnitude,
&self.fast.energy,
&shape.scale,
&shape.weight,
headroom,
shape.overall_level,
shape.summary_level,
)
}
fn synthesise(
&mut self,
spectrum: &mut crate::analysis::Spectrum,
magnitude: &[i16; BINS],
floor: &[i16; BINS],
headroom: i16,
) -> [i16; HOP] {
shaping::suppress(spectrum, magnitude, floor, headroom);
let mut span = shaping::inverse_transform(&spectrum.re, &spectrum.im);
self.smoother.run(&mut span);
self.overlap.emit(&span, headroom)
}
pub fn run(
&mut self,
spectrum: &mut crate::analysis::Spectrum,
magnitude: &[i16; BINS],
headroom: i16,
voicing: i16,
) -> [i16; HOP] {
let decision = self.decide(magnitude, headroom, voicing);
let floor = self.noise_floor(magnitude, headroom, decision);
self.synthesise(spectrum, magnitude, &floor, headroom)
}
}
const _: () = assert!(SPAN == 256);
use crate::analysis::{self, Analysis, Direction, WINDOW};
use crate::preprocess::{self, Highpass};
use crate::{FRAME, HALF};
#[derive(Default)]
pub struct Frontend {
input: Highpass,
analysis: Analysis,
suppressor: Suppressor,
}
impl Frontend {
pub fn condition(&mut self, frame: &[u8; FRAME]) -> [i16; FRAME] {
let mut linear = [0i16; FRAME];
for (l, &b) in linear.iter_mut().zip(frame.iter()) {
*l = preprocess::ulaw_to_linear(b);
}
self.input.run(&mut linear);
linear
}
pub fn process(&mut self, block: &[i16; HALF]) -> [i16; HOP] {
let (mut window, headroom) = self.analysis.window(block);
let voicing = analysis::voicing(&window);
self.analysis.preemphasise(&mut window, headroom);
let mut spectrum = analysis::deinterleave(&window);
analysis::fft(&mut spectrum);
analysis::unpack_real(&mut spectrum, Direction::Forward);
let magnitude = analysis::magnitude(&spectrum);
self.suppressor
.run(&mut spectrum, &magnitude, headroom, voicing)
}
}
const _: () = assert!(WINDOW == SPAN);