use anyhow::Result;
use knyst::gen::delay::allpass_feedback_delay;
#[allow(unused)]
use knyst::{
audio_backend::{CpalBackend, CpalBackendOptions, JackBackend},
controller::print_error_handler,
envelope::Envelope,
handles::{graph_output, handle, Handle},
modal_interface::knyst_commands,
prelude::{delay::static_sample_delay, *},
sphere::{KnystSphere, SphereSettings},
};
use rand::{thread_rng, Rng};
fn main() -> Result<()> {
let mut backend =
CpalBackend::new(CpalBackendOptions::default()).expect("Unable to connect to CPAL backend");
let _sphere = KnystSphere::start(
&mut backend,
SphereSettings {
num_inputs: 0,
num_outputs: 2,
..Default::default()
},
print_error_handler,
);
let delay = allpass_feedback_delay(48000).feedback(0.9).delay_time(0.23);
graph_output(0, (delay + static_sample_delay(87).input(delay)) * 0.5);
graph_output(1, (delay + static_sample_delay(62).input(delay)) * 0.5);
let outer_graph = upload_graph(knyst_commands().default_graph_settings(), || {});
delay.input(outer_graph);
outer_graph.activate();
let mut rng = thread_rng();
let freq_var = bus(1).set(0, 440.);
for _ in 0..10 {
let freq = (sine().freq(
sine()
.freq(
sine()
.freq(0.01)
.range(0.02, rng.gen_range(0.05..0.3 as Sample)),
)
.range(0.0, 400.),
) * 100.0)
+ freq_var;
let node0 = sine();
node0.freq(freq);
let modulator = sine();
modulator.freq(sine().freq(0.09) * -5.0 + 6.0);
graph_output(0, (node0 * modulator * 0.025).repeat_outputs(1));
}
std::thread::spawn(move || {
outer_graph.activate();
for &ratio in [1.0, 1.5, 5. / 4.].iter().cycle() {
let graph = upload_graph(
knyst_commands().default_graph_settings().num_inputs(1),
|| {
let freq_var = graph_input(0, 1);
let sig = sine().freq(freq_var * ratio).out("sig") * 0.25;
let env = Envelope {
points: vec![(1.0, 0.005), (0.0, 0.5)],
stop_action: StopAction::FreeGraph,
..Default::default()
};
let sig = sig * handle(env.to_gen());
graph_output(0, sig.repeat_outputs(1));
},
);
graph.set(0, freq_var);
outer_graph.activate();
let sig = graph + static_sample_delay(48 * 500).input(graph.out(0));
graph_output(0, sig.repeat_outputs(1));
std::thread::sleep(std::time::Duration::from_millis(2500));
}
});
std::thread::spawn(move || {
outer_graph.activate();
loop {
for &ratio in [1.0, 5. / 4., 1.5, 7. / 4., 2., 17. / 8.].iter() {
let graph = upload_graph(
knyst_commands().default_graph_settings().num_inputs(1),
|| {
let freq_var = graph_input(0, 1);
let sig = sine().freq(freq_var * ratio).out("sig") * 0.25;
let env = Envelope {
points: vec![(1.0, 0.005), (0.0, 0.5)],
stop_action: StopAction::FreeGraph,
..Default::default()
};
let sig = sig * handle(env.to_gen());
graph_output(0, sig.repeat_outputs(1));
},
);
graph.set(0, freq_var);
outer_graph.activate();
graph_output(0, graph.repeat_outputs(1) * 0.3);
std::thread::sleep(std::time::Duration::from_millis(250));
}
std::thread::sleep(std::time::Duration::from_millis(3500));
}
});
let mut input = String::new();
loop {
println!("Input a frequency for the root note, or 'q' to quit: ");
match std::io::stdin().read_line(&mut input) {
Ok(_n) => {
let input = input.trim();
if let Ok(freq) = input.parse::<f32>() {
println!("New freq: {}", input.trim());
freq_var.set(0, freq as Sample);
} else if input == "q" {
break;
}
}
Err(error) => println!("error: {}", error),
}
input.clear();
}
Ok(())
}
fn sine() -> Handle<OscillatorHandle> {
oscillator(WavetableId::cos())
}