From 5e7af6ef47da8c7b6e9e03419167949388f47887 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Tue, 27 Oct 2020 00:43:42 +0100 Subject: [PATCH] finish the song + make the instrument act like a xylophone or somethiung --- src/beep/instrument.rs | 48 +++++++++++++++-- src/beep/mod.rs | 118 +++++++++++++++++++++++++++++++++++++---- 2 files changed, 153 insertions(+), 13 deletions(-) diff --git a/src/beep/instrument.rs b/src/beep/instrument.rs index a4c7d3d..fe04085 100644 --- a/src/beep/instrument.rs +++ b/src/beep/instrument.rs @@ -17,6 +17,10 @@ pub struct Instrument { pub(crate) ratio_right : f32, /// Master gain gain: Tween, + /// Master gain 2 (the two may be used for fade in & out) + gain2: Tween, + /// Gain always applied to the instrument on top of master gain + intrinsic_gain: f32, } impl Instrument { @@ -45,17 +49,30 @@ impl Instrument { min: 0.0, max: 1.0, sample_rate - } + }, + gain2: Tween { + actual: 0.0, + target: 0.0, + step: None, + min: 0.0, + max: 1.0, + sample_rate + }, + intrinsic_gain: 1.0 }; o.update_side_ratios(); o } + pub fn set_intrinsic_gain(&mut self, gain : f32) { + self.intrinsic_gain = gain; + } + /// Update the pre-computed channel gain variables pub fn update_side_ratios(&mut self) { let angle = ((1.0 + self.balance.actual) / 2.0) * std::f32::consts::FRAC_PI_2; - self.ratio_left = angle.sin(); - self.ratio_right = angle.cos(); + self.ratio_left = angle.cos(); + self.ratio_right = angle.sin(); } /// Get amplitude @@ -78,6 +95,27 @@ impl Instrument { self.gain.fade(amp, time); } + + /// Get amplitude + pub fn get_amp2(&self) -> f32 { + self.gain.actual() + } + + /// Set amplitude (0..1), change at the end of the current waveform to reduce popping + pub fn set_amp2(&mut self, amp : f32) { + self.gain2.set_at_crossover(amp); + } + + /// Set amplitude (0..1) immediate + pub fn set_amp2_imm(&mut self, amp : f32) { + self.gain2.set_immediate(amp); + } + + /// Fade amplitude over a given time + pub fn fade_amp2(&mut self, amp : f32, time: Duration) { + self.gain2.fade(amp, time); + } + /// Get balance value (-1..1) pub fn get_balance(&self) -> f32 { self.balance.actual @@ -101,6 +139,7 @@ impl Instrument { pub fn get_peak_amplitude(&self) -> f32 { self.waveforms.iter() .fold((0.0), |acc, item| acc + item.gain.actual) + * self.intrinsic_gain // ??? } /// Get base frequency value (1..22050) @@ -136,10 +175,11 @@ impl Instrument { pub fn sample(&mut self) -> f32 { self.balance.tick(); self.gain.tick(); + self.gain2.tick(); self.waveforms.iter_mut() .fold(0.0, |mut acc, item| { acc + item.sample() - }) * self.gain.actual + }) * self.gain.actual * self.gain2.actual * self.intrinsic_gain } } diff --git a/src/beep/mod.rs b/src/beep/mod.rs index 3e0d570..1ac8750 100644 --- a/src/beep/mod.rs +++ b/src/beep/mod.rs @@ -63,17 +63,20 @@ fn run(device: &cpal::Device, config: &cpal::StreamConfig) -> Result<(), anyh // Produce a sinusoid of maximum amplitude. - let ins1 = Instrument::new(vec![ + let mut alt_synth = Instrument::new(vec![ HarmonicOscillator::new(1.0, 1.0), HarmonicOscillator::new(0.5, 5.0), ], sr); + alt_synth.set_balance_imm(0.3); - let ins2 = Instrument::new(vec![ + let mut bas_synth = Instrument::new(vec![ HarmonicOscillator::new(1.0, 1.0), HarmonicOscillator::new(0.5, 5.0), ], sr); + bas_synth.set_intrinsic_gain(0.5); + bas_synth.set_baance_imm(-0.3); - let mut orch = Orchestra::new(vec![ins1, ins2], sr); + let mut orch = Orchestra::new(vec![alt_synth, bas_synth], sr); orch.normalize(true); let handle = Arc::new(parking_lot::RwLock::new(orch)); @@ -265,6 +268,50 @@ fn run(device: &cpal::Device, config: &cpal::StreamConfig) -> Result<(), anyh (4, B4), (2, G4X), (4, E4), + (2, A4),// end of 1st line + + (4, C5), + (2, D5), + (3, E5), (1, F5X), (2, E5), + + (4, D5), + (2, B4), + (3, G4), (1, A4), (2, B4), + + (3, C5), (1, B4), (2, A4), + (3, G4X), (1, F4X), (2, G4X), + + (6, A4), + (6, A4),// end of 2nd line + + (6, G5), + (3, G5), (1, F5X), (2, E5), + + (4, D5), + (2, B4), + (3, G4), (1, A4), (2, B4), + + (4, C5), + (2, A4), + (3, A4), (1, G4X), (2, A4), + + (4, B4), + (2, G4X), + (6, E4),// end of 3rd line + + (6, G5), + (3, G5), (1, F5X), (2, E5), + + (4, D5), + (2, B4), + (3, G4), (1, A4), (2, B4), + + (3, C5), (1, B4), (2, A4), + (2, G4X), (2, F4X), (2, G4X), + + (6, A4), + (4, A4),// end of 4th line + (2, -1), ]; // Bass line, must be kept in sync with alt. Insert -1 notes for padding where needed. @@ -275,13 +322,50 @@ fn run(device: &cpal::Device, config: &cpal::StreamConfig) -> Result<(), anyh (6, C4), (6, G3), - (6, G4), + (6, G3), (6, A3), - (6, A4), + (6, A3), (6, E3), - (6, E4), + (6, E3),// end of 1st line + + (6, A3), + (6, C4), + + (6, G3), + (6, E3), + + (6, A3), + (6, E3), + + (6, A3), + (6, A3),// end of 2nd line + + (6, C4), + (6, C4), + + (6, G3), + (6, G3), + + (6, A3), + (6, A3), + + (6, E3), + (6, E3), // end of line 3 + + (6, C4), + (6, C4), + + (6, G3), + (6, E3), + + (6, A3), + (6, E3), + + (6, A3), + (4, A3), // end of line 4 + (2, -1), ]; const D_ONOFF: Duration = Duration::from_millis(10); @@ -300,22 +384,38 @@ fn run(device: &cpal::Device, config: &cpal::StreamConfig) -> Result<(), anyh ticks_alt = *len; if *key >= 0 { let f = key2freq(*key); - wg.instruments[0].fade_amp(1.0, D_ONOFF); + //wg.instruments[0].fade_amp(1.0, D_ONOFF); + + wg.instruments[0].set_amp2_imm(0.0); + wg.instruments[0].fade_amp2(1.0, D_ONOFF); + wg.instruments[0].set_amp_imm(1.0); wg.instruments[0].set_freq_imm(f); + wg.instruments[0].fade_amp(0.0, Duration::from_secs_f32((60.0/bpm) / 16.0) * *len); + } else { wg.instruments[0].fade_amp(0.0, D_ONOFF); + wg.instruments[0].fade_amp2(0.0, D_ONOFF); } } } if ticks_bass == 0 { if let Some((len, key)) = bass_iter.next() { - ticks_bass = len - 1; + ticks_bass = *len; if *key >= 0 { let f = key2freq(*key); - wg.instruments[1].fade_amp(0.5, D_ONOFF); + //wg.instruments[1].fade_amp(1.0, D_ONOFF); + // wg.instruments[1].set_amp_imm(1.0); + // wg.instruments[1].fade_amp(0.0, Duration::from_secs_f32((60.0/bpm) / 16.0) * *len); + // wg.instruments[1].set_freq_imm(f); + + wg.instruments[1].set_amp2_imm(0.0); + wg.instruments[1].fade_amp2(1.0, D_ONOFF); + wg.instruments[1].set_amp_imm(1.0); wg.instruments[1].set_freq_imm(f); + wg.instruments[1].fade_amp(0.0, Duration::from_secs_f32((60.0/bpm) / 16.0) * *len); } else { wg.instruments[1].fade_amp(0.0, D_ONOFF); + wg.instruments[1].fade_amp2(0.0, D_ONOFF); } } }