use rodio;
use rodio::Endpoint;
use rodio::Sink;
use rodio::source;
use rodio::buffer::SamplesBuffer;
use rodio::Source;
use std::thread;
use std::time::Duration;
use std::f32::consts::PI;
use rand::random;
pub enum Wave {
Sine,
Square,
Saw,
Noise,
}
pub struct Audact {
endpoint: Endpoint,
channels: Vec<(Sink, Vec<i32>)>,
steps: i32,
bpm_duration: Duration,
}
impl Audact {
pub fn new(steps:i32, bpm:i32, per_bar:f32) -> Audact {
let endpoint = rodio::get_default_endpoint().unwrap();
Audact {
endpoint: endpoint,
channels: Vec::new(),
steps: steps,
bpm_duration: Duration::from_millis((((60f32 / bpm as f32) * 1000f32) / per_bar) as u64),
}
}
fn sine_wave(t:f32) -> f32 {
t.sin()
}
fn square_wave(t:f32) -> f32 {
t.sin().round()
}
fn saw_wave(t:f32) -> f32 {
t - t.floor()
}
fn noise_wave(_:f32) -> f32 {
(random::<f32>() * 2f32) - 1f32
}
pub fn channel(&mut self, freq: f32, wave: Wave, volume: f32,
filter: (f32, f32), seq: Vec<i32>) {
let sink = Sink::new(&self.endpoint);
let wave = match wave {
Wave::Sine => Audact::sine_wave,
Wave::Square => Audact::square_wave,
Wave::Saw => Audact::saw_wave,
Wave::Noise => Audact::noise_wave,
};
let (_, lp) = filter;
let samples_rate = 44100f32;
let data_source = (0u64..).map(move |t| {
let freq = t as f32 * freq * PI / samples_rate; let sample = wave(freq);
SamplesBuffer::new(2, samples_rate as u32, vec![sample])
});
let source = source::from_iter(data_source);
sink.append(source.low_pass(lp as u32)
.amplify(volume));
sink.pause();
self.channels.push((sink, seq));
}
pub fn start(audact:Audact, bars: i32) {
let steps = audact.steps;
let bpm_duration = audact.bpm_duration;
let tmp_voice_channels = audact.channels;
let handle = thread::spawn(move || {
for _ in 0 .. bars {
for step in 0 .. steps {
for i in 0 .. tmp_voice_channels.len() {
if let Ok(_) = tmp_voice_channels[i].1.binary_search(&step) {
tmp_voice_channels[i].0.play();
} else {
tmp_voice_channels[i].0.pause();
}
}
thread::sleep(bpm_duration);
}
}
for i in 0 .. tmp_voice_channels.len() {
tmp_voice_channels[i].0.stop();
}
});
let _ = handle.join().unwrap();
}
}