diff --git a/plugins/spectral_compressor/src/compressor_bank.rs b/plugins/spectral_compressor/src/compressor_bank.rs index 910c4185..3ab2f217 100644 --- a/plugins/spectral_compressor/src/compressor_bank.rs +++ b/plugins/spectral_compressor/src/compressor_bank.rs @@ -23,19 +23,30 @@ use nih_plug::prelude::*; /// will have a capacity of `MAX_WINDOW_SIZE / 2 + 1` and a size that matches the current complex /// FFT buffer size. This is stored as a struct of arrays to make SIMD-ing easier in the future. pub struct CompressorBank { - // TODO: The thresholds and ratios need to be split up in downwards and upwards variants - /// If set, then the thresholds should be updated on the next processing cycle. Can be set from - /// a parameter value change listener, and is also set when calling `.reset_for_size`. - pub should_update_thresholds: Arc, - /// If set, then the ratios should be updated on the next processing cycle. Can be set from a - /// parameter value change listener, and is also set when calling `.reset_for_size`. - pub should_update_ratios: Arc, + /// If set, then the downwards thresholds should be updated on the next processing cycle. Can be + /// set from a parameter value change listener, and is also set when calling `.reset_for_size`. + pub should_update_downwards_thresholds: Arc, + /// The same as `should_update_downwards_thresholds`, but for upwards thresholds. + pub should_update_upwards_thresholds: Arc, + /// If set, then the downwards ratios should be updated on the next processing cycle. Can be set + /// from a parameter value change listener, and is also set when calling `.reset_for_size`. + pub should_update_downwards_ratios: Arc, + /// The same as `should_update_downwards_ratios`, but for upwards ratios. + pub should_update_upwards_ratios: Arc, + + /// Downwards compressor thresholds, in linear space. + downwards_thresholds: Vec, + /// Upwards compressor thresholds, in linear space. + upwards_thresholds: Vec, + /// Downwards compressor ratios. At 1.0 the cmopressor won't do anything. If + /// [`CompressorBankParams::high_freq_ratio_rolloff`] is set to 1.0, then this will be the same + /// for each compressor. + downwards_ratios: Vec, + /// Upwards compressor ratios. At 1.0 the cmopressor won't do anything. If + /// [`CompressorBankParams::high_freq_ratio_rolloff`] is set to 1.0, then this will be the same + /// for each compressor. + upwards_ratios: Vec, - /// Compressor thresholds, in linear space. - thresholds: Vec, - /// Compressor ratios. If [`CompressorBankParams::high_freq_ratio_rolloff`] is set to 1.0, then - /// this will be the same for each compressor. - ratios: Vec, /// The current envelope value for this bin, in linear space. Indexed by /// `[channel_idx][compressor_idx]`. envelopes: Vec>, @@ -113,9 +124,14 @@ impl ThresholdParams { /// Create a new [`ThresholdParams`] object. Changing any of the threshold parameters causes the /// passed compressor bank's thresholds to be updated. pub fn new(compressor_bank: &CompressorBank) -> Self { - let should_update_thresholds = compressor_bank.should_update_thresholds.clone(); - let set_update_thresholds = - Arc::new(move |_| should_update_thresholds.store(true, Ordering::SeqCst)); + let should_update_downwards_thresholds = + compressor_bank.should_update_downwards_thresholds.clone(); + let should_update_upwards_thresholds = + compressor_bank.should_update_upwards_thresholds.clone(); + let set_update_both_thresholds = Arc::new(move |_| { + should_update_downwards_thresholds.store(true, Ordering::SeqCst); + should_update_upwards_thresholds.store(true, Ordering::SeqCst); + }); ThresholdParams { center_frequency: FloatParam::new( @@ -127,7 +143,7 @@ impl ThresholdParams { factor: FloatRange::skew_factor(-2.0), }, ) - .with_callback(set_update_thresholds.clone()) + .with_callback(set_update_both_thresholds.clone()) // 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()), @@ -141,7 +157,7 @@ impl ThresholdParams { max: 50.0, }, ) - .with_callback(set_update_thresholds.clone()) + .with_callback(set_update_both_thresholds.clone()) .with_unit(" dB") .with_step_size(0.1), curve_slope: FloatParam::new( @@ -152,7 +168,7 @@ impl ThresholdParams { max: 24.0, }, ) - .with_callback(set_update_thresholds.clone()) + .with_callback(set_update_both_thresholds.clone()) .with_unit(" dB/oct") .with_step_size(0.1), curve_curve: FloatParam::new( @@ -163,7 +179,7 @@ impl ThresholdParams { max: 24.0, }, ) - .with_callback(set_update_thresholds) + .with_callback(set_update_both_thresholds) .with_unit(" dB/oct²") .with_step_size(0.1), } @@ -174,12 +190,27 @@ impl CompressorBankParams { /// Create a new [`CompressorBankParams`] object. Changing any of the threshold or ratio /// parameters causes the passed compressor bank's parameters to be updated. pub fn new(compressor_bank: &CompressorBank) -> Self { - let should_update_thresholds = compressor_bank.should_update_thresholds.clone(); - let set_update_thresholds = - Arc::new(move |_| should_update_thresholds.store(true, Ordering::SeqCst)); - let should_update_ratios = compressor_bank.should_update_ratios.clone(); - let set_update_ratios = - Arc::new(move |_| should_update_ratios.store(true, Ordering::SeqCst)); + let should_update_downwards_thresholds = + compressor_bank.should_update_downwards_thresholds.clone(); + let set_update_downwards_thresholds = + Arc::new(move |_| should_update_downwards_thresholds.store(true, Ordering::SeqCst)); + let should_update_upwards_thresholds = + compressor_bank.should_update_upwards_thresholds.clone(); + let set_update_upwards_thresholds = + Arc::new(move |_| should_update_upwards_thresholds.store(true, Ordering::SeqCst)); + let should_update_downwards_ratios = compressor_bank.should_update_downwards_ratios.clone(); + let set_update_downwards_ratios = + Arc::new(move |_| should_update_downwards_ratios.store(true, Ordering::SeqCst)); + let should_update_upwards_ratios = compressor_bank.should_update_upwards_ratios.clone(); + let set_update_upwards_ratios = + Arc::new(move |_| should_update_upwards_ratios.store(true, Ordering::SeqCst)); + + let should_update_downwards_ratios = compressor_bank.should_update_downwards_ratios.clone(); + let should_update_upwards_ratios = compressor_bank.should_update_upwards_ratios.clone(); + let set_update_both_ratios = Arc::new(move |_| { + should_update_downwards_ratios.store(true, Ordering::SeqCst); + should_update_upwards_ratios.store(true, Ordering::SeqCst); + }); CompressorBankParams { // TODO: Set nicer default values for these things @@ -192,7 +223,7 @@ impl CompressorBankParams { max: 50.0, }, ) - .with_callback(set_update_thresholds.clone()) + .with_callback(set_update_downwards_thresholds) .with_unit(" dB") .with_step_size(0.1), upwards_threshold_offset_db: FloatParam::new( @@ -203,7 +234,7 @@ impl CompressorBankParams { max: 50.0, }, ) - .with_callback(set_update_thresholds) + .with_callback(set_update_upwards_thresholds) .with_unit(" dB") .with_step_size(0.1), @@ -212,7 +243,7 @@ impl CompressorBankParams { 0.5, FloatRange::Linear { min: 0.0, max: 1.0 }, ) - .with_callback(set_update_ratios.clone()) + .with_callback(set_update_both_ratios) .with_unit("%") .with_value_to_string(formatters::v2s_f32_percentage(0)) .with_string_to_value(formatters::s2v_f32_percentage()), @@ -225,7 +256,7 @@ impl CompressorBankParams { factor: FloatRange::skew_factor(-2.0), }, ) - .with_callback(set_update_ratios.clone()) + .with_callback(set_update_downwards_ratios) .with_step_size(0.1) .with_value_to_string(formatters::v2s_compression_ratio(1)) .with_string_to_value(formatters::s2v_compression_ratio()), @@ -238,7 +269,7 @@ impl CompressorBankParams { factor: FloatRange::skew_factor(-2.0), }, ) - .with_callback(set_update_ratios) + .with_callback(set_update_upwards_ratios) .with_step_size(0.1) .with_value_to_string(formatters::v2s_compression_ratio(1)) .with_string_to_value(formatters::s2v_compression_ratio()), @@ -300,11 +331,16 @@ impl CompressorBank { let complex_buffer_len = max_window_size / 2 + 1; CompressorBank { - should_update_thresholds: Arc::new(AtomicBool::new(true)), - should_update_ratios: Arc::new(AtomicBool::new(true)), + should_update_downwards_thresholds: Arc::new(AtomicBool::new(true)), + should_update_upwards_thresholds: Arc::new(AtomicBool::new(true)), + should_update_downwards_ratios: Arc::new(AtomicBool::new(true)), + should_update_upwards_ratios: Arc::new(AtomicBool::new(true)), + + downwards_thresholds: Vec::with_capacity(complex_buffer_len), + upwards_thresholds: Vec::with_capacity(complex_buffer_len), + downwards_ratios: Vec::with_capacity(complex_buffer_len), + upwards_ratios: Vec::with_capacity(complex_buffer_len), - thresholds: Vec::with_capacity(complex_buffer_len), - ratios: Vec::with_capacity(complex_buffer_len), envelopes: vec![Vec::with_capacity(complex_buffer_len); num_channels], } } @@ -314,10 +350,15 @@ impl CompressorBank { pub fn update_capacity(&mut self, num_channels: usize, max_window_size: usize) { let complex_buffer_len = max_window_size / 2 + 1; - self.thresholds - .reserve_exact(complex_buffer_len.saturating_sub(self.thresholds.len())); - self.ratios - .reserve_exact(complex_buffer_len.saturating_sub(self.ratios.len())); + self.downwards_thresholds + .reserve_exact(complex_buffer_len.saturating_sub(self.downwards_thresholds.len())); + self.upwards_thresholds + .reserve_exact(complex_buffer_len.saturating_sub(self.upwards_thresholds.len())); + self.downwards_ratios + .reserve_exact(complex_buffer_len.saturating_sub(self.downwards_ratios.len())); + self.upwards_ratios + .reserve_exact(complex_buffer_len.saturating_sub(self.upwards_ratios.len())); + self.envelopes.resize_with(num_channels, Vec::new); for envelopes in self.envelopes.iter_mut() { envelopes.reserve_exact(complex_buffer_len.saturating_sub(envelopes.len())); @@ -330,15 +371,24 @@ impl CompressorBank { pub fn resize(&mut self, window_size: usize) { let complex_buffer_len = window_size / 2 + 1; - self.thresholds.resize(complex_buffer_len, 1.0); - self.ratios.resize(complex_buffer_len, 1.0); + self.downwards_thresholds.resize(complex_buffer_len, 1.0); + self.upwards_thresholds.resize(complex_buffer_len, 1.0); + self.downwards_ratios.resize(complex_buffer_len, 1.0); + self.upwards_ratios.resize(complex_buffer_len, 1.0); + for envelopes in self.envelopes.iter_mut() { envelopes.resize(complex_buffer_len, 0.0); } // The compressors need to be updated on the next processing cycle - self.should_update_thresholds.store(true, Ordering::SeqCst); - self.should_update_ratios.store(true, Ordering::SeqCst); + self.should_update_downwards_thresholds + .store(true, Ordering::SeqCst); + self.should_update_upwards_thresholds + .store(true, Ordering::SeqCst); + self.should_update_downwards_ratios + .store(true, Ordering::SeqCst); + self.should_update_upwards_ratios + .store(true, Ordering::SeqCst); } /// Clear out the envelope followers.