use crate::envelope::{AdsrStage, Envelope};
const MIN_TIME: f32 = 0.001;
const MIN_LEVEL: f32 = 0.0;
const MAX_LEVEL: f32 = 1.0;
pub struct LinearAdsr {
sample_rate: f32,
attack: f32,
decay: f32,
sustain: f32,
release: f32,
attack_rate: f32,
decay_rate: f32,
release_rate: f32,
stage: AdsrStage,
level: f32,
retrigger: bool,
}
impl LinearAdsr {
pub fn new(sample_rate: f32, attack: f32, decay: f32, sustain: f32, release: f32) -> Self {
let attack = attack.max(MIN_TIME);
let decay = decay.max(MIN_TIME);
let release = release.max(MIN_TIME);
Self {
sample_rate,
attack,
decay,
sustain: sustain.clamp(MIN_LEVEL, MAX_LEVEL),
release,
attack_rate: 1.0 / (attack * sample_rate),
decay_rate: 1.0 / (decay * sample_rate),
release_rate: 1.0 / (release * sample_rate),
stage: AdsrStage::Idle,
level: MIN_LEVEL,
retrigger: true,
}
}
pub fn pad(sample_rate: f32) -> Self {
Self::new(sample_rate, 0.01, 0.1, 0.7, 0.3)
}
pub fn pluck(sample_rate: f32) -> Self {
Self::new(sample_rate, 0.001, 0.3, 0.0, 0.1)
}
pub fn percussion(sample_rate: f32) -> Self {
Self::new(sample_rate, 0.001, 0.1, 0.0, 0.05)
}
pub fn set_attack(&mut self, seconds: f32) {
self.attack = seconds.max(MIN_TIME);
self.attack_rate = 1.0 / (self.attack * self.sample_rate);
}
pub fn set_decay(&mut self, seconds: f32) {
self.decay = seconds.max(MIN_TIME);
self.decay_rate = 1.0 / (self.decay * self.sample_rate);
}
pub fn set_sustain(&mut self, level: f32) {
self.sustain = level.clamp(MIN_LEVEL, MAX_LEVEL);
}
pub fn set_release(&mut self, seconds: f32) {
self.release = seconds.max(MIN_TIME);
self.release_rate = 1.0 / (self.release * self.sample_rate);
}
pub fn attack(&self) -> f32 {
self.attack
}
pub fn decay(&self) -> f32 {
self.decay
}
pub fn sustain(&self) -> f32 {
self.sustain
}
pub fn release(&self) -> f32 {
self.release
}
pub fn retrigger(&self) -> bool {
self.retrigger
}
pub fn set_retrigger(&mut self, retrigger: bool) {
self.retrigger = retrigger;
}
pub fn stage(&self) -> AdsrStage {
self.stage
}
pub fn level(&self) -> f32 {
self.level
}
}
impl Envelope for LinearAdsr {
fn gate_on(&mut self) {
if self.retrigger {
self.level = MIN_LEVEL;
}
self.stage = if self.level >= MAX_LEVEL {
AdsrStage::Decay
} else {
AdsrStage::Attack
};
}
fn gate_off(&mut self) {
if self.stage != AdsrStage::Idle {
self.stage = AdsrStage::Release;
}
}
fn next_sample(&mut self) -> f32 {
match self.stage {
AdsrStage::Idle => {}
AdsrStage::Attack => {
self.level += self.attack_rate;
if self.level >= MAX_LEVEL {
self.level = MAX_LEVEL;
self.stage = AdsrStage::Decay;
}
}
AdsrStage::Decay => {
self.level -= self.decay_rate;
if self.level <= self.sustain {
self.level = self.sustain;
self.stage = AdsrStage::Sustain;
}
}
AdsrStage::Sustain => {}
AdsrStage::Release => {
self.level -= self.release_rate;
if self.level <= MIN_LEVEL {
self.level = MIN_LEVEL;
self.stage = AdsrStage::Idle;
}
}
}
self.level
}
fn is_active(&self) -> bool {
self.stage != AdsrStage::Idle
}
fn reset(&mut self) {
self.level = MIN_LEVEL;
self.stage = AdsrStage::Idle;
}
}