use crate::beep::osc::HarmonicOscillator; use crate::beep::tween::{Tween, GainScale}; use std::time::Duration; use crate::beep::sample::StereoSample; use crate::beep::hack::StableClamp; /// Waveform generator with multiple frequencies / waveforms #[derive(Clone,Debug)] pub struct Instrument { /// Waveforms to combine to produce the final sound pub waveforms: Vec, /// Balance fader -1..1 balance: Tween, /// 0-1 left gain pub(crate) ratio_left : f32, /// 0-1 right gain 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 { pub fn new(mut waveforms: Vec, sample_rate: f32) -> Self { for (n, o) in waveforms.iter_mut().enumerate() { o.set_sample_rate(sample_rate); o.set_freq_imm(sample_rate * (n as f32 + 1.0)); } let mut o = Self { waveforms, balance: Tween { actual: 0.0, target: 0.0, min: -1.0, max: 1.0, step: None, sample_rate }, ratio_left: 0.7, ratio_right: 0.7, gain: Tween { actual: 0.0, target: 0.0, step: None, 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.cos(); self.ratio_right = angle.sin(); } /// Get amplitude pub fn get_amp(&self) -> f32 { self.gain.actual() } /// Set amplitude (0..1), change at the end of the current waveform to reduce popping pub fn set_amp(&mut self, amp : f32) { self.gain.set_at_crossover(amp); } /// Set amplitude (0..1) immediate pub fn set_amp_imm(&mut self, amp : f32) { self.gain.set_immediate(amp); } /// Fade amplitude over a given time pub fn fade_amp(&mut self, amp : f32, time: Duration) { 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 } /// Set balance (-1..1), change at the end of the current waveform to reduce popping pub fn set_balance(&mut self, balance : f32) { self.balance.set_at_crossover(balance); } /// Set balance (-1..1) immediate pub fn set_balance_imm(&mut self, balance : f32) { self.balance.set_immediate(balance); } /// Fade to balance (-1..1) over a given time pub fn fade_balance(&mut self, balance : f32, time: Duration) { self.balance.fade(balance, time); } 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) pub fn get_freq(&self) -> f32 { self.waveforms[0].get_freq() // TODO error checking } /// Set base and harmonics frequency (1..22050), change at the end of the current waveform to reduce popping pub fn set_freq(&mut self, freq : f32) { let mut f = freq; self.waveforms.iter_mut().for_each(|w| { w.set_freq(f); }); } /// Set base and harmonics frequency (1..22050) immediate pub fn set_freq_imm(&mut self, freq : f32) { let mut f = freq; self.waveforms.iter_mut().for_each(|w| { w.set_freq_imm(f); }); } /// Fade base and harmonics to frequency (1..22050) over a given time pub fn fade_freq(&mut self, freq : f32, time: Duration) { let mut f = freq; self.waveforms.iter_mut().for_each(|w| { w.fade_freq(f, time); }); } /// Get a raw sample (with panning) 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.gain2.actual * self.intrinsic_gain } }