use quiver::prelude::*;
use quiver::render::write_wav;
use std::path::Path;
fn main() {
let sample_rate = 44100.0;
let mut patch = Patch::new(sample_rate);
let vco = patch.add("vco", Vco::new(sample_rate));
let vcf = patch.add("vcf", Svf::new(sample_rate));
let output = patch.add("output", StereoOutput::new());
let cutoff = patch.add("cutoff", Offset::new(0.35));
patch.connect(vco.out("saw"), vcf.in_("in")).unwrap();
patch.connect(cutoff.out("out"), vcf.in_("cutoff")).unwrap();
patch.connect(vcf.out("lp"), output.in_("left")).unwrap();
patch.set_output(output.id());
patch.compile().unwrap();
println!("=== Subtractive Synthesis Demo ===\n");
let period_samples = (sample_rate / 261.63) as usize;
let mut samples: Vec<f64> = Vec::new();
for _ in 0..period_samples * 10 {
let (left, _) = patch.tick();
samples.push(left);
}
let peak = samples.iter().map(|s| s.abs()).fold(0.0_f64, f64::max);
let rms = (samples.iter().map(|s| s * s).sum::<f64>() / samples.len() as f64).sqrt();
println!("Sawtooth → Lowpass Filter");
println!(" Peak amplitude: {:.2}V", peak);
println!(" RMS level: {:.2}V", rms);
println!(" Samples generated: {}", samples.len());
let mut raw_patch = Patch::new(sample_rate);
let raw_vco = raw_patch.add("vco", Vco::new(sample_rate));
let raw_out = raw_patch.add("output", StereoOutput::new());
raw_patch
.connect(raw_vco.out("saw"), raw_out.in_("left"))
.unwrap();
raw_patch.set_output(raw_out.id());
raw_patch.compile().unwrap();
let mut raw_samples: Vec<f64> = Vec::new();
for _ in 0..period_samples * 10 {
let (left, _) = raw_patch.tick();
raw_samples.push(left);
}
let raw_peak = raw_samples.iter().map(|s| s.abs()).fold(0.0_f64, f64::max);
let raw_rms =
(raw_samples.iter().map(|s| s * s).sum::<f64>() / raw_samples.len() as f64).sqrt();
println!("\nRaw Sawtooth (unfiltered)");
println!(" Peak amplitude: {:.2}V", raw_peak);
println!(" RMS level: {:.2}V", raw_rms);
println!("\nThe filter has smoothed the waveform by removing high harmonics.");
println!("Notice the lower RMS - less high-frequency energy means a softer sound.");
let (wav_left, wav_right) = render(&mut patch, 2.0);
let to_full_scale = |buf: &[f64]| -> Vec<f64> { buf.iter().map(|s| s / 5.0).collect() };
let wav_path = Path::new("target/tutorial_subtractive.wav");
write_wav(
wav_path,
sample_rate as u32,
&to_full_scale(&wav_left),
&to_full_scale(&wav_right),
)
.expect("failed to write WAV file");
println!(
"\nWrote {} - play it to hear the filtered sawtooth!",
wav_path.display()
);
}