1use crate::control::{Automaton, Range, Time};
7
8#[derive(Debug, Clone, Copy, PartialEq)]
10pub enum EnvelopeType {
11 ADSR,
13 AR,
15 ASR,
17 AHDSR,
19}
20
21#[derive(Debug, Clone, Copy, PartialEq)]
23pub enum EnvelopeStage {
24 Attack,
25 Hold,
26 Decay,
27 Sustain,
28 Release,
29 Off,
30}
31
32impl EnvelopeStage {
33 pub fn name(&self) -> &'static str {
34 match self {
35 EnvelopeStage::Attack => "Attack",
36 EnvelopeStage::Hold => "Hold",
37 EnvelopeStage::Decay => "Decay",
38 EnvelopeStage::Sustain => "Sustain",
39 EnvelopeStage::Release => "Release",
40 EnvelopeStage::Off => "Off",
41 }
42 }
43}
44
45#[derive(Debug, Clone)]
47pub struct EnvelopeState {
48 pub stage: EnvelopeStage,
50 pub level: f64,
52 pub stage_start_time: Time,
54 pub stage_start_level: f64,
56 pub stage_target_level: f64,
58 pub stage_duration: f64,
60 pub gate: bool,
62}
63
64#[derive(Debug, Clone)]
66pub struct EnvelopeAutomaton {
67 name: String,
69 env_type: EnvelopeType,
71 attack: f64,
73 hold: f64,
75 decay: f64,
77 sustain: f64,
79 release: f64,
81 range: Range,
83 curve: f64,
85}
86
87impl EnvelopeAutomaton {
88 pub fn adsr(name: &str, attack: f64, decay: f64, sustain: f64, release: f64) -> Self {
90 Self {
91 name: name.to_string(),
92 env_type: EnvelopeType::ADSR,
93 attack: attack.max(0.001),
94 hold: 0.0,
95 decay: decay.max(0.001),
96 sustain: sustain.clamp(0.0, 1.0),
97 release: release.max(0.001),
98 range: Range::unipolar(),
99 curve: 1.0,
100 }
101 }
102
103 pub fn ar(name: &str, attack: f64, release: f64) -> Self {
105 Self {
106 name: name.to_string(),
107 env_type: EnvelopeType::AR,
108 attack: attack.max(0.001),
109 hold: 0.0,
110 decay: 0.0,
111 sustain: 0.0,
112 release: release.max(0.001),
113 range: Range::unipolar(),
114 curve: 1.0,
115 }
116 }
117
118 pub fn asr(name: &str, attack: f64, sustain: f64, release: f64) -> Self {
120 Self {
121 name: name.to_string(),
122 env_type: EnvelopeType::ASR,
123 attack: attack.max(0.001),
124 hold: 0.0,
125 decay: 0.0,
126 sustain: sustain.clamp(0.0, 1.0),
127 release: release.max(0.001),
128 range: Range::unipolar(),
129 curve: 1.0,
130 }
131 }
132
133 pub fn ahdsr(
135 name: &str,
136 attack: f64,
137 hold: f64,
138 decay: f64,
139 sustain: f64,
140 release: f64,
141 ) -> Self {
142 Self {
143 name: name.to_string(),
144 env_type: EnvelopeType::AHDSR,
145 attack: attack.max(0.001),
146 hold: hold.max(0.001),
147 decay: decay.max(0.001),
148 sustain: sustain.clamp(0.0, 1.0),
149 release: release.max(0.001),
150 range: Range::unipolar(),
151 curve: 1.0,
152 }
153 }
154
155 pub fn with_curve(mut self, curve: f64) -> Self {
157 self.curve = curve.max(0.1);
158 self
159 }
160
161 pub fn with_range(mut self, range: Range) -> Self {
163 self.range = range;
164 self
165 }
166
167 fn apply_curve(&self, t: f64) -> f64 {
169 if self.curve == 1.0 {
170 t
171 } else {
172 t.powf(self.curve)
173 }
174 }
175
176 fn update_stage(&self, state: &mut EnvelopeState, time: Time) {
178 let elapsed = time - state.stage_start_time;
179
180 match state.stage {
181 EnvelopeStage::Attack => {
182 if elapsed >= self.attack {
183 match self.env_type {
185 EnvelopeType::ADSR => {
186 state.stage = EnvelopeStage::Decay;
187 state.stage_start_time = time;
188 state.stage_start_level = 1.0;
189 state.stage_target_level = self.sustain;
190 state.stage_duration = self.decay;
191 }
192 EnvelopeType::AR => {
193 state.stage = EnvelopeStage::Release;
194 state.stage_start_time = time;
195 state.stage_start_level = 1.0;
196 state.stage_target_level = 0.0;
197 state.stage_duration = self.release;
198 }
199 EnvelopeType::ASR => {
200 state.stage = EnvelopeStage::Sustain;
201 state.stage_start_time = time;
202 state.stage_start_level = 1.0;
203 state.stage_target_level = self.sustain;
204 state.stage_duration = 0.0;
205 }
206 EnvelopeType::AHDSR => {
207 state.stage = EnvelopeStage::Hold;
208 state.stage_start_time = time;
209 state.stage_start_level = 1.0;
210 state.stage_target_level = 1.0;
211 state.stage_duration = self.hold;
212 }
213 }
214 } else {
215 let t = elapsed / self.attack;
216 state.level = state.stage_start_level
217 + (state.stage_target_level - state.stage_start_level)
218 * self.apply_curve(t);
219 }
220 }
221
222 EnvelopeStage::Hold => {
223 if elapsed >= self.hold {
224 state.stage = EnvelopeStage::Decay;
225 state.stage_start_time = time;
226 state.stage_start_level = 1.0;
227 state.stage_target_level = self.sustain;
228 state.stage_duration = self.decay;
229 } else {
230 state.level = 1.0;
231 }
232 }
233
234 EnvelopeStage::Decay => {
235 if elapsed >= self.decay {
236 state.stage = EnvelopeStage::Sustain;
237 state.level = self.sustain;
238 } else {
239 let t = elapsed / self.decay;
240 state.level = state.stage_start_level
241 + (state.stage_target_level - state.stage_start_level)
242 * self.apply_curve(t);
243 }
244 }
245
246 EnvelopeStage::Sustain => {
247 state.level = self.sustain;
248 }
249
250 EnvelopeStage::Release => {
251 if elapsed >= self.release {
252 state.stage = EnvelopeStage::Off;
253 state.level = 0.0;
254 } else {
255 let t = elapsed / self.release;
256 state.level = state.stage_start_level
257 + (state.stage_target_level - state.stage_start_level)
258 * self.apply_curve(t);
259 }
260 }
261
262 EnvelopeStage::Off => {
263 state.level = 0.0;
264 }
265 }
266 }
267}
268
269#[derive(Debug, Clone, Default)]
271pub enum EnvelopeAction {
272 #[default]
273 None,
275 GateOn,
277 GateOff,
279}
280
281impl Automaton for EnvelopeAutomaton {
282 type State = EnvelopeState;
283 type Action = EnvelopeAction;
284
285 fn step(
286 &self,
287 time: Time,
288 action: &Self::Action,
289 state: &Self::State,
290 ) -> (Self::State, Option<f64>) {
291 let mut new_state = state.clone();
292
293 match action {
295 EnvelopeAction::GateOn => {
296 new_state.gate = true;
297 new_state.stage = EnvelopeStage::Attack;
298 new_state.stage_start_time = time;
299 new_state.stage_start_level = new_state.level;
300 new_state.stage_target_level = 1.0;
301 }
302 EnvelopeAction::GateOff => {
303 new_state.gate = false;
304 new_state.stage = EnvelopeStage::Release;
305 new_state.stage_start_time = time;
306 new_state.stage_start_level = new_state.level;
307 new_state.stage_target_level = 0.0;
308 }
309 EnvelopeAction::None => {}
310 }
311
312 self.update_stage(&mut new_state, time);
313
314 let value = self.range.denormalize(new_state.level);
315
316 (new_state, Some(value))
317 }
318
319 fn initial_state(&self) -> Self::State {
320 EnvelopeState {
321 stage: EnvelopeStage::Off,
322 level: 0.0,
323 stage_start_time: 0.0,
324 stage_start_level: 0.0,
325 stage_target_level: 0.0,
326 stage_duration: 0.0,
327 gate: false,
328 }
329 }
330
331 fn name(&self) -> &str {
332 &self.name
333 }
334
335 fn extract_value(&self, state: &Self::State) -> f64 {
336 self.range.denormalize(state.level)
337 }
338}
339
340#[cfg(test)]
341mod tests {
342 use super::*;
343
344 #[test]
345 fn test_adsr_envelope() {
346 let env = EnvelopeAutomaton::adsr("ADSR", 0.1, 0.2, 0.7, 0.3);
347 let mut state = env.initial_state();
348
349 assert_eq!(state.stage, EnvelopeStage::Off);
350
351 let (_s, _value) = env.step(0.0, &EnvelopeAction::GateOn, &state);
353 state = _s;
354 assert_eq!(state.stage, EnvelopeStage::Attack);
355
356 let (s, value) = env.step(0.05, &EnvelopeAction::None, &state);
358 state = s;
359 assert!(value.unwrap() > 0.0);
360 assert!(value.unwrap() < 1.0);
361
362 let (s, _) = env.step(0.5, &EnvelopeAction::GateOff, &state);
364 assert_eq!(s.stage, EnvelopeStage::Release);
365 }
366}