1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
|
// use gdnative::api::Resource;
use gdnative::prelude::*;
#[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) {
match test::test() {
Ok(()) => godot_print!("POOOP"),
Err(error) => godot_print!("SHITE! {:?}", error),
};
}
}
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(())
}
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
}
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
fn init(handle: InitHandle) {
// Register the `Synth` type we declared.
handle.add_class::<Synth>();
}
// Macro that creates the entry-points of the dynamic library.
godot_init!(init);
|