diff options
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | klangfarbrs/Cargo.toml | 3 | ||||
-rw-r--r-- | klangfarbrs/src/lib.rs | 156 | ||||
-rw-r--r-- | klangfarbrs/src/main.rs | 5 |
4 files changed, 88 insertions, 77 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0fa3499 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/klangfarbrs/target/ diff --git a/klangfarbrs/Cargo.toml b/klangfarbrs/Cargo.toml index 14d2e64..10988cf 100644 --- a/klangfarbrs/Cargo.toml +++ b/klangfarbrs/Cargo.toml @@ -6,7 +6,8 @@ edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [lib] -crate-type = ["cdylib"] +crate-type = ["cdylib", "lib"] +name = "klangfarbrs" [dependencies] gdnative = "0.9" diff --git a/klangfarbrs/src/lib.rs b/klangfarbrs/src/lib.rs index 2dbc299..0da53b2 100644 --- a/klangfarbrs/src/lib.rs +++ b/klangfarbrs/src/lib.rs @@ -1,10 +1,5 @@ use gdnative::api::Resource; use gdnative::prelude::*; -use cpal; -use cpal::traits::{DeviceTrait, HostTrait, StreamTrait}; -use dasp::{Sample}; -use dasp_signal::{self as signal, Signal}; -use std::sync::mpsc; /// The HelloWorld "class" #[derive(NativeClass)] @@ -49,86 +44,95 @@ impl Synth { #[export] fn _ready(&self, _owner: &Node) { godot_print!("POOOP"); - play(); + test::test(); } } -fn play() -> Result<(), anyhow::Error> { - let host = cpal::default_host(); - let device = host - .default_output_device() - .expect("failed to find a default output device"); - let config = device.default_output_config()?; - - match config.sample_format() { - cpal::SampleFormat::F32 => run::<f32>(&device, &config.into())?, - cpal::SampleFormat::I16 => run::<i16>(&device, &config.into())?, - cpal::SampleFormat::U16 => run::<u16>(&device, &config.into())?, - } +pub mod test { + use cpal; + use cpal::traits::{DeviceTrait, HostTrait, StreamTrait}; + use dasp::{Sample}; + use dasp_signal::{self as signal, Signal}; + use std::sync::mpsc; + + pub fn test() -> Result<(), anyhow::Error> { + let host = cpal::default_host(); + let device = host + .default_output_device() + .expect("failed to find a default output device"); + let config = device.default_output_config()?; + + match config.sample_format() { + cpal::SampleFormat::F32 => run::<f32>(&device, &config.into())?, + cpal::SampleFormat::I16 => run::<i16>(&device, &config.into())?, + cpal::SampleFormat::U16 => run::<u16>(&device, &config.into())?, + } - Ok(()) -} + Ok(()) + } -fn run<T>(device: &cpal::Device, config: &cpal::StreamConfig) -> Result<(), anyhow::Error> -where - T: cpal::Sample, -{ - // Create a signal chain to play back 1 second of each oscillator at A4. - let hz = signal::rate(config.sample_rate.0 as f64).const_hz(440.0); - let one_sec = config.sample_rate.0 as usize; - let mut synth = hz - .clone() - .sine() - .take(one_sec) - .chain(hz.clone().saw().take(one_sec)) - .chain(hz.clone().square().take(one_sec)) - .chain(hz.clone().noise_simplex().take(one_sec)) - .chain(signal::noise(0).take(one_sec)) - .map(|s| s.to_sample::<f32>() * 0.2); - - // A channel for indicating when playback has completed. - let (complete_tx, complete_rx) = mpsc::sync_channel(1); - - // Create and run the stream. - let err_fn = |err| eprintln!("an error occurred on stream: {}", err); - let channels = config.channels as usize; - let stream = device.build_output_stream( - config, - move |data: &mut [T], _: &cpal::OutputCallbackInfo| { - write_data(data, channels, &complete_tx, &mut synth) - }, - err_fn, - )?; - stream.play()?; - - // Wait for playback to complete. - complete_rx.recv().unwrap(); - stream.pause()?; - - Ok(()) -} + fn run<T>(device: &cpal::Device, config: &cpal::StreamConfig) -> Result<(), anyhow::Error> + where + T: cpal::Sample, + { + // Create a signal chain to play back 1 second of each oscillator at A4. + let hz = signal::rate(config.sample_rate.0 as f64).const_hz(440.0); + let one_sec = config.sample_rate.0 as usize; + let mut synth = hz + .clone() + .sine() + .take(one_sec) + .chain(hz.clone().saw().take(one_sec)) + .chain(hz.clone().square().take(one_sec)) + .chain(hz.clone().noise_simplex().take(one_sec)) + .chain(signal::noise(0).take(one_sec)) + .map(|s| s.to_sample::<f32>() * 0.2); + + // A channel for indicating when playback has completed. + let (complete_tx, complete_rx) = mpsc::sync_channel(1); + + // Create and run the stream. + let err_fn = |err| eprintln!("an error occurred on stream: {}", err); + let channels = config.channels as usize; + let stream = device.build_output_stream( + config, + move |data: &mut [T], _: &cpal::OutputCallbackInfo| { + write_data(data, channels, &complete_tx, &mut synth) + }, + err_fn, + )?; + stream.play()?; + + // Wait for playback to complete. + complete_rx.recv().unwrap(); + stream.pause()?; + + Ok(()) + } -fn write_data<T>( - output: &mut [T], - channels: usize, - complete_tx: &mpsc::SyncSender<()>, - signal: &mut dyn Iterator<Item = f32>, -) where - T: cpal::Sample, -{ - for frame in output.chunks_mut(channels) { - let sample = match signal.next() { - None => { - complete_tx.try_send(()).ok(); - 0.0 + fn write_data<T>( + output: &mut [T], + channels: usize, + complete_tx: &mpsc::SyncSender<()>, + signal: &mut dyn Iterator<Item = f32>, + ) where + T: cpal::Sample, + { + for frame in output.chunks_mut(channels) { + let sample = match signal.next() { + None => { + complete_tx.try_send(()).ok(); + 0.0 + } + Some(sample) => sample, + }; + let value: T = cpal::Sample::from::<f32>(&sample); + for sample in frame.iter_mut() { + *sample = value; } - Some(sample) => sample, - }; - let value: T = cpal::Sample::from::<f32>(&sample); - for sample in frame.iter_mut() { - *sample = value; } } + } // Function that registers all exposed classes to Godot diff --git a/klangfarbrs/src/main.rs b/klangfarbrs/src/main.rs new file mode 100644 index 0000000..066cd9d --- /dev/null +++ b/klangfarbrs/src/main.rs @@ -0,0 +1,5 @@ +use klangfarbrs::test::test; + +fn main() { + test(); +} |