use super::bits::BitWriter;
use super::enc_quant::{MAX_FLAT_SHORT, MAX_GROUPS};
use super::swb::{LONG_WINDOW_LEN, SHORT_WINDOW_LEN};
const QUIET_FLOOR: f64 = 1e-6;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum MaskForm {
Off,
All,
PerBand,
}
pub struct MsBands {
used: [bool; MAX_FLAT_SHORT],
n: usize,
}
impl MsBands {
pub fn off() -> Self {
Self {
used: [false; MAX_FLAT_SHORT],
n: 0,
}
}
pub fn form(&self) -> MaskForm {
let live = &self.used[..self.n];
if live.iter().all(|&u| u) && self.n > 0 {
MaskForm::All
} else if live.iter().any(|&u| u) {
MaskForm::PerBand
} else {
MaskForm::Off
}
}
pub fn overhead_bits(&self) -> usize {
match self.form() {
MaskForm::PerBand => 2 + self.n,
MaskForm::Off | MaskForm::All => 2,
}
}
pub fn emit(&self, w: &mut BitWriter) {
match self.form() {
MaskForm::Off => w.write(0, 2),
MaskForm::All => w.write(2, 2),
MaskForm::PerBand => {
w.write(1, 2);
for &u in &self.used[..self.n] {
w.write_bit(u);
}
}
}
}
pub fn apply_long_to(&self, specs: &mut [[f32; LONG_WINDOW_LEN]; 2], offsets: &[u16]) {
apply_long(specs, offsets, &self.used[..self.n]);
}
#[cfg(test)]
pub fn used(&self, i: usize) -> bool {
self.used[i]
}
}
const MS_MARGIN: f64 = 3.0;
fn band_prefers_ms(e_left: f64, e_right: f64, e_side: f64) -> bool {
MS_MARGIN * e_side < e_left.min(e_right)
}
fn fold_quiet(used: &mut [bool], quiet: &[bool]) {
let mut any_loud = false;
let mut all_ms = true;
for (&q, &u) in quiet.iter().zip(used.iter()) {
if !q {
any_loud = true;
all_ms &= u;
}
}
if !any_loud {
used.fill(false); return;
}
if all_ms {
used.fill(true); }
}
pub fn decide_long(
specs: &mut [[f32; LONG_WINDOW_LEN]; 2],
offsets: &[u16],
per_band: bool,
) -> MsBands {
let n_bands = offsets.len() - 1;
let [l, r] = specs;
let mut e_l = [0.0f64; MAX_FLAT_SHORT];
let mut e_r = [0.0f64; MAX_FLAT_SHORT];
let mut e_s = [0.0f64; MAX_FLAT_SHORT];
let mut out = MsBands {
used: [false; MAX_FLAT_SHORT],
n: n_bands,
};
let mut loudest = 0.0f64;
for b in 0..n_bands {
let (lo, hi) = (usize::from(offsets[b]), usize::from(offsets[b + 1]));
for (&lv, &rv) in l[lo..hi].iter().zip(r[lo..hi].iter()) {
let s = f64::from((lv - rv) * 0.5);
e_l[b] += f64::from(lv) * f64::from(lv);
e_r[b] += f64::from(rv) * f64::from(rv);
e_s[b] += s * s;
}
loudest = loudest.max(e_l[b].max(e_r[b]));
out.used[b] = band_prefers_ms(e_l[b], e_r[b], e_s[b]);
}
let mut quiet = [false; MAX_FLAT_SHORT];
for b in 0..n_bands {
quiet[b] = e_l[b].max(e_r[b]) < loudest * QUIET_FLOOR;
}
if per_band {
fold_quiet(&mut out.used[..n_bands], &quiet[..n_bands]);
} else {
let (mut tl, mut tr, mut ts) = (0.0f64, 0.0f64, 0.0f64);
for b in 0..n_bands {
tl += e_l[b];
tr += e_r[b];
ts += e_s[b];
}
out.used[..n_bands].fill(band_prefers_ms(tl, tr, ts));
}
apply_long(specs, offsets, &out.used[..n_bands]);
out
}
fn apply_long(specs: &mut [[f32; LONG_WINDOW_LEN]; 2], offsets: &[u16], used: &[bool]) {
let [l, r] = specs;
for (b, &u) in used.iter().enumerate() {
if !u {
continue;
}
let (lo, hi) = (usize::from(offsets[b]), usize::from(offsets[b + 1]));
for (lv, rv) in l[lo..hi].iter_mut().zip(r[lo..hi].iter_mut()) {
let (a, b2) = (*lv, *rv);
*lv = (a + b2) * 0.5;
*rv = (a - b2) * 0.5;
}
}
}
pub fn decide_short(
specs: &mut [[f32; LONG_WINDOW_LEN]; 2],
offsets: &[u16],
per_band: bool,
) -> MsBands {
let n_sfb = offsets.len() - 1;
let n = MAX_GROUPS * n_sfb;
let [l, r] = specs;
let mut e_l = [0.0f64; MAX_FLAT_SHORT];
let mut e_r = [0.0f64; MAX_FLAT_SHORT];
let mut e_s = [0.0f64; MAX_FLAT_SHORT];
let mut loudest = 0.0f64;
let mut out = MsBands {
used: [false; MAX_FLAT_SHORT],
n,
};
for w in 0..MAX_GROUPS {
for b in 0..n_sfb {
let idx = w * n_sfb + b;
let lo = w * SHORT_WINDOW_LEN + usize::from(offsets[b]);
let hi = w * SHORT_WINDOW_LEN + usize::from(offsets[b + 1]);
for (&lv, &rv) in l[lo..hi].iter().zip(r[lo..hi].iter()) {
let s = f64::from((lv - rv) * 0.5);
e_l[idx] += f64::from(lv) * f64::from(lv);
e_r[idx] += f64::from(rv) * f64::from(rv);
e_s[idx] += s * s;
}
loudest = loudest.max(e_l[idx].max(e_r[idx]));
out.used[idx] = band_prefers_ms(e_l[idx], e_r[idx], e_s[idx]);
}
}
let mut quiet = [false; MAX_FLAT_SHORT];
for i in 0..n {
quiet[i] = e_l[i].max(e_r[i]) < loudest * QUIET_FLOOR;
}
if per_band {
fold_quiet(&mut out.used[..n], &quiet[..n]);
} else {
let (mut tl, mut tr, mut ts) = (0.0f64, 0.0f64, 0.0f64);
for i in 0..n {
tl += e_l[i];
tr += e_r[i];
ts += e_s[i];
}
out.used[..n].fill(band_prefers_ms(tl, tr, ts));
}
let [l, r] = specs;
for w in 0..MAX_GROUPS {
for b in 0..n_sfb {
if !out.used[w * n_sfb + b] {
continue;
}
let lo = w * SHORT_WINDOW_LEN + usize::from(offsets[b]);
let hi = w * SHORT_WINDOW_LEN + usize::from(offsets[b + 1]);
for (lv, rv) in l[lo..hi].iter_mut().zip(r[lo..hi].iter_mut()) {
let (a, b2) = (*lv, *rv);
*lv = (a + b2) * 0.5;
*rv = (a - b2) * 0.5;
}
}
}
out
}
#[cfg(test)]
#[path = "enc_ms_tests.rs"]
mod enc_ms_tests;