const Q_MAX : usize = 128;
const BUF_SIZE : usize = 2 * 1024 * 1024;
const HMP_TRACK0 : [u8; 19] = [
b'M', b'T', b'r', b'k', 0, 0, 0, 11, 0, 0xFF, 0x51, 0x03, 0x18, 0x7F, 0xFF,
0, 0xFF, 0x2F, 0
];
pub struct Hmi2mid {
bw : u32,
buf : Vec <u8>,
q_rel : Vec <QRel>
}
#[derive(Clone, Default)]
struct QRel {
pub tm : u32,
pub ch : u8,
pub n : u8
}
impl Hmi2mid {
pub fn new() -> Self {
Hmi2mid {
bw: 0,
buf: vec![0; BUF_SIZE],
q_rel: vec![QRel::default(); Q_MAX]
}
}
pub fn hmi_rip (&mut self, source : Vec <u8>) -> Result <Vec <u8>, ()> {
let mut out = Vec::new();
out.resize(14, 0);
let bbuf = &source;
let mut ptr = 0;
loop {
if ptr >= bbuf.len() {
eprintln!("ptr >= bbuf.len()");
return Err(())
}
if &bbuf[ptr..ptr+4] == &b"TRAC"[..] {
break
}
ptr += 1;
}
ptr -= 8;
let nft : u32 = u32::from_le_bytes([
bbuf[0xE4],
bbuf[0xE4+1],
bbuf[0xE4+2],
bbuf[0xE4+3]
]);
let mut ntrax : u16 = 1;
out.extend_from_slice (&HMP_TRACK0);
for _ in 0..nft {
if &bbuf[ptr..ptr+13] != &b"HMI-MIDITRACK"[..] {
eprintln!(r#"&bbuf[ptr..ptr+13] != &b"HMI-MIDITRACK"[..]"#);
return Err(())
}
ntrax += 1;
ptr += bbuf[ptr + 0x57] as usize;
let dd = self.do_track(&bbuf[ptr..]);
if dd == std::usize::MAX {
eprintln!("dd == std::usize::MAX");
return Err(())
}
ptr += dd;
out.extend_from_slice(&b"MTrk"[..]);
out.extend_from_slice(&self.bw.to_be_bytes());
out.extend_from_slice(&self.buf[0..self.bw as usize]);
}
&out[0..4].copy_from_slice(&b"MThd"[..]);
&out[4..8].copy_from_slice(&0x06000000u32.to_le_bytes());
out[8] = 0x00;
out[9] = 0x01;
&out[10..12].copy_from_slice(&ntrax.to_be_bytes());
out[12] = 0x00;
out[13] = 0xC0;
Ok (out)
}
fn do_track (&mut self, t : &[u8]) -> usize {
for n in 0..Q_MAX {
self.q_rel[n].tm = std::u32::MAX;
}
let mut pt : usize = 0;
let mut ct : u32 = 0;
let mut tw : u32 = 0;
let mut run : u8 = 0;
let mut rrun : u8 = 0;
self.bw = 0;
loop {
ct += self.read_delta (t, &mut pt);
self.do_queue (ct, &mut tw, &mut rrun);
let mut c : u8 = t[pt];
if c == 0xFF {
self.do_queue (std::u32::MAX-1, &mut tw, &mut rrun);
if t[pt+1] == 0x2F {
pt += 3;
self.buf[self.bw as usize] = 0;
self.bw += 1;
self.buf[self.bw as usize] = 0xFF;
self.bw += 1;
self.buf[self.bw as usize] = 0x2F;
self.bw += 1;
self.buf[self.bw as usize] = 0;
self.bw += 1;
break
}
return std::usize::MAX
} else if c == 0xF0 {
self.bw += Self::write_delta (
&mut self.buf[self.bw as usize..], ct - tw);
tw = ct;
while t[pt] != 0xF7 {
self.buf[self.bw as usize] = t[pt];
self.bw += 1;
pt += 1;
}
} else if c == 0xFE {
c = t[pt+1];
if c == 0x10 {
pt += t[pt+4] as usize + 9;
} else if c == 0x14 {
pt += 4;
} else if c == 0x15 {
pt += 8;
} else {
return std::usize::MAX
}
} else {
self.bw += Self::write_delta (
&mut self.buf[self.bw as usize..], ct - tw);
tw = ct;
if c & 0x80 != 0 {
pt += 1;
run = c;
} else {
c = run;
}
if c != rrun {
self.buf[self.bw as usize] = c;
self.bw += 1;
rrun = c;
}
self.buf[self.bw as usize] = t[pt];
self.bw += 1;
pt += 1;
let c1 : u8 = c & 0xF0;
if c1 != 0xC0 && c1 != 0xD0 {
self.buf[self.bw as usize] = t[pt];
self.bw += 1;
pt += 1;
}
if c1 == 0x90 {
let b : u8 = t[pt-2];
let tt : u32 = ct + self.read_delta (t, &mut pt);
self.q_add (c & 0xF, b, tt);
}
}
}
pt
}
fn q_add (&mut self, ch : u8, nt : u8, t : u32) {
let mut n : usize = 0;
while self.q_rel[n].tm != std::u32::MAX {
n += 1;
}
self.q_rel[n] = QRel {
tm: t,
n: nt,
ch
};
}
fn write_delta (t : &mut [u8], dt : u32) -> u32 {
let mut tl : isize = 3;
let mut pos : usize = 0;
if dt != 0 {
while dt >> (7*tl) == 0 {
tl -= 1;
}
loop {
t[pos] = (((dt >> (7*tl)) & 0x7F) | 0x80) as u8;
tl -= 1;
pos += 1;
if tl < 0 {
break
}
}
t[pos-1] &= 0x7F;
} else {
t[pos] = 0;
pos += 1;
}
pos as u32
}
fn read_delta (&self, t : &[u8], p : &mut usize) -> u32 {
let mut d : u32 = 0;
let mut b;
loop {
b = t[*p];
*p += 1;
d = (d << 7) | (b & 0x7F) as u32;
if b & 0x80 == 0 {
break
}
}
d
}
fn do_queue (&mut self, ct : u32, tw : &mut u32, run : &mut u8) {
let mut mt : u32;
let mut nn : usize = std::usize::MAX;
loop {
mt = std::u32::MAX;
for n in 0..Q_MAX {
if self.q_rel[n].tm < mt {
nn = n;
mt = self.q_rel[n].tm;
}
}
if mt > ct {
return
}
debug_assert!(nn != std::usize::MAX);
self.bw += Self::write_delta (
&mut self.buf[self.bw as usize..], mt - *tw);
*tw = mt;
let e : u8 = self.q_rel[nn].ch | 0x90;
if e != *run {
self.buf[self.bw as usize] = e;
self.bw += 1;
*run = e;
}
self.buf[self.bw as usize] = self.q_rel[nn].n;
self.bw += 1;
self.buf[self.bw as usize] = 0;
self.bw += 1;
self.q_rel[nn].tm = std::u32::MAX;
}
}
}