1
0
Fork 0

Move attack and release to global parameters

This commit is contained in:
Robbert van der Helm 2022-07-23 16:03:21 +02:00
parent 3c1a1c8f14
commit fa392e61f1
2 changed files with 61 additions and 62 deletions

View file

@ -14,15 +14,12 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
use nih_plug::prelude::*;
use realfft::num_complex::Complex32;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use nih_plug::prelude::*;
use realfft::num_complex::Complex32;
/// Type alias for the compressor parameters. These two are split up so the parameter list/tree
/// looks a bit nicer.
pub type CompressorParams<'a> = (&'a ThresholdParams, &'a CompressorBankParams);
use crate::SpectralCompressorParams;
/// A bank of compressors so each FFT bin can be compressed individually. The vectors in this struct
/// will have a capacity of `MAX_WINDOW_SIZE / 2 + 1` and a size that matches the current complex
@ -124,15 +121,6 @@ pub struct CompressorBankParams {
/// separate controls for both
#[id = "ratio_hi_freq_rolloff"]
high_freq_ratio_rolloff: FloatParam,
/// The compressor's attack time in milliseconds. Controls both upwards and downwards
/// compression.
#[id = "attack"]
compressor_attack_ms: FloatParam,
/// The compressor's release time in milliseconds. Controls both upwards and downwards
/// compression.
#[id = "release"]
compressor_release_ms: FloatParam,
}
impl ThresholdParams {
@ -311,29 +299,6 @@ impl CompressorBankParams {
.with_unit("%")
.with_value_to_string(formatters::v2s_f32_percentage(0))
.with_string_to_value(formatters::s2v_f32_percentage()),
compressor_attack_ms: FloatParam::new(
"Attack",
150.0,
FloatRange::Skewed {
min: 0.0,
max: 10_000.0,
factor: FloatRange::skew_factor(-2.0),
},
)
.with_unit(" ms")
.with_step_size(0.1),
compressor_release_ms: FloatParam::new(
"Release",
300.0,
FloatRange::Skewed {
min: 0.0,
max: 10_000.0,
factor: FloatRange::skew_factor(-2.0),
},
)
.with_unit(" ms")
.with_step_size(0.1),
}
}
}
@ -439,7 +404,7 @@ impl CompressorBank {
&mut self,
buffer: &mut [Complex32],
channel_idx: usize,
params: CompressorParams,
params: &SpectralCompressorParams,
overlap_times: usize,
skip_bins_below: usize,
) {
@ -455,7 +420,7 @@ impl CompressorBank {
&mut self,
buffer: &mut [Complex32],
channel_idx: usize,
(_, compressor): CompressorParams,
params: &SpectralCompressorParams,
overlap_times: usize,
skip_bins_below: usize,
) {
@ -467,17 +432,19 @@ impl CompressorBank {
// for every 512 samples.
let effective_sample_rate =
self.sample_rate / (self.window_size as f32 / overlap_times as f32);
let attack_old_t = if compressor.compressor_attack_ms.value == 0.0 {
let attack_old_t = if params.global.compressor_attack_ms.value == 0.0 {
0.0
} else {
(-1.0 / (compressor.compressor_attack_ms.value / 1000.0 * effective_sample_rate)).exp()
(-1.0 / (params.global.compressor_attack_ms.value / 1000.0 * effective_sample_rate))
.exp()
};
let attack_new_t = 1.0 - attack_old_t;
// The same as `attack_old_t`, but for the release phase of the envelope follower
let release_old_t = if compressor.compressor_release_ms.value == 0.0 {
let release_old_t = if params.global.compressor_release_ms.value == 0.0 {
0.0
} else {
(-1.0 / (compressor.compressor_release_ms.value / 1000.0 * effective_sample_rate)).exp()
(-1.0 / (params.global.compressor_release_ms.value / 1000.0 * effective_sample_rate))
.exp()
};
let release_new_t = 1.0 - release_old_t;
@ -503,16 +470,16 @@ impl CompressorBank {
&self,
buffer: &mut [Complex32],
channel_idx: usize,
(_, compressor): CompressorParams,
params: &SpectralCompressorParams,
skip_bins_below: usize,
) {
// Well I'm not sure at all why this scaling works, but it does. With higher knee
// bandwidths, the middle values needs to be pushed more towards the post-knee threshold
// than with lower knee values.
let downwards_knee_scaling_factor =
((compressor.downwards_knee_width_db.value * 2.0) + 2.0).log2() - 1.0;
((params.compressors.downwards_knee_width_db.value * 2.0) + 2.0).log2() - 1.0;
let upwards_knee_scaling_factor =
((compressor.upwards_knee_width_db.value * 2.0) + 2.0).log2() - 1.0;
((params.compressors.upwards_knee_width_db.value * 2.0) + 2.0).log2() - 1.0;
// Is this what they mean by zip and and ship it?
let downwards_values = self
@ -559,17 +526,17 @@ impl CompressorBank {
/// Update the compressors if needed. This is called just before processing, and the compressors
/// are updated in accordance to the atomic flags set on this struct.
fn update_if_needed(&mut self, (threshold, compressor): CompressorParams) {
fn update_if_needed(&mut self, params: &SpectralCompressorParams) {
// The threshold curve is a polynomial in log-log (decibels-octaves) space. The reuslt from
// evaluating this needs to be converted to linear gain for the compressors.
let intercept = threshold.threshold_db.value;
let intercept = params.threshold.threshold_db.value;
// The cheeky 3 additional dB/octave attenuation is to match pink noise with the default
// settings
let slope = threshold.curve_slope.value - 3.0;
let curve = threshold.curve_curve.value;
let log2_center_freq = threshold.center_frequency.value.log2();
let slope = params.threshold.curve_slope.value - 3.0;
let curve = params.threshold.curve_curve.value;
let log2_center_freq = params.threshold.center_frequency.value.log2();
let high_freq_ratio_rolloff = compressor.high_freq_ratio_rolloff.value;
let high_freq_ratio_rolloff = params.compressors.high_freq_ratio_rolloff.value;
let log2_nyquist_freq = self
.log2_freqs
.last()
@ -580,7 +547,7 @@ impl CompressorBank {
.compare_exchange(true, false, Ordering::SeqCst, Ordering::SeqCst)
.is_ok()
{
let intercept = intercept + compressor.downwards_threshold_offset_db.value;
let intercept = intercept + params.compressors.downwards_threshold_offset_db.value;
for (log2_freq, threshold) in self
.log2_freqs
.iter()
@ -599,7 +566,7 @@ impl CompressorBank {
.compare_exchange(true, false, Ordering::SeqCst, Ordering::SeqCst)
.is_ok()
{
let intercept = intercept + compressor.upwards_threshold_offset_db.value;
let intercept = intercept + params.compressors.upwards_threshold_offset_db.value;
for (log2_freq, threshold) in self
.log2_freqs
.iter()
@ -618,7 +585,7 @@ impl CompressorBank {
{
// If the high-frequency rolloff is enabled then higher frequency bins will have their
// ratios reduced to reduce harshness. This follows the octave scale.
let target_ratio_recip = compressor.downwards_ratio.value.recip();
let target_ratio_recip = params.compressors.downwards_ratio.value.recip();
if high_freq_ratio_rolloff == 0.0 {
self.downwards_ratio_recips.fill(target_ratio_recip);
} else {
@ -641,7 +608,7 @@ impl CompressorBank {
.compare_exchange(true, false, Ordering::SeqCst, Ordering::SeqCst)
.is_ok()
{
let target_ratio_recip = compressor.upwards_ratio.value.recip();
let target_ratio_recip = params.compressors.upwards_ratio.value.recip();
if high_freq_ratio_rolloff == 0.0 {
self.upwards_ratio_recips.fill(target_ratio_recip);
} else {

View file

@ -78,15 +78,15 @@ struct Plan {
}
#[derive(Params)]
struct SpectralCompressorParams {
pub struct SpectralCompressorParams {
/// Global parameters. These could just live in this struct but I wanted a separate generic UI
/// just for these.
#[nested = "global"]
global: GlobalParams,
/// Parameters controlling the compressor thresholds and curves.
#[nested = "threhold"]
threhold: compressor_bank::ThresholdParams,
#[nested = "threshold"]
threshold: compressor_bank::ThresholdParams,
/// Parameters for the compressor bank.
#[nested = "compressors"]
compressors: compressor_bank::CompressorBankParams,
@ -118,6 +118,15 @@ struct GlobalParams {
/// prevent invalid inputs).
#[id = "stft_overlap"]
overlap_times_order: IntParam,
/// The compressor's attack time in milliseconds. Controls both upwards and downwards
/// compression.
#[id = "attack"]
compressor_attack_ms: FloatParam,
/// The compressor's release time in milliseconds. Controls both upwards and downwards
/// compression.
#[id = "release"]
compressor_release_ms: FloatParam,
}
impl Default for SpectralCompressor {
@ -197,6 +206,29 @@ impl Default for GlobalParams {
)
.with_value_to_string(formatters::v2s_i32_power_of_two())
.with_string_to_value(formatters::s2v_i32_power_of_two()),
compressor_attack_ms: FloatParam::new(
"Attack",
150.0,
FloatRange::Skewed {
min: 0.0,
max: 10_000.0,
factor: FloatRange::skew_factor(-2.0),
},
)
.with_unit(" ms")
.with_step_size(0.1),
compressor_release_ms: FloatParam::new(
"Release",
300.0,
FloatRange::Skewed {
min: 0.0,
max: 10_000.0,
factor: FloatRange::skew_factor(-2.0),
},
)
.with_unit(" ms")
.with_step_size(0.1),
}
}
}
@ -210,7 +242,7 @@ impl SpectralCompressorParams {
// will require updating the compressor bank.
global: GlobalParams::default(),
threhold: compressor_bank::ThresholdParams::new(compressor_bank),
threshold: compressor_bank::ThresholdParams::new(compressor_bank),
compressors: compressor_bank::CompressorBankParams::new(compressor_bank),
}
}
@ -358,7 +390,7 @@ impl Plugin for SpectralCompressor {
self.compressor_bank.process(
&mut self.complex_fft_buffer,
channel_idx,
(&self.params.threhold, &self.params.compressors),
&self.params,
overlap_times,
highest_dcish_bin_idx,
);