rust_audio_api/nodes/
oscillator.rs1use crate::types::AudioUnit;
2use dasp::signal::{self, Signal};
3use ringbuf::storage::Heap;
4use ringbuf::traits::{Consumer, Observer, Producer, Split};
5use ringbuf::wrap::caching::Caching;
6use ringbuf::{HeapRb, SharedRb};
7use std::sync::Arc;
8use std::sync::atomic::{AtomicBool, Ordering};
9use std::thread;
10use std::time::Duration;
11
12pub struct OscillatorNode {
18 consumer: Caching<Arc<SharedRb<Heap<[f32; 2]>>>, false, true>,
19 gain: f32,
20 _running: Arc<AtomicBool>,
21}
22
23impl OscillatorNode {
24 pub fn new(sample_rate: f64, frequency: f64) -> Self {
30 let capacity = (sample_rate * 0.5) as usize;
32 let ringbuf = HeapRb::<[f32; 2]>::new(capacity);
33 let (mut producer, consumer) = ringbuf.split();
34
35 let running = Arc::new(AtomicBool::new(true));
36 let running_clone = running.clone();
37
38 thread::spawn(move || {
39 let mut sig = signal::rate(sample_rate).const_hz(frequency).sine();
40 while running_clone.load(Ordering::Relaxed) {
41 if producer.is_full() {
43 thread::sleep(Duration::from_millis(5));
44 continue;
45 }
46
47 let sample = sig.next() as f32;
48 let frame = [sample, sample];
49 let _ = producer.try_push(frame); }
51 });
52
53 Self {
54 consumer,
55 gain: 1.0,
56 _running: running,
57 }
58 }
59
60 pub fn set_gain(&mut self, gain: f32) {
62 self.gain = gain;
63 }
64
65 #[inline(always)]
67 pub fn process(&mut self, _input: Option<&AudioUnit>, output: &mut AudioUnit) {
68 dasp::slice::map_in_place(&mut output[..], |_| {
69 if let Some(sample) = self.consumer.try_pop() {
70 [sample[0] * self.gain, sample[1] * self.gain]
71 } else {
72 [0.0, 0.0]
73 }
74 });
75 }
76}
77
78impl Drop for OscillatorNode {
79 fn drop(&mut self) {
80 self._running.store(false, Ordering::Relaxed);
81 }
82}