1
0
Fork 0

Somewhat mitigate phasing in crossovers

This commit is contained in:
Robbert van der Helm 2022-05-29 16:57:39 +02:00
parent ebe2b24146
commit c9332d332b
2 changed files with 38 additions and 12 deletions

View file

@ -100,19 +100,31 @@ impl IirCrossover {
}
/// Update the crossover frequencies for all filters. If the frequencies are not monotonic then
/// this function will ensure that they are.
pub fn update(&mut self, sample_rate: f32, mut frequencies: [f32; NUM_BANDS - 1]) {
// Make sure the frequencies are monotonic
for frequency_idx in 1..NUM_BANDS - 1 {
if frequencies[frequency_idx] < frequencies[frequency_idx - 1] {
frequencies[frequency_idx] = frequencies[frequency_idx - 1];
/// this function will ensure that they are. The active number of bands is used to make sure
/// unused bands are not part of the normalization.
pub fn update(
&mut self,
sample_rate: f32,
num_bands: usize,
mut frequencies: [f32; NUM_BANDS - 1],
) {
// Make sure the frequencies are monotonic by pushing bands down when they are too close to
// the next band
for frequency_idx in (1..num_bands - 1).rev() {
if frequencies[frequency_idx - 1] > frequencies[frequency_idx] / 2.0 {
frequencies[frequency_idx - 1] = frequencies[frequency_idx] / 2.0;
}
}
match self.mode {
IirCrossoverType::LinkwitzRiley24 => {
const Q: f32 = std::f32::consts::FRAC_1_SQRT_2;
for (crossover, frequency) in self.crossovers.iter_mut().zip(frequencies) {
for (crossover, frequency) in self
.crossovers
.iter_mut()
.zip(frequencies)
.take(num_bands - 1)
{
let lp_coefs = BiquadCoefficients::lowpass(sample_rate, frequency, Q);
let hp_coefs = BiquadCoefficients::highpass(sample_rate, frequency, Q);
crossover.update_coefficients(lp_coefs, hp_coefs);

View file

@ -21,6 +21,7 @@ compile_error!("Compiling without SIMD support is currently not supported");
use crossover::iir::{IirCrossover, IirCrossoverType};
use nih_plug::prelude::*;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
mod crossover;
@ -39,6 +40,8 @@ struct Crossover {
/// Provides the LR24 crossover.
iir_crossover: IirCrossover,
/// Set when the number of bands has changed and the filters must be updated.
should_update_filters: Arc<AtomicBool>,
}
// TODO: Add multiple crossover types. Haven't added the control for that yet because the current
@ -63,8 +66,8 @@ struct CrossoverParams {
pub crossover_4_freq: FloatParam,
}
impl Default for CrossoverParams {
fn default() -> Self {
impl CrossoverParams {
fn new(should_update_filters: Arc<AtomicBool>) -> Self {
let crossover_range = FloatRange::Skewed {
min: MIN_CROSSOVER_FREQUENCY,
max: MAX_CROSSOVER_FREQUENCY,
@ -82,7 +85,10 @@ impl Default for CrossoverParams {
min: 2,
max: NUM_BANDS as i32,
},
),
)
.with_callback(Arc::new(move |_| {
should_update_filters.store(true, Ordering::Relaxed)
})),
// TODO: More sensible default frequencies
crossover_1_freq: FloatParam::new("Crossover 1", 200.0, crossover_range)
.with_smoother(crossover_smoothing_style)
@ -106,8 +112,10 @@ impl Default for CrossoverParams {
impl Default for Crossover {
fn default() -> Self {
let should_update_filters = Arc::new(AtomicBool::new(false));
Crossover {
params: Arc::new(CrossoverParams::default()),
params: Arc::new(CrossoverParams::new(should_update_filters.clone())),
buffer_config: BufferConfig {
sample_rate: 1.0,
@ -117,6 +125,7 @@ impl Default for Crossover {
},
iir_crossover: IirCrossover::new(IirCrossoverType::LinkwitzRiley24),
should_update_filters,
}
}
}
@ -238,7 +247,11 @@ impl Plugin for Crossover {
impl Crossover {
/// Update the filter coefficients for the crossovers, but only if it's needed.
fn maybe_update_filters(&mut self) {
if self.params.crossover_1_freq.smoothed.is_smoothing()
if self
.should_update_filters
.compare_exchange(true, false, Ordering::Relaxed, Ordering::Relaxed)
.is_ok()
|| self.params.crossover_1_freq.smoothed.is_smoothing()
|| self.params.crossover_2_freq.smoothed.is_smoothing()
|| self.params.crossover_3_freq.smoothed.is_smoothing()
|| self.params.crossover_4_freq.smoothed.is_smoothing()
@ -253,6 +266,7 @@ impl Crossover {
// crossover 2 being lower than crossover 1
self.iir_crossover.update(
self.buffer_config.sample_rate,
self.params.num_bands.value as usize,
[
self.params.crossover_1_freq.smoothed.next(),
self.params.crossover_2_freq.smoothed.next(),