use std::f32::consts::FRAC_1_SQRT_2;
pub fn mid_side(left: &[f32], right: &[f32]) -> Vec<Vec<f32>> {
let n = left.len().min(right.len());
let mut mid = vec![0.0f32; n];
let mut side = vec![0.0f32; n];
for i in 0..n {
mid[i] = (left[i] + right[i]) * FRAC_1_SQRT_2;
side[i] = (left[i] - right[i]) * FRAC_1_SQRT_2;
}
vec![mid, side]
}
pub fn prefer_mid_side(left: &[f32], right: &[f32]) -> bool {
let mut mid_e = 0f64;
let mut side_e = 0f64;
let n = left.len().min(right.len());
for i in 0..n {
let m = (left[i] + right[i]) as f64;
let s = (left[i] - right[i]) as f64;
mid_e += m * m;
side_e += s * s;
}
side_e * 2.0 < mid_e
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn mid_side_inverts_to_left_right() {
let l = [0.5f32, -0.3, 0.1, 0.8];
let r = [0.4f32, -0.2, -0.1, 0.7];
let ms = mid_side(&l, &r);
for i in 0..4 {
let dl = (ms[0][i] + ms[1][i]) * FRAC_1_SQRT_2;
let dr = (ms[0][i] - ms[1][i]) * FRAC_1_SQRT_2;
assert!((dl - l[i]).abs() < 1e-6 && (dr - r[i]).abs() < 1e-6);
}
}
#[test]
fn decision_tracks_correlation() {
let mono = vec![0.5f32; 1152];
assert!(prefer_mid_side(&mono, &mono));
let anti: Vec<f32> = mono.iter().map(|x| -x).collect();
assert!(!prefer_mid_side(&mono, &anti));
}
}