diff --git a/plugins/spectral_compressor/src/compressor_bank.rs b/plugins/spectral_compressor/src/compressor_bank.rs index 776e9d2c..9a70f9f1 100644 --- a/plugins/spectral_compressor/src/compressor_bank.rs +++ b/plugins/spectral_compressor/src/compressor_bank.rs @@ -16,6 +16,31 @@ use nih_plug::prelude::*; +#[derive(Params)] +pub struct ThresholdParams { + // TODO: Sidechaining + /// 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. + #[id = "input_db"] + threshold_db: FloatParam, + /// 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 = log2(center_frequency) - log2(bin_frequency)`. In other words, this is + /// evaluated in the log/log domain for decibels and octaves. + #[id = "thresh_center_freq"] + center_frequency: FloatParam, + /// The slope for the curve, in the log/log domain. See the polynomial above. + #[id = "thresh_curve_slope"] + curve_slope: FloatParam, + /// 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. + #[id = "thresh_curve_curve"] + curve_curve: FloatParam, +} + #[derive(Params)] pub struct CompressorBankParams { // TODO: Target curve options @@ -58,9 +83,60 @@ pub struct CompressorBankParams { compressor_release_ms: FloatParam, } +impl Default for ThresholdParams { + fn default() -> Self { + ThresholdParams { + threshold_db: FloatParam::new( + "Global Threshold", + 0.0, + FloatRange::Linear { + min: -50.0, + max: 50.0, + }, + ) + .with_unit(" dB") + .with_step_size(0.1), + center_frequency: FloatParam::new( + "Threshold Center", + 500.0, + FloatRange::Skewed { + min: 20.0, + max: 20_000.0, + factor: FloatRange::skew_factor(-1.0), + }, + ) + // This includes the unit + .with_value_to_string(formatters::v2s_f32_hz_then_khz(0)) + .with_string_to_value(formatters::s2v_f32_hz_then_khz()), + // These are polynomial coefficients that are evaluated in the log/log domain + // (octaves/decibels). The threshold is the intercept. + curve_slope: FloatParam::new( + "Threshold Slope", + 0.0, + FloatRange::Linear { + min: -24.0, + max: 24.0, + }, + ) + .with_unit(" dB/oct") + .with_step_size(0.1), + curve_curve: FloatParam::new( + "Threshold Curve", + 0.0, + FloatRange::Linear { + min: -24.0, + max: 24.0, + }, + ) + .with_unit(" dB/oct^2") + .with_step_size(0.1), + } + } +} + impl Default for CompressorBankParams { fn default() -> Self { - Self { + CompressorBankParams { // TODO: Set nicer default values for these things // As explained above, these offsets are relative to the target curve downwards_threshold_offset_db: FloatParam::new( diff --git a/plugins/spectral_compressor/src/lib.rs b/plugins/spectral_compressor/src/lib.rs index 41e79b2f..4a9b95bb 100644 --- a/plugins/spectral_compressor/src/lib.rs +++ b/plugins/spectral_compressor/src/lib.rs @@ -73,9 +73,6 @@ struct Plan { #[derive(Params)] struct SpectralCompressorParams { - /// Gain applied just before the DFT as part of the STFT process. - #[id = "input_db"] - input_gain_db: FloatParam, /// Makeup gain applied after the IDFT in the STFT process. If automatic makeup gain is enabled, /// then this acts as an offset on top of that. #[id = "output_db"] @@ -93,10 +90,10 @@ struct SpectralCompressorParams { #[id = "dc_filter"] dc_filter: BoolParam, - // TODO: Custom target curves for the non-sidechained version - // - // TODO: Sidechaining - // + /// Parameters controlling the compressor thresholds and curves. + #[nested = "threhold"] + threhold: compressor_bank::ThresholdParams, + /// Parameters for the compressor bank. #[nested = "compressors"] compressors: compressor_bank::CompressorBankParams, } @@ -127,16 +124,6 @@ impl Default for SpectralCompressorParams { // We don't need any smoothing for these parameters as the overlap-add process will // already act as a form of smoothing - input_gain_db: FloatParam::new( - "Input Gain", - 0.0, - FloatRange::Linear { - min: -50.0, - max: 50.0, - }, - ) - .with_unit(" dB") - .with_step_size(0.1), output_gain_db: FloatParam::new( "Output Gain", 0.0, @@ -155,6 +142,7 @@ impl Default for SpectralCompressorParams { .with_string_to_value(formatters::s2v_f32_percentage()), dc_filter: BoolParam::new("DC Filter", true), + threhold: compressor_bank::ThresholdParams::default(), compressors: compressor_bank::CompressorBankParams::default(), } } @@ -266,9 +254,11 @@ impl Plugin for SpectralCompressor { ((overlap_times as f32 / 4.0) * 1.5).recip() / window_size as f32; // We'll apply the square root of the total gain compensation at the DFT and the IDFT - // stages. That way the compressor threshold values make much more sense. - let input_gain = - util::db_to_gain(self.params.input_gain_db.value) * gain_compensation.sqrt(); + // stages. That way the compressor threshold values make much more sense. This version of + // Spectral Compressor does not have in input gain option and instead has the curve + // threshold option. When sidechaining is enabled this is used to gain up the sidechain + // signal instead. + let input_gain = gain_compensation.sqrt(); let output_gain = util::db_to_gain(self.params.output_gain_db.value) * gain_compensation.sqrt(); // TODO: Auto makeup gain