Somewhat mitigate phasing in crossovers
This commit is contained in:
parent
ebe2b24146
commit
c9332d332b
2 changed files with 38 additions and 12 deletions
|
@ -100,19 +100,31 @@ impl IirCrossover {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Update the crossover frequencies for all filters. If the frequencies are not monotonic then
|
/// Update the crossover frequencies for all filters. If the frequencies are not monotonic then
|
||||||
/// this function will ensure that they are.
|
/// this function will ensure that they are. The active number of bands is used to make sure
|
||||||
pub fn update(&mut self, sample_rate: f32, mut frequencies: [f32; NUM_BANDS - 1]) {
|
/// unused bands are not part of the normalization.
|
||||||
// Make sure the frequencies are monotonic
|
pub fn update(
|
||||||
for frequency_idx in 1..NUM_BANDS - 1 {
|
&mut self,
|
||||||
if frequencies[frequency_idx] < frequencies[frequency_idx - 1] {
|
sample_rate: f32,
|
||||||
frequencies[frequency_idx] = frequencies[frequency_idx - 1];
|
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 {
|
match self.mode {
|
||||||
IirCrossoverType::LinkwitzRiley24 => {
|
IirCrossoverType::LinkwitzRiley24 => {
|
||||||
const Q: f32 = std::f32::consts::FRAC_1_SQRT_2;
|
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 lp_coefs = BiquadCoefficients::lowpass(sample_rate, frequency, Q);
|
||||||
let hp_coefs = BiquadCoefficients::highpass(sample_rate, frequency, Q);
|
let hp_coefs = BiquadCoefficients::highpass(sample_rate, frequency, Q);
|
||||||
crossover.update_coefficients(lp_coefs, hp_coefs);
|
crossover.update_coefficients(lp_coefs, hp_coefs);
|
||||||
|
|
|
@ -21,6 +21,7 @@ compile_error!("Compiling without SIMD support is currently not supported");
|
||||||
|
|
||||||
use crossover::iir::{IirCrossover, IirCrossoverType};
|
use crossover::iir::{IirCrossover, IirCrossoverType};
|
||||||
use nih_plug::prelude::*;
|
use nih_plug::prelude::*;
|
||||||
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
mod crossover;
|
mod crossover;
|
||||||
|
@ -39,6 +40,8 @@ struct Crossover {
|
||||||
|
|
||||||
/// Provides the LR24 crossover.
|
/// Provides the LR24 crossover.
|
||||||
iir_crossover: IirCrossover,
|
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
|
// 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,
|
pub crossover_4_freq: FloatParam,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for CrossoverParams {
|
impl CrossoverParams {
|
||||||
fn default() -> Self {
|
fn new(should_update_filters: Arc<AtomicBool>) -> Self {
|
||||||
let crossover_range = FloatRange::Skewed {
|
let crossover_range = FloatRange::Skewed {
|
||||||
min: MIN_CROSSOVER_FREQUENCY,
|
min: MIN_CROSSOVER_FREQUENCY,
|
||||||
max: MAX_CROSSOVER_FREQUENCY,
|
max: MAX_CROSSOVER_FREQUENCY,
|
||||||
|
@ -82,7 +85,10 @@ impl Default for CrossoverParams {
|
||||||
min: 2,
|
min: 2,
|
||||||
max: NUM_BANDS as i32,
|
max: NUM_BANDS as i32,
|
||||||
},
|
},
|
||||||
),
|
)
|
||||||
|
.with_callback(Arc::new(move |_| {
|
||||||
|
should_update_filters.store(true, Ordering::Relaxed)
|
||||||
|
})),
|
||||||
// TODO: More sensible default frequencies
|
// TODO: More sensible default frequencies
|
||||||
crossover_1_freq: FloatParam::new("Crossover 1", 200.0, crossover_range)
|
crossover_1_freq: FloatParam::new("Crossover 1", 200.0, crossover_range)
|
||||||
.with_smoother(crossover_smoothing_style)
|
.with_smoother(crossover_smoothing_style)
|
||||||
|
@ -106,8 +112,10 @@ impl Default for CrossoverParams {
|
||||||
|
|
||||||
impl Default for Crossover {
|
impl Default for Crossover {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
|
let should_update_filters = Arc::new(AtomicBool::new(false));
|
||||||
|
|
||||||
Crossover {
|
Crossover {
|
||||||
params: Arc::new(CrossoverParams::default()),
|
params: Arc::new(CrossoverParams::new(should_update_filters.clone())),
|
||||||
|
|
||||||
buffer_config: BufferConfig {
|
buffer_config: BufferConfig {
|
||||||
sample_rate: 1.0,
|
sample_rate: 1.0,
|
||||||
|
@ -117,6 +125,7 @@ impl Default for Crossover {
|
||||||
},
|
},
|
||||||
|
|
||||||
iir_crossover: IirCrossover::new(IirCrossoverType::LinkwitzRiley24),
|
iir_crossover: IirCrossover::new(IirCrossoverType::LinkwitzRiley24),
|
||||||
|
should_update_filters,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -238,7 +247,11 @@ impl Plugin for Crossover {
|
||||||
impl Crossover {
|
impl Crossover {
|
||||||
/// Update the filter coefficients for the crossovers, but only if it's needed.
|
/// Update the filter coefficients for the crossovers, but only if it's needed.
|
||||||
fn maybe_update_filters(&mut self) {
|
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_2_freq.smoothed.is_smoothing()
|
||||||
|| self.params.crossover_3_freq.smoothed.is_smoothing()
|
|| self.params.crossover_3_freq.smoothed.is_smoothing()
|
||||||
|| self.params.crossover_4_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
|
// crossover 2 being lower than crossover 1
|
||||||
self.iir_crossover.update(
|
self.iir_crossover.update(
|
||||||
self.buffer_config.sample_rate,
|
self.buffer_config.sample_rate,
|
||||||
|
self.params.num_bands.value as usize,
|
||||||
[
|
[
|
||||||
self.params.crossover_1_freq.smoothed.next(),
|
self.params.crossover_1_freq.smoothed.next(),
|
||||||
self.params.crossover_2_freq.smoothed.next(),
|
self.params.crossover_2_freq.smoothed.next(),
|
||||||
|
|
Loading…
Add table
Reference in a new issue