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