use crate::analysis::{BINS, Direction, FFT_POINTS, Spectrum, fft, negate, ratio, unpack_real};
use crate::bands::{BANDS, band_bins};
use crate::fixed::{DB_PER_OCTAVE, acc, exp, hi, low, mulr, norm, round, sat, scale32, shift};
use crate::tables::{SCALE_SMOOTH_ACTIVE as SMOOTH_ACTIVE, SCALE_SMOOTH_IDLE as SMOOTH_IDLE};
pub const SPAN: usize = 256;
pub const HOP: usize = 160;
pub const SEAM: usize = 40;
const START: usize = 96;
const WEIGHT_STEP: i16 = 512;
const WEIGHT_TOTAL: i16 = 20480;
const WEIGHT_GAIN: i16 = 26214;
#[derive(Clone, Copy)]
pub struct Overlap {
tail: [i16; SEAM],
scale: Option<i16>,
}
impl Default for Overlap {
fn default() -> Self {
Overlap {
tail: [0; SEAM],
scale: None,
}
}
}
impl Overlap {
pub fn emit(&mut self, span: &[i16; SPAN], headroom: i16) -> [i16; HOP] {
if let Some(previous) = self.scale {
let step = headroom - previous;
for v in self.tail.iter_mut() {
*v = hi(norm((*v as i64) << 16, step));
}
}
let mut out = [0i16; HOP];
let seam = &span[START - SEAM..START];
for i in 0..SEAM {
let rising = WEIGHT_STEP * i as i16;
let falling = WEIGHT_TOTAL - rising;
let mut a = sat((seam[i] as i64) * (rising as i64) * 2);
let b = sat((self.tail[i] as i64) * (falling as i64) * 2);
a = acc(((hi(a) as i64) << 16) + b);
let mixed = sat((WEIGHT_GAIN as i64) * (hi(a) as i64) * 2);
out[i] = hi(sat(shift((hi(mixed) as i64) << 16, 1)));
}
out[SEAM..].copy_from_slice(&span[START..START + HOP - SEAM]);
self.tail.copy_from_slice(&span[SPAN - SEAM..]);
self.scale = Some(headroom);
for v in out.iter_mut() {
*v = hi(norm((*v as i64) << 16, -headroom));
}
out
}
}
const LEAK: i16 = 26214;
#[derive(Clone, Copy, Default)]
pub struct Smoother {
state: i16,
}
impl Smoother {
pub fn run(&mut self, span: &mut [i16; SPAN]) {
for v in span.iter_mut() {
let leaked = round(sat((LEAK as i64) * (self.state as i64) * 2));
self.state = hi(sat(acc(leaked + ((*v as i64) << 16))));
*v = self.state;
}
}
}
const HALF: i16 = 16384;
const REGAIN: i32 = 2;
pub fn inverse_transform(re: &[i16; BINS], im: &[i16; BINS]) -> [i16; SPAN] {
let mut s = Spectrum { re: *re, im: *im };
unpack_real(&mut s, Direction::Inverse);
for v in s.im[..FFT_POINTS].iter_mut() {
*v = negate(*v);
}
fft(&mut s);
let mut out = [0i16; SPAN];
for i in 0..FFT_POINTS {
out[2 * i] = rescale(s.re[i], HALF);
out[2 * i + 1] = rescale(s.im[i], -HALF);
}
out
}
fn rescale(v: i16, gain: i16) -> i16 {
let halved = sat((v as i64) * (gain as i64) * 2);
hi(sat(shift((hi(halved) as i64) << 16, REGAIN)))
}
pub fn suppress(
spectrum: &mut Spectrum,
magnitude: &[i16; BINS],
floor: &[i16; BINS],
headroom: i16,
) {
for i in 0..BINS {
let gain = if magnitude[i] <= 0 {
0
} else if magnitude[i] <= floor[i] {
32767
} else {
ratio(floor[i], magnitude[i])
};
spectrum.re[i] = scaled(spectrum.re[i], gain, headroom);
spectrum.im[i] = scaled(spectrum.im[i], gain, headroom);
}
}
fn scaled(v: i16, gain: i16, headroom: i16) -> i16 {
let product = sat((v as i64) * (gain as i64) * 2);
hi(sat(acc(norm(product, headroom) + 32768)))
}
const FLOOR_GAINS: [i16; 3] = [5194, 7337, 10361];
const LOUD_LEVEL: i16 = 15360;
const QUIET: i16 = 6144;
const MODERATE: i16 = 12288;
fn floor_gain(level: i16, secondary: i16) -> i16 {
if level >= LOUD_LEVEL {
FLOOR_GAINS[2]
} else if secondary < QUIET {
FLOOR_GAINS[0]
} else if secondary < MODERATE {
FLOOR_GAINS[1]
} else {
FLOOR_GAINS[2]
}
}
fn scaled_band_noise(energy: i64, scale: i16, headroom: i16) -> i64 {
let raised = norm(energy, headroom);
hi(shift(mulr(scale, hi(raised)), -4)) as i64
}
fn bin_noise_floor(magnitude: i16, noise: i64, weight: i16, gain: i16, headroom: i16) -> i16 {
let magnitude = magnitude as i64;
let subtracted = norm(mulr(weight, hi(acc((magnitude - noise) << 16))), -headroom);
let scaled = norm(magnitude << 16, -headroom);
let fraction = sat((gain as i64) * (hi(scaled) as i64) * 2);
hi(acc((hi(subtracted) as i64) << 16).max(acc((hi(fraction) as i64) << 16)))
}
pub fn noise_floor(
magnitude: &[i16; BINS],
energy: &[i64; BANDS],
scale: &[i16; BANDS],
weight: &[i16; BANDS],
headroom: i16,
level: i16,
secondary: i16,
) -> [i16; BINS] {
let gain = floor_gain(level, secondary);
let mut out = [0i16; BINS];
for band in 0..BANDS {
let noise = scaled_band_noise(energy[band], scale[band], headroom);
for bin in band_bins(band) {
out[bin] = bin_noise_floor(magnitude[bin], noise, weight[band], gain, headroom);
}
}
out
}
const SCALE_UNITY: i16 = 16384;
#[derive(Clone, Copy, Default)]
pub struct Scale {
previous: [i16; BANDS],
}
impl Scale {
pub fn smooth(&mut self, scale: &mut [i16; BANDS], active: bool) {
let table = BANDS * !active as usize;
for (band, (current, previous)) in
scale.iter_mut().zip(self.previous.iter_mut()).enumerate()
{
let c = crate::tables::BAND_SMOOTH[table + band];
let mut b = sat((c as i64) * (*current as i64) * 2);
b = sat(acc(b + (*previous as i64) * ((SCALE_UNITY - c) as i64) * 2));
let v = hi(sat(acc(sat(shift(b, 1)) + 32768)));
*current = v;
*previous = v;
}
}
}
const LEVEL_CLIP: i16 = 7936;
const LEVEL_MAX: i16 = 31744;
const LEVEL_WEIGHT: i16 = 1638;
#[derive(Clone, Copy, Default)]
pub struct Levels {
state: i64,
previous: [i16; BANDS],
}
fn band_mean(magnitude: &[i16; BINS], band: usize) -> i64 {
let mut sum = 0i64;
for bin in band_bins(band) {
sum = sat(acc(sum + ((magnitude[bin] as i64) << 16)));
}
scale32(sum, crate::tables::BAND_INV_WIDTH_HALVED[band])
}
fn relative_band_level(mean: i64, blend: i64, headroom: i16) -> i16 {
let blend_exp = exp(blend);
let mean_exp = exp(mean) - 1;
let shift_out = headroom as i64 - blend_exp as i64 + 16 + mean_exp as i64;
let ratio = divide32(norm32(mean, mean_exp), norm32(blend, blend_exp));
let log = crate::bands::log2(ratio);
let combined = acc(((hi(log) as i64 - shift_out) << 16) + (log & 0xffff));
let db = scale32(acc(shift(combined, -1) - (5 << 16)), DB_PER_OCTAVE);
if acc(sat(shift(db, 12)) - ((LEVEL_CLIP as i64) << 16)) > 0 {
LEVEL_MAX
} else {
hi(sat(shift(db, 14)).max(0))
}
}
fn level_total(level: &[i16; BANDS]) -> i16 {
let mut total = 0i64;
for &value in level.iter() {
total = sat(acc(total + (value as i64) * (LEVEL_WEIGHT as i64) * 2));
}
hi(round(total))
}
impl Levels {
fn blend_reference(
&mut self,
band: usize,
slow: i64,
mean: i64,
confidence: i16,
headroom: i16,
) -> i64 {
let rate = crate::tables::STATE_RATE[band];
let mut state = sat(shift(scale32(self.state, rate), -5));
state = sat(acc(
state + (confidence as i64) * ((32767 - rate) as i64) * 2
));
self.state = sat(shift(state, -5));
let mix = hi(state);
sat(acc(
scale32(slow, 32767 - mix) + norm(scale32(mean, mix), 5 - headroom)
))
}
fn band_level(
&mut self,
band: usize,
magnitude: &[i16; BINS],
slow: i64,
confidence: i16,
headroom: i16,
) -> i16 {
if slow == 0 {
return 32767;
}
let mean = band_mean(magnitude, band);
let blend = self.blend_reference(band, slow, mean, confidence, headroom);
relative_band_level(mean, blend, headroom)
}
pub fn run(
&mut self,
magnitude: &[i16; BINS],
slow: &[i64; BANDS],
score: i16,
headroom: i16,
) -> ([i16; BANDS], i16) {
let confidence =
crate::tables::CONFIDENCE[(crate::tables::CONFIDENCE_ZERO as i16 + score) as usize];
let mut level = [0i16; BANDS];
for band in 0..BANDS {
level[band] = self.band_level(band, magnitude, slow[band], confidence, headroom);
}
self.smooth(&mut level, score);
let total = level_total(&level);
(level, total)
}
fn smooth(&mut self, level: &mut [i16; BANDS], score: i16) {
let table = if score >= 0 {
SMOOTH_ACTIVE
} else {
SMOOTH_IDLE
};
for band in 0..BANDS - 1 {
let c = crate::tables::SCALE_SMOOTH[table + band];
let mut b = sat((level[band] as i64) * ((32767 - c) as i64) * 2);
b = round(sat(acc(b + (level[band + 1] as i64) * (c as i64) * 2)));
level[band + 1] = hi(b);
}
for band in (0..BANDS).rev() {
let c = crate::tables::SCALE_SMOOTH[table + band - 1];
let mut b = sat((self.previous[band] as i64) * ((32767 - c) as i64) * 2);
b = round(sat(acc(b + (level[band] as i64) * (c as i64) * 2)));
level[band] = hi(b);
self.previous[band] = hi(b);
}
}
}
fn norm32(v: i64, amount: i32) -> i64 {
sat(shift(acc(v), amount))
}
fn divide32(numerator: i64, denominator: i64) -> i64 {
let seed = low(crate::fixed::restoring_divide(
16383i64 << 16,
hi(denominator),
15,
));
let product = scale32(denominator, seed);
let error = sat(acc(sat(shift(16384i64 << 16, 8)) - product));
let refined = sat(shift(scale32(error, seed), 0));
mul32(numerator, refined)
}
fn mul32(x: i64, y: i64) -> i64 {
let xl = ((x as u32 as u16) >> 1) as i64;
let yl = ((y as u32 as u16) >> 1) as i64;
let mut b = shift(sat((hi(x) as i64) * yl * 2), -16);
b = sat(acc(b + shift(sat((hi(y) as i64) * xl * 2), -16)));
let mut a = sat(shift(b, 1));
a = sat(acc(a + (hi(x) as i64) * (hi(y) as i64) * 2));
sat(shift(a, 2))
}