use super::super::DUAL_MONO_CORRELATION_THRESHOLD;
pub fn mix_channels_to_mono(channels: &[Vec<f32>]) -> Vec<f32> {
if channels.is_empty() {
return Vec::new();
}
let n = channels.iter().map(|c| c.len()).min().unwrap_or(0);
(0..n)
.map(|i| channels.iter().map(|c| c[i]).sum::<f32>() / channels.len() as f32)
.collect()
}
pub fn is_dual_mono(channels: &[Vec<f32>]) -> bool {
if channels.len() != 2 {
return false;
}
let (left, right) = (&channels[0], &channels[1]);
if left.is_empty() || right.is_empty() {
return false;
}
let len = left.len().min(right.len());
normalized_correlation(&left[..len], &right[..len]) > DUAL_MONO_CORRELATION_THRESHOLD
}
#[derive(Debug, Default, Clone)]
pub struct DualMonoDetector {
n: f64,
mean_a: f64,
mean_b: f64,
c_ab: f64,
m2_a: f64,
m2_b: f64,
}
impl DualMonoDetector {
pub fn new() -> Self {
Self::default()
}
pub fn push(&mut self, a: &[f32], b: &[f32]) {
for (&x, &y) in a.iter().zip(b) {
let (x, y) = (x as f64, y as f64);
self.n += 1.0;
let dx = x - self.mean_a;
let dy = y - self.mean_b;
self.mean_a += dx / self.n;
self.mean_b += dy / self.n;
self.c_ab += dx * (y - self.mean_b);
self.m2_a += dx * (x - self.mean_a);
self.m2_b += dy * (y - self.mean_b);
}
}
pub fn correlation(&self) -> f64 {
if self.n == 0.0 {
return 0.0;
}
let denom = self.m2_a.sqrt() * self.m2_b.sqrt();
if denom < 1e-12 {
return 0.0;
}
self.c_ab / denom
}
pub fn is_dual_mono(&self) -> bool {
self.n > 0.0 && self.correlation() > DUAL_MONO_CORRELATION_THRESHOLD
}
}
#[cfg(test)]
pub(crate) fn normalized_correlation_for_test(a: &[f32], b: &[f32]) -> f64 {
normalized_correlation(a, b)
}
fn normalized_correlation(a: &[f32], b: &[f32]) -> f64 {
let n = a.len();
if n == 0 || n != b.len() {
return 0.0;
}
let mean_a = a.iter().map(|&x| x as f64).sum::<f64>() / n as f64;
let mean_b = b.iter().map(|&x| x as f64).sum::<f64>() / n as f64;
let mut cov = 0.0;
let mut var_a = 0.0;
let mut var_b = 0.0;
for (&x, &y) in a.iter().zip(b) {
let dx = x as f64 - mean_a;
let dy = y as f64 - mean_b;
cov += dx * dy;
var_a += dx * dx;
var_b += dy * dy;
}
let denom = var_a.sqrt() * var_b.sqrt();
if denom < 1e-12 {
return 0.0;
}
cov / denom
}