Add a crossover type parameter
This commit is contained in:
parent
694996dcf4
commit
06f5048b0b
1 changed files with 62 additions and 28 deletions
|
@ -20,6 +20,7 @@
|
||||||
compile_error!("Compiling without SIMD support is currently not supported");
|
compile_error!("Compiling without SIMD support is currently not supported");
|
||||||
|
|
||||||
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;
|
||||||
|
@ -45,10 +46,6 @@ struct Crossover {
|
||||||
should_update_filters: Arc<AtomicBool>,
|
should_update_filters: Arc<AtomicBool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Add multiple crossover types. Haven't added the control for that yet because the current
|
|
||||||
// type (LR24) would become the second one in the list, and EnumParams are keyed by index so
|
|
||||||
// then we'd have an LR12 doing nothing instead. Aside form those two LR48 and some linear
|
|
||||||
// phase crossovers would also be nice
|
|
||||||
#[derive(Params)]
|
#[derive(Params)]
|
||||||
struct CrossoverParams {
|
struct CrossoverParams {
|
||||||
/// The number of bands between 2 and 5
|
/// The number of bands between 2 and 5
|
||||||
|
@ -65,6 +62,22 @@ struct CrossoverParams {
|
||||||
pub crossover_3_freq: FloatParam,
|
pub crossover_3_freq: FloatParam,
|
||||||
#[id = "xov4fq"]
|
#[id = "xov4fq"]
|
||||||
pub crossover_4_freq: FloatParam,
|
pub crossover_4_freq: FloatParam,
|
||||||
|
|
||||||
|
// Having this parameter first or after the number of bands makes more sense, but this way the
|
||||||
|
// band control plus the four crossovers fits exactly in Bitwig's parameter list
|
||||||
|
#[id = "xovtyp"]
|
||||||
|
pub crossover_type: EnumParam<CrossoverType>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Enum)]
|
||||||
|
enum CrossoverType {
|
||||||
|
#[id = "lr24"]
|
||||||
|
#[name = "LR24"]
|
||||||
|
LinkwitzRiley24,
|
||||||
|
// TODO: Add this next
|
||||||
|
// #[id = "lr24-lp"]
|
||||||
|
// #[name = "LR24 (LP)"]
|
||||||
|
// LinkwitzRiley24LinearPhase,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CrossoverParams {
|
impl CrossoverParams {
|
||||||
|
@ -90,6 +103,7 @@ impl CrossoverParams {
|
||||||
.with_callback(Arc::new(move |_| {
|
.with_callback(Arc::new(move |_| {
|
||||||
should_update_filters.store(true, Ordering::Relaxed)
|
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)
|
||||||
|
@ -107,6 +121,8 @@ impl CrossoverParams {
|
||||||
.with_smoother(crossover_smoothing_style)
|
.with_smoother(crossover_smoothing_style)
|
||||||
.with_value_to_string(crossover_value_to_string.clone())
|
.with_value_to_string(crossover_value_to_string.clone())
|
||||||
.with_string_to_value(crossover_string_to_value.clone()),
|
.with_string_to_value(crossover_string_to_value.clone()),
|
||||||
|
|
||||||
|
crossover_type: EnumParam::new("Type", CrossoverType::LinkwitzRiley24),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -191,6 +207,35 @@ impl Plugin for Crossover {
|
||||||
aux: &mut AuxiliaryBuffers,
|
aux: &mut AuxiliaryBuffers,
|
||||||
_context: &mut impl ProcessContext,
|
_context: &mut impl ProcessContext,
|
||||||
) -> ProcessStatus {
|
) -> ProcessStatus {
|
||||||
|
match self.params.crossover_type.value() {
|
||||||
|
CrossoverType::LinkwitzRiley24 => {
|
||||||
|
Self::do_process(buffer, aux, |main_channel_samples, bands| {
|
||||||
|
// 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,
|
||||||
|
);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ProcessStatus::Normal
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Crossover {
|
||||||
|
/// Takes care of all of the boilerplate in zipping the outputs together to get a nice iterator
|
||||||
|
/// 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
|
||||||
|
/// band to the array.
|
||||||
|
fn do_process(
|
||||||
|
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();
|
||||||
|
@ -225,14 +270,7 @@ impl Plugin for Crossover {
|
||||||
band_5_channel_samples,
|
band_5_channel_samples,
|
||||||
];
|
];
|
||||||
|
|
||||||
// Only update the filters when needed
|
f(&main_channel_samples, bands);
|
||||||
self.maybe_update_filters();
|
|
||||||
|
|
||||||
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
|
||||||
|
@ -240,12 +278,8 @@ impl Plugin for Crossover {
|
||||||
*sample = 0.0;
|
*sample = 0.0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ProcessStatus::Normal
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
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
|
if self
|
||||||
|
@ -263,18 +297,18 @@ impl Crossover {
|
||||||
|
|
||||||
/// Update the filter coefficients for the crossovers.
|
/// Update the filter coefficients for the crossovers.
|
||||||
fn update_filters(&mut self) {
|
fn update_filters(&mut self) {
|
||||||
// This function will take care of non-monotonic crossover frequencies for us, e.g.
|
match self.params.crossover_type.value() {
|
||||||
// crossover 2 being lower than crossover 1
|
CrossoverType::LinkwitzRiley24 => 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.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(),
|
self.params.crossover_3_freq.smoothed.next(),
|
||||||
self.params.crossover_3_freq.smoothed.next(),
|
self.params.crossover_4_freq.smoothed.next(),
|
||||||
self.params.crossover_4_freq.smoothed.next(),
|
],
|
||||||
],
|
),
|
||||||
)
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue