1
0
Fork 0
nih-plug/plugins/spectral_compressor/src/curve.rs
Robbert van der Helm 144fafbed6 Swap log2 in Spectral Compressor out for ln
The ln() implementation is usually faster, and there's no reason to
prefer a specific base.
2023-03-21 22:56:49 +01:00

62 lines
2.8 KiB
Rust

//! Abstractions for the parameterized threshold curve.
//!
//! This was previously computed directly inside of the `CompressorBank` but this makes it easier to
//! reuse it when drawing the GUI.
/// Parameters for a curve, similar to the fields found in `ThresholdParams` but using plain floats
/// instead of parameters.
#[derive(Debug, Default, Clone, Copy)]
pub struct CurveParams {
/// The compressor threshold at the center frequency. When sidechaining is enabled, the input
/// signal is gained by the inverse of this value. This replaces the input gain in the original
/// Spectral Compressor. In the polynomial below, this is the intercept.
pub intercept: f32,
/// The center frqeuency for the target curve when sidechaining is not enabled. The curve is a
/// polynomial `threshold_db + curve_slope*x + curve_curve*(x^2)` that evaluates to a decibel
/// value, where `x = ln(center_frequency) - ln(bin_frequency)`. In other words, this is
/// evaluated in the log/log domain for decibels and octaves.
pub center_frequency: f32,
/// The slope for the curve, in the log/log domain. See the polynomial above.
pub slope: f32,
/// The, uh, 'curve' for the curve, in the logarithmic domain. This is the third coefficient in
/// the quadratic polynomial and controls the parabolic behavior. Positive values turn the curve
/// into a v-shaped curve, while negative values attenuate everything outside of the center
/// frequency. See the polynomial above.
pub curve: f32,
}
/// Evaluates the quadratic threshold curve. This used to be calculated directly inside of the
/// compressor bank since it's so simple, but the editor also needs to compute this so it makes
/// sense to deduplicate it a bit.
///
/// The curve is evaluated in log-log space (so with octaves being the independent variable and gain
/// in decibels being the output of the equation).
pub struct Curve<'a> {
params: &'a CurveParams,
/// The natural logarithm of [`CurveParams::cemter_frequency`].
ln_center_frequency: f32,
}
impl<'a> Curve<'a> {
pub fn new(params: &'a CurveParams) -> Self {
Self {
params,
ln_center_frequency: params.center_frequency.ln(),
}
}
/// Evaluate the curve for the natural logarithm of the frequency value. This can be used as an
/// optimization to avoid computing these logarithms all the time.
#[inline]
pub fn evaluate_ln(&self, ln_freq: f32) -> f32 {
let offset = ln_freq - self.ln_center_frequency;
self.params.intercept + (self.params.slope * offset) + (self.params.curve * offset * offset)
}
/// Evaluate the curve for a value in Hertz.
#[inline]
#[allow(unused)]
pub fn evaluate_linear(&self, freq: f32) -> f32 {
self.evaluate_ln(freq.ln())
}
}