use super::*;
use crate::fixedmath::{apply_scalar_i, widen_i};
#[derive(Clone)]
pub struct RingMod<Smp> {
outbuf: BufferT<Smp>,
}
pub struct RingModParams<'a, Smp> {
pub mix_out: &'a [Smp],
pub mix_a: &'a [Smp],
pub mix_b: &'a [Smp],
}
impl<'a, Smp> RingModParams<'a, Smp> {
pub fn len(&self) -> usize {
min_size(&[self.mix_a.len(), self.mix_b.len(), self.mix_out.len()])
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
}
pub struct MutRingModParams<'a, Smp> {
pub mix_out: &'a mut [Smp],
pub mix_a: &'a mut [Smp],
pub mix_b: &'a mut [Smp],
}
impl<'a, Smp> MutRingModParams<'a, Smp> {
pub fn len(&self) -> usize {
min_size(&[self.mix_a.len(), self.mix_b.len(), self.mix_out.len()])
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
}
impl<'a, Smp> From<MutRingModParams<'a, Smp>> for RingModParams<'a, Smp> {
fn from(value: MutRingModParams<'a, Smp>) -> Self {
RingModParams {
mix_out: value.mix_out,
mix_a: value.mix_a,
mix_b: value.mix_b,
}
}
}
impl<Smp: Float> RingMod<Smp> {
pub fn new() -> Self {
Self {
outbuf: [Smp::ZERO; STATIC_BUFFER_SIZE],
}
}
pub fn process(
&mut self,
_ctx: &Context<Smp>,
a: &[Smp],
b: &[Smp],
params: RingModParams<Smp>,
) -> &[Smp] {
let numsamples = min_size(&[params.len(), a.len(), b.len(), STATIC_BUFFER_SIZE]);
for i in 0..numsamples {
let out = a[i] * b[i];
self.outbuf[i] =
out * params.mix_out[i] + a[i] * params.mix_a[i] + b[i] * params.mix_b[i];
}
&self.outbuf[0..numsamples]
}
}
impl<Smp: Float> Default for RingMod<Smp> {
fn default() -> Self {
Self::new()
}
}
pub struct RingModParamsFxP<'a> {
pub mix_out: &'a [ScalarFxP],
pub mix_a: &'a [ScalarFxP],
pub mix_b: &'a [ScalarFxP],
}
impl<'a> RingModParamsFxP<'a> {
pub fn len(&self) -> usize {
min_size(&[self.mix_a.len(), self.mix_b.len(), self.mix_out.len()])
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
}
pub struct MutRingModParamsFxP<'a> {
pub mix_out: &'a mut [ScalarFxP],
pub mix_a: &'a mut [ScalarFxP],
pub mix_b: &'a mut [ScalarFxP],
}
impl<'a> MutRingModParamsFxP<'a> {
pub fn len(&self) -> usize {
min_size(&[self.mix_a.len(), self.mix_b.len(), self.mix_out.len()])
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
}
impl<'a> From<MutRingModParamsFxP<'a>> for RingModParamsFxP<'a> {
fn from(value: MutRingModParamsFxP<'a>) -> Self {
Self {
mix_a: value.mix_a,
mix_b: value.mix_b,
mix_out: value.mix_out,
}
}
}
#[derive(Clone)]
pub struct RingModFxP {
outbuf: BufferT<SampleFxP>,
}
impl RingModFxP {
pub fn new() -> Self {
Self {
outbuf: [SampleFxP::ZERO; STATIC_BUFFER_SIZE],
}
}
pub fn process(
&mut self,
_ctx: &ContextFxP,
a: &[SampleFxP],
b: &[SampleFxP],
params: RingModParamsFxP,
) -> &[SampleFxP] {
let numsamples = min_size(&[params.len(), a.len(), b.len(), STATIC_BUFFER_SIZE]);
for i in 0..numsamples {
let out = SampleFxP::saturating_from_num(a[i].wide_mul(b[i]));
let mixed_32bits = widen_i(apply_scalar_i(out, params.mix_out[i]))
+ widen_i(apply_scalar_i(a[i], params.mix_a[i]))
+ widen_i(apply_scalar_i(b[i], params.mix_b[i]));
self.outbuf[i] = SampleFxP::saturating_from_num(mixed_32bits);
}
&self.outbuf[0..numsamples]
}
}
impl Default for RingModFxP {
fn default() -> Self {
Self::new()
}
}