midip/src/osc.rs

112 lines
2.8 KiB
Rust

use portaudio as pa;
use std::f32::consts::PI;
use std::sync::mpsc::channel;
use std::sync::mpsc::Receiver;
use std::sync::mpsc::Sender;
use std::sync::Arc;
use vst::util::AtomicFloat;
const CHANNELS: i32 = 1;
const SAMPLE_RATE: f32 = 44_100.0;
const FRAMES_PER_BUFFER: u32 = 256;
pub struct Oscilador {
volume: f32,
frequencia: f32,
controlador_frequencia: Arc<AtomicFloat>,
controlador_volume: Arc<AtomicFloat>,
controlador_desligar: Sender<()>,
}
impl Oscilador {
pub fn novo() -> Self {
let volume = 0.2;
let frequencia = 0.0;
let frq = Arc::new(AtomicFloat::new(frequencia));
let controlador_frequencia = frq.clone();
let receptor_freq = frq.clone();
let vol = Arc::new(AtomicFloat::new(volume));
let controlador_volume = vol.clone();
let receptor_vol = vol.clone();
let (controlador_desligar, desligar) = channel();
std::thread::spawn(
move || match tocador(receptor_vol, receptor_freq, desligar) {
Ok(_) => {}
e => {
eprintln!("Example failed with the following: {:?}", e);
}
},
);
Oscilador {
volume,
frequencia,
controlador_frequencia,
controlador_volume,
controlador_desligar,
}
}
pub fn desligar(&self) {
let _ = self.controlador_desligar.send(());
}
pub fn frequencia(&self) -> f32 {
self.frequencia
}
pub fn volume(&self) -> f32 {
self.volume
}
pub fn setar_frequencia(&mut self, f: f32) {
self.frequencia = f;
self.controlador_frequencia.set(f);
}
pub fn setar_volume(&mut self, v: f32) {
self.volume = v;
self.controlador_volume.set(v);
}
}
fn tocador(
volume_geral: Arc<AtomicFloat>,
freq_controle: Arc<AtomicFloat>,
sinal_desligar: Receiver<()>,
) -> Result<(), pa::Error> {
let pa = pa::PortAudio::new()?;
let mut settings =
pa.default_output_stream_settings(CHANNELS, SAMPLE_RATE as f64, FRAMES_PER_BUFFER)?;
settings.flags = pa::stream_flags::CLIP_OFF;
let mut fase = 0.0;
let mut prox_sample = move || {
let step = ((*freq_controle).get() * 2.0 * PI) as f32 / SAMPLE_RATE;
fase = (fase + 1.0) % SAMPLE_RATE;
return (fase * step).sin() as f32;
};
let callback = move |pa::OutputStreamCallbackArgs { buffer, frames, .. }| {
let mut idx = 0;
for _ in 0..frames {
buffer[idx] = prox_sample() * volume_geral.get();
idx += 1;
}
pa::Continue
};
let mut stream = pa.open_non_blocking_stream(settings, callback)?;
stream.start()?;
sinal_desligar.recv().unwrap();
stream.stop()?;
stream.close()?;
Ok(())
}