old school music tracker audio backend
at main 290 lines 7.4 kB view raw
1// look at player/csndfile.c csf_read_sample 2 3use std::num::NonZeroU32; 4 5use crate::file::{ 6 err::{LoadDefect, LoadErr}, 7 InFilePtr, 8}; 9 10use super::header; 11 12#[derive(Debug, Default, Clone, Copy)] 13pub enum VibratoWave { 14 #[default] 15 Sine = 0, 16 RampDown = 1, 17 Square = 2, 18 Random = 3, 19} 20 21impl TryFrom<u8> for VibratoWave { 22 type Error = u8; 23 24 fn try_from(value: u8) -> Result<Self, Self::Error> { 25 match value { 26 0 => Ok(Self::Sine), 27 1 => Ok(Self::RampDown), 28 2 => Ok(Self::Square), 29 3 => Ok(Self::Random), 30 _ => Err(value), 31 } 32 } 33} 34 35enum ImpulseSampleBitWidth { 36 Seven, 37 Eight, 38 Sixteen, 39 TwentyFour, 40 ThirtyTwo, 41} 42 43impl From<ImpulseSampleBitWidth> for usize { 44 fn from(value: ImpulseSampleBitWidth) -> Self { 45 match value { 46 ImpulseSampleBitWidth::Seven => 7, 47 ImpulseSampleBitWidth::Eight => 8, 48 ImpulseSampleBitWidth::Sixteen => 16, 49 ImpulseSampleBitWidth::TwentyFour => 24, 50 ImpulseSampleBitWidth::ThirtyTwo => 32, 51 } 52 } 53} 54 55enum ImpulseSampleChannels { 56 Mono, 57 StereoInterleaved, 58 StereoSplit, 59} 60 61enum ImpulseSampleEndianness { 62 Little, 63 Big, 64} 65 66/// don't know what most of them are. Just took them from include/sndfile.h of schism tracker 67enum ImpulseSampleEncoding { 68 PCMSigned, 69 PCMUnsigned, 70 PCMDelta, 71 IT2_14Comp, 72 IT2_15Comp, 73 Ams, 74 Dmf, 75 Mdl, 76 Ptm, 77 PCM16, 78} 79 80/// don't understand what bit 3 is supposed to do 81#[derive(Debug, Copy, Clone)] 82pub struct SampleFormatConvert(u8); 83 84impl SampleFormatConvert { 85 // alternative is unsigned 86 pub fn is_signed(self) -> bool { 87 (self.0 & 0x1) != 0 88 } 89 /// should only be true for very old files (isn't even supported in C schism) 90 pub fn is_big_endian(self) -> bool { 91 (self.0 & 0x2) != 0 92 } 93 /// alternative is PCM samples 94 pub fn delta_samples(self) -> bool { 95 (self.0 & 0x4) != 0 96 } 97 /// not supported 98 pub fn byte_delta(self) -> bool { 99 (self.0 & 0x8) != 0 100 } 101 /// don't support in first step 102 pub fn tx_wave_12bit(self) -> bool { 103 (self.0 & 0x10) != 0 104 } 105 /// don't know if this also means that the sample is stereo 106 pub fn should_show_stereo_prompt(self) -> bool { 107 (self.0 & 0x20) != 0 108 } 109} 110 111#[derive(Debug, Copy, Clone)] 112pub struct SampleFormatFlags(u8); 113 114impl SampleFormatFlags { 115 pub fn has_sample(self) -> bool { 116 (self.0 & 0x01) != 0 117 } 118 pub fn is_16bit(self) -> bool { 119 (self.0 & 0x02) != 0 120 } 121 pub fn is_8bit(self) -> bool { 122 !self.is_16bit() 123 } 124 pub fn is_steroe(self) -> bool { 125 (self.0 & 0x04) != 0 126 } 127 pub fn is_compressed(self) -> bool { 128 (self.0 & 0x08) != 0 129 } 130 pub fn uses_loop(self) -> bool { 131 (self.0 & 0x10) != 0 132 } 133 pub fn uses_sustain_loop(self) -> bool { 134 (self.0 & 0x20) != 0 135 } 136 pub fn ping_pong_loop(self) -> bool { 137 (self.0 & 0x40) != 0 138 } 139 pub fn forward_loop(self) -> bool { 140 !self.ping_pong_loop() 141 } 142 pub fn ping_pong_sustain_loop(self) -> bool { 143 (self.0 & 0x80) != 0 144 } 145 pub fn forward_sustain_loop(self) -> bool { 146 !self.ping_pong_sustain_loop() 147 } 148} 149 150#[derive(Debug)] 151pub struct ImpulseSampleHeader { 152 pub dos_filename: Box<[u8]>, 153 pub sample_name: String, 154 pub global_volume: u8, 155 pub flags: SampleFormatFlags, 156 pub default_volume: u8, 157 pub convert: SampleFormatConvert, 158 pub default_pan: u8, 159 // frame count 160 pub length: u32, 161 pub loop_start: u32, 162 pub loop_end: u32, 163 pub c5_speed: u32, 164 pub sustain_start: u32, 165 pub sustain_end: u32, 166 pub data_ptr: InFilePtr, 167 pub vibrato_speed: u8, 168 pub vibrato_depth: u8, 169 pub vibrato_type: VibratoWave, 170 pub vibrato_rate: u8, 171} 172 173impl ImpulseSampleHeader { 174 const SIZE: usize = 80; 175 176 pub fn parse<H: FnMut(LoadDefect)>( 177 buf: &[u8; Self::SIZE], 178 defect_handler: &mut H, 179 ) -> Result<Self, LoadErr> { 180 if !buf.starts_with(b"IMPS") { 181 return Err(LoadErr::Invalid); 182 } 183 184 let dos_filename = buf[0x4..=0xF].to_vec().into_boxed_slice(); 185 if buf[0x10] != 0 { 186 return Err(LoadErr::Invalid); 187 } 188 189 let global_volume = if buf[0x11] > 64 { 190 defect_handler(LoadDefect::OutOfBoundsValue); 191 64 192 } else { 193 buf[0x11] 194 }; 195 196 let flags = SampleFormatFlags(buf[0x12]); 197 let default_volume = buf[0x13]; 198 let sample_name = { 199 let str = buf[0x14..=0x2D].split(|b| *b == 0).next().unwrap().to_vec(); 200 let str = String::from_utf8(str); 201 if str.is_err() { 202 defect_handler(LoadDefect::InvalidText); 203 } 204 str.unwrap_or_default() 205 }; 206 207 let convert = SampleFormatConvert(buf[0x2E]); 208 209 let default_pan = buf[0x2F]; 210 211 // in samples, not bytes 212 let length = u32::from_le_bytes([buf[0x30], buf[0x31], buf[0x32], buf[0x33]]); 213 let loop_start = u32::from_le_bytes([buf[0x34], buf[0x35], buf[0x36], buf[0x37]]); 214 let loop_end = u32::from_le_bytes([buf[0x38], buf[0x39], buf[0x3A], buf[0x3B]]); 215 216 // bytes per second at c5 217 let c5_speed = { 218 let speed = u32::from_le_bytes([buf[0x3C], buf[0x3D], buf[0x3E], buf[0x3F]]); 219 if speed > 9999999 { 220 defect_handler(LoadDefect::OutOfBoundsValue); 221 // no idea what is a good default here 222 9999999 / 2 223 } else { 224 speed 225 } 226 }; 227 228 // in samples, not bytes 229 let sustain_start = u32::from_le_bytes([buf[0x40], buf[0x41], buf[0x42], buf[0x43]]); 230 let sustain_end = u32::from_le_bytes([buf[0x44], buf[0x45], buf[0x46], buf[0x47]]); 231 232 let data_ptr = { 233 let value = u32::from_le_bytes([buf[0x48], buf[0x49], buf[0x4A], buf[0x4B]]); 234 if value < header::ImpulseHeader::BASE_SIZE as u32 { 235 return Err(LoadErr::Invalid); 236 } 237 InFilePtr(NonZeroU32::new(value).unwrap()) 238 }; 239 240 let vibrato_speed = if buf[0x4C] > 64 { 241 defect_handler(LoadDefect::OutOfBoundsValue); 242 32 243 } else { 244 buf[0x4C] 245 }; 246 247 let vibrato_depth = if buf[0x4D] > 64 { 248 defect_handler(LoadDefect::OutOfBoundsValue); 249 32 250 } else { 251 buf[0x4D] 252 }; 253 254 let vibrato_rate = if buf[0x4E] > 64 { 255 defect_handler(LoadDefect::OutOfBoundsValue); 256 32 257 } else { 258 buf[0x4E] 259 }; 260 261 let vibrato_type = { 262 let wave = VibratoWave::try_from(buf[0x4F]); 263 if wave.is_err() { 264 defect_handler(LoadDefect::OutOfBoundsValue); 265 } 266 wave.unwrap_or_default() 267 }; 268 269 Ok(Self { 270 dos_filename, 271 sample_name, 272 global_volume, 273 flags, 274 default_volume, 275 convert, 276 default_pan, 277 length, 278 loop_start, 279 loop_end, 280 c5_speed, 281 sustain_start, 282 sustain_end, 283 data_ptr, 284 vibrato_speed, 285 vibrato_depth, 286 vibrato_type, 287 vibrato_rate, 288 }) 289 } 290}