use super::*;
use fixedmath::apply_scalar_u;
pub struct ModFiltParams<'a, Smp> {
pub env_mod: &'a [Smp],
pub vel_mod: &'a [Smp],
pub kbd: &'a [Smp],
pub cutoff: &'a [Smp],
pub resonance: &'a [Smp],
pub low_mix: &'a [Smp],
pub band_mix: &'a [Smp],
pub high_mix: &'a [Smp],
}
impl<'a, Smp> ModFiltParams<'a, Smp> {
pub fn len(&self) -> usize {
min_size(&[
self.env_mod.len(),
self.vel_mod.len(),
self.kbd.len(),
self.cutoff.len(),
self.resonance.len(),
self.low_mix.len(),
self.band_mix.len(),
self.high_mix.len(),
])
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
}
pub struct MutModFiltParams<'a, Smp> {
pub env_mod: &'a mut [Smp],
pub vel_mod: &'a mut [Smp],
pub kbd: &'a mut [Smp],
pub cutoff: &'a mut [Smp],
pub resonance: &'a mut [Smp],
pub low_mix: &'a mut [Smp],
pub band_mix: &'a mut [Smp],
pub high_mix: &'a mut [Smp],
}
impl<'a, Smp> MutModFiltParams<'a, Smp> {
pub fn len(&self) -> usize {
min_size(&[
self.env_mod.len(),
self.vel_mod.len(),
self.kbd.len(),
self.cutoff.len(),
self.resonance.len(),
self.low_mix.len(),
self.band_mix.len(),
self.high_mix.len(),
])
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
}
impl<'a, Smp> From<MutModFiltParams<'a, Smp>> for ModFiltParams<'a, Smp> {
fn from(value: MutModFiltParams<'a, Smp>) -> Self {
Self {
env_mod: value.env_mod,
vel_mod: value.vel_mod,
kbd: value.kbd,
cutoff: value.cutoff,
resonance: value.resonance,
low_mix: value.low_mix,
band_mix: value.band_mix,
high_mix: value.high_mix,
}
}
}
#[derive(Clone)]
pub struct ModFilt<Smp> {
filter: Filt<Smp>,
outbuf: BufferT<Smp>,
}
impl<Smp: Float> ModFilt<Smp> {
pub fn new() -> Self {
Self {
filter: Default::default(),
outbuf: [Smp::ZERO; STATIC_BUFFER_SIZE],
}
}
pub fn process(
&mut self,
ctx: &Context<Smp>,
input: &[Smp],
env: &[Smp],
note: &[Smp],
vel: &[Smp],
params: ModFiltParams<Smp>,
) -> &[Smp] {
let numsamples = min_size(&[input.len(), env.len(), note.len(), vel.len(), params.len()]);
for i in 0..numsamples {
self.outbuf[i] = Smp::NOTE_MAX * params.env_mod[i] * env[i];
self.outbuf[i] = self.outbuf[i] + (Smp::NOTE_MAX * params.vel_mod[i] * vel[i]);
self.outbuf[i] = self.outbuf[i] + params.cutoff[i] + (params.kbd[i] * note[i]);
if self.outbuf[i] > Smp::NOTE_MAX {
self.outbuf[i] = Smp::NOTE_MAX;
}
}
let filt_out = self.filter.process(
ctx,
input,
FiltParams {
cutoff: &self.outbuf[0..numsamples],
resonance: params.resonance,
},
);
for i in 0..numsamples {
self.outbuf[i] = (params.low_mix[i] * filt_out.low[i])
+ (params.band_mix[i] * filt_out.band[i])
+ (params.high_mix[i] * filt_out.high[i]);
}
&self.outbuf[0..numsamples]
}
}
impl<Smp: Float> Default for ModFilt<Smp> {
fn default() -> Self {
Self::new()
}
}
pub struct ModFiltParamsFxP<'a> {
pub env_mod: &'a [ScalarFxP],
pub vel_mod: &'a [ScalarFxP],
pub kbd: &'a [ScalarFxP],
pub cutoff: &'a [NoteFxP],
pub resonance: &'a [ScalarFxP],
pub low_mix: &'a [ScalarFxP],
pub band_mix: &'a [ScalarFxP],
pub high_mix: &'a [ScalarFxP],
}
impl<'a> ModFiltParamsFxP<'a> {
pub fn len(&self) -> usize {
min_size(&[
self.env_mod.len(),
self.kbd.len(),
self.cutoff.len(),
self.resonance.len(),
self.low_mix.len(),
self.band_mix.len(),
self.high_mix.len(),
])
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
}
pub struct MutModFiltParamsFxP<'a> {
pub env_mod: &'a mut [ScalarFxP],
pub vel_mod: &'a mut [ScalarFxP],
pub kbd: &'a mut [ScalarFxP],
pub cutoff: &'a mut [NoteFxP],
pub resonance: &'a mut [ScalarFxP],
pub low_mix: &'a mut [ScalarFxP],
pub band_mix: &'a mut [ScalarFxP],
pub high_mix: &'a mut [ScalarFxP],
}
impl<'a> MutModFiltParamsFxP<'a> {
pub fn len(&self) -> usize {
min_size(&[
self.env_mod.len(),
self.vel_mod.len(),
self.kbd.len(),
self.cutoff.len(),
self.resonance.len(),
self.low_mix.len(),
self.band_mix.len(),
self.high_mix.len(),
])
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
}
impl<'a> From<MutModFiltParamsFxP<'a>> for ModFiltParamsFxP<'a> {
fn from(value: MutModFiltParamsFxP<'a>) -> Self {
Self {
env_mod: value.env_mod,
vel_mod: value.vel_mod,
kbd: value.kbd,
cutoff: value.cutoff,
resonance: value.resonance,
low_mix: value.low_mix,
band_mix: value.band_mix,
high_mix: value.high_mix,
}
}
}
#[derive(Clone)]
pub struct ModFiltFxP {
filter: FiltFxP,
modbuf: BufferT<NoteFxP>,
outbuf: BufferT<SampleFxP>,
}
impl ModFiltFxP {
pub fn new() -> Self {
Self {
filter: Default::default(),
modbuf: [NoteFxP::ZERO; STATIC_BUFFER_SIZE],
outbuf: [SampleFxP::ZERO; STATIC_BUFFER_SIZE],
}
}
pub fn process(
&mut self,
ctx: &ContextFxP,
input: &[SampleFxP],
env: &[ScalarFxP],
note: &[NoteFxP],
vel: &[ScalarFxP],
params: ModFiltParamsFxP,
) -> &[SampleFxP] {
let numsamples = min_size(&[input.len(), env.len(), note.len(), params.len()]);
for i in 0..numsamples {
let envmod = apply_scalar_u(NoteFxP::from_bits(params.env_mod[i].to_bits()), env[i]);
let velmod = apply_scalar_u(NoteFxP::from_bits(params.vel_mod[i].to_bits()), vel[i]);
let kbdmod = apply_scalar_u(note[i], params.kbd[i]);
self.modbuf[i] = params.cutoff[i]
.saturating_add(envmod)
.saturating_add(velmod)
.saturating_add(kbdmod);
}
let filt_out = self.filter.process(
ctx,
input,
FiltParamsFxP {
cutoff: &self.modbuf[0..numsamples],
resonance: params.resonance,
},
);
for i in 0..numsamples {
let low = params.low_mix[i].wide_mul_signed(filt_out.low[i]);
let band = params.band_mix[i].wide_mul_signed(filt_out.band[i]);
let high = params.high_mix[i].wide_mul_signed(filt_out.high[i]);
self.outbuf[i] = SampleFxP::from_num(low.saturating_add(band).saturating_add(high));
}
&self.outbuf[0..numsamples]
}
}
impl Default for ModFiltFxP {
fn default() -> Self {
Self::new()
}
}