diff options
author | 2025-03-02 21:21:56 -0500 | |
---|---|---|
committer | 2025-03-02 21:21:56 -0500 | |
commit | 473d6e1d506cb6e0ac3c763871c5c8f9e4395ae5 (patch) | |
tree | c5f0397f6899fdb3603c393ed2bf3fcd0fa1572f | |
parent | e9aaf095a805f08fccc4407c8f1dc60780382f63 (diff) | |
download | it2midi-473d6e1d506cb6e0ac3c763871c5c8f9e4395ae5.tar.xz |
Sample loading and conversion.
-rw-r--r-- | src/itfile.rs | 42 | ||||
-rw-r--r-- | src/main.rs | 6 |
2 files changed, 46 insertions, 2 deletions
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<u8> } impl Samp { + // This does NOT load the actual sample data! pub fn load(f: &mut File) -> Result<Samp, self::Error> { 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<f32> { + let mut ret = Vec::<f32>::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)] diff --git a/src/main.rs b/src/main.rs index 8ae139b..6ad1421 100644 --- a/src/main.rs +++ b/src/main.rs @@ -20,6 +20,12 @@ fn main() -> Result<(), itfile::Error> { }?;*/ match itfile::load("/home/chrisoft/Music/mods/nb_tear of the sun.it") { Ok(f) => { + for s in &f.samps { + let converted = s.convert_samples(); + for v in converted { + std::io::Write::write(&mut std::io::stderr(), &v.to_le_bytes()).unwrap(); + } + } let player = player::BasePlayer::new(&f); player::Player::play(&player); Ok(()) |