use crate::core::cell_note::CellNote;
use crate::core::pitch::Pitch;
use crate::tracker::import::bin_reader::ImportError;
use crate::tracker::import::patternslot::PatternSlot;
use alloc::vec::Vec;
impl PatternSlot {
pub fn load_xm(src: &[u8]) -> Result<(&[u8], PatternSlot), ImportError> {
let mut dst: [u8; 5] = [0; 5];
let mut i = 0;
let take = |i: &mut usize| -> Result<u8, ImportError> {
let b = *src.get(*i).ok_or(ImportError::UnexpectedEof)?;
*i += 1;
Ok(b)
};
let note = take(&mut i)?;
if note & 0b1000_0000 != 0 {
for (j, mask) in [
0b0000_0001,
0b0000_0010,
0b0000_0100,
0b0000_1000,
0b0001_0000,
]
.iter()
.enumerate()
{
if note & mask != 0 {
dst[j] = take(&mut i)?;
}
}
} else {
dst[0] = note;
dst[1] = take(&mut i)?;
dst[2] = take(&mut i)?;
dst[3] = take(&mut i)?;
dst[4] = take(&mut i)?;
}
Ok((
&src[i..],
PatternSlot {
note: {
if dst[0] == 97 {
CellNote::KeyOff
} else if dst[0] == 0 {
CellNote::Empty
} else {
match Pitch::try_from(dst[0] - 1) {
Ok(p) => CellNote::Play(p),
Err(_) => CellNote::Empty,
}
}
},
instrument: {
if dst[1] != 0 {
Some(dst[1] as usize - 1)
} else {
None
}
},
volume: dst[2],
effect_type: dst[3],
effect_parameter: dst[4],
},
))
}
pub fn save_xm_unpack(&self) -> Vec<u8> {
let mut bytes: [u8; 5] = [0; 5];
bytes[0] = cell_note_to_xm_byte(&self.note);
bytes[1] = {
if let Some(instr) = self.instrument {
(instr + 1) as u8
} else {
0
}
};
bytes[2] = self.volume;
bytes[3] = self.effect_type;
bytes[4] = self.effect_parameter;
bytes.to_vec()
}
pub fn save_xm(&self) -> Vec<u8> {
let mut bytes: [u8; 5] = [0; 5];
bytes[0] = cell_note_to_xm_byte(&self.note);
bytes[1] = {
if let Some(instr) = self.instrument {
(instr + 1) as u8
} else {
0
}
};
bytes[2] = self.volume;
bytes[3] = self.effect_type;
bytes[4] = self.effect_parameter;
let mut dst: [u8; 5] = [0; 5];
let mut pack_bits = 0;
let mut i = 1;
if bytes[0] > 0 {
pack_bits |= 0b0001;
dst[i] = bytes[0];
i += 1;
} if bytes[1] > 0 {
pack_bits |= 0b0010;
dst[i] = bytes[1];
i += 1;
} if bytes[2] > 0 {
pack_bits |= 0b0100;
dst[i] = bytes[2];
i += 1;
} if bytes[3] > 0 {
pack_bits |= 0b1000;
dst[i] = bytes[3];
i += 1;
}
if pack_bits == 15 {
return bytes.to_vec();
}
if bytes[4] > 0 {
pack_bits |= 16;
dst[i] = bytes[4];
i += 1;
} dst[0] = pack_bits | 0b1000_0000;
dst[0..i].to_vec()
}
}
fn cell_note_to_xm_byte(n: &CellNote) -> u8 {
match n {
CellNote::Empty => 0,
CellNote::Play(p) => p.value() + 1,
CellNote::KeyOff => 97,
CellNote::NoteCut | CellNote::NoteFade => 0,
}
}