diff --git a/knyst/examples/cpal_example.rs b/knyst/examples/cpal_example.rs deleted file mode 100644 index 954cd6f..0000000 --- a/knyst/examples/cpal_example.rs +++ /dev/null @@ -1,68 +0,0 @@ -use anyhow::Result; -use knyst::{ - audio_backend::{CpalBackend, CpalBackendOptions}, - controller::{print_error_handler, KnystCommands}, - graph::Mult, - prelude::*, -}; -use std::time::Duration; - -fn main() -> Result<()> { - let mut backend = CpalBackend::new(CpalBackendOptions::default())?; - - let sample_rate = backend.sample_rate() as Sample; - let block_size = backend.block_size().unwrap_or(64); - let resources = Resources::new(ResourcesSettings { - ..Default::default() - }); - let graph: Graph = Graph::new(GraphSettings { - block_size, - sample_rate, - num_outputs: backend.num_outputs(), - ..Default::default() - }); - let mut k = backend - .start_processing( - graph, - resources, - RunGraphSettings { - scheduling_latency: Duration::from_millis(100), - }, - Box::new(print_error_handler), - ) - .unwrap(); - let node0 = k.push( - WavetableOscillatorOwned::new(Wavetable::sine()), - inputs!(("freq" : 440.)), - ); - let modulator = k.push( - WavetableOscillatorOwned::new(Wavetable::sine()), - inputs!(("freq" : 5.)), - ); - let mod_amp = k.push(Mult, inputs!((0 ; modulator.out(0)), (1 : 0.25))); - let amp = k.push( - Mult, - inputs!((0 ; node0.out(0)), (1 : 0.5 ; mod_amp.out(0))), - ); - k.connect(amp.to_graph_out()); - k.connect(amp.to_graph_out().to_index(1)); - - let mut input = String::new(); - loop { - match std::io::stdin().read_line(&mut input) { - Ok(n) => { - println!("{} bytes read", n); - println!("{}", input.trim()); - let input = input.trim(); - if let Ok(freq) = input.parse::() { - k.schedule_change(ParameterChange::now(node0.input("freq"), freq as Sample)); - } else if input == "q" { - break; - } - } - Err(error) => println!("error: {}", error), - } - input.clear(); - } - Ok(()) -} diff --git a/knyst/examples/modal_example.rs b/knyst/examples/more_advanced_example.rs similarity index 94% rename from knyst/examples/modal_example.rs rename to knyst/examples/more_advanced_example.rs index 34d82ae..c049bab 100644 --- a/knyst/examples/modal_example.rs +++ b/knyst/examples/more_advanced_example.rs @@ -29,10 +29,14 @@ fn main() -> Result<()> { 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(), || {}); + // Nothing is passed into the delay until now. Pass any output of the "outer_graph" into the delay. delay.input(outer_graph); + // Make the "outer_graph" the active graph, meaning any new nodes are pushed to it. outer_graph.activate(); let mut rng = thread_rng(); + // Create a node for the frequency value so that this value can be changed once and + // propagated to many other nodes. let freq_var = bus(1).set(0, 440.); for _ in 0..10 { let freq = (sine().freq( @@ -45,7 +49,6 @@ fn main() -> Result<()> { .range(0.0, 400.), ) * 100.0) + freq_var; - // let freq = sine().freq(0.5).range(200.0, 200.0 * 9.0 / 8.0); let node0 = sine(); node0.freq(freq); let modulator = sine(); diff --git a/knyst/examples/jack_example.rs b/knyst/examples/simple_example.rs similarity index 66% rename from knyst/examples/jack_example.rs rename to knyst/examples/simple_example.rs index d41920e..e5cbdf5 100644 --- a/knyst/examples/jack_example.rs +++ b/knyst/examples/simple_example.rs @@ -1,13 +1,22 @@ use anyhow::Result; -use knyst::{audio_backend::JackBackend, controller::print_error_handler, prelude::*}; +#[allow(unused)] +use knyst::{ + audio_backend::{CpalBackend, CpalBackendOptions, JackBackend}, + controller::print_error_handler, + prelude::*, +}; fn main() -> Result<()> { - let mut backend = JackBackend::new("Knyst<3JACK")?; + let mut backend = CpalBackend::new(CpalBackendOptions::default())?; + // Uncomment the line below and comment the line above to use the JACK backend instead + // let mut backend = JackBackend::new("Knyst<3JACK")?; let sample_rate = backend.sample_rate() as Sample; let block_size = backend.block_size().unwrap_or(64); println!("sr: {sample_rate}, block: {block_size}"); + // Start with an automatic helper thread for scheduling changes and managing resources. + // If you want to manage the `Controller` yourself, use `start_return_controller`. let _sphere = KnystSphere::start( &mut backend, SphereSettings { @@ -22,11 +31,14 @@ fn main() -> Result<()> { // We can also use a shared wavetable oscillator which reads its wavetable from `Resources`. A cosine wavetable // is created by default. let modulator = oscillator(WavetableId::cos()).freq(5.); - + // Output to the zeroth (left) channel graph_output(0, node0 * (modulator * 0.25 + 0.5)); let node1 = wavetable_oscillator_owned(Wavetable::sine()).freq(220.); let modulator = oscillator(WavetableId::cos()).freq(3.); + // Output a different sound to the first (right) channel graph_output(1, node1 * (modulator * 0.25 + 0.5)); + + // Respond to user input. This kind of interaction can be put in a different thread and/or in an async runtime. let mut input = String::new(); loop { match std::io::stdin().read_line(&mut input) { diff --git a/knyst/examples/sound_file_playback.rs b/knyst/examples/sound_file_playback.rs index eb2aaf9..3129dcb 100644 --- a/knyst/examples/sound_file_playback.rs +++ b/knyst/examples/sound_file_playback.rs @@ -3,19 +3,23 @@ use std::time::Duration; use knyst::{ audio_backend::{CpalBackend, CpalBackendOptions}, - controller, + controller::print_error_handler, + knyst_commands, prelude::*, }; fn main() -> anyhow::Result<()> { - // Create the backend to get the backend settings needed to create a Graph with the correct block size and sample rate etc. let mut backend = CpalBackend::new(CpalBackendOptions::default())?; - - let sample_rate = backend.sample_rate() as Sample; - let block_size = backend.block_size().unwrap_or(64); - let mut resources = Resources::new(ResourcesSettings { - ..Default::default() - }); + // let mut backend = JackBackend::new("Knyst<3JACK")?; + let _sphere = KnystSphere::start( + &mut backend, + SphereSettings { + num_inputs: 0, + num_outputs: 2, + ..Default::default() + }, + print_error_handler, + ); // Get file path to a sound file from the user let file_path = dialog::FileSelection::new("Please select an audio file") @@ -24,36 +28,19 @@ fn main() -> anyhow::Result<()> { .expect("Could not display dialog box") .unwrap(); // Insert the buffer before sending Resources to the audio thread - let buffer = resources.insert_buffer(Buffer::from_sound_file(file_path)?)?; - - let graph_settings = GraphSettings { - block_size, - sample_rate, - num_outputs: backend.num_outputs(), - ..Default::default() - }; - println!("{graph_settings:#?}"); - // Create the Graph with the settings above - let g: Graph = Graph::new(graph_settings); - // The backend will split the Graph into two - let mut k = backend.start_processing( - g, - resources, - RunGraphSettings::default(), - Box::new(controller::print_error_handler), - )?; + let sound_buffer = Buffer::from_sound_file(file_path)?; + let channels = sound_buffer.num_channels(); + let buffer = knyst_commands().insert_buffer(sound_buffer); // Create a node which reads the buffer we inserted earlier and plays it back // `channels(2)` means we are expecting a stereo buffer // `looping(false)` means the buffer will not be looped - let buf_playback_node = k.push( - BufferReaderMulti::new(buffer, 1.0, StopAction::FreeSelf) - .channels(2) - .looping(true), - inputs!(), - ); - // Connect the buffer to the outputs. - k.connect(buf_playback_node.to_graph_out().channels(2)); + let buf_playback_node = BufferReaderMulti::new(buffer, 1.0, StopAction::FreeSelf) + .channels(channels) + .looping(true) + .upload(); + // Connect the buffer to the outputs, connecting 2 channels (a mono buffer will be played in both the left and right channels) + graph_output(0, buf_playback_node.channels(2)); println!("Playing back sound for 10 seconds"); std::thread::sleep(Duration::from_millis(10000)); diff --git a/knyst/src/gen/osc.rs b/knyst/src/gen/osc.rs index 86ae89e..95c3548 100644 --- a/knyst/src/gen/osc.rs +++ b/knyst/src/gen/osc.rs @@ -276,6 +276,15 @@ impl BufferReaderMulti { self.read_pointer = new_pointer_pos; self.finished = false; } + /// Upload to the current graph, returning a handle to the new node + pub fn upload(self) -> knyst::handles::Handle { + let num_channels = self.num_channels; + let id = knyst::prelude::KnystCommands::push_without_inputs(&mut knyst_commands(), self); + knyst::handles::Handle::new(BufferReaderMultiHandle { + node_id: id, + num_channels, + }) + } } impl Gen for BufferReaderMulti {