use rustzx_core::{
zx::{machine::ZXMachine, sound::ay::ZXAYMode},
EmulationSpeed, RustzxSettings,
};
use std::path::PathBuf;
use structopt::StructOpt;
#[derive(StructOpt)]
pub struct Settings {
#[structopt(verbatim_doc_comment, short, long, default_value = "48k", parse(try_from_str = machine_from_str))]
pub machine: ZXMachine,
#[structopt(long, default_value = "1", parse(try_from_str = emualtion_speed_from_str))]
pub speed: EmulationSpeed,
#[structopt(long = "nofastload")]
pub disable_fastload: bool,
#[structopt(short, long, default_value = "2", parse(try_from_str = scale_from_str))]
pub scale: usize,
#[structopt(long = "nokempston")]
pub disable_kempston: bool,
#[structopt(long, default_value = "abc", parse(try_from_str = ay_mode_from_str))]
pub ay_mode: ZXAYMode,
#[structopt(long = "ay", conflicts_with = "force-disable-ay")]
pub force_enable_ay: bool,
#[structopt(long = "noay", conflicts_with = "force-enable-ay")]
pub force_disable_ay: bool,
#[structopt(long = "nobeeper")]
pub disable_beeper: bool,
#[structopt(long = "nosound")]
pub disable_sound: bool,
#[structopt(long, default_value = "1024", parse(try_from_str = sound_latency_from_str))]
pub sound_latency: usize,
#[structopt(long, default_value = "44100", parse(try_from_str = sound_sample_rate_from_str))]
pub sound_sample_rate: usize,
#[structopt(long, conflicts_with = "file-autodetect")]
pub rom: Option<PathBuf>,
#[structopt(long, conflicts_with = "file-autodetect")]
pub tape: Option<PathBuf>,
#[structopt(long, conflicts_with = "file-autodetect")]
pub snap: Option<PathBuf>,
pub file_autodetect: Option<PathBuf>,
}
fn machine_from_str(s: &str) -> Result<ZXMachine, anyhow::Error> {
match s.to_lowercase().as_str() {
"48k" | "48" => Ok(ZXMachine::Sinclair48K),
"128k" | "128" => Ok(ZXMachine::Sinclair128K),
s => Err(anyhow::anyhow!("Invalid machine type `{}`", s)),
}
}
fn emualtion_speed_from_str(s: &str) -> Result<EmulationSpeed, anyhow::Error> {
match s.to_lowercase().as_str() {
"max" => Ok(EmulationSpeed::Max),
s => {
let speed: std::num::NonZeroUsize = s
.parse()
.map_err(|_| anyhow::anyhow!("Invalid emulation speed `{}`", s))?;
Ok(EmulationSpeed::Definite(speed.into()))
}
}
}
fn scale_from_str(s: &str) -> Result<usize, anyhow::Error> {
let scale: std::num::NonZeroUsize = s
.parse()
.map_err(|_| anyhow::anyhow!("Invalid screen scale `{}`", s))?;
Ok(scale.into())
}
fn ay_mode_from_str(s: &str) -> Result<ZXAYMode, anyhow::Error> {
match s.to_lowercase().as_str() {
"mono" => Ok(ZXAYMode::Mono),
"abc" => Ok(ZXAYMode::ABC),
"acb" => Ok(ZXAYMode::ACB),
s => Err(anyhow::anyhow!("Invalid AY chip mode `{}`", s)),
}
}
fn sound_latency_from_str(s: &str) -> Result<usize, anyhow::Error> {
let latency = s
.parse::<usize>()
.map_err(|_| anyhow::anyhow!("Invalid sound latency `{}`", s))?;
if latency < 64 {
anyhow::bail!("Setting sound latency lower than 64 is bad for your health");
}
if latency > 1024 * 64 {
anyhow::bail!("This sound latency is HUGE. Please don't try this at home!");
}
Ok(latency)
}
fn sound_sample_rate_from_str(s: &str) -> Result<usize, anyhow::Error> {
let sample_rate = s
.parse::<usize>()
.map_err(|_| anyhow::anyhow!("Invalid sound sample rate {}", s))?;
if sample_rate < 8000 {
anyhow::bail!("Provided sound sample rate `{}` is too low", sample_rate);
}
if sample_rate > 384000 {
anyhow::bail!("Provided sound sample rate `{}` is too high", sample_rate);
}
Ok(sample_rate)
}
impl Settings {
pub fn to_rustzx_settings(&self) -> RustzxSettings {
let ay_enabled = (matches!(self.machine, ZXMachine::Sinclair128K) || self.force_enable_ay)
&& (!self.force_disable_ay);
RustzxSettings {
machine: self.machine,
emulation_speed: self.speed,
tape_fastload: !self.disable_fastload,
enable_kempston: !self.disable_kempston,
ay_mode: self.ay_mode,
ay_enabled,
beeper_enabled: !self.disable_beeper,
sound_enabled: !self.disable_sound,
sound_volume: 100,
load_default_rom: self.rom.is_none(),
sound_sample_rate: self.sound_sample_rate,
}
}
}