use gdnative::api::Resource; use gdnative::prelude::*; /// The HelloWorld "class" #[derive(NativeClass)] #[inherit(Node)] pub struct HelloWorld; #[methods] impl HelloWorld { fn new(_owner: &Node) -> Self { HelloWorld } #[export] fn _ready(&self, _owner: &Node) { // The `godot_print!` macro works like `println!` but prints to the Godot-editor // output tab as well. godot_print!("Hello, world!"); } } #[derive(NativeClass)] #[inherit(Node)] pub struct Synth { frequency: f32 } #[methods] impl Synth { fn new(_owner: &Node) -> Self { Synth { frequency: 220.0 } } #[export] fn set_freq( &mut self, _owner: &Node, freq: f32 ) { self.frequency = freq; } #[export] fn _ready(&self, _owner: &Node) { godot_print!("POOOP"); test::test(); } } 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::(&device, &config.into())?, cpal::SampleFormat::I16 => run::(&device, &config.into())?, cpal::SampleFormat::U16 => run::(&device, &config.into())?, } Ok(()) } fn run(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::() * 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( output: &mut [T], channels: usize, complete_tx: &mpsc::SyncSender<()>, signal: &mut dyn Iterator, ) 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::(&sample); for sample in frame.iter_mut() { *sample = value; } } } } // Function that registers all exposed classes to Godot fn init(handle: InitHandle) { // Register the new `HelloWorld` type we just declared. handle.add_class::(); handle.add_class::(); } // Macro that creates the entry-points of the dynamic library. godot_init!(init);