rill_core_dsp/generators/
envelope.rs1use super::Generator;
4use crate::math::Smoother;
5use crate::vector::prelude::*;
6use rill_core::traits::algorithm::{Algorithm, AlgorithmCategory, AlgorithmMetadata};
7use rill_core::traits::ProcessResult;
8use rill_core::Transcendental;
9
10#[derive(Debug, Clone, Copy, PartialEq)]
12pub enum EnvelopeStage {
13 Attack,
15 Decay,
17 Sustain,
19 Release,
21 Off,
23}
24
25impl EnvelopeStage {
26 pub fn name(&self) -> &'static str {
28 match self {
29 EnvelopeStage::Attack => "Attack",
30 EnvelopeStage::Decay => "Decay",
31 EnvelopeStage::Sustain => "Sustain",
32 EnvelopeStage::Release => "Release",
33 EnvelopeStage::Off => "Off",
34 }
35 }
36}
37
38#[derive(Debug, Clone, Copy, PartialEq)]
40pub enum EnvelopeType {
41 ADSR,
43 AR,
45 ASR,
47}
48
49pub struct EnvelopeGenerator<T: Transcendental> {
55 env_type: EnvelopeType,
56 attack: f32,
57 decay: f32,
58 sustain: ScalarVector1<T>,
59 release: f32,
60 stage: EnvelopeStage,
61 level: ScalarVector1<T>,
62 smoother: Smoother<T>,
63 attack_samples: usize,
64 decay_samples: usize,
65 release_samples: usize,
66 position: usize,
67 sample_rate: f32,
68 gate: bool,
69}
70
71impl<T: Transcendental> EnvelopeGenerator<T> {
72 pub fn adsr(attack: f32, decay: f32, sustain: T, release: f32) -> Self {
79 Self {
80 env_type: EnvelopeType::ADSR,
81 attack,
82 decay,
83 sustain: ScalarVector1::splat(sustain),
84 release,
85 stage: EnvelopeStage::Off,
86 level: ScalarVector1::splat(T::ZERO),
87 smoother: Smoother::new(T::from_f32(0.5)),
88 attack_samples: 0,
89 decay_samples: 0,
90 release_samples: 0,
91 position: 0,
92 sample_rate: 44100.0,
93 gate: false,
94 }
95 }
96
97 pub fn ar(attack: f32, release: f32) -> Self {
99 Self {
100 env_type: EnvelopeType::AR,
101 attack,
102 decay: 0.0,
103 sustain: ScalarVector1::splat(T::ZERO),
104 release,
105 stage: EnvelopeStage::Off,
106 level: ScalarVector1::splat(T::ZERO),
107 smoother: Smoother::new(T::from_f32(0.5)),
108 attack_samples: 0,
109 decay_samples: 0,
110 release_samples: 0,
111 position: 0,
112 sample_rate: 44100.0,
113 gate: false,
114 }
115 }
116
117 pub fn asr(attack: f32, sustain: T, release: f32) -> Self {
119 Self {
120 env_type: EnvelopeType::ASR,
121 attack,
122 decay: 0.0,
123 sustain: ScalarVector1::splat(sustain),
124 release,
125 stage: EnvelopeStage::Off,
126 level: ScalarVector1::splat(T::ZERO),
127 smoother: Smoother::new(T::from_f32(0.5)),
128 attack_samples: 0,
129 decay_samples: 0,
130 release_samples: 0,
131 position: 0,
132 sample_rate: 44100.0,
133 gate: false,
134 }
135 }
136
137 fn update_samples(&mut self) {
139 self.attack_samples = (self.attack * self.sample_rate) as usize;
140 self.decay_samples = (self.decay * self.sample_rate) as usize;
141 self.release_samples = (self.release * self.sample_rate) as usize;
142 }
143
144 pub fn trigger(&mut self) {
146 self.gate = true;
147 self.stage = EnvelopeStage::Attack;
148 self.position = 0;
149 }
150
151 pub fn release(&mut self) {
153 self.gate = false;
154 self.stage = EnvelopeStage::Release;
155 self.position = 0;
156 }
157
158 pub fn stage(&self) -> EnvelopeStage {
160 self.stage
161 }
162
163 pub fn is_active(&self) -> bool {
165 self.stage != EnvelopeStage::Off
166 }
167}
168
169impl<T: Transcendental> Algorithm<T> for EnvelopeGenerator<T> {
170 fn init(&mut self, sample_rate: f32) {
171 self.sample_rate = sample_rate;
172 self.update_samples();
173 self.reset();
174 }
175
176 fn reset(&mut self) {
177 self.stage = EnvelopeStage::Off;
178 self.level = ScalarVector1::splat(T::ZERO);
179 self.position = 0;
180 self.gate = false;
181 self.smoother.set_current(T::ZERO);
182 }
183
184 fn process(&mut self, input: Option<&[T]>, output: &mut [T]) -> ProcessResult<()> {
185 let input = input.unwrap_or(&[]);
186 let len = input.len().min(output.len());
187 for i in 0..len {
188 let gate_signal = input[i];
189 if gate_signal.to_f32() > 0.5 && !self.gate {
191 self.trigger();
192 } else if gate_signal.to_f32() <= 0.5 && self.gate {
193 self.release();
194 }
195
196 match self.stage {
198 EnvelopeStage::Attack => {
199 let target = ScalarVector1::splat(T::from_f32(1.0));
200 self.level = self.level
201 + (target - self.level)
202 * ScalarVector1::splat(T::from_f32(1.0 / self.attack_samples as f32));
203 self.position += 1;
204
205 if self.position >= self.attack_samples {
206 match self.env_type {
207 EnvelopeType::ADSR => self.stage = EnvelopeStage::Decay,
208 EnvelopeType::AR => self.stage = EnvelopeStage::Release,
209 EnvelopeType::ASR => self.stage = EnvelopeStage::Sustain,
210 }
211 self.position = 0;
212 }
213 }
214
215 EnvelopeStage::Decay => {
216 let target = self.sustain;
217 self.level = self.level
218 + (target - self.level)
219 * ScalarVector1::splat(T::from_f32(1.0 / self.decay_samples as f32));
220 self.position += 1;
221
222 if self.position >= self.decay_samples {
223 self.stage = EnvelopeStage::Sustain;
224 self.position = 0;
225 }
226 }
227
228 EnvelopeStage::Sustain => {
229 self.level = self.sustain;
231 }
232
233 EnvelopeStage::Release => {
234 let target = ScalarVector1::splat(T::ZERO);
235 self.level = self.level
236 + (target - self.level)
237 * ScalarVector1::splat(T::from_f32(1.0 / self.release_samples as f32));
238 self.position += 1;
239
240 if self.position >= self.release_samples {
241 self.stage = EnvelopeStage::Off;
242 self.position = 0;
243 }
244 }
245
246 EnvelopeStage::Off => {
247 self.level = ScalarVector1::splat(T::ZERO);
248 }
249 }
250
251 output[i] = self.smoother.process_sample(self.level.extract(0));
253 }
254 Ok(())
255 }
256
257 fn metadata(&self) -> AlgorithmMetadata {
258 AlgorithmMetadata {
259 name: match self.env_type {
260 EnvelopeType::ADSR => "ADSR Envelope",
261 EnvelopeType::AR => "AR Envelope",
262 EnvelopeType::ASR => "ASR Envelope",
263 },
264 category: AlgorithmCategory::Generator,
265 description: match self.env_type {
266 EnvelopeType::ADSR => "Attack-Decay-Sustain-Release envelope generator",
267 EnvelopeType::AR => "Attack-Release envelope generator (percussion)",
268 EnvelopeType::ASR => "Attack-Sustain-Release envelope generator (organ)",
269 },
270 author: "Rill",
271 version: env!("CARGO_PKG_VERSION"),
272 }
273 }
274}
275
276impl<T: Transcendental> Generator<T> for EnvelopeGenerator<T> {
277 fn phase(&self) -> T {
278 T::ZERO
279 }
280 fn set_phase(&mut self, _phase: T) {}
281 fn frequency(&self) -> f32 {
282 0.0
283 }
284 fn set_frequency(&mut self, _freq: f32) {}
285 fn amplitude(&self) -> T {
286 self.level.extract(0)
287 }
288 fn set_amplitude(&mut self, _amp: T) {}
289}