Skip to main content

rill_core_dsp/generators/
envelope.rs

1//! Генераторы огибающих (ADSR, AR, ASR)
2
3use 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/// Стадия огибающей
11#[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/// Тип огибающей
33#[derive(Debug, Clone, Copy, PartialEq)]
34pub enum EnvelopeType {
35    ADSR, // Attack, Decay, Sustain, Release
36    AR,   // Attack, Release
37    ASR,  // Attack, Sustain, Release
38}
39
40/// Генератор огибающей ADSR
41pub struct EnvelopeGenerator<T: Transcendental> {
42    /// Тип огибающей
43    env_type: EnvelopeType,
44    /// Времена (в секундах)
45    attack: f32,
46    decay: f32,
47    sustain: ScalarVector1<T>,
48    release: f32,
49    /// Текущая стадия
50    stage: EnvelopeStage,
51    /// Текущий уровень
52    level: ScalarVector1<T>,
53    /// Сглаживатель для устранения щелчков
54    smoother: Smoother<T>,
55    /// Счётчики в семплах
56    attack_samples: usize,
57    decay_samples: usize,
58    release_samples: usize,
59    position: usize,
60    /// Частота дискретизации
61    sample_rate: f32,
62    /// Запущена ли
63    gate: bool,
64}
65
66impl<T: Transcendental> EnvelopeGenerator<T> {
67    /// Создать новую ADSR огибающую
68    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    /// Создать новую AR огибающую (для перкуссии)
88    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    /// Создать новую ASR огибающую (для орга́нных звуков)
108    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    /// Обновить счётчики семплов
128    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    /// Запустить огибающую (gate on)
135    pub fn trigger(&mut self) {
136        self.gate = true;
137        self.stage = EnvelopeStage::Attack;
138        self.position = 0;
139    }
140
141    /// Отпустить огибающую (gate off)
142    pub fn release(&mut self) {
143        self.gate = false;
144        self.stage = EnvelopeStage::Release;
145        self.position = 0;
146    }
147
148    /// Получить текущую стадию
149    pub fn stage(&self) -> EnvelopeStage {
150        self.stage
151    }
152
153    /// Проверить, активна ли огибающая
154    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            // Обновляем gate из входного сигнала если есть
185            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            // Генерация огибающей
192            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                    // Просто держим уровень
225                    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            // Применяем сглаживание
247            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}