wip audio synthesizer based on the rust crate cpal
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
beeper/src/beep/orchestra.rs

86 lines
2.2 KiB

use crate::beep::instrument::Instrument;
use crate::beep::tween::Tween;
use std::time::Duration;
use crate::beep::sample::StereoSample;
use crate::beep::hack::StableClamp;
/// A set of instruments
pub struct Orchestra {
pub instruments: Vec<Instrument>,
/// Normalize the output to produce constant amplitude of 1.0 (instead of clipping)
normalize: bool,
/// Sample rate, used to calculate time based effects
sample_rate : f32,
/// Master gain
gain: Tween,
}
impl Orchestra {
pub fn new(instruments: Vec<Instrument>, sample_rate: f32) -> Self {
let mut o = Self {
instruments,
normalize: false,
sample_rate,
gain: Tween {
actual: 1.0,
target: 1.0,
step: None,
min: 0.0,
max: 1.0,
sample_rate
}
};
o
}
pub fn normalize(&mut self, normalize: bool) {
self.normalize = normalize;
}
pub fn get_amp(&self) -> f32 {
self.gain.actual()
}
pub fn set_amp(&mut self, amp : f32) {
self.gain.set_immediate(amp);
}
pub fn fade_amp(&mut self, amp : f32, time: Duration) {
self.gain.fade(amp, time);
}
fn calc_gain(&self) -> f32 {
(if self.normalize {
1.0 / (
self.instruments.iter()
.fold(0.0, |acc, item| acc + item.get_peak_amplitude())
)
} else { 1.0 }) * self.gain.actual
}
pub fn sample_stereo(&mut self) -> StereoSample {
let gain = self.calc_gain();
self.instruments
.iter_mut()
.fold(StereoSample::default(), |mut acc, item| {
let s = item.sample() * gain;
acc.left += s * item.ratio_left;
acc.right += s * item.ratio_left;
acc
})
.clip()
}
pub fn sample_mono(&mut self) -> f32 {
let gain = self.calc_gain();
self.instruments
.iter_mut()
.fold(0.0, |mut acc, item| {
acc + item.sample() * gain
})
.clamp_(0.0, 1.0)
}
}