#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub(crate) enum State {
Attack,
Decay(usize),
Release(usize),
Done,
}
#[derive(Debug)]
pub(crate) struct Envelope {
attack_slope: f32,
decay_slope: f32,
sustain_height: f32,
release_slope: f32,
state: State,
}
impl Envelope {
pub fn new(sample_rate: f32, attack: f32, decay: f32, sustain: f32, release: f32) -> Self {
Self {
attack_slope: 1.0 / attack / sample_rate,
decay_slope: 1.0 / decay / sustain / sample_rate,
sustain_height: sustain,
release_slope: 1.0 / release / sustain / sample_rate,
state: State::Attack,
}
}
pub fn apply(&mut self, buffer: &mut [f32], offset: usize) -> State {
buffer.iter_mut().enumerate().for_each(|(index, tone)| {
let index_with_offset = index + offset;
*tone *= match self.state {
State::Attack => {
let multiplier = index_with_offset as f32 * self.attack_slope;
if multiplier >= 1.0 {
self.state = State::Decay(index_with_offset);
1.0
} else {
multiplier
}
}
State::Decay(last_offset) => {
let multiplier =
1.0 - ((index_with_offset - last_offset) as f32 * self.decay_slope);
if multiplier <= self.sustain_height {
self.state = State::Release(index_with_offset);
self.sustain_height
} else {
multiplier
}
}
State::Release(last_offset) => {
let multiplier = self.sustain_height
- ((index_with_offset - last_offset) as f32 * self.release_slope);
if multiplier <= 0.0 {
self.state = State::Done;
0.0
} else {
multiplier
}
}
State::Done => 0.0,
}
});
self.state
}
}