1use crate::engine::{Automaton, Range, Time};
6use rill_core::traits::ParamValue;
7
8#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
10#[derive(Debug, Clone, Copy, PartialEq)]
11pub enum EnvelopeType {
12 ADSR,
14 AR,
16 ASR,
18 AHDSR,
20}
21
22#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
24#[derive(Debug, Clone, Copy, PartialEq)]
25pub enum EnvelopeStage {
26 Attack,
28 Hold,
30 Decay,
32 Sustain,
34 Release,
36 Off,
38}
39
40impl EnvelopeStage {
41 pub fn name(&self) -> &'static str {
43 match self {
44 EnvelopeStage::Attack => "Attack",
45 EnvelopeStage::Hold => "Hold",
46 EnvelopeStage::Decay => "Decay",
47 EnvelopeStage::Sustain => "Sustain",
48 EnvelopeStage::Release => "Release",
49 EnvelopeStage::Off => "Off",
50 }
51 }
52}
53
54#[derive(Debug, Clone)]
60pub struct EnvelopeAutomaton {
61 name: String,
62 env_type: EnvelopeType,
63 attack: f64,
64 hold: f64,
65 decay: f64,
66 sustain: f64,
67 release: f64,
68 range: Range,
69 curve: f64,
70}
71
72type EnvelopeInternal = (EnvelopeStage, f64, f64);
74
75impl EnvelopeAutomaton {
76 pub fn adsr(name: &str, attack: f64, decay: f64, sustain: f64, release: f64) -> Self {
78 Self {
79 name: name.to_string(),
80 env_type: EnvelopeType::ADSR,
81 attack: attack.max(0.001),
82 hold: 0.0,
83 decay: decay.max(0.001),
84 sustain: sustain.clamp(0.0, 1.0),
85 release: release.max(0.001),
86 range: Range::unipolar(),
87 curve: 1.0,
88 }
89 }
90
91 pub fn ar(name: &str, attack: f64, release: f64) -> Self {
93 Self {
94 name: name.to_string(),
95 env_type: EnvelopeType::AR,
96 attack: attack.max(0.001),
97 hold: 0.0,
98 decay: 0.0,
99 sustain: 0.0,
100 release: release.max(0.001),
101 range: Range::unipolar(),
102 curve: 1.0,
103 }
104 }
105
106 pub fn asr(name: &str, attack: f64, sustain: f64, release: f64) -> Self {
108 Self {
109 name: name.to_string(),
110 env_type: EnvelopeType::ASR,
111 attack: attack.max(0.001),
112 hold: 0.0,
113 decay: 0.0,
114 sustain: sustain.clamp(0.0, 1.0),
115 release: release.max(0.001),
116 range: Range::unipolar(),
117 curve: 1.0,
118 }
119 }
120
121 pub fn ahdsr(
123 name: &str,
124 attack: f64,
125 hold: f64,
126 decay: f64,
127 sustain: f64,
128 release: f64,
129 ) -> Self {
130 Self {
131 name: name.to_string(),
132 env_type: EnvelopeType::AHDSR,
133 attack: attack.max(0.001),
134 hold: hold.max(0.001),
135 decay: decay.max(0.001),
136 sustain: sustain.clamp(0.0, 1.0),
137 release: release.max(0.001),
138 range: Range::unipolar(),
139 curve: 1.0,
140 }
141 }
142
143 pub fn with_curve(mut self, curve: f64) -> Self {
145 self.curve = curve.max(0.1);
146 self
147 }
148
149 pub fn with_range(mut self, range: Range) -> Self {
151 self.range = range;
152 self
153 }
154
155 fn apply_curve(&self, t: f64) -> f64 {
157 if self.curve == 1.0 {
158 t
159 } else {
160 t.powf(self.curve)
161 }
162 }
163
164 fn stage_duration(&self, stage: EnvelopeStage) -> f64 {
166 match stage {
167 EnvelopeStage::Attack => self.attack,
168 EnvelopeStage::Hold => self.hold,
169 EnvelopeStage::Decay => self.decay,
170 EnvelopeStage::Release => self.release,
171 EnvelopeStage::Sustain | EnvelopeStage::Off => f64::INFINITY,
172 }
173 }
174
175 fn stage_target(&self, stage: EnvelopeStage) -> f64 {
177 match stage {
178 EnvelopeStage::Attack => 1.0,
179 EnvelopeStage::Hold => 1.0,
180 EnvelopeStage::Decay => self.sustain,
181 EnvelopeStage::Sustain => self.sustain,
182 EnvelopeStage::Release => 0.0,
183 EnvelopeStage::Off => 0.0,
184 }
185 }
186
187 fn next_stage(&self, current: EnvelopeStage) -> EnvelopeStage {
189 match (current, self.env_type) {
190 (EnvelopeStage::Attack, EnvelopeType::ADSR) => EnvelopeStage::Decay,
191 (EnvelopeStage::Attack, EnvelopeType::AR) => EnvelopeStage::Release,
192 (EnvelopeStage::Attack, EnvelopeType::ASR) => EnvelopeStage::Sustain,
193 (EnvelopeStage::Attack, EnvelopeType::AHDSR) => EnvelopeStage::Hold,
194 (EnvelopeStage::Hold, _) => EnvelopeStage::Decay,
195 (EnvelopeStage::Decay, _) => EnvelopeStage::Sustain,
196 (EnvelopeStage::Release, _) => EnvelopeStage::Off,
197 (EnvelopeStage::Sustain, _) => EnvelopeStage::Sustain,
198 (EnvelopeStage::Off, _) => EnvelopeStage::Off,
199 }
200 }
201}
202
203#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
207#[derive(Debug, Clone, Default)]
208pub enum EnvelopeAction {
209 #[default]
210 None,
212 GateOn,
214 GateOff,
216}
217
218impl Automaton for EnvelopeAutomaton {
219 type Internal = EnvelopeInternal;
220 type Action = EnvelopeAction;
221
222 fn step(
223 &self,
224 internal: &mut Self::Internal,
225 current: &ParamValue,
226 time: Time,
227 action: &Self::Action,
228 ) -> ParamValue {
229 let (stage, stage_start_time, stage_start_level) = *internal;
230 let current_level = current.as_f32().unwrap_or(0.0) as f64;
231
232 let (new_stage, new_start_time, new_start_level) = match action {
233 EnvelopeAction::GateOn => (EnvelopeStage::Attack, time, current_level),
234 EnvelopeAction::GateOff => (EnvelopeStage::Release, time, current_level),
235 EnvelopeAction::None => (stage, stage_start_time, stage_start_level),
236 };
237
238 let elapsed = time - new_start_time;
239 let duration = self.stage_duration(new_stage);
240 let target = self.stage_target(new_stage);
241
242 let (next_stage, next_start_time, next_start_level, level) = if elapsed >= duration {
243 let next = self.next_stage(new_stage);
244 let next_target = self.stage_target(next);
245 let next_dur = self.stage_duration(next);
246 if next_dur.is_infinite() {
247 (next, time, next_target, next_target)
248 } else {
249 (next, time, target, target)
251 }
252 } else {
253 let t = elapsed / duration;
254 let curved = self.apply_curve(t);
255 let lvl = new_start_level + (target - new_start_level) * curved;
256 (new_stage, new_start_time, new_start_level, lvl)
257 };
258
259 *internal = (next_stage, next_start_time, next_start_level);
260 let value = self.range.denormalize(level);
261 ParamValue::Float(value as f32)
262 }
263
264 fn initial_internal(&self) -> Self::Internal {
265 (EnvelopeStage::Off, 0.0, 0.0)
266 }
267
268 fn name(&self) -> &str {
269 &self.name
270 }
271}
272
273#[cfg(test)]
274mod tests {
275 use super::*;
276
277 #[test]
278 fn test_adsr_envelope() {
279 let env = EnvelopeAutomaton::adsr("ADSR", 0.1, 0.2, 0.7, 0.3);
280 let mut internal = env.initial_internal();
281 let current = ParamValue::Float(0.0);
282
283 assert_eq!(internal.0, EnvelopeStage::Off);
284
285 let value = env.step(&mut internal, ¤t, 0.0, &EnvelopeAction::GateOn);
286 assert_eq!(internal.0, EnvelopeStage::Attack);
287
288 let value = env.step(&mut internal, &value, 0.05, &EnvelopeAction::None);
289 let val = value.as_f32().unwrap();
290 assert!(val > 0.0);
291 assert!(val < 1.0);
292
293 let _value = env.step(&mut internal, &value, 0.5, &EnvelopeAction::GateOff);
294 assert_eq!(internal.0, EnvelopeStage::Release);
295 }
296}