1
0
Fork 0

Fix disabled DC filter behavior

This fixes a NaN from taking the logarithm of zero, and the lower bins
are not actually compressed when this option is disabled. This is useful
when using tiny window sizes as the first bin will span quite a chunk of
the spectrum.
This commit is contained in:
Robbert van der Helm 2022-07-24 18:25:46 +02:00
parent 74b33af7d7
commit ce72dc5f03
2 changed files with 14 additions and 10 deletions

View file

@ -402,7 +402,8 @@ impl CompressorBank {
// These 2-log frequencies are needed when updating the compressor parameters, so we'll just // These 2-log frequencies are needed when updating the compressor parameters, so we'll just
// precompute them to avoid having to repeat the same expensive computations all the time // precompute them to avoid having to repeat the same expensive computations all the time
self.log2_freqs.resize(complex_buffer_len, 0.0); self.log2_freqs.resize(complex_buffer_len, 0.0);
for (i, log2_freq) in self.log2_freqs.iter_mut().enumerate() { // The first one should always stay at zero, `0.0f32.log2() == NaN`.
for (i, log2_freq) in self.log2_freqs.iter_mut().enumerate().skip(1) {
let freq = (i as f32 / window_size as f32) * buffer_config.sample_rate; let freq = (i as f32 / window_size as f32) * buffer_config.sample_rate;
*log2_freq = freq.log2(); *log2_freq = freq.log2();
} }

View file

@ -348,10 +348,14 @@ impl Plugin for SpectralCompressor {
let fft_plan = &mut self.plan_for_order.as_mut().unwrap() let fft_plan = &mut self.plan_for_order.as_mut().unwrap()
[self.params.global.window_size_order.value as usize - MIN_WINDOW_ORDER]; [self.params.global.window_size_order.value as usize - MIN_WINDOW_ORDER];
let num_bins = self.complex_fft_buffer.len(); let num_bins = self.complex_fft_buffer.len();
// The Hann window function spreads the DC signal out slightly, so we'll clear // The Hann window function spreads the DC signal out slightly, so we'll clear all 0-20 Hz
// all 0-20 Hz bins for this. // bins for this. With small window sizes you probably don't want this as it would result in
let highest_dcish_bin_idx = // a significant low-pass filter. When it's disabled, the DC bin will also be compressed.
(20.0 / ((self.buffer_config.sample_rate / 2.0) / num_bins as f32)).floor() as usize; let first_non_dc_bin_idx = if self.params.global.dc_filter.value {
(20.0 / ((self.buffer_config.sample_rate / 2.0) / num_bins as f32)).floor() as usize + 1
} else {
0
};
// The overlap gain compensation is based on a squared Hann window, which will sum perfectly // The overlap gain compensation is based on a squared Hann window, which will sum perfectly
// at four times overlap or higher. We'll apply a regular Hann window before the analysis // at four times overlap or higher. We'll apply a regular Hann window before the analysis
@ -395,14 +399,13 @@ impl Plugin for SpectralCompressor {
channel_idx, channel_idx,
&self.params, &self.params,
overlap_times, overlap_times,
highest_dcish_bin_idx + 1, first_non_dc_bin_idx,
); );
// The DC and other low frequency bins doesn't contain much semantic meaning anymore // The DC and other low frequency bins doesn't contain much semantic meaning anymore
// after all of this, so it only ends up consuming headroom. // after all of this, so it only ends up consuming headroom. If the DC filter is
if self.params.global.dc_filter.value { // disabled then this won't do anything.
self.complex_fft_buffer[..highest_dcish_bin_idx + 1].fill(Complex32::default()); self.complex_fft_buffer[..first_non_dc_bin_idx].fill(Complex32::default());
}
// Inverse FFT back into the scratch buffer. This will be added to a ring buffer // Inverse FFT back into the scratch buffer. This will be added to a ring buffer
// which gets written back to the host at a one block delay. // which gets written back to the host at a one block delay.