pub(crate) const SAMPLED: usize = 32;
const FRAC: u32 = 4;
const EWMA_SHIFT: u32 = 4;
pub(crate) struct ThresholdState {
base: [u32; SAMPLED],
buf_len: usize,
hold_until_us: u64,
}
impl ThresholdState {
pub(crate) const fn new() -> Self {
Self {
base: [0; SAMPLED],
buf_len: 0,
hold_until_us: 0,
}
}
pub(crate) fn reset(&mut self) {
*self = Self::new();
}
pub(crate) fn score(&mut self, buf: &[i8]) -> u16 {
let pairs = buf.len() / 2;
if pairs == 0 {
return 0;
}
let n = pairs.min(SAMPLED);
let step = pairs / n;
let restart = buf.len() != self.buf_len;
self.buf_len = buf.len();
let mut amp = [0u32; SAMPLED];
let mut a_tot: u64 = 0;
let mut b_tot: u64 = 0;
for (k, slot) in amp.iter_mut().enumerate().take(n) {
let i = 2 * (k * step);
*slot = ((buf[i] as i32).unsigned_abs() + (buf[i + 1] as i32).unsigned_abs()) << FRAC;
a_tot += *slot as u64;
b_tot += self.base[k] as u64;
}
let mut dist: u64 = 0;
for (k, &a) in amp.iter().enumerate().take(n) {
let b = &mut self.base[k];
if restart {
*b = a;
continue;
}
dist += (a as u64 * b_tot).abs_diff(*b as u64 * a_tot);
if a >= *b {
*b += (a - *b) >> EWMA_SHIFT;
} else {
*b -= (*b - a) >> EWMA_SHIFT;
}
}
if restart || a_tot == 0 || b_tot == 0 {
return 0;
}
let denom = a_tot * b_tot;
(dist.saturating_mul(u16::MAX as u64 / 2) / denom).min(u16::MAX as u64) as u16
}
pub(crate) fn decide(&mut self, score: u16, level: u16, hold_ms: u16, now_us: u64) -> bool {
if score >= level {
self.hold_until_us = now_us + hold_ms as u64 * 1000;
return true;
}
now_us < self.hold_until_us
}
}
pub(crate) struct Decimator {
count: u16,
}
impl Decimator {
pub(crate) const fn new() -> Self {
Self { count: 0 }
}
pub(crate) fn reset(&mut self) {
self.count = 0;
}
pub(crate) fn tick(&mut self, n: u16) -> bool {
let keep = self.count == 0;
self.count += 1;
if self.count >= n.max(1) {
self.count = 0;
}
keep
}
}