112 lines
2.8 KiB
Rust
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(())
|
|
}
|