use crate::midi_shim::{
MIDI_PATCH_ACOUSTIC_BASS, MIDI_PATCH_ACOUSTIC_GRAND_PIANO,
MIDI_PATCH_ACOUSTIC_GUITAR_NYLON, MIDI_PATCH_CLARINET, MIDI_PATCH_ELECTRIC_GUITAR_JAZZ,
MIDI_PATCH_FLUTE, MIDI_PATCH_FRENCH_HORN, MIDI_PATCH_HAMMOND_ORGAN, MIDI_PATCH_HARPSICHORD,
MIDI_PATCH_OBOE, MIDI_PATCH_OCARINA, MIDI_PATCH_PAD_3_POLYSYNTH, MIDI_PATCH_SYNTH_BASS_2,
MIDI_PATCH_SYNTH_STRINGS_1, MIDI_PATCH_TRUMPET, MIDI_PATCH_VIBRAPHONE,
};
use crate::vgm2mid::{PITCHWHEEL_SENSITIVITY_DEFAULT, PITCHWHEEL_STEPS_DEFAULT};
use crate::{strict, verbose};
use anyhow::Result;
use serde::{Deserialize, Serialize};
use std::path::{Path, PathBuf};
#[derive(Serialize, Deserialize)]
pub struct Config {
pub strict: bool,
pub verbose: bool,
pub dualchips: bool,
pub pitchwheel_sensitivity: u8,
pub pitchwheel_steps: u16,
pub cnv_accuracy: u16,
pub vgm_loops: u16,
pub tempo_mod: bool,
pub tempo_bpm: f64,
pub tempo_mult: f64,
pub tempo_div: f64,
pub sn76489_ch_disabled: [bool; 4],
pub sn76489_noise_disabled: bool,
pub sn76489_vol_disabled: [bool; 4],
pub sn76489_voldep_notes: u8,
pub ym2413_ch_disabled: [bool; 9],
pub ym2413_vol_disabled: [bool; 9],
pub ym2413_prog_disabled: [bool; 9],
pub ym2413_percussion_disabled: bool,
pub ym2413_optimized_vgms: bool,
pub ym2413_midi_patch: [u8; 16],
pub ym2612_ch_disabled: [bool; 6],
pub ym2612_vol_disabled: [bool; 6],
pub ym2612_prog_disabled: [bool; 6],
pub ym2612_pan_disabled: [bool; 6],
pub ym2612_midi_patch: [u8; 6],
pub ym2612_dac_disabled: bool,
pub ym2151_ch_disabled: [bool; 8],
pub ym2151_vol_disabled: [bool; 8],
pub ym2151_prog_disabled: [bool; 8],
pub ym2151_pan_disabled: [bool; 8],
}
impl Default for Config {
fn default() -> Self {
Config {
strict: true,
verbose: false,
dualchips: false,
pitchwheel_sensitivity: PITCHWHEEL_SENSITIVITY_DEFAULT.into(),
pitchwheel_steps: PITCHWHEEL_STEPS_DEFAULT.into(),
cnv_accuracy: 480,
vgm_loops: 0,
tempo_mod: false,
tempo_bpm: 120.0,
tempo_mult: 256.0,
tempo_div: 256.0,
sn76489_ch_disabled: [false; 4],
sn76489_noise_disabled: false,
sn76489_vol_disabled: [false; 4],
sn76489_voldep_notes: 2,
ym2413_ch_disabled: [false; 9],
ym2413_vol_disabled: [false; 9],
ym2413_prog_disabled: [false; 9],
ym2413_percussion_disabled: false,
ym2413_optimized_vgms: false,
ym2413_midi_patch: [
MIDI_PATCH_OCARINA.into(),
MIDI_PATCH_SYNTH_STRINGS_1.into(),
MIDI_PATCH_ACOUSTIC_GUITAR_NYLON.into(),
MIDI_PATCH_ACOUSTIC_GRAND_PIANO.into(),
MIDI_PATCH_FLUTE.into(),
MIDI_PATCH_CLARINET.into(),
MIDI_PATCH_OBOE.into(),
MIDI_PATCH_TRUMPET.into(),
MIDI_PATCH_HAMMOND_ORGAN.into(),
MIDI_PATCH_FRENCH_HORN.into(),
MIDI_PATCH_PAD_3_POLYSYNTH.into(),
MIDI_PATCH_HARPSICHORD.into(),
MIDI_PATCH_VIBRAPHONE.into(),
MIDI_PATCH_SYNTH_BASS_2.into(),
MIDI_PATCH_ACOUSTIC_BASS.into(),
MIDI_PATCH_ELECTRIC_GUITAR_JAZZ.into(),
],
ym2612_ch_disabled: [false; 6],
ym2612_vol_disabled: [false; 6],
ym2612_prog_disabled: [false; 6],
ym2612_pan_disabled: [false; 6],
ym2612_dac_disabled: false,
ym2612_midi_patch: [0, 0, 0, 0, 0, 0],
ym2151_ch_disabled: [false; 8],
ym2151_vol_disabled: [false; 8],
ym2151_prog_disabled: [false; 8],
ym2151_pan_disabled: [false; 8],
}
}
}
impl Config {
pub(crate) fn get_tempo_modifier(&self) -> f64 {
if self.tempo_mod {
self.tempo_mult / self.tempo_div
} else {
120.0 / self.tempo_bpm
}
}
}
pub fn load_config_or_default(file_path: Option<&Path>) -> Result<Config> {
let config_path = file_path.map_or_else(
try_get_default_config_path,
|path| Ok(Some(path.to_path_buf())),
)?;
config_path.map_or_else(use_default_config, fun_name1)
}
fn fun_name1(path: PathBuf) -> Result<Config> {
match path.try_exists() {
Ok(true) => {
verbose!("Found configuration file at {}", path.display());
fun_name(path)
},
Ok(false) => {
strict!("Could not find configuration file at {}", path.display());
use_default_config()
},
Err(error) => {
strict!("{}", error);
use_default_config()
},
}
}
fn fun_name(path: PathBuf) -> Result<Config> {
std::fs::read_to_string(path).map_or_else(
|err| {
strict!("{}", err);
use_default_config()
},
|cfg_string| {
toml::from_str(&cfg_string).or_else(|err| {
strict!("{}", err);
use_default_config()
})
},
)
}
fn use_default_config() -> Result<Config> {
verbose!("Using default configuration.");
Ok(Config::default())
}
fn try_get_default_config_path() -> Result<Option<PathBuf>> {
directories::ProjectDirs::from("net", "vgmrips", "vgm-rs").map_or_else(
|| {
strict!("Failed to load default config path.");
Ok(None)
},
|dirs| Ok(Some(dirs.config_dir().to_path_buf())),
)
}