1
0
Fork 0

Adjust windowing behavior in Puberty Simulator

We should indeed be windowing twice like we did before. A squared Hann
window doesn't work at 2x overlap, so that option has been removed. The
gain compensation is now also correct.
This commit is contained in:
Robbert van der Helm 2022-05-09 16:22:26 +02:00
parent d589f81228
commit 081487fdcb

View file

@ -29,9 +29,9 @@ const DEFAULT_WINDOW_SIZE: usize = 1 << DEFAULT_WINDOW_ORDER; // 1024
const MAX_WINDOW_ORDER: usize = 15; const MAX_WINDOW_ORDER: usize = 15;
const MAX_WINDOW_SIZE: usize = 1 << MAX_WINDOW_ORDER; // 32768 const MAX_WINDOW_SIZE: usize = 1 << MAX_WINDOW_ORDER; // 32768
const MIN_OVERLAP_ORDER: usize = 1; const MIN_OVERLAP_ORDER: usize = 2;
#[allow(dead_code)] #[allow(dead_code)]
const MIN_OVERLAP_TIMES: usize = 1 << MIN_OVERLAP_ORDER; // 2 const MIN_OVERLAP_TIMES: usize = 2 << MIN_OVERLAP_ORDER; // 4
const DEFAULT_OVERLAP_ORDER: usize = 3; const DEFAULT_OVERLAP_ORDER: usize = 3;
#[allow(dead_code)] #[allow(dead_code)]
const DEFAULT_OVERLAP_TIMES: usize = 1 << DEFAULT_OVERLAP_ORDER; // 4 const DEFAULT_OVERLAP_TIMES: usize = 1 << DEFAULT_OVERLAP_ORDER; // 4
@ -205,7 +205,11 @@ impl Plugin for PubertySimulator {
let window_size = self.window_size(); let window_size = self.window_size();
let overlap_times = self.overlap_times(); let overlap_times = self.overlap_times();
let sample_rate = context.transport().sample_rate; let sample_rate = context.transport().sample_rate;
let gain_compensation: f32 = (overlap_times as f32 / 2.0).recip() / window_size as f32; // 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
// and after the synthesis.
let gain_compensation: f32 =
((overlap_times as f32 / 4.0) * 1.5).recip() / window_size as f32;
// If the window size has changed since the last process call, reset the buffers and chance // If the window size has changed since the last process call, reset the buffers and chance
// our latency. All of these buffers already have enough capacity // our latency. All of these buffers already have enough capacity
@ -236,6 +240,9 @@ impl Plugin for PubertySimulator {
// Negated because pitching down should cause us to take values from higher frequency bins // Negated because pitching down should cause us to take values from higher frequency bins
let frequency_multiplier = 2.0f32.powf(-smoothed_pitch_value); let frequency_multiplier = 2.0f32.powf(-smoothed_pitch_value);
// We'll window the input with a Hann function to avoid spectral leakage
util::window::multiply_with_window(real_fft_buffer, &self.window_function);
// RustFFT doesn't actually need a scratch buffer here, so we'll pass an empty // RustFFT doesn't actually need a scratch buffer here, so we'll pass an empty
// buffer instead // buffer instead
fft_plan fft_plan
@ -295,7 +302,9 @@ impl Plugin for PubertySimulator {
.process_with_scratch(&mut self.complex_fft_buffer, real_fft_buffer, &mut []) .process_with_scratch(&mut self.complex_fft_buffer, real_fft_buffer, &mut [])
.unwrap(); .unwrap();
// Apply the window function. We can do this either before the DFT or after the IDFT // Apply the window function once more to reduce time domain aliasing. The gain
// compensation compensates for the squared Hann window that would be applied if we
// didn't do any processing at all.
util::window::multiply_with_window(real_fft_buffer, &self.window_function); util::window::multiply_with_window(real_fft_buffer, &self.window_function);
}); });