pub mod ambisonics;
pub mod convolver;
pub mod delay;
pub mod envelopes;
pub mod filters;
pub mod interpolation;
pub mod bitcrusher;
pub mod limiter;
pub mod modulator;
pub mod oscillators;
pub mod reverb;
pub mod routing;
pub mod sampler;
pub mod waveshaper;
use filters::DummyFilter;
pub use crate::building_blocks::envelopes::source_env::*;
use crate::building_blocks::filters::*;
pub use crate::building_blocks::modulator::Modulator;
use self::bitcrusher::BitcrusherMode;
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub enum OscillatorType {
Sine,
LFTri,
LFSquare,
LFSaw,
LFRsaw,
LFCub,
FMSquare,
FMSaw,
FMTri,
WTSaw,
Wavetable,
Wavematrix,
WhiteNoise,
BrownNoise,
NaiveBlit,
}
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub enum FilterType {
Dummy,
Lpf18,
BiquadHpf12dB,
BiquadLpf12dB,
BiquadHpf24dB,
BiquadLpf24dB,
ButterworthLpf(usize),
ButterworthHpf(usize),
PeakEQ,
}
#[repr(C)]
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum EffectType {
Bitcrusher(BitcrusherMode),
Waveshaper,
}
#[derive(Clone, Copy)]
pub enum SynthState {
Fresh, Finished,
}
#[allow(dead_code)]
#[repr(C)]
#[derive(Hash, Eq, PartialEq, Clone, Copy, Debug)]
pub enum SynthParameterLabel {
Attack, AttackType, AttackPeakLevel, Decay, DecayType, DelayDampeningFrequency, DelayDampeningFilterType, DelayFeedback, DelayMix, DelayTime, DelayRate, Duration, Envelope, PitchFrequency, PitchNote, HighpassCutoffFrequency, HighpassQFactor, HighpassFilterType, EnvelopeLevel, OscillatorType, OscillatorAmplitude, OscillatorPhaseRelative, OscillatorPhaseEffective, LowpassCutoffFrequency, LowpassQFactor, LowpassFilterDistortion, LowpassFilterType, PeakFrequency, PeakGain, PeakBandwidth, Pulsewidth, PlaybackRate, PlaybackStart, PlaybackLoop, Release, ReleaseType, ReverbDampening, ReverbMix, ReverbRoomsize, SampleBufferNumber, Samplerate, ChannelPosition, AmbisonicAzimuth, AmbisonicElevation, Sustain, Wavetable, Wavematrix, WavematrixTableIndex, WaveshaperMix, FilterType, BitcrusherMix, BitcrusherBits, BitcrusherDownsampling, BitcrusherMode, NumHarmonics, EffectActive, }
#[derive(Clone, Copy, Debug)]
pub enum ValOp {
Replace,
Add,
Subtract,
Multiply,
Divide,
}
#[derive(Clone, Copy, Debug)]
pub enum EnvelopeSegmentType {
Lin,
Log,
Exp,
Sin,
Cos,
Constant,
}
pub enum SampleBuffer {
Mono(Vec<f32>),
Stereo(Vec<f32>, Vec<f32>),
Placeholder,
}
#[derive(Clone, Copy, Debug)]
pub struct EnvelopeSegmentInfo {
pub from: f32, pub to: f32, pub time: f32, pub segment_type: EnvelopeSegmentType,
}
#[derive(Clone, Debug)]
#[rustfmt::skip]
pub enum SynthParameterValue {
ScalarF32(f32),
ScalarU32(u32),
ScalarUsize(usize),
VecF32(Vec<f32>),
FilterType(FilterType), OscillatorType(OscillatorType), BitcrusherMode(BitcrusherMode), MatrixF32((usize, usize), Vec<Vec<f32>>), Lfo(f32, Box<SynthParameterValue>, f32, Box<SynthParameterValue>, f32, ValOp), LFSaw(f32, Box<SynthParameterValue>, f32, Box<SynthParameterValue>, f32, ValOp), LFRSaw(f32, Box<SynthParameterValue>, f32, Box<SynthParameterValue>, f32, ValOp), LFTri(f32, Box<SynthParameterValue>, f32, Box<SynthParameterValue>, f32, ValOp), LFSquare(f32, Box<SynthParameterValue>, f32, Box<SynthParameterValue>, f32, ValOp), LinRamp(f32, f32, f32, ValOp), LogRamp(f32, f32, f32, ValOp), ExpRamp(f32, f32, f32, ValOp), EnvFollower(f32,f32,f32,f32,f32, ValOp), EnvelopeSegmentType(EnvelopeSegmentType),
MultiPointEnvelope(Vec<EnvelopeSegmentInfo>, bool, ValOp), Symbolic(String),
Boolean(bool),
}
#[derive(Clone)]
pub enum ValueOrModulator<const BUFSIZE: usize> {
Val(SynthParameterValue),
Mod(f32, Modulator<BUFSIZE>),
}
pub fn resolve_parameter_value<const BUFSIZE: usize>(
par: SynthParameterLabel,
val: &SynthParameterValue,
samplerate: f32,
) -> ValueOrModulator<BUFSIZE> {
match val {
SynthParameterValue::EnvFollower(from, to, attack, release, gain, op) => {
ValueOrModulator::Mod(
*from,
Modulator::env_follower(
*op,
*from,
to - from,
*gain,
*attack,
*release,
0.0,
false,
false,
samplerate,
),
)
}
SynthParameterValue::Lfo(init, freq, eff_phase, amp, add, op) => ValueOrModulator::Mod(
*init,
match par {
SynthParameterLabel::LowpassCutoffFrequency => Modulator::lfo(
*op,
resolve_parameter_value(SynthParameterLabel::PitchFrequency, freq, samplerate),
*eff_phase,
resolve_parameter_value(
SynthParameterLabel::OscillatorAmplitude,
amp,
samplerate,
),
*add,
true,
false,
samplerate,
),
SynthParameterLabel::HighpassCutoffFrequency => Modulator::lfo(
*op,
resolve_parameter_value(SynthParameterLabel::PitchFrequency, freq, samplerate),
*eff_phase,
resolve_parameter_value(
SynthParameterLabel::OscillatorAmplitude,
amp,
samplerate,
),
*add,
true,
false,
samplerate,
),
SynthParameterLabel::PeakFrequency => Modulator::lfo(
*op,
resolve_parameter_value(SynthParameterLabel::PitchFrequency, freq, samplerate),
*eff_phase,
resolve_parameter_value(
SynthParameterLabel::OscillatorAmplitude,
amp,
samplerate,
),
*add,
true,
false,
samplerate,
),
_ => Modulator::lfo(
*op,
resolve_parameter_value(SynthParameterLabel::PitchFrequency, freq, samplerate),
*eff_phase,
resolve_parameter_value(
SynthParameterLabel::OscillatorAmplitude,
amp,
samplerate,
),
*add,
false,
false,
samplerate,
),
},
),
SynthParameterValue::LFSaw(init, freq, eff_phase, amp, add, op) => ValueOrModulator::Mod(
*init,
match par {
SynthParameterLabel::LowpassCutoffFrequency => Modulator::lfsaw(
*op,
resolve_parameter_value(SynthParameterLabel::PitchFrequency, freq, samplerate),
*eff_phase,
resolve_parameter_value(
SynthParameterLabel::OscillatorAmplitude,
amp,
samplerate,
),
*add,
true,
false,
samplerate,
),
SynthParameterLabel::HighpassCutoffFrequency => Modulator::lfsaw(
*op,
resolve_parameter_value(SynthParameterLabel::PitchFrequency, freq, samplerate),
*eff_phase,
resolve_parameter_value(
SynthParameterLabel::OscillatorAmplitude,
amp,
samplerate,
),
*add,
true,
false,
samplerate,
),
SynthParameterLabel::PeakFrequency => Modulator::lfsaw(
*op,
resolve_parameter_value(SynthParameterLabel::PitchFrequency, freq, samplerate),
*eff_phase,
resolve_parameter_value(
SynthParameterLabel::OscillatorAmplitude,
amp,
samplerate,
),
*add,
true,
false,
samplerate,
),
_ => Modulator::lfsaw(
*op,
resolve_parameter_value(SynthParameterLabel::PitchFrequency, freq, samplerate),
*eff_phase,
resolve_parameter_value(
SynthParameterLabel::OscillatorAmplitude,
amp,
samplerate,
),
*add,
false,
false,
samplerate,
),
},
),
SynthParameterValue::LFRSaw(init, freq, eff_phase, amp, add, op) => ValueOrModulator::Mod(
*init,
match par {
SynthParameterLabel::LowpassCutoffFrequency => Modulator::lfrsaw(
*op,
resolve_parameter_value(SynthParameterLabel::PitchFrequency, freq, samplerate),
*eff_phase,
resolve_parameter_value(
SynthParameterLabel::OscillatorAmplitude,
amp,
samplerate,
),
*add,
true,
false,
samplerate,
),
SynthParameterLabel::HighpassCutoffFrequency => Modulator::lfrsaw(
*op,
resolve_parameter_value(SynthParameterLabel::PitchFrequency, freq, samplerate),
*eff_phase,
resolve_parameter_value(
SynthParameterLabel::OscillatorAmplitude,
amp,
samplerate,
),
*add,
true,
false,
samplerate,
),
SynthParameterLabel::PeakFrequency => Modulator::lfrsaw(
*op,
resolve_parameter_value(SynthParameterLabel::PitchFrequency, freq, samplerate),
*eff_phase,
resolve_parameter_value(
SynthParameterLabel::OscillatorAmplitude,
amp,
samplerate,
),
*add,
true,
false,
samplerate,
),
_ => Modulator::lfrsaw(
*op,
resolve_parameter_value(SynthParameterLabel::PitchFrequency, freq, samplerate),
*eff_phase,
resolve_parameter_value(
SynthParameterLabel::OscillatorAmplitude,
amp,
samplerate,
),
*add,
false,
false,
samplerate,
),
},
),
SynthParameterValue::LFTri(init, freq, eff_phase, amp, add, op) => ValueOrModulator::Mod(
*init,
match par {
SynthParameterLabel::LowpassCutoffFrequency => Modulator::lftri(
*op,
resolve_parameter_value(SynthParameterLabel::PitchFrequency, freq, samplerate),
*eff_phase,
resolve_parameter_value(
SynthParameterLabel::OscillatorAmplitude,
amp,
samplerate,
),
*add,
true,
false,
samplerate,
),
SynthParameterLabel::HighpassCutoffFrequency => Modulator::lftri(
*op,
resolve_parameter_value(SynthParameterLabel::PitchFrequency, freq, samplerate),
*eff_phase,
resolve_parameter_value(
SynthParameterLabel::OscillatorAmplitude,
amp,
samplerate,
),
*add,
true,
false,
samplerate,
),
SynthParameterLabel::PeakFrequency => Modulator::lftri(
*op,
resolve_parameter_value(SynthParameterLabel::PitchFrequency, freq, samplerate),
*eff_phase,
resolve_parameter_value(
SynthParameterLabel::OscillatorAmplitude,
amp,
samplerate,
),
*add,
true,
false,
samplerate,
),
_ => Modulator::lftri(
*op,
resolve_parameter_value(SynthParameterLabel::PitchFrequency, freq, samplerate),
*eff_phase,
resolve_parameter_value(
SynthParameterLabel::OscillatorAmplitude,
amp,
samplerate,
),
*add,
false,
false,
samplerate,
),
},
),
SynthParameterValue::LFSquare(init, freq, pw, amp, add, op) => ValueOrModulator::Mod(
*init,
match par {
SynthParameterLabel::LowpassCutoffFrequency => Modulator::lfsquare(
*op,
resolve_parameter_value(SynthParameterLabel::PitchFrequency, freq, samplerate),
*pw,
resolve_parameter_value(
SynthParameterLabel::OscillatorAmplitude,
amp,
samplerate,
),
*add,
true,
false,
samplerate,
),
SynthParameterLabel::HighpassCutoffFrequency => Modulator::lfsquare(
*op,
resolve_parameter_value(SynthParameterLabel::PitchFrequency, freq, samplerate),
*pw,
resolve_parameter_value(
SynthParameterLabel::OscillatorAmplitude,
amp,
samplerate,
),
*add,
true,
false,
samplerate,
),
SynthParameterLabel::PeakFrequency => Modulator::lfsquare(
*op,
resolve_parameter_value(SynthParameterLabel::PitchFrequency, freq, samplerate),
*pw,
resolve_parameter_value(
SynthParameterLabel::OscillatorAmplitude,
amp,
samplerate,
),
*add,
true,
false,
samplerate,
),
_ => Modulator::lfsquare(
*op,
resolve_parameter_value(SynthParameterLabel::PitchFrequency, freq, samplerate),
*pw,
resolve_parameter_value(
SynthParameterLabel::OscillatorAmplitude,
amp,
samplerate,
),
*add,
false,
false,
samplerate,
),
},
),
SynthParameterValue::LinRamp(from, to, time, op) => ValueOrModulator::Mod(
*from,
Modulator::lin_ramp(*op, *from, *to, *time, samplerate),
),
SynthParameterValue::LogRamp(from, to, time, op) => ValueOrModulator::Mod(
*from,
Modulator::log_ramp(*op, *from, *to, *time, samplerate),
),
SynthParameterValue::ExpRamp(from, to, time, op) => ValueOrModulator::Mod(
*from,
Modulator::exp_ramp(*op, *from, *to, *time, samplerate),
),
SynthParameterValue::MultiPointEnvelope(segments, loop_env, op) => {
if let SynthParameterLabel::Envelope = par {
ValueOrModulator::Val(SynthParameterValue::MultiPointEnvelope(
segments.to_vec(),
*loop_env,
*op,
))
} else {
let init = if let Some(seg) = segments.first() {
seg.from
} else {
0.0
};
ValueOrModulator::Mod(
init,
Modulator::multi_point_envelope(*op, segments.to_vec(), *loop_env, samplerate),
)
}
}
_ => ValueOrModulator::Val(val.clone()),
}
}
pub trait MonoSource<const BUFSIZE: usize>: MonoSourceClone<BUFSIZE> {
fn set_parameter(&mut self, par: SynthParameterLabel, value: &SynthParameterValue);
fn set_modulator(&mut self, par: SynthParameterLabel, init: f32, modulator: Modulator<BUFSIZE>);
fn set_param_or_modulator(
&mut self,
par: SynthParameterLabel,
val_or_mod: ValueOrModulator<BUFSIZE>,
) {
match val_or_mod {
ValueOrModulator::Val(val) => self.set_parameter(par, &val),
ValueOrModulator::Mod(init, modulator) => self.set_modulator(par, init, modulator),
}
}
fn finish(&mut self);
fn reset(&mut self);
fn is_finished(&self) -> bool;
fn get_next_block(
&mut self,
start_sample: usize,
in_buffers: &[SampleBuffer],
) -> [f32; BUFSIZE];
fn get_next_block_with_input(
&mut self,
start_sample: usize,
_input: &[f32; BUFSIZE],
in_buffers: &[SampleBuffer],
) -> [f32; BUFSIZE] {
self.get_next_block(start_sample, in_buffers)
}
}
pub trait MonoSourceClone<const BUFSIZE: usize> {
fn clone_box(&self) -> Box<dyn MonoSource<BUFSIZE> + Send + Sync>;
}
impl<const BUFSIZE: usize, T> MonoSourceClone<BUFSIZE> for T
where
T: 'static + MonoSource<BUFSIZE> + Clone + Send + Sync,
{
fn clone_box(&self) -> Box<dyn MonoSource<BUFSIZE> + Send + Sync> {
Box::new(self.clone())
}
}
impl<const BUFSIZE: usize> Clone for Box<dyn MonoSource<BUFSIZE> + Send + Sync> {
fn clone(&self) -> Box<dyn MonoSource<BUFSIZE> + Send + Sync> {
self.clone_box()
}
}
pub trait StereoSource<const BUFSIZE: usize>: StereoSourceClone<BUFSIZE> {
fn set_parameter(&mut self, par: SynthParameterLabel, value: &SynthParameterValue);
fn set_modulator(&mut self, par: SynthParameterLabel, init: f32, modulator: Modulator<BUFSIZE>);
fn set_param_or_modulator(
&mut self,
par: SynthParameterLabel,
val_or_mod: ValueOrModulator<BUFSIZE>,
) {
match val_or_mod {
ValueOrModulator::Val(val) => self.set_parameter(par, &val),
ValueOrModulator::Mod(init, modulator) => self.set_modulator(par, init, modulator),
}
}
fn finish(&mut self);
fn reset(&mut self);
fn is_finished(&self) -> bool;
fn get_next_block(
&mut self,
start_sample: usize,
sample_buffers: &[SampleBuffer],
) -> [[f32; BUFSIZE]; 2];
}
pub trait StereoSourceClone<const BUFSIZE: usize> {
fn clone_box(&self) -> Box<dyn StereoSource<BUFSIZE> + Send + Sync>;
}
impl<const BUFSIZE: usize, T> StereoSourceClone<BUFSIZE> for T
where
T: 'static + StereoSource<BUFSIZE> + Clone + Send + Sync,
{
fn clone_box(&self) -> Box<dyn StereoSource<BUFSIZE> + Send + Sync> {
Box::new(self.clone())
}
}
impl<const BUFSIZE: usize> Clone for Box<dyn StereoSource<BUFSIZE> + Send + Sync> {
fn clone(&self) -> Box<dyn StereoSource<BUFSIZE> + Send + Sync> {
self.clone_box()
}
}
pub trait MonoEffect<const BUFSIZE: usize> {
fn finish(&mut self);
fn is_finished(&self) -> bool;
fn set_parameter(&mut self, par: SynthParameterLabel, value: &SynthParameterValue);
fn set_modulator(&mut self, par: SynthParameterLabel, init: f32, modulator: Modulator<BUFSIZE>);
fn set_param_or_modulator(
&mut self,
par: SynthParameterLabel,
val_or_mod: ValueOrModulator<BUFSIZE>,
) {
match val_or_mod {
ValueOrModulator::Val(val) => self.set_parameter(par, &val),
ValueOrModulator::Mod(init, modulator) => self.set_modulator(par, init, modulator),
}
}
fn process_block(
&mut self,
block: [f32; BUFSIZE],
start_sample: usize,
in_buffers: &[SampleBuffer],
) -> [f32; BUFSIZE];
fn maybe_process_sample(&mut self, sample: f32) -> f32 {
sample
}
}
pub trait MultichannelReverb<const BUFSIZE: usize, const NCHAN: usize> {
fn set_parameter(&mut self, par: SynthParameterLabel, value: &SynthParameterValue);
fn set_param_or_modulator(
&mut self,
par: SynthParameterLabel,
val_or_mod: ValueOrModulator<BUFSIZE>,
) {
match val_or_mod {
ValueOrModulator::Val(val) => self.set_parameter(par, &val),
ValueOrModulator::Mod(_, _) => {} }
}
fn process(&mut self, block: [[f32; BUFSIZE]; NCHAN]) -> [[f32; BUFSIZE]; NCHAN];
}
pub trait Panner<const BUFSIZE: usize, const NCHAN: usize> {
fn set_parameter(&mut self, par: SynthParameterLabel, value: &SynthParameterValue);
fn set_modulator(&mut self, par: SynthParameterLabel, init: f32, modulator: Modulator<BUFSIZE>);
fn set_param_or_modulator(
&mut self,
par: SynthParameterLabel,
val_or_mod: ValueOrModulator<BUFSIZE>,
) {
match val_or_mod {
ValueOrModulator::Val(val) => self.set_parameter(par, &val),
ValueOrModulator::Mod(_, _) => {} }
}
fn process_block(
&mut self,
block: [f32; BUFSIZE],
start_sample: usize,
sample_buffers: &[SampleBuffer],
) -> [[f32; BUFSIZE]; NCHAN];
}
pub trait StereoPanner<const BUFSIZE: usize, const NCHAN: usize> {
fn set_parameter(&mut self, par: SynthParameterLabel, value: &SynthParameterValue);
fn set_modulator(&mut self, par: SynthParameterLabel, init: f32, modulator: Modulator<BUFSIZE>);
fn set_param_or_modulator(
&mut self,
par: SynthParameterLabel,
val_or_mod: ValueOrModulator<BUFSIZE>,
) {
match val_or_mod {
ValueOrModulator::Val(val) => self.set_parameter(par, &val),
ValueOrModulator::Mod(_, _) => {} }
}
fn process_block(
&mut self,
block: [[f32; BUFSIZE]; 2],
start_sample: usize,
sample_buffers: &[SampleBuffer],
) -> [[f32; BUFSIZE]; NCHAN];
}
#[derive(Clone, Copy, Hash, PartialEq, Eq, Debug)]
pub struct SynthParameterAddress {
pub label: SynthParameterLabel,
pub idx: Option<usize>,
}
impl From<SynthParameterLabel> for SynthParameterAddress {
fn from(label: SynthParameterLabel) -> Self {
SynthParameterAddress { label, idx: None }
}
}
impl SynthParameterLabel {
pub fn with_index(self, idx: usize) -> SynthParameterAddress {
SynthParameterAddress {
label: self,
idx: Some(idx),
}
}
}
pub trait Synth<const BUFSIZE: usize, const NCHAN: usize> {
fn set_parameter(&mut self, par: SynthParameterAddress, value: &SynthParameterValue);
fn set_modulator(
&mut self,
par: SynthParameterAddress,
init: f32,
modulator: Modulator<BUFSIZE>,
);
fn set_param_or_modulator(
&mut self,
par: SynthParameterAddress,
val_or_mod: ValueOrModulator<BUFSIZE>,
) {
match val_or_mod {
ValueOrModulator::Val(val) => self.set_parameter(par, &val),
ValueOrModulator::Mod(init, modulator) => self.set_modulator(par, init, modulator),
}
}
fn finish(&mut self);
fn is_finished(&self) -> bool;
fn get_next_block(
&mut self,
start_sample: usize,
in_buffers: &[SampleBuffer],
) -> [[f32; BUFSIZE]; NCHAN];
fn reverb_level(&self) -> f32;
fn delay_level(&self) -> f32;
}
pub struct MultichannelFilter<const BUFSIZE: usize, const NCHAN: usize> {
fx: Vec<Box<dyn MonoEffect<BUFSIZE> + Sync + Send>>,
fx_active: bool,
}
impl<const BUFSIZE: usize, const NCHAN: usize> MultichannelFilter<BUFSIZE, NCHAN> {
pub fn new(ftype: FilterType, sr: f32) -> Self {
let mut fx = vec![];
for _ in 0..NCHAN {
let filter: Box<dyn MonoEffect<BUFSIZE> + Sync + Send> = match ftype {
FilterType::Dummy => Box::new(DummyFilter::new()),
FilterType::Lpf18 => Box::new(Lpf18::new(19000.0, 0.1, 0.01, sr)),
FilterType::BiquadHpf12dB => Box::new(BiquadHpf12dB::new(20.0, 0.3, sr)),
FilterType::BiquadLpf12dB => Box::new(BiquadLpf12dB::new(19000.0, 0.3, sr)),
FilterType::BiquadHpf24dB => Box::new(BiquadHpf24dB::new(20.0, 0.3, sr)),
FilterType::BiquadLpf24dB => Box::new(BiquadLpf24dB::new(19000.0, 0.3, sr)),
FilterType::ButterworthLpf(o) => Box::new(ButterworthLpf::new(19000.0, o, sr)),
FilterType::ButterworthHpf(o) => Box::new(ButterworthHpf::new(20.0, o, sr)),
FilterType::PeakEQ => Box::new(PeakEq::new(700.0, 100.0, 0.0, sr)),
};
fx.push(filter);
}
Self {
fx,
fx_active: false,
}
}
pub fn set_parameter(&mut self, par: SynthParameterLabel, val: &SynthParameterValue) {
match par {
SynthParameterLabel::EffectActive => {
match val {
SynthParameterValue::Boolean(b) => {
self.fx_active = *b;
}
_ => { }
}
}
_ => {
for c in 0..NCHAN {
self.fx[c].set_parameter(par, val);
}
}
}
}
pub fn set_param_or_modulator(
&mut self,
par: SynthParameterLabel,
val_or_mod: ValueOrModulator<BUFSIZE>,
) {
match val_or_mod {
ValueOrModulator::Val(val) => self.set_parameter(par, &val),
ValueOrModulator::Mod(init, modulator) => self.set_modulator(par, init, modulator),
}
}
pub fn set_modulator(
&mut self,
par: SynthParameterLabel,
init: f32,
modulator: Modulator<BUFSIZE>,
) {
for c in 0..NCHAN {
self.fx[c].set_modulator(par, init, modulator.clone());
}
}
pub fn process(
&mut self,
block: [[f32; BUFSIZE]; NCHAN],
sample_buffers: &[SampleBuffer],
) -> [[f32; BUFSIZE]; NCHAN] {
let mut out_buf = [[0.0; BUFSIZE]; NCHAN];
if self.fx_active {
for c in 0..NCHAN {
out_buf[c] = self.fx[c].process_block(block[c], 0, sample_buffers);
}
} else {
for c in 0..NCHAN {
out_buf[c].copy_from_slice(&block[c]);
}
}
out_buf
}
}