use fundsp::{
math::{clamp01, xerp},
net::Net,
prelude::AudioUnit,
prelude64::{adsr_live, envelope2, moog_q},
};
use crate::{SharedMidiState, SynthFunc};
#[macro_export]
macro_rules! program_table {
($( ($s:expr, $f:expr)),* ) => {vec![$(($s.to_owned(), Arc::new($f)),)*]}
}
pub const NUM_PROGRAM_SLOTS: usize = 2_usize.pow(7);
pub type ProgramTable = Vec<(String, SynthFunc)>;
pub fn simple_sound(state: &SharedMidiState, synth: Box<dyn AudioUnit>) -> Box<dyn AudioUnit> {
let control = state.control_var();
state.assemble_unpitched_sound(
synth,
Box::new(control >> envelope2(move |_, n| clamp01(n))),
)
}
#[derive(Copy, Clone, Debug)]
pub struct Adsr {
pub attack: f32,
pub decay: f32,
pub sustain: f32,
pub release: f32,
}
impl Adsr {
pub fn boxed(&self, state: &SharedMidiState) -> Box<dyn AudioUnit> {
let control = state.control_var();
Box::new(control >> adsr_live(self.attack, self.decay, self.sustain, self.release))
}
pub fn net64ed(&self, state: &SharedMidiState) -> Net {
Net::wrap(self.boxed(state))
}
pub fn timed_sound(&self, timed_sound: Box<dyn AudioUnit>, state: &SharedMidiState) -> Net {
Net::pipe(
Net::stack(state.bent_pitch(), self.net64ed(state)),
Net::wrap(timed_sound),
)
}
pub fn timed_moog(&self, source: Box<dyn AudioUnit>, state: &SharedMidiState) -> Net {
Net::pipe(
Net::stack(
Net::wrap(source),
Net::pipe(
self.net64ed(state),
Net::wrap(Box::new(envelope2(move |_, n| xerp(1100.0, 11000.0, n)))),
),
),
Net::wrap(Box::new(moog_q(0.6))),
)
}
pub fn assemble_timed(
&self,
timed_sound: Box<dyn AudioUnit>,
state: &SharedMidiState,
) -> Box<dyn AudioUnit> {
state.assemble_pitched_sound(
Box::new(self.timed_sound(timed_sound, state)),
self.boxed(state),
)
}
}