use alloc::boxed::Box;
use alloc::string::String;
use alloc::string::ToString;
use alloc::vec;
use crate::import::bin_reader::{bytes_to_trimmed_string, BinReader, ImportError};
use super::xminstrument::{
XmInstrDefault, XmInstrument, XmInstrumentHeader, XmInstrumentType, XMINSTRUMENT_HEADER_SIZE,
};
use super::xmsample::{XmSample, XMSAMPLE_HEADER_SIZE};
#[derive(Debug)]
pub struct XiInstrumentHeader {
id_text: String, name: String,
right_arrow: u8, tracker_name: String,
version_number: u16,
}
impl Default for XiInstrumentHeader {
fn default() -> Self {
Self {
id_text: "Extended Instrument: ".to_string(),
name: "".to_string(),
right_arrow: 0x1A,
tracker_name: "XMrs".to_string(),
version_number: 0x0104,
}
}
}
#[derive(Debug)]
pub struct XiInstrument {
header: XiInstrumentHeader,
instr: XmInstrDefault,
reserved: [u8; 15],
num_samples: u16,
}
impl XiInstrument {
pub fn load(data: &[u8]) -> Result<XmInstrument, ImportError> {
let mut r = BinReader::new(data);
let id_bytes: [u8; 21] = r.read_array()?;
let name_bytes: [u8; 22] = r.read_array()?;
let right_arrow = r.read_u8()?;
let tracker_bytes: [u8; 20] = r.read_array()?;
let version_number = r.read_u16_le()?;
let header = XiInstrumentHeader {
id_text: bytes_to_trimmed_string(&id_bytes),
name: bytes_to_trimmed_string(&name_bytes),
right_arrow,
tracker_name: bytes_to_trimmed_string(&tracker_bytes),
version_number,
};
if header.id_text != "Extended Instrument:" {
return Err(ImportError::InvalidMagic("Not an Extended Instrument?"));
}
let instr = XmInstrDefault::read(&mut r)?;
let _reserved: [u8; 15] = r.read_array()?;
let num_samples = r.read_u16_le()?;
let data_after_header = r.tail();
let xm_header = XmInstrumentHeader {
name: header.name,
instr_type: 0,
num_samples,
};
if num_samples == 0 {
return Ok(XmInstrument {
instrument_header_len: 4 + XMINSTRUMENT_HEADER_SIZE as u32,
header: xm_header,
sample_header_size: XMSAMPLE_HEADER_SIZE as u32,
instr: XmInstrumentType::Default(Box::new(instr)),
sample: vec![],
});
}
let mut sample = vec![];
let mut d3 = data_after_header;
for _ in 0..num_samples {
let (d, s) = XmSample::load(d3)?;
sample.push(s);
d3 = d;
}
for s in &mut sample {
let d = s.add_sample(d3)?;
d3 = d;
}
Ok(XmInstrument {
instrument_header_len: 4 + XMINSTRUMENT_HEADER_SIZE as u32,
header: xm_header,
sample_header_size: XMSAMPLE_HEADER_SIZE as u32,
instr: XmInstrumentType::Default(Box::new(instr)),
sample,
})
}
}