From 473d6e1d506cb6e0ac3c763871c5c8f9e4395ae5 Mon Sep 17 00:00:00 2001 From: Chris Xiong Date: Sun, 2 Mar 2025 21:21:56 -0500 Subject: Sample loading and conversion. --- src/itfile.rs | 42 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 40 insertions(+), 2 deletions(-) (limited to 'src/itfile.rs') diff --git a/src/itfile.rs b/src/itfile.rs index 311207b..a4b2d83 100644 --- a/src/itfile.rs +++ b/src/itfile.rs @@ -171,24 +171,62 @@ pub struct SampHeader pub struct Samp { - pub header: SampHeader + pub header: SampHeader, + pub data: Vec } impl Samp { + // This does NOT load the actual sample data! pub fn load(f: &mut File) -> Result { let header: SampHeader = read_struct(f)?; - Ok(Samp{header}) + let mut ret = Samp{header, data: Vec::new()}; + f.seek(SeekFrom::Start(ret.header.samp_ptr.into()))?; + if !ret.is_compressed() + { + let data_len = ret.header.length * ret.num_channels() as u32 * ret.bits_per_sample() as u32 / 8; + ret.data.resize(data_len as usize, 0); + f.read_exact(&mut ret.data[..]).map_err(|e| Error::IOError(e))?; + } + Ok(ret) } pub fn sample_name(self: &Self) -> String { String::from_utf8_lossy(terminate_cstr(&self.header.sample_name)).into_owned() } pub fn filename(self: &Self) -> String { String::from_utf8_lossy(terminate_cstr(&self.header.dos_filename)).into_owned() } pub fn is_compressed(self: &Self) -> bool { self.header.flag & 0x8 != 0 } + pub fn is_signed(self: &Self) -> bool { self.header.convert & 0x1 != 0 } pub fn num_channels(self: &Self) -> u8 { if self.header.flag & 0x4 != 0 { 2 } else { 1 }} pub fn bits_per_sample(self: &Self) -> u8 { if self.header.flag & 0x2 != 0 { 16 } else { 8 }} pub fn default_vol(self: &Self) -> u8 { self.header.default_volume } + pub fn convert_samples(self: &Self) -> Vec { + let mut ret = Vec::::new(); + ret.resize(self.header.length as usize, 0.); + for i in 0..ret.len() { + if self.bits_per_sample() == 16 { + let data_slice:&[u8; 2] = &self.data[i * 2 .. i * 2 + 2].try_into().unwrap(); + if self.is_signed() { + let val = i16::from_le_bytes(*data_slice); + ret[i] = val as f32 / i16::MAX as f32; + } else { + let val = u16::from_le_bytes(*data_slice); + ret[i] = val as f32 / u16::MAX as f32; + ret[i] = (ret[i] - 0.5) * 2.; + } + } else { + if self.is_signed() { + let val = i8::from_le_bytes([self.data[i]]); + ret[i] = val as f32 / i8::MAX as f32; + } else { + let val = self.data[i]; + ret[i] = val as f32 / u8::MAX as f32; + ret[i] = (ret[i] - 0.5) * 2.; + } + } + } + ret + } } #[derive(Copy, Clone, Default)] -- cgit v1.2.3