extern crate dsp;
extern crate portaudio;
use dsp::{Graph, Node, Frame, FromSample, Sample, Walker};
use dsp::sample::ToFrameSliceMut;
use portaudio as pa;
type Output = f32;
type Phase = f64;
type Frequency = f64;
type Volume = f32;
const CHANNELS: usize = 2;
const FRAMES: u32 = 64;
const SAMPLE_HZ: f64 = 44_100.0;
const A5_HZ: Frequency = 440.0;
const D5_HZ: Frequency = 587.33;
const F5_HZ: Frequency = 698.46;
fn main() {
run().unwrap()
}
fn run() -> Result<(), pa::Error> {
let mut graph = Graph::new();
let synth = graph.add_node(DspNode::Synth);
let (_, oscillator_a) = graph.add_input(DspNode::Oscillator(0.0, A5_HZ, 0.2), synth);
graph.add_input(DspNode::Oscillator(0.0, D5_HZ, 0.1), synth);
graph.add_input(DspNode::Oscillator(0.0, F5_HZ, 0.15), synth);
if let Err(err) = graph.add_connection(synth, oscillator_a) {
println!("Testing for cycle error: {:?}", ::std::error::Error::description(&err));
}
graph.set_master(Some(synth));
let mut timer: f64 = 3.0;
let mut prev_time = None;
let callback = move |pa::OutputStreamCallbackArgs { buffer, time, .. }| {
let buffer: &mut [[Output; CHANNELS]] = buffer.to_frame_slice_mut().unwrap();
dsp::slice::equilibrium(buffer);
graph.audio_requested(buffer, SAMPLE_HZ);
let last_time = prev_time.unwrap_or(time.current);
let dt = time.current - last_time;
timer -= dt;
prev_time = Some(time.current);
let mut inputs = graph.inputs(synth);
while let Some(input_idx) = inputs.next_node(&graph) {
if let DspNode::Oscillator(_, ref mut pitch, _) = graph[input_idx] {
*pitch -= 0.1;
}
}
if timer >= 0.0 { pa::Continue } else { pa::Complete }
};
let pa = try!(pa::PortAudio::new());
let settings = try!(pa.default_output_stream_settings::<Output>(CHANNELS as i32, SAMPLE_HZ, FRAMES));
let mut stream = try!(pa.open_non_blocking_stream(settings, callback));
try!(stream.start());
while let true = try!(stream.is_active()) {
::std::thread::sleep(::std::time::Duration::from_millis(16));
}
Ok(())
}
#[derive(Debug)]
enum DspNode {
Synth,
Oscillator(Phase, Frequency, Volume),
}
impl Node<[Output; CHANNELS]> for DspNode {
fn audio_requested(&mut self, buffer: &mut [[Output; CHANNELS]], sample_hz: f64) {
match *self {
DspNode::Synth => (),
DspNode::Oscillator(ref mut phase, frequency, volume) => {
dsp::slice::map_in_place(buffer, |_| {
let val = sine_wave(*phase, volume);
*phase += frequency / sample_hz;
Frame::from_fn(|_| val)
});
},
}
}
}
fn sine_wave<S: Sample>(phase: Phase, volume: Volume) -> S
where S: Sample + FromSample<f32>,
{
use std::f64::consts::PI;
((phase * PI * 2.0).sin() as f32 * volume).to_sample::<S>()
}