tixonome 0.3.2

A simple CLI metronome in Rust
Documentation
/*  Copyright (c) 2021, Momozor <momozor4@gmail.com>
 *  All rights reserved.
 *
 *  This source code is licensed under the BSD-style license found in the
 *  LICENSE file in the root directory of this source tree.
 */

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));
    }
}