use super::*;
use super::EnvParamFxP;
#[derive(Eq, PartialEq, Clone, Copy)]
enum EnvState {
Release,
Attack,
Decay,
}
pub struct EnvParams<'a, Smp> {
pub attack: &'a [Smp],
pub decay: &'a [Smp],
pub sustain: &'a [Smp],
pub release: &'a [Smp],
}
impl<'a, Smp> EnvParams<'a, Smp> {
pub fn len(&self) -> usize {
min_size(&[
self.attack.len(),
self.decay.len(),
self.sustain.len(),
self.release.len(),
])
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
}
pub struct MutEnvParams<'a, Smp> {
pub attack: &'a mut [Smp],
pub decay: &'a mut [Smp],
pub sustain: &'a mut [Smp],
pub release: &'a mut [Smp],
}
impl<'a, Smp> MutEnvParams<'a, Smp> {
pub fn len(&self) -> usize {
min_size(&[
self.attack.len(),
self.decay.len(),
self.sustain.len(),
self.release.len(),
])
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
}
impl<'a, Smp: Float> From<MutEnvParams<'a, Smp>> for EnvParams<'a, Smp> {
fn from(value: MutEnvParams<'a, Smp>) -> Self {
Self {
attack: value.attack,
decay: value.decay,
sustain: value.sustain,
release: value.release,
}
}
}
#[derive(Clone)]
pub struct Env<Smp> {
state: EnvState,
outbuf: BufferT<Smp>,
setpoint: Smp,
last: Smp,
}
impl<Smp: Float> Env<Smp> {
const GATE_THRESHOLD: Smp = Smp::ONE_HALF;
const ATTACK_THRESHOLD: Smp = Smp::POINT_NINE_EIGHT;
const SIGNAL_MAX: Smp = Smp::ONE;
const SIGNAL_MIN: Smp = Smp::ZERO;
pub fn new() -> Self {
Self {
state: EnvState::Release,
outbuf: [Smp::ZERO; STATIC_BUFFER_SIZE],
setpoint: Self::SIGNAL_MIN,
last: Self::SIGNAL_MIN,
}
}
pub fn process(&mut self, ctx: &Context<Smp>, gate: &[Smp], params: EnvParams<Smp>) -> &[Smp] {
let attack = params.attack;
let decay = params.decay;
let sustain = params.sustain;
let release = params.release;
let numsamples = min_size(&[
attack.len(),
decay.len(),
sustain.len(),
release.len(),
gate.len(),
STATIC_BUFFER_SIZE,
]);
let setpoint_old = self.setpoint;
for i in 0..numsamples {
if gate[i] <= Self::GATE_THRESHOLD {
self.state = EnvState::Release;
self.setpoint = Self::SIGNAL_MIN;
} else if self.state == EnvState::Release {
self.state = EnvState::Attack;
self.setpoint = Self::SIGNAL_MAX;
} else if self.state == EnvState::Attack && self.last > Self::ATTACK_THRESHOLD {
self.state = EnvState::Decay;
}
let rise = if self.state == EnvState::Attack {
attack[i]
} else if self.state == EnvState::Decay {
self.setpoint = sustain[i];
decay[i]
} else {
release[i]
};
let k = rise * (ctx.sample_rate / Smp::TWO) + Smp::ONE;
let pro = setpoint_old + self.setpoint - self.last - self.last;
let delta = pro / k;
self.last = self.last + delta;
self.outbuf[i] = self.last;
}
&self.outbuf[0..numsamples]
}
}
impl<Smp: Float> Default for Env<Smp> {
fn default() -> Self {
Self::new()
}
}
pub struct EnvParamsFxP<'a> {
pub attack: &'a [EnvParamFxP],
pub decay: &'a [EnvParamFxP],
pub sustain: &'a [ScalarFxP],
pub release: &'a [EnvParamFxP],
}
impl<'a> EnvParamsFxP<'a> {
pub fn len(&self) -> usize {
min_size(&[
self.attack.len(),
self.decay.len(),
self.sustain.len(),
self.release.len(),
])
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
}
pub struct MutEnvParamsFxP<'a> {
pub attack: &'a mut [EnvParamFxP],
pub decay: &'a mut [EnvParamFxP],
pub sustain: &'a mut [ScalarFxP],
pub release: &'a mut [EnvParamFxP],
}
impl<'a> MutEnvParamsFxP<'a> {
pub fn len(&self) -> usize {
min_size(&[
self.attack.len(),
self.decay.len(),
self.sustain.len(),
self.release.len(),
])
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
}
impl<'a> From<MutEnvParamsFxP<'a>> for EnvParamsFxP<'a> {
fn from(value: MutEnvParamsFxP<'a>) -> Self {
Self {
attack: value.attack,
decay: value.decay,
sustain: value.sustain,
release: value.release,
}
}
}
#[derive(Clone)]
pub struct EnvFxP {
state: EnvState,
outbuf: BufferT<ScalarFxP>,
setpoint: fixedmath::I3F29,
last: fixedmath::I3F29,
}
impl EnvFxP {
const GATE_THRESHOLD: SampleFxP = SampleFxP::lit("0.5");
const ATTACK_THRESHOLD: ScalarFxP = ScalarFxP::lit("0.98");
const SIGNAL_MAX: ScalarFxP = ScalarFxP::lit("0x0.FFFC");
const SIGNAL_MIN: fixedmath::I3F29 = fixedmath::I3F29::lit("0x0.0004");
pub fn new() -> Self {
Self {
state: EnvState::Release,
outbuf: [ScalarFxP::ZERO; STATIC_BUFFER_SIZE],
setpoint: Self::SIGNAL_MIN,
last: Self::SIGNAL_MIN,
}
}
pub fn process(
&mut self,
ctx: &ContextFxP,
gate: &[SampleFxP],
params: EnvParamsFxP,
) -> &[ScalarFxP] {
let attack = params.attack;
let decay = params.decay;
let sustain = params.sustain;
let release = params.release;
let numsamples = min_size(&[
attack.len(),
decay.len(),
sustain.len(),
release.len(),
gate.len(),
STATIC_BUFFER_SIZE,
]);
let setpoint_old = self.setpoint;
for i in 0..numsamples {
if gate[i] <= Self::GATE_THRESHOLD {
self.state = EnvState::Release;
self.setpoint = Self::SIGNAL_MIN;
} else if self.state == EnvState::Release {
self.state = EnvState::Attack;
self.setpoint = fixedmath::I3F29::from_num(Self::SIGNAL_MAX);
} else if self.state == EnvState::Attack && self.last > Self::ATTACK_THRESHOLD {
self.state = EnvState::Decay;
}
let rise = if self.state == EnvState::Attack {
attack[i]
} else if self.state == EnvState::Decay {
self.setpoint = core::cmp::max(
fixedmath::I3F29::from_num(core::cmp::min(sustain[i], Self::SIGNAL_MAX)),
Self::SIGNAL_MIN,
);
decay[i]
} else {
release[i]
};
let sr = fixedmath::U16F0::from_bits(ctx.sample_rate.value() >> 1);
let k = rise.wide_mul(sr);
let (gain, shift) = fixedmath::one_over_one_plus(k);
let pro = fixedmath::I2F14::saturating_from_num(
setpoint_old + self.setpoint - self.last.unwrapped_shl(1),
);
let delta = pro.wide_mul_unsigned(gain).unwrapped_shr(shift);
self.last += delta;
self.outbuf[i] = ScalarFxP::saturating_from_num(self.last);
}
&self.outbuf[0..numsamples]
}
}
impl Default for EnvFxP {
fn default() -> Self {
Self::new()
}
}