From a17829f5412ee0757574b34e34ce78b2975df1fe Mon Sep 17 00:00:00 2001 From: Grant Shangreaux Date: Thu, 11 Nov 2021 10:20:59 -0600 Subject: Add: poorly implemented but working amplitude envelope --- klangfarbrs/src/adsr.rs | 54 ++++++++++++++++++++++++++++++++++++++++--------- klangfarbrs/src/lib.rs | 48 +++++++++++++++++++++++++++++++------------ 2 files changed, 79 insertions(+), 23 deletions(-) (limited to 'klangfarbrs') diff --git a/klangfarbrs/src/adsr.rs b/klangfarbrs/src/adsr.rs index 682cc8a..9d51ba3 100644 --- a/klangfarbrs/src/adsr.rs +++ b/klangfarbrs/src/adsr.rs @@ -1,16 +1,18 @@ -use crate::{Millisecond, Amplitude}; +use super::{Millisecond, Amplitude, SamplesPerSecond}; pub struct Envelope { - attack: Vec, - decay: Vec, - release: Vec, + pub attack: Vec, + pub decay: Vec, + pub release: Vec, } impl Envelope { - pub fn new(attack: Millisecond, decay: Millisecond, sustain: Amplitude, release: Millisecond) -> Self { - let attack = vec![sustain; attack as usize]; - let decay = vec![sustain; decay as usize]; - let release = vec![sustain; release as usize]; + pub fn new( + attack: Millisecond, decay: Millisecond, sustain: Amplitude, release: Millisecond, sample_rate: SamplesPerSecond + ) -> Self { + let attack = interpolate(0.0, 1.0, ms_to_samples(attack, sample_rate)); + let decay = interpolate(1.0, sustain, ms_to_samples(decay, sample_rate)); + let release = interpolate(sustain, 0.0, ms_to_samples(release, sample_rate)); Self{attack, decay, release} } @@ -20,13 +22,45 @@ impl Envelope { } } +fn interpolate(start: Amplitude, end: Amplitude, milliseconds: Millisecond) -> Vec { + let step_size = (end - start) / milliseconds as f32; + let mut amps = vec!(); + let mut current_val = start + step_size; + + for i in 0..=milliseconds { + if i == 0 { + amps.push(start) + } else if i == milliseconds { + amps.push(end) + } else { + amps.push(current_val); + current_val += step_size; + } + } + + amps +} + +fn ms_to_samples(ms: Millisecond, sample_rate: SamplesPerSecond) -> u32 { + let multiplier = sample_rate as u32 / 1000; + multiplier * ms +} + #[cfg(test)] mod tests { use super::*; #[test] fn it_has_expected_total_length() { - let total = Envelope::new(10, 10, 1.0, 10).len(); - assert_eq! (30, total) + let expected = 3 + ms_to_samples(30, 48000.0) as usize; + let total = Envelope::new(10, 10, 1.0, 10, 48000.0).len(); + assert_eq! (expected, total) + } + + #[test] + fn interpolate_works() { + let expected = vec![0.0, 0.2, 0.4, 0.6, 0.8, 1.0]; + let result = interpolate(0.0, 1.0, 5); + assert_eq!(expected, result) } } diff --git a/klangfarbrs/src/lib.rs b/klangfarbrs/src/lib.rs index 0fc7936..ef9417c 100644 --- a/klangfarbrs/src/lib.rs +++ b/klangfarbrs/src/lib.rs @@ -47,10 +47,7 @@ pub struct MonoSynth { pub continuous: bool, pub duration: Millisecond, // ADSR amplifier - pub attack: Millisecond, - pub decay: Millisecond, - pub sustain: Amplitude, - pub release: Millisecond, + envelope: Envelope, // filter pub cutoff: Hz, // pub resonance: @@ -59,6 +56,7 @@ pub struct MonoSynth { pub fm_frequency: Hz, pub fm_depth: Amplitude, fm_phasor: Phasor, + current_envelope_position: usize, } pub struct Phasor { @@ -113,15 +111,13 @@ impl MonoSynth { phasor_bend: Vector2::new(0.0, 0.0), continuous: true, duration: 0, - attack: 0, - decay: 0, - sustain: 0.0, - release: 0, + envelope: Envelope::new(500, 1000, 0.5, 4000, 48000.0), cutoff: 0.0, frequency_modulation: false, fm_frequency: 10.0, fm_depth: 0.1, - fm_phasor: Phasor { phase: 0.0 } + fm_phasor: Phasor { phase: 0.0 }, + current_envelope_position: 0, } } @@ -155,6 +151,11 @@ impl MonoSynth { self.frequency = frequency } + #[export] + fn continuous(&mut self, _owner: &Node, state: bool) { + self.continuous = state; + } + #[export] fn phasor_bend(&mut self, _owner: &Node, phasor_bend: Vector2) { self.phasor_bend = phasor_bend @@ -185,11 +186,12 @@ impl MonoSynth { self.fm_depth = fm_depth } + #[export] fn envelope( - &self, _owner: &Node, + &mut self, _owner: &Node, attack: Millisecond, decay: Millisecond, sustain: Amplitude, release: Millisecond - ) -> Envelope { - Envelope::new(attack, decay, sustain, release) + ) { + self.envelope = Envelope::new(attack, decay, sustain, release, self.sample_rate); } #[export] @@ -197,7 +199,7 @@ impl MonoSynth { let mut frames = TypedArray::new(); for _i in 0..samples { - let sample = Osc::generate_sample(&self.waveform, self.phasor.phase); + let mut sample = Osc::generate_sample(&self.waveform, self.phasor.phase); let next_phase : f32; if self.frequency_modulation { @@ -214,6 +216,26 @@ impl MonoSynth { self.phasor.phase = next_phase; } + if !self.continuous { + let pos = self.current_envelope_position; + let atk = self.envelope.attack.len(); + let atkdcy = atk + self.envelope.decay.len(); + + if pos < atk { + sample = sample * self.envelope.attack[pos] + } else if pos >= atk && pos < atkdcy { + sample = sample * self.envelope.decay[pos - atk] + } else if pos < self.envelope.len() { + sample = sample * self.envelope.release[pos - atkdcy] + } + + self.current_envelope_position += 1; + + if self.current_envelope_position >= self.envelope.len() { + self.current_envelope_position = 0; + } + } + frames.push(Vector2::new(sample, sample)); } -- cgit v1.2.3