//! Host-independent controls. Gains in dB, frequencies in Hz, times in seconds. use serde::{Deserialize, Serialize}; /// What the plugin outputs. #[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Default)] pub enum Listen { /// The aligned main layer only. The sidechain layer reaches the mix on its own track. #[default] Layer, /// Aligned main layer plus the sidechain layer, to judge the sum in one place. Sum, /// Unprocessed main layer plus the sidechain layer, to compare with `Sum`. SumDry, } /// How the alignment is found. #[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Default)] pub enum Mode { /// Keep measuring and refit when a clearly better alignment shows up. #[default] Follow, /// Measure from the moment Learn starts, with equal weight; the result is applied /// when Learn ends. Learn, /// Keep the current alignment. The display keeps measuring. Hold, } #[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq)] #[serde(deny_unknown_fields)] pub struct Settings { pub mode: Mode, /// Averaging time of the measurement in Follow mode. pub response: f32, /// Lowest frequency the fit listens to. pub low: f32, /// Highest frequency the fit listens to. pub high: f32, /// Largest number of allpass sections the fit may use. pub sections: usize, /// Frames quieter than this (dBFS RMS) on either layer are not measured. pub gate: f32, pub listen: Listen, pub output: f32, pub bypass: bool, } impl Default for Settings { fn default() -> Self { Self { mode: Mode::Follow, response: 1.5, low: 60., high: 6000., sections: 4, gate: -50., listen: Listen::Layer, output: 0., bypass: false, } } } impl Settings { pub fn validate(&self) -> Result<(), &'static str> { let values = [self.response, self.low, self.high, self.gate, self.output]; if values.iter().any(|v| !v.is_finite()) { return Err("non-finite setting"); } if (0.3..=5.).contains(&self.response) && (30.0..=400.).contains(&self.low) && (1000.0..=12000.).contains(&self.high) && (1..=crate::chain::MAX_SECTIONS).contains(&self.sections) && (-70.0..=-30.).contains(&self.gate) && (-12.0..=12.).contains(&self.output) { Ok(()) } else { Err("setting out of range") } } }