use std::sync::Arc;
use crate::sound_builders::{Adsr, ProgramTable, simple_sound};
use crate::{SharedMidiState, program_table};
use fundsp::net::Net;
use fundsp::prelude::{
AudioUnit, U2, brown, db_amp, dcblock, highshelf_hz, join, limiter, lowpass_hz, mul, pass,
resonator_hz,
};
use fundsp::prelude64::{
adsr_live, clip, constant, dsf_saw, dsf_square, follow, highpass_hz, lowpass_q, organ, product,
pulse, saw, shared, sine, soft_saw, square, triangle, var,
};
pub fn options() -> ProgramTable {
program_table![
("Simple Triangle", simple_triangle),
("Triangle", adsr_triangle),
("Organ", adsr_organ),
("Sine", adsr_sine),
("Saw", adsr_saw),
("Soft Saw", adsr_soft_saw),
("Square", adsr_square),
("Pulse", adsr_pulse),
("DSF Saw", adsr_dsf_saw),
("DSF Square", adsr_dsf_square),
("Moog Organ", moog_organ),
("Moog Saw", moog_saw),
("Moog Soft Saw", moog_soft_saw),
("Moog Square", moog_square),
("Moog Pulse", moog_pulse),
("Acoustic Grand Piano", acoustic_grand_piano),
("Xylophone", xylophone),
("Clavichord (Sharp)", clavichord_sharp),
("Clavichord (Soft)", clavichord_soft),
("Guitar-ish", guitarish),
("Music Box", music_box::<74>)
]
}
pub fn favorites() -> ProgramTable {
program_table![
("80s Beep", simple_triangle),
("Triangle", adsr_triangle),
("Organ", adsr_organ),
("Saw", adsr_saw),
("Soft Saw", adsr_soft_saw),
("Square", adsr_square),
("Pulse", adsr_pulse),
("Moog Organ", moog_organ),
("Moog Saw", moog_saw),
("Moog Square", moog_square),
("Moog Pulse", moog_pulse),
("Acoustic Grand Piano", acoustic_grand_piano),
("Xylophone", xylophone),
("Clavichord (Sharp)", clavichord_sharp),
("Clavichord (Soft)", clavichord_soft),
("Guitar-ish", guitarish)
]
}
pub fn moogs() -> ProgramTable {
program_table![
("Moog Organ", moog_organ),
("Moog Pulse", moog_pulse),
("Moog Saw", moog_saw),
("Moog Square", moog_square)
]
}
pub fn simple_triangle(state: &SharedMidiState) -> Box<dyn AudioUnit> {
simple_sound(state, Box::new(triangle() * 4.4))
}
pub const ADSR1: Adsr = Adsr {
attack: 0.1,
decay: 0.2,
sustain: 0.4,
release: 0.4,
};
pub const ADSR2: Adsr = Adsr {
attack: 0.1,
decay: 0.4,
sustain: 0.4,
release: 0.6,
};
pub fn adsr_triangle(state: &SharedMidiState) -> Box<dyn AudioUnit> {
state.assemble_unpitched_sound(Box::new(triangle() * 4.4), ADSR1.boxed(state))
}
pub fn adsr_organ(state: &SharedMidiState) -> Box<dyn AudioUnit> {
state.assemble_unpitched_sound(Box::new(organ() * 3.45), ADSR1.boxed(state))
}
pub fn adsr_sine(state: &SharedMidiState) -> Box<dyn AudioUnit> {
state.assemble_unpitched_sound(Box::new(sine()), ADSR1.boxed(state))
}
pub fn adsr_saw(state: &SharedMidiState) -> Box<dyn AudioUnit> {
state.assemble_unpitched_sound(Box::new(saw() * 2.3), ADSR1.boxed(state))
}
pub fn adsr_soft_saw(state: &SharedMidiState) -> Box<dyn AudioUnit> {
state.assemble_unpitched_sound(Box::new(soft_saw() * 4.0), ADSR1.boxed(state))
}
pub fn adsr_square(state: &SharedMidiState) -> Box<dyn AudioUnit> {
state.assemble_unpitched_sound(Box::new(square() * 2.5), ADSR1.boxed(state))
}
pub fn adsr_pulse(state: &SharedMidiState) -> Box<dyn AudioUnit> {
ADSR2.assemble_timed(Box::new(pulse() * 2.8), state)
}
pub fn adsr_dsf_saw(state: &SharedMidiState) -> Box<dyn AudioUnit> {
ADSR2.assemble_timed(Box::new(dsf_saw() * 0.08), state)
}
pub fn adsr_dsf_square(state: &SharedMidiState) -> Box<dyn AudioUnit> {
ADSR2.assemble_timed(Box::new(dsf_square() * 0.08), state)
}
pub fn moog_pulse(state: &SharedMidiState) -> Box<dyn AudioUnit> {
state.assemble_pitched_sound(
Box::new(ADSR2.timed_moog(
Box::new(ADSR2.timed_sound(Box::new(pulse() * 4.5), state)),
state,
)),
ADSR2.boxed(state),
)
}
pub fn moog_square(state: &SharedMidiState) -> Box<dyn AudioUnit> {
state.assemble_unpitched_sound(
Box::new(ADSR2.timed_moog(Box::new(square() * 5.625), state)),
ADSR2.boxed(state),
)
}
pub fn moog_saw(state: &SharedMidiState) -> Box<dyn AudioUnit> {
state.assemble_unpitched_sound(
Box::new(ADSR2.timed_moog(Box::new(saw() * 5.0), state)),
ADSR2.boxed(state),
)
}
pub fn moog_soft_saw(state: &SharedMidiState) -> Box<dyn AudioUnit> {
state.assemble_unpitched_sound(
Box::new(ADSR2.timed_moog(Box::new(soft_saw() * 7.6), state)),
ADSR2.boxed(state),
)
}
pub fn moog_organ(state: &SharedMidiState) -> Box<dyn AudioUnit> {
state.assemble_unpitched_sound(
Box::new(ADSR2.timed_moog(Box::new(organ() * 6.7), state)),
ADSR2.boxed(state),
)
}
pub fn acoustic_grand_piano(state: &SharedMidiState) -> Box<dyn AudioUnit> {
let piano_adsr = Adsr {
attack: 0.002,
decay: 0.8,
sustain: 0.2,
release: 0.7,
};
let a1 = 0.9;
let a2 = 0.55;
let a3 = 0.42;
let a4 = 0.38;
let a5 = 0.25;
let a6 = 0.13;
let a7 = 0.02;
let a8 = 0.015;
let a9 = 0.01;
let tone = (mul(1.0) >> sine() * a1)
& (mul(2.0) >> sine() * a2)
& (mul(3.0) >> sine() * a3)
& (mul(4.0) >> sine() * a4)
& (mul(5.0) >> sine() * a5)
& (mul(6.0) >> sine() * a6)
& (mul(7.0) >> sine() * a7)
& (mul(8.0) >> sine() * a8)
& (mul(9.0) >> sine() * a9)
>> lowpass_hz(400.0, 0.8)
>> highshelf_hz(2000.0, db_amp(-12.0), 0.0)
>> dcblock::<f64>();
let body = pass()
& (0.25 * resonator_hz(82.4, 25.0))
& (0.20 * resonator_hz(110.0, 22.0))
& (0.18 * resonator_hz(146.8, 20.0))
& (0.15 * resonator_hz(220.0, 18.0))
& (0.12 * resonator_hz(293.7, 16.0))
& (0.10 * resonator_hz(440.0, 14.0))
& (0.08 * resonator_hz(587.3, 12.0))
& (0.06 * resonator_hz(880.0, 10.0))
& (0.04 * resonator_hz(1760.0, 8.0))
& (0.02 * resonator_hz::<f64>(800.0, 10.0) * brown::<f64>());
let synth = Box::new(
tone >> body >> highpass_hz(20.0, 0.7) >> limiter(0.002, 0.06) >> dcblock::<f64>(),
);
state.assemble_unpitched_sound(synth, piano_adsr.boxed(state))
}
pub fn xylophone(state: &SharedMidiState) -> Box<dyn AudioUnit> {
let xylophone_adsr = Adsr {
attack: 0.01,
decay: 0.3,
sustain: 0.0,
release: 0.15,
};
let a1 = 0.70;
let a2 = 0.28;
let a3 = 0.14;
let a4 = 0.07;
let a5 = 0.03;
let bar_modes = (mul(1.0) >> sine() * a1)
& (mul(3.998) >> sine() * a2)
& (mul(10.0) >> sine() * a3)
& (mul(20.0) >> sine() * a4)
& (mul(27.0) >> sine() * a5)
>> highshelf_hz(2500.0, db_amp(1.5), 0.2)
>> lowpass_hz(6500.0, 0.7)
>> dcblock::<f64>();
let tone = bar_modes >> (pass() ^ (highpass_hz(3000.0, 0.7) * 0.18)) >> join::<U2>();
let body = (pass() * 0.7)
& (0.18 * resonator_hz(800.0, 85.0))
& (0.14 * resonator_hz(1600.0, 95.0))
& (0.10 * resonator_hz(2400.0, 110.0))
& (0.07 * resonator_hz(3200.0, 130.0));
let synth = Box::new(
tone >> body >> highpass_hz(30.0, 0.7) >> dcblock::<f64>() >> limiter(0.002, 0.12),
);
state.assemble_unpitched_sound(synth, xylophone_adsr.boxed(state))
}
pub fn clavichord_sharp(state: &SharedMidiState) -> Box<dyn AudioUnit> {
let adsr = Adsr {
attack: 0.005,
decay: 0.2,
sustain: 0.0,
release: 0.5,
};
state.assemble_unpitched_sound(basic_pluck(), adsr.boxed(state))
}
pub fn clavichord_soft(state: &SharedMidiState) -> Box<dyn AudioUnit> {
let adsr = Adsr {
attack: 0.01,
decay: 0.2,
sustain: 0.1,
release: 0.5,
};
state.assemble_unpitched_sound(basic_pluck(), adsr.boxed(state))
}
fn basic_pluck() -> Box<dyn AudioUnit> {
Box::new((square() & saw()) >> lowpass_hz::<f32>(3000.0, 0.5))
}
pub fn guitarish(state: &SharedMidiState) -> Box<dyn AudioUnit> {
let adsr = Adsr {
attack: 0.005,
decay: 1.0,
sustain: 0.0,
release: 0.5,
};
let mix = Net::stack(state.bent_pitch(), Net::wrap(Box::new(var(&shared(0.3)))))
>> pulse()
>> lowpass_hz::<f32>(3000.0, 0.5);
state.assemble_pitched_sound(Box::new(mix), adsr.boxed(state))
}
pub fn music_box<const CC: usize>(state: &SharedMidiState) -> Box<dyn AudioUnit> {
let synth_adsr = Adsr {
attack: 0.002,
decay: 0.0,
sustain: 1.0,
release: 0.6,
};
let a1 = 0.600;
let a2 = 0.350;
let a3 = 0.200;
let a4 = 0.100;
let gate = state.control_var();
let modes = mul(1.000)
>> sine() * (gate.clone() >> adsr_live(0.002, 0.5, 0.0, synth_adsr.release))
& (mul(2.756) >> sine() * a1)
* (gate.clone() >> adsr_live(0.002, 0.5 / 2.0, 0.0, synth_adsr.release))
& (mul(5.404) >> sine() * a2)
* (gate.clone() >> adsr_live(0.002, 0.5 / 5.0, 0.0, synth_adsr.release))
& (mul(8.933) >> sine() * a3)
* (gate.clone() >> adsr_live(0.002, 0.5 / 10.0, 0.0, synth_adsr.release))
& (mul(13.34) >> sine() * a4)
* (gate.clone() >> adsr_live(0.002, 0.5 / 18.0, 0.0, synth_adsr.release))
>> dcblock::<f64>();
let tone = modes >> (pass() ^ (highpass_hz(100.0, 0.7) * 0.10)) >> join::<U2>();
let body = (pass() * 0.4)
& (0.5 * resonator_hz(150.0, 20.0))
& (0.3 * resonator_hz(320.0, 25.0))
& (0.1 * resonator_hz(550.0, 15.0));
let cutoff_val = state.control_change_var(CC);
let max_cutoff_hz = 5_000.0;
let combined = tone >> body >> highpass_hz(30.0, 0.7) * db_amp(-4.0);
let cutoff_hrz = product(constant(max_cutoff_hz / 127.0), cutoff_val);
let synth = Box::new(
(combined | cutoff_hrz >> follow(0.05_f32)) >> lowpass_q(2.0) >> dcblock::<f64>() >> clip(),
);
state.assemble_unpitched_sound(synth, synth_adsr.boxed(state))
}