1
0
Fork 0

Refactor IIR crossover process loop, disable FIR

The FIR crossover will need to use FFT convolution, so it can't use the
same loop. Because of that we'll need to rework the FIR crossover to not
use channel SIMD and to work on channel slices instead.
This commit is contained in:
Robbert van der Helm 2022-06-07 16:13:39 +02:00
parent 7e3dfe904d
commit 2c48ceb392

View file

@ -21,7 +21,6 @@ compile_error!("Compiling without SIMD support is currently not supported");
use crossover::fir::{FirCrossover, FirCrossoverType}; use crossover::fir::{FirCrossover, FirCrossoverType};
use crossover::iir::{IirCrossover, IirCrossoverType}; use crossover::iir::{IirCrossover, IirCrossoverType};
use nih_plug::buffer::ChannelSamples;
use nih_plug::prelude::*; use nih_plug::prelude::*;
use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc; use std::sync::Arc;
@ -201,7 +200,7 @@ impl Plugin for Crossover {
self.buffer_config = *buffer_config; self.buffer_config = *buffer_config;
// Make sure the filter states match the current parameters // Make sure the filter states match the current parameters
self.update_filters(); self.update_filters(1);
// The FIR filters are linear-phase and introduce latency // The FIR filters are linear-phase and introduce latency
match self.params.crossover_type.value() { match self.params.crossover_type.value() {
@ -228,29 +227,23 @@ impl Plugin for Crossover {
// Right now both crossover types only do 24 dB/octave Linkwitz-Riley style crossovers // Right now both crossover types only do 24 dB/octave Linkwitz-Riley style crossovers
match self.params.crossover_type.value() { match self.params.crossover_type.value() {
CrossoverType::LinkwitzRiley24 => { CrossoverType::LinkwitzRiley24 => {
Self::do_process(buffer, aux, |main_channel_samples, bands| { self.process_iir(buffer, aux);
// Only update the filters when needed
self.maybe_update_filters();
self.iir_crossover.process(
self.params.num_bands.value as usize,
main_channel_samples,
bands,
);
})
} }
CrossoverType::LinkwitzRiley24LinearPhase => { CrossoverType::LinkwitzRiley24LinearPhase => {
context.set_latency_samples(self.fir_crossover.latency()); context.set_latency_samples(self.fir_crossover.latency());
Self::do_process(buffer, aux, |main_channel_samples, bands| { todo!();
self.maybe_update_filters(); // Self::do_process(buffer, aux, |main_channel_samples, bands| {
// if self.should_update_filters() {
// self.update_filters(buffer.len() as u32);
// }
self.fir_crossover.process( // self.fir_crossover.process(
self.params.num_bands.value as usize, // self.params.num_bands.value as usize,
main_channel_samples, // main_channel_samples,
bands, // bands,
); // );
}) // })
} }
} }
@ -263,11 +256,7 @@ impl Crossover {
/// friendly and SIMD-able interface for the processing function. Prevents havign to branch per /// friendly and SIMD-able interface for the processing function. Prevents havign to branch per
/// sample. The closure receives an input sample and it should write the output samples for each /// sample. The closure receives an input sample and it should write the output samples for each
/// band to the array. /// band to the array.
fn do_process( fn process_iir(&mut self, buffer: &mut Buffer, aux: &mut AuxiliaryBuffers) {
buffer: &mut Buffer,
aux: &mut AuxiliaryBuffers,
mut f: impl FnMut(&ChannelSamples, [ChannelSamples; NUM_BANDS]),
) {
let aux_outputs = &mut aux.outputs; let aux_outputs = &mut aux.outputs;
let (band_1_buffer, aux_outputs) = aux_outputs.split_first_mut().unwrap(); let (band_1_buffer, aux_outputs) = aux_outputs.split_first_mut().unwrap();
let (band_2_buffer, aux_outputs) = aux_outputs.split_first_mut().unwrap(); let (band_2_buffer, aux_outputs) = aux_outputs.split_first_mut().unwrap();
@ -302,7 +291,16 @@ impl Crossover {
band_5_channel_samples, band_5_channel_samples,
]; ];
f(&main_channel_samples, bands); // Only update the filters when needed
if self.should_update_filters() {
self.update_filters(1);
}
self.iir_crossover.process(
self.params.num_bands.value as usize,
&main_channel_samples,
bands,
);
// The main output should be silent as the signal is already evenly split over the other // The main output should be silent as the signal is already evenly split over the other
// bands // bands
@ -312,28 +310,29 @@ impl Crossover {
} }
} }
/// Update the filter coefficients for the crossovers, but only if it's needed. /// Returns whether the filters should be updated. There are different updating functions for
fn maybe_update_filters(&mut self) { /// the IIR and FIR crossovers.
if self fn should_update_filters(&mut self) -> bool {
.should_update_filters // Technically this would only require a &self since `should_update_filters` has interior
// mutability, but with the current setup this doesn't cause any problems and makes the
// former a bit more obvious
self.should_update_filters
.compare_exchange(true, false, Ordering::Relaxed, Ordering::Relaxed) .compare_exchange(true, false, Ordering::Relaxed, Ordering::Relaxed)
.is_ok() .is_ok()
|| self.params.crossover_1_freq.smoothed.is_smoothing() || 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()
{
self.update_filters();
}
} }
/// Update the filter coefficients for the crossovers. /// Update the filter coefficients for the crossovers. The step size can be used when the filter
fn update_filters(&mut self) { /// coefficietns aren't updated every sample.
fn update_filters(&mut self, step_size: u32) {
let crossover_frequencies = [ let crossover_frequencies = [
self.params.crossover_1_freq.smoothed.next(), self.params.crossover_1_freq.smoothed.next_step(step_size),
self.params.crossover_2_freq.smoothed.next(), self.params.crossover_2_freq.smoothed.next_step(step_size),
self.params.crossover_3_freq.smoothed.next(), self.params.crossover_3_freq.smoothed.next_step(step_size),
self.params.crossover_4_freq.smoothed.next(), self.params.crossover_4_freq.smoothed.next_step(step_size),
]; ];
match self.params.crossover_type.value() { match self.params.crossover_type.value() {