use rodio::source::{SineWave, Source};
use rodio::{OutputStream, OutputStreamHandle, Sink};
use std::time::Duration;
use structopt::StructOpt;
use tixonome::{is_bpb_valid, is_bpm_valid, Opt};
#[macro_use]
extern crate die;
const MINIMUM_BPM: u32 = 40;
const MAXIMUM_BPM: u32 = 180;
const MINIMUM_BPB: u8 = 2;
const MAXIMUM_BPB: u8 = 4;
fn main() {
let (_stream, stream_handle) = OutputStream::try_default().unwrap_or_else(|error| {
die!("Cannot open output stream.\n More info: {}", error);
});
run(Opt::from_args(), &stream_handle);
}
fn play_sound(stream_handle: &OutputStreamHandle, is_accent: bool) {
let low_pitch = 440;
let amplification = 0.20;
let beep_duration = 0.050;
let sink = Sink::try_new(stream_handle).unwrap_or_else(|error| {
die!("Cannot open sink stream!\n More info: {}", error);
});
let small_hertz_leap = 40;
let medium_pitch = low_pitch + small_hertz_leap;
let source = SineWave::new(match is_accent {
true => medium_pitch,
_ => low_pitch,
})
.take_duration(Duration::from_secs_f32(beep_duration))
.amplify(amplification);
sink.append(source);
sink.sleep_until_end();
}
fn run(opt: Opt, stream_handle: &OutputStreamHandle) {
if !is_bpm_valid(&opt, MINIMUM_BPM, MAXIMUM_BPM) {
die!(
"Beats per minute must be in range of {} to {}",
MINIMUM_BPM,
MAXIMUM_BPM
);
}
if !is_bpb_valid(&opt, MINIMUM_BPB, MAXIMUM_BPB) {
die!(
"Beats per bar must be in range of {} to {}",
MINIMUM_BPB,
MAXIMUM_BPB
);
}
let minute = 60.0;
let duration = minute / opt.beats_per_minute as f32;
let mut counter: u8 = 0;
println!("Ctrl+C to quit");
loop {
counter += 1;
if counter % opt.beats_per_bar as u8 != 0 {
play_sound(stream_handle, false);
} else {
play_sound(stream_handle, true);
counter = 0;
}
std::thread::sleep(Duration::from_secs_f32(duration));
}
}