use quiver::prelude::*;
use quiver::render::write_wav;
use std::path::Path;
use std::sync::Arc;
fn midi_to_voct(note: u8) -> f64 {
(note as f64 - 60.0) / 12.0
}
fn main() {
let sample_rate = 44100.0;
let mut patch = Patch::new(sample_rate);
let pitch_cv = Arc::new(AtomicF64::new(0.0));
let gate_cv = Arc::new(AtomicF64::new(0.0));
let pitch = patch.add("pitch", ExternalInput::voct(Arc::clone(&pitch_cv)));
let gate = patch.add("gate", ExternalInput::gate(Arc::clone(&gate_cv)));
let vco = patch.add("vco", Vco::new(sample_rate));
let vcf = patch.add("vcf", Svf::new(sample_rate));
let vca = patch.add("vca", Vca::new());
let env = patch.add("env", Adsr::new(sample_rate));
let output = patch.add("output", StereoOutput::new());
patch.connect(pitch.out("out"), vco.in_("voct")).unwrap();
patch.connect(gate.out("out"), env.in_("gate")).unwrap();
patch.connect(vco.out("saw"), vcf.in_("in")).unwrap();
patch.connect(vcf.out("lp"), vca.in_("in")).unwrap();
patch.connect(vca.out("out"), output.in_("left")).unwrap();
patch.connect(vca.out("out"), output.in_("right")).unwrap();
patch.connect(env.out("env"), vca.in_("cv")).unwrap();
patch.connect(env.out("env"), vcf.in_("cutoff")).unwrap();
patch.set_output(output.id());
patch.compile().unwrap();
let phrase = [48u8, 52, 55, 60, 48, 52, 55, 60];
let note_seconds = 0.25;
let gate_high_seconds = note_seconds * 0.8;
let gate_low_seconds = note_seconds - gate_high_seconds;
println!("=== Render to WAV: Arpeggio Phrase ===\n");
let mut left_all = Vec::new();
let mut right_all = Vec::new();
for (i, ¬e) in phrase.iter().enumerate() {
let voct = midi_to_voct(note);
println!("Step {}: MIDI {note} ({voct:.3}V)", i + 1);
pitch_cv.set(voct);
gate_cv.set(5.0);
let (l, r) = render(&mut patch, gate_high_seconds);
left_all.extend(l);
right_all.extend(r);
gate_cv.set(0.0);
let (l, r) = render(&mut patch, gate_low_seconds);
left_all.extend(l);
right_all.extend(r);
}
let peak = left_all.iter().map(|s| s.abs()).fold(0.0_f64, f64::max);
println!(
"\nGenerated {} samples ({:.2}s)",
left_all.len(),
left_all.len() as f64 / sample_rate
);
println!("Peak amplitude: {peak:.2}V");
let to_full_scale = |buf: &[f64]| -> Vec<f64> { buf.iter().map(|s| s / 6.0).collect() };
let path = Path::new("target/render_wav.wav");
write_wav(
path,
sample_rate as u32,
&to_full_scale(&left_all),
&to_full_scale(&right_all),
)
.expect("failed to write WAV file");
println!(
"\nWrote {} - play it in any audio player to hear Quiver make sound!",
path.display()
);
}