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