From b9031ecd2ff5749ff374fc649ec38acdf9cb26bc Mon Sep 17 00:00:00 2001 From: Robbert van der Helm Date: Mon, 27 Mar 2023 17:26:38 +0200 Subject: [PATCH] Fix sidechain matching + soft knee in SC These coefficients change with the thresholds. --- plugins/spectral_compressor/CHANGELOG.md | 3 ++ .../src/compressor_bank.rs | 36 +++++++++---------- 2 files changed, 21 insertions(+), 18 deletions(-) diff --git a/plugins/spectral_compressor/CHANGELOG.md b/plugins/spectral_compressor/CHANGELOG.md index 84c8cf3f..3316d76d 100644 --- a/plugins/spectral_compressor/CHANGELOG.md +++ b/plugins/spectral_compressor/CHANGELOG.md @@ -16,6 +16,9 @@ Versioning](https://semver.org/spec/v2.0.0.html). ### Fixed +- Fixed the soft-knee options in the sidechain matching mode. They previously + didn't account for the changing compressor thresholds, which could result in + unexpected loud volume spikes. - The sidechain matching mode now caps the relative thresholds to behave more consistently with quiet inputs. diff --git a/plugins/spectral_compressor/src/compressor_bank.rs b/plugins/spectral_compressor/src/compressor_bank.rs index 10327fa5..3aeea248 100644 --- a/plugins/spectral_compressor/src/compressor_bank.rs +++ b/plugins/spectral_compressor/src/compressor_bank.rs @@ -953,12 +953,8 @@ impl CompressorBank { assert!(self.sidechain_spectrum_magnitudes[channel_idx].len() == buffer.len()); assert!(self.downwards_thresholds_db.len() == buffer.len()); assert!(self.downwards_ratios.len() == buffer.len()); - assert!(self.downwards_knee_parabola_scale.len() == buffer.len()); - assert!(self.downwards_knee_parabola_intercept.len() == buffer.len()); assert!(self.upwards_thresholds_db.len() == buffer.len()); assert!(self.upwards_ratios.len() == buffer.len()); - assert!(self.upwards_knee_parabola_scale.len() == buffer.len()); - assert!(self.upwards_knee_parabola_intercept.len() == buffer.len()); for (bin_idx, (bin, envelope)) in buffer .iter_mut() .zip(self.envelopes[channel_idx].iter()) @@ -991,40 +987,44 @@ impl CompressorBank { unsafe { self.downwards_thresholds_db.get_unchecked(bin_idx) + sidechain_scale_db } .max(util::MINUS_INFINITY_DB); let downwards_ratio = unsafe { self.downwards_ratios.get_unchecked(bin_idx) }; - let downwards_knee_parabola_scale = - unsafe { self.downwards_knee_parabola_scale.get_unchecked(bin_idx) }; - let downwards_knee_parabola_intercept = unsafe { - self.downwards_knee_parabola_intercept - .get_unchecked(bin_idx) - }; + // Because the thresholds are scaled based on the sidechain input, we also need to + // recompute the knee coefficients + let (downwards_knee_parabola_scale, downwards_knee_parabola_intercept) = + downwards_soft_knee_coefficients( + downwards_threshold_db, + downwards_knee_width_db, + *downwards_ratio, + ); let downwards_compressed = compress_downwards( envelope_db, downwards_threshold_db, *downwards_ratio, downwards_knee_width_db, - *downwards_knee_parabola_scale, - *downwards_knee_parabola_intercept, + downwards_knee_parabola_scale, + downwards_knee_parabola_intercept, ); let upwards_threshold_db = unsafe { self.upwards_thresholds_db.get_unchecked(bin_idx) + sidechain_scale_db } .max(util::MINUS_INFINITY_DB); let upwards_ratio = unsafe { self.upwards_ratios.get_unchecked(bin_idx) }; - let upwards_knee_parabola_scale = - unsafe { self.upwards_knee_parabola_scale.get_unchecked(bin_idx) }; - let upwards_knee_parabola_intercept = - unsafe { self.upwards_knee_parabola_intercept.get_unchecked(bin_idx) }; let upwards_compressed = if bin_idx >= first_non_dc_bin && *upwards_ratio != 1.0 && envelope_db > util::MINUS_INFINITY_DB { + let (upwards_knee_parabola_scale, upwards_knee_parabola_intercept) = + upwards_soft_knee_coefficients( + upwards_threshold_db, + upwards_knee_width_db, + *upwards_ratio, + ); compress_upwards( envelope_db, upwards_threshold_db, *upwards_ratio, upwards_knee_width_db, - *upwards_knee_parabola_scale, - *upwards_knee_parabola_intercept, + upwards_knee_parabola_scale, + upwards_knee_parabola_intercept, ) } else { envelope_db