use crate::midi_shim::MIDIShim;
use crate::sn76489::{SN76489, SN76489_TONE_1, SN76489_TONE_2, SN76489_TONE_3};
use crate::ym2612::YM2612;
use crate::config::Config;
use anyhow::{bail, Result};
const DELAY_166MS: u8 = 0;
const YM2612_PORT0: u8 = 1;
const YM2612_PORT1: u8 = 2;
const YM2612_PSG: u8 = 3;
struct GYMHeader {
str_gymx: [u8; 4],
}
fn parse_gym_file_header(file_data: &[u8]) -> Result<Option<GYMHeader>> {
if file_data.len() < 428 {
return Ok(None);
}
let mut header = GYMHeader { str_gymx: [0; 4] };
if &file_data[0..4] != "GYMX".as_bytes() {
return Ok(None);
} else {
header.str_gymx.clone_from_slice(&file_data[0..4]);
}
Ok(Some(header))
}
pub(crate) fn convert_gym_to_mid(
file_data: &[u8],
config: &Config,
midi: &mut MIDIShim,
) -> Result<()> {
let _file_header = parse_gym_file_header(file_data)?;
let mut file_pos = 0_usize;
let register = 0_u8;
let mut _conversion_status_current = 0;
let _conversion_status_total = file_data.len();
let _mid_trackdata: Vec<u8> = Vec::new();
let _mid_file_pos = 0;
let clock_sn76489 = 3579545;
let clock_ym2612 = 3579545;
let fsam_2612 = clock_ym2612 as f64 / 72.0;
let mut ym2612 = YM2612::new(config, None);
let mut sn76489 = SN76489::new(false, clock_sn76489, config, None);
let t6w28_sn76489 = false;
midi.data_init(true, t6w28_sn76489);
loop {
let switch = file_data[file_pos];
match switch {
DELAY_166MS => {
process_delay(midi, &mut sn76489, &mut file_pos);
},
YM2612_PORT0 | YM2612_PORT1 => {
process_ym2612(
switch,
file_data,
&mut file_pos,
&mut ym2612,
register,
fsam_2612,
midi,
)?;
},
YM2612_PSG => {
process_sn76489(file_data, &mut file_pos, &mut sn76489, midi)?;
},
_ => file_pos += 1,
}
_conversion_status_current = file_pos;
if file_pos >= file_data.len() {
break;
}
}
Ok(())
}
fn process_delay(midi: &mut MIDIShim, sn76489: &mut SN76489, file_pos: &mut usize) {
midi.delta_time += 735;
for channel in 0x0..=0x2 {
sn76489.state.note_delay[channel] += 735;
}
*file_pos += 1;
}
fn process_ym2612(
switch: u8,
file_data: &[u8],
file_pos: &mut usize,
ym2612: &mut YM2612,
register: u8,
fsam_2612: f64,
midi: &mut MIDIShim,
) -> Result<()> {
let port = match switch {
YM2612_PORT0 => 0,
YM2612_PORT1 => 3,
_ => bail!("Pattern matched to a number other YM2612_PORT0 or YM2612_PORT1. This should never occur.")
};
let data = file_data[*file_pos + 2];
ym2612.command_handle(port, register, data, fsam_2612, midi)?;
*file_pos += 3;
Ok(())
}
fn process_sn76489(
file_data: &[u8],
file_pos: &mut usize,
sn76489: &mut SN76489,
midi: &mut MIDIShim,
) -> Result<()> {
let sn76489_msb = file_data[*file_pos + 1];
let mut sn76489_lsb = 0;
match sn76489_msb & 240 {
SN76489_TONE_1 | SN76489_TONE_2 | SN76489_TONE_3 => {
sn76489_lsb = file_data[*file_pos + 3];
*file_pos += 4;
},
_ => *file_pos += 2,
}
sn76489.command_handle(sn76489_msb, 0, midi)?;
sn76489.command_handle(sn76489_lsb, 0, midi)?;
Ok(())
}