1use aether_core::{node::DspNode, param::ParamBlock, state::StateBlob, BUFFER_SIZE, MAX_INPUTS};
11
12#[derive(Clone, Copy, PartialEq)]
13enum Stage {
14 Idle,
15 Attack,
16 Decay,
17 Sustain,
18 Release,
19}
20
21#[derive(Clone, Copy)]
22struct EnvState {
23 level: f32,
24 stage: u8,
25}
26
27pub struct AdsrEnvelope {
28 level: f32,
29 stage: Stage,
30 prev_gate: f32,
31}
32
33impl AdsrEnvelope {
34 pub fn new() -> Self {
35 Self {
36 level: 0.0,
37 stage: Stage::Idle,
38 prev_gate: 0.0,
39 }
40 }
41
42 #[inline(always)]
43 fn tick_sample(
44 &mut self,
45 gate: f32,
46 attack: f32,
47 decay: f32,
48 sustain: f32,
49 release: f32,
50 sr: f32,
51 ) -> f32 {
52 if gate > 0.5 && self.prev_gate <= 0.5 {
54 self.stage = Stage::Attack;
55 } else if gate <= 0.5 && self.prev_gate > 0.5 {
56 self.stage = Stage::Release;
57 }
58 self.prev_gate = gate;
59
60 let attack_rate = if attack > 0.0 {
61 1.0 / (attack * sr)
62 } else {
63 1.0
64 };
65 let decay_rate = if decay > 0.0 { 1.0 / (decay * sr) } else { 1.0 };
66 let release_rate = if release > 0.0 {
67 1.0 / (release * sr)
68 } else {
69 1.0
70 };
71
72 match self.stage {
73 Stage::Idle => {}
74 Stage::Attack => {
75 self.level += attack_rate;
76 if self.level >= 1.0 {
77 self.level = 1.0;
78 self.stage = Stage::Decay;
79 }
80 }
81 Stage::Decay => {
82 self.level -= decay_rate;
83 if self.level <= sustain {
84 self.level = sustain;
85 self.stage = Stage::Sustain;
86 }
87 }
88 Stage::Sustain => {
89 self.level = sustain;
90 }
91 Stage::Release => {
92 self.level -= release_rate;
93 if self.level <= 0.0 {
94 self.level = 0.0;
95 self.stage = Stage::Idle;
96 }
97 }
98 }
99 self.level
100 }
101}
102
103impl Default for AdsrEnvelope {
104 fn default() -> Self {
105 Self::new()
106 }
107}
108
109impl DspNode for AdsrEnvelope {
110 fn process(
111 &mut self,
112 inputs: &[Option<&[f32; BUFFER_SIZE]>; MAX_INPUTS],
113 output: &mut [f32; BUFFER_SIZE],
114 params: &mut ParamBlock,
115 sample_rate: f32,
116 ) {
117 let _silence = [0.0f32; BUFFER_SIZE];
119 let audio_in = inputs[0];
120
121 for (i, out) in output.iter_mut().enumerate() {
122 let attack = params.get(0).current.max(0.0);
123 let decay = params.get(1).current.max(0.0);
124 let sustain = params.get(2).current.clamp(0.0, 1.0);
125 let release = params.get(3).current.max(0.0);
126 let gate = params.get(4).current;
127
128 let env = self.tick_sample(gate, attack, decay, sustain, release, sample_rate);
129 *out = match audio_in {
130 Some(buf) => buf[i] * env,
131 None => env,
132 };
133 params.tick_all();
134 }
135 }
136
137 fn capture_state(&self) -> StateBlob {
138 StateBlob::from_value(&EnvState {
139 level: self.level,
140 stage: self.stage as u8,
141 })
142 }
143
144 fn restore_state(&mut self, state: StateBlob) {
145 let s: EnvState = state.to_value();
146 self.level = s.level;
147 self.stage = match s.stage {
148 0 => Stage::Idle,
149 1 => Stage::Attack,
150 2 => Stage::Decay,
151 3 => Stage::Sustain,
152 _ => Stage::Release,
153 };
154 }
155
156 fn type_name(&self) -> &'static str {
157 "AdsrEnvelope"
158 }
159}