1
0
Fork 0

Precompute 2-log frequencies for the compressors

This commit is contained in:
Robbert van der Helm 2022-07-22 18:00:29 +02:00
parent b8525cac4d
commit fad560ab9f
2 changed files with 38 additions and 6 deletions

View file

@ -34,6 +34,10 @@ pub struct CompressorBank {
/// The same as `should_update_downwards_ratios`, but for upwards ratios.
pub should_update_upwards_ratios: Arc<AtomicBool>,
/// For each compressor bin, `log2(freq)` where `freq` is the frequency associated with that
/// compressor. This is precomputed since all update functions need it.
log2_freqs: Vec<f32>,
/// Downwards compressor thresholds, in linear space.
downwards_thresholds: Vec<f32>,
/// Upwards compressor thresholds, in linear space.
@ -336,6 +340,8 @@ impl CompressorBank {
should_update_downwards_ratios: Arc::new(AtomicBool::new(true)),
should_update_upwards_ratios: Arc::new(AtomicBool::new(true)),
log2_freqs: Vec::with_capacity(complex_buffer_len),
downwards_thresholds: Vec::with_capacity(complex_buffer_len),
upwards_thresholds: Vec::with_capacity(complex_buffer_len),
downwards_ratios: Vec::with_capacity(complex_buffer_len),
@ -350,6 +356,9 @@ 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.log2_freqs
.reserve_exact(complex_buffer_len.saturating_sub(self.log2_freqs.len()));
self.downwards_thresholds
.reserve_exact(complex_buffer_len.saturating_sub(self.downwards_thresholds.len()));
self.upwards_thresholds
@ -365,12 +374,21 @@ impl CompressorBank {
}
}
/// Resize the number of compressors to match the current window size.
/// Resize the number of compressors to match the current window size. Also precomputes the
/// 2-log frequencies for each bin.
///
/// If the window size is larger than the maximum window size, then this will allocate.
pub fn resize(&mut self, window_size: usize) {
pub fn resize(&mut self, buffer_config: &BufferConfig, window_size: usize) {
let complex_buffer_len = window_size / 2 + 1;
// 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
self.log2_freqs.resize(complex_buffer_len, 0.0);
for (i, log2_freq) in self.log2_freqs.iter_mut().enumerate() {
let freq = (i as f32 / window_size as f32) * buffer_config.sample_rate;
*log2_freq = freq.log2();
}
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);

View file

@ -48,6 +48,9 @@ struct SpectralCompressor {
params: Arc<SpectralCompressorParams>,
editor_state: Arc<ViziaState>,
/// The current buffer config, used for updating the compressors.
buffer_config: BufferConfig,
/// An adapter that performs most of the overlap-add algorithm for us.
stft: util::StftHelper,
/// Contains a Hann window function of the current window length, passed to the overlap-add
@ -122,6 +125,13 @@ impl Default for SpectralCompressor {
params: Arc::new(SpectralCompressorParams::new(&compressor_bank)),
editor_state: editor::default_state(),
buffer_config: BufferConfig {
sample_rate: 1.0,
min_buffer_size: None,
max_buffer_size: 0,
process_mode: ProcessMode::Realtime,
},
// These three will be set to the correct values in the initialize function
stft: util::StftHelper::new(Self::DEFAULT_NUM_OUTPUTS as usize, MAX_WINDOW_SIZE, 0),
window_function: Vec::with_capacity(MAX_WINDOW_SIZE),
@ -222,6 +232,9 @@ impl Plugin for SpectralCompressor {
buffer_config: &BufferConfig,
context: &mut impl InitContext,
) -> bool {
// Needed to update the compressors later
self.buffer_config = *buffer_config;
// This plugin can accept any number of channels, so we need to resize channel-dependent
// data structures accordinly
if self.stft.num_channels() != bus_config.num_output_channels as usize {
@ -284,7 +297,6 @@ impl Plugin for SpectralCompressor {
let fft_plan = &mut self.plan_for_order.as_mut().unwrap()
[self.params.window_size_order.value as usize - MIN_WINDOW_ORDER];
let num_bins = self.complex_fft_buffer.len();
let sample_rate = context.transport().sample_rate;
// 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
@ -329,8 +341,9 @@ impl Plugin for SpectralCompressor {
if self.params.dc_filter.value {
// The Hann window function spreads the DC signal out slightly, so we'll clear
// all 0-20 Hz bins for this.
let highest_dcish_bin_idx =
(20.0 / ((sample_rate / 2.0) / num_bins as f32)).floor() as usize;
let highest_dcish_bin_idx = (20.0
/ ((self.buffer_config.sample_rate / 2.0) / num_bins as f32))
.floor() as usize;
self.complex_fft_buffer[..highest_dcish_bin_idx + 1].fill(Complex32::default());
}
@ -386,7 +399,8 @@ impl SpectralCompressor {
.resize(window_size / 2 + 1, Complex32::default());
// This also causes the thresholds and ratios to be updated on the next STFT process cycle.
self.compressor_bank.resize(window_size);
self.compressor_bank
.resize(&self.buffer_config, window_size);
}
}