#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Blend {
pub first: u32,
pub weight_next: f32,
pub slope: f32,
pub rms: f32,
pub margin: f32,
}
impl Blend {
pub fn dominant(&self) -> u32 {
if self.weight_next < 0.5 {
self.first
} else {
self.first + 1
}
}
pub fn is_mixed(&self) -> bool {
(0.05..=0.95).contains(&self.weight_next)
}
}
pub const MAX_RMS: f32 = 0.2;
pub const MIN_MARGIN: f32 = 1.25;
pub(crate) fn choose(fits: &[Blend]) -> Option<Blend> {
let best = fits.iter().min_by(|a, b| a.rms.total_cmp(&b.rms))?;
let runner = fits
.iter()
.filter(|f| f.dominant() != best.dominant())
.map(|f| f.rms)
.fold(f32::INFINITY, f32::min);
let mut fit = Blend {
margin: runner / best.rms.max(1e-6),
..*best
};
if !fit.is_mixed() && fit.weight_next >= 0.5 {
fit.first += 1;
fit.weight_next = 0.0;
}
(fit.rms < MAX_RMS && fit.margin >= MIN_MARGIN).then_some(fit)
}