use std::{
sync::{Arc, Mutex},
thread::sleep,
time::Duration,
};
use clap::{Arg, ArgMatches};
use log::error;
use proteus_audio::{player, reporter::Report, test_data};
use rand::Rng;
use symphonia::core::errors::Result;
fn main() {
let args = clap::Command::new("Prot Play")
.version("1.0")
.author("Adam Howard <adam.thomas.howard@gmail.com>")
.about("Play Prot audio")
.arg(
Arg::new("seek")
.long("seek")
.short('s')
.value_name("TIME")
.help("Seek to the given time in seconds")
.conflicts_with_all(&["verify", "decode-only", "verify-only", "probe-only"]),
)
.arg(
Arg::new("GAIN")
.long("gain")
.short('g')
.value_name("GAIN")
.default_value("70")
.help("The playback gain"),
)
.arg(
Arg::new("decode-only")
.long("decode-only")
.help("Decode, but do not play the audio")
.conflicts_with_all(&["probe-only", "verify-only", "verify"]),
)
.arg(
Arg::new("probe-only")
.long("probe-only")
.help("Only probe the input for metadata")
.conflicts_with_all(&["decode-only", "verify-only"]),
)
.arg(
Arg::new("verify-only")
.long("verify-only")
.help("Verify the decoded audio is valid, but do not play the audio")
.conflicts_with_all(&["verify"]),
)
.arg(
Arg::new("verify")
.long("verify")
.short('v')
.help("Verify the decoded audio is valid during playback"),
)
.arg(
Arg::new("no-progress")
.long("no-progress")
.help("Do not display playback progress"),
)
.arg(
Arg::new("no-gapless")
.long("no-gapless")
.help("Disable gapless decoding and playback"),
)
.arg(Arg::new("debug").short('d').help("Show debug output"))
.arg(
Arg::new("INPUT")
.help("The input file path, or - to use standard input")
.required(true)
.index(1),
)
.get_matches();
let code = match run(&args) {
Ok(code) => code,
Err(err) => {
error!("{}", err.to_string().to_lowercase());
-1
}
};
std::process::exit(code)
}
fn format_time(time: f64) -> String {
let seconds = (time / 1000.0).ceil() as u32;
let minutes = seconds / 60;
let seconds = seconds % 60;
let hours = minutes / 60;
let minutes = minutes % 60;
format!("{:02}:{:02}:{:02}", hours, minutes, seconds)
}
fn run(args: &ArgMatches) -> Result<i32> {
let file_path = args.get_one::<String>("INPUT").unwrap().clone();
let gain = args
.get_one::<String>("GAIN")
.unwrap()
.parse::<f32>()
.unwrap()
.clone();
if !(file_path.ends_with(".prot") || file_path.ends_with(".mka")) {
panic!("File is not a .prot file");
}
let test_data = test_data::TestData::new();
let mut player = player::Player::new_from_file_paths(&test_data.wavs);
println!("Test info: {:?}", player.info);
player.play();
player.set_volume(gain / 100.0);
let mut loop_iteration = 0;
let reporting_function = |Report { time, playing, .. }| {
println!(
"Time: {} ({})",
format_time(time * 1000.0),
if playing { "Playing" } else { "Paused" }
);
};
player.set_reporting(
Arc::new(Mutex::new(reporting_function)),
Duration::from_millis(100),
);
while !player.is_finished() {
sleep(Duration::from_secs(1));
}
Ok(0)
}