#![feature(proc_macro)]
extern crate tuple;
extern crate jack;
extern crate termion;
extern crate math_traits;
extern crate bullet_macros;
use bullet_macros::math;
use tuple::T2;
use math_traits::Real;
use std::sync::mpsc::channel;
use termion::event::Key;
use termion::input::TermRead;
use jack::client::{Client, ClientOptions, ClosureProcessHandler, ProcessScope, AsyncClient};
use jack::port::{AudioInSpec, AudioOutSpec, AudioOutPort, AudioInPort};
use jack::jack_enums::JackControl;
#[derive(Copy, Clone)]
struct DuffingParams {
epsilon: f32,
lambda: f32,
omega: f32,
alpha: f32,
beta: f32
}
impl Default for DuffingParams {
fn default() -> DuffingParams {
DuffingParams {
epsilon: 7.72,
lambda: 0.2,
omega: 1.0,
alpha: 0.1,
beta: 1.0
}
}
}
fn main() {
let (tx, rx) = channel();
let (client, _) = Client::new("Duffing", ClientOptions::empty()).unwrap();
let port_in = client.register_port("duffing_in", AudioInSpec).unwrap();
let mut port_out_x = client.register_port("duffing_out_x", AudioOutSpec).unwrap();
let mut port_out_y = client.register_port("duffing_out_y", AudioOutSpec).unwrap();
let dt = 880.0 / (client.sample_rate() as f32);
let mut x = T2(0.2, 0.2);
let mut p = DuffingParams::default();
let scale = 20.;
let scale_inv = 1.0 / scale;
let process = ClosureProcessHandler::new(move |_: &Client, ps: &ProcessScope| {
if let Ok(params) = rx.try_recv() {
p = params;
}
let mut port_out_x = AudioOutPort::new(&mut port_out_x, ps);
let mut port_out_y = AudioOutPort::new(&mut port_out_y, ps);
let port_in = AudioInPort::new(&port_in, ps);
for (&sample_in, sample_out) in port_in.iter().zip(T2(port_out_x.iter_mut(), port_out_y.iter_mut())) {
let drive = sample_in * scale;
let dx_dt = T2(
x.1,
p.epsilon * drive - p.lambda * x.1 - x.0 * (p.alpha + (x.0 * x.0 * p.beta))
);
x += dx_dt * dt;
*sample_out.0 = (x.0 * scale_inv).clamp(-1.0, 1.0);
*sample_out.1 = (x.1 * scale_inv).clamp(-1.0, 1.0);
}
JackControl::Continue
});
let _active_client = AsyncClient::new(client, (), process).unwrap();
let stdin = std::io::stdin();
let mut params = DuffingParams::default();
let update = |p: &mut DuffingParams, idx, fac| {
{
let f = match idx {
0 => &mut p.epsilon,
1 => &mut p.lambda,
2 => &mut p.omega,
3 => &mut p.alpha,
4 => &mut p.beta,
_ => panic!()
};
*f *= fac;
}
println!(
"epsilon: {:6.4} lambda: {:6.4} omega: {:6.4} alpha: {:6.4} beta: {:6.4}\r",
p.epsilon, p.lambda, p.omega, p.alpha, p.beta
);
tx.send(*p).unwrap();
};
let mut idx = 0;
for evt in stdin.keys() {
match evt.unwrap() {
Key::Char('1') => idx = 0,
Key::Char('2') => idx = 1,
Key::Char('3') => idx = 2,
Key::Char('4') => idx = 3,
Key::Char('5') => idx = 4,
Key::Up => update(&mut params, idx, 1.1),
Key::Down => update(&mut params, idx, 1.0 / 1.1),
Key::Esc => break,
Key::Char('q') => break,
_ => ()
}
let name = match idx {
0 => "epsilon",
1 => "lambda",
2 => "omega",
3 => "alpha",
4 => "beta",
_ => panic!()
};
println!("selected: {}\r", name);
}
}