//! ADSR envelope generator. use crate::{AudioProcessor, config::SampleRate}; use crate::descriptor::{ComponentDescriptor, Direction, JackDescriptor, ParamDescriptor, SignalKind}; #[derive(Clone, Copy, Debug, PartialEq)] enum Stage { Idle, Attack, Decay, Sustain, Release } pub struct Adsr { pub attack_s: f32, pub decay_s: f32, pub sustain: f32, // 0.0–1.0 pub release_s: f32, sample_rate: SampleRate, stage: Stage, level: f32, } impl Adsr { pub fn new(sample_rate: SampleRate) -> Self { Self { attack_s: 0.01, decay_s: 0.1, sustain: 0.7, release_s: 0.3, sample_rate, stage: Stage::Idle, level: 0.0, } } pub const DESCRIPTOR: ComponentDescriptor = ComponentDescriptor { kind: "adsr", label: "ADSR", jacks: &[ JackDescriptor { id: "gate_in", label: "Gate", direction: Direction::Input, signal: SignalKind::Gate }, JackDescriptor { id: "env_out", label: "Env", direction: Direction::Output, signal: SignalKind::Cv }, ], params: &[ ParamDescriptor { id: "attack_s", label: "Attack", min: 0.001, max: 4.0, default: 0.01, unit: "s" }, ParamDescriptor { id: "decay_s", label: "Decay", min: 0.001, max: 4.0, default: 0.1, unit: "s" }, ParamDescriptor { id: "sustain", label: "Sustain", min: 0.0, max: 1.0, default: 0.7, unit: "" }, ParamDescriptor { id: "release_s", label: "Release", min: 0.001, max: 8.0, default: 0.3, unit: "s" }, ], }; pub fn gate_on(&mut self) { self.stage = Stage::Attack; } pub fn gate_off(&mut self) { self.stage = Stage::Release; } pub fn is_idle(&self) -> bool { self.stage == Stage::Idle } #[inline] fn next_sample(&mut self) -> f32 { let dt = self.sample_rate.period(); match self.stage { Stage::Idle => {}, Stage::Attack => { self.level += dt / self.attack_s.max(dt); if self.level >= 1.0 { self.level = 1.0; self.stage = Stage::Decay; } } Stage::Decay => { self.level -= dt / self.decay_s.max(dt) * (1.0 - self.sustain); if self.level <= self.sustain { self.level = self.sustain; self.stage = Stage::Sustain; } } Stage::Sustain => { self.level = self.sustain; } Stage::Release => { self.level -= dt / self.release_s.max(dt) * self.level; if self.level <= 0.0001 { self.level = 0.0; self.stage = Stage::Idle; } } } self.level } } impl AudioProcessor for Adsr { fn process(&mut self, out: &mut [f32; B]) { for s in out.iter_mut() { *s = self.next_sample(); } } fn reset(&mut self) { self.stage = Stage::Idle; self.level = 0.0; } }