old school music tracker audio backend
at sans-io 304 lines 10 kB view raw
1use crate::file::{SansIO, err}; 2use crate::project::event_command::NoteCommand; 3use crate::project::note_event::{Note, NoteEvent, VolumeEffect}; 4use crate::project::pattern::{InPatternPosition, Pattern}; 5use core::error::Error; 6use core::fmt::Display; 7use std::io::Read; 8 9use core::mem; 10 11/// reader should be buffered in some way and not do a syscall on every read call. 12/// 13/// This function does a lot of read calls 14pub fn parse_pattern<R: Read>(reader: &mut R) -> Result<Pattern, err::LoadErr> { 15 const PATTERN_HEADER_SIZE: usize = 8; 16 17 let (length, num_rows) = { 18 let mut header = [0; PATTERN_HEADER_SIZE]; 19 reader.read_exact(&mut header)?; 20 ( 21 u64::from(u16::from_le_bytes([header[0], header[1]])) + PATTERN_HEADER_SIZE as u64, 22 u16::from_le_bytes([header[2], header[3]]), 23 ) 24 }; 25 26 // a guarantee given by the impulse tracker "specs" 27 if length >= 64_000 { 28 return Err(err::LoadErr::Invalid); 29 } 30 31 if !(32..=200).contains(&num_rows) { 32 return Err(err::LoadErr::Invalid); 33 } 34 35 let mut pattern = Pattern::new(num_rows); 36 37 let mut row_num: u16 = 0; 38 39 let mut last_mask = [0; 64]; 40 let mut last_event = [NoteEvent::default(); 64]; 41 42 let mut scratch = [0; 1]; 43 44 while row_num < num_rows { 45 let channel_variable = scratch[0]; 46 47 if channel_variable == 0 { 48 row_num += 1; 49 continue; 50 } 51 52 let channel = (channel_variable - 1) & 63; // 64 channels, 0 based 53 let channel_id = usize::from(channel); 54 55 let maskvar = if (channel_variable & 0b10000000) != 0 { 56 reader.read_exact(&mut scratch)?; 57 let val = scratch[0]; 58 last_mask[channel_id] = val; 59 val 60 } else { 61 last_mask[channel_id] 62 }; 63 64 let mut event = NoteEvent::default(); 65 66 // Note 67 if (maskvar & 0b00000001) != 0 { 68 reader.read_exact(&mut scratch)?; 69 // let note = match Note::new(scratch[0]) { 70 // Ok(n) => n, 71 // Err(_) => { 72 // // defect_handler(LoadDefect::OutOfBoundsValue); 73 // Note::default() 74 // } 75 // }; 76 let note = Note::new(scratch[0]).unwrap_or_default(); 77 78 event.note = note; 79 last_event[channel_id].note = note; 80 } 81 82 // Instrument / Sample 83 if (maskvar & 0b00000010) != 0 { 84 reader.read_exact(&mut scratch)?; 85 let instrument = scratch[0]; 86 87 event.sample_instr = instrument; 88 last_event[channel_id].sample_instr = instrument; 89 } 90 91 // Volume 92 if (maskvar & 0b00000100) != 0 { 93 reader.read_exact(&mut scratch)?; 94 // let vol_pan = match vol_pan_raw.try_into() { 95 // Ok(v) => v, 96 // Err(_) => { 97 // // defect_handler(LoadDefect::OutOfBoundsValue); 98 // VolumeEffect::default() 99 // } 100 // }; 101 let vol_pan = volumeeffect_try_from(scratch[0]).unwrap_or_default(); 102 103 last_event[channel_id].vol = vol_pan; 104 event.vol = vol_pan; 105 } 106 107 // Effect 108 if (maskvar & 0b00001000) != 0 { 109 reader.read_exact(&mut scratch)?; 110 let command = scratch[0]; 111 reader.read_exact(&mut scratch)?; 112 let cmd_val = scratch[0]; 113 114 // let cmd = match NoteCommand::try_from((command, cmd_val)) { 115 // Ok(cmd) => cmd, 116 // Err(_) => { 117 // // defect_handler(LoadDefect::OutOfBoundsValue); 118 // NoteCommand::default() 119 // } 120 // }; 121 let cmd = note_command_try_from((command, cmd_val)).unwrap_or_default(); 122 123 last_event[channel_id].command = cmd; 124 event.command = cmd; 125 } 126 127 // Same note 128 if (maskvar & 0b00010000) != 0 { 129 event.note = last_event[channel_id].note; 130 } 131 132 // Same Instr / Sample 133 if (maskvar & 0b00100000) != 0 { 134 event.sample_instr = last_event[channel_id].sample_instr; 135 } 136 137 // Same volume 138 if (maskvar & 0b01000000) != 0 { 139 event.vol = last_event[channel_id].vol; 140 } 141 142 // Same Command 143 if (maskvar & 0b10000000) != 0 { 144 event.command = last_event[channel_id].command; 145 } 146 147 pattern.set_event( 148 InPatternPosition { 149 row: row_num, 150 channel, 151 }, 152 event, 153 ); 154 } 155 156 Ok(pattern) 157} 158 159#[derive(Debug, Clone, Copy)] 160pub struct InvalidVolumeEffect; 161 162impl Display for InvalidVolumeEffect { 163 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 164 write!(f, "Invalid Volume Effect") 165 } 166} 167 168impl Error for InvalidVolumeEffect {} 169 170/// IT Tracker Format Conversion 171/// no way to get None, as then it just doesn't get set 172fn volumeeffect_try_from(value: u8) -> Result<VolumeEffect, InvalidVolumeEffect> { 173 match value { 174 0..=64 => Ok(VolumeEffect::Volume(value)), 175 65..=74 => Ok(VolumeEffect::FineVolSlideUp(value - 65)), 176 75..=84 => Ok(VolumeEffect::FineVolSlideDown(value - 75)), 177 85..=94 => Ok(VolumeEffect::VolSlideUp(value - 85)), 178 95..=104 => Ok(VolumeEffect::VolSlideDown(value - 95)), 179 105..=114 => Ok(VolumeEffect::PitchSlideDown(value - 105)), 180 115..=124 => Ok(VolumeEffect::PitchSlideUp(value - 115)), 181 128..=192 => Ok(VolumeEffect::Panning(value - 128)), 182 193..=202 => Ok(VolumeEffect::SlideToNoteWithSpeed(value - 193)), 183 203..=212 => Ok(VolumeEffect::VibratoWithSpeed(value - 203)), 184 _ => Err(InvalidVolumeEffect), 185 } 186} 187 188#[derive(Debug, Clone, Copy)] 189pub struct UnknownNoteCommand; 190 191impl Display for UnknownNoteCommand { 192 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 193 write!(f, "Unknown Note Command") 194 } 195} 196 197impl Error for UnknownNoteCommand {} 198 199fn note_command_try_from( 200 (command_type, command_value): (u8, u8), 201) -> Result<NoteCommand, UnknownNoteCommand> { 202 match command_type { 203 0 => Ok(NoteCommand::None), 204 1 => Ok(NoteCommand::SetTempo(command_value)), 205 2 => Ok(NoteCommand::JumpToOrder(command_value)), 206 3 => Ok(NoteCommand::BreakToRow(command_value)), 207 4 => Ok(NoteCommand::VolumeSlideDown(command_value)), 208 5 => Ok(NoteCommand::PitchSlideDown(command_value)), 209 6 => Ok(NoteCommand::PitchSlideUp(command_value)), 210 7 => Ok(NoteCommand::SlideToNote(command_value)), 211 8 => Ok(NoteCommand::Vibrato(command_value)), 212 9 => Ok(NoteCommand::Tremor(command_value)), 213 10 => Ok(NoteCommand::Arpeggio(command_value)), 214 11 => Ok(NoteCommand::VibratoAndVolSlideDown(command_value)), 215 12 => Ok(NoteCommand::SlideToNoteAndVolSlideDown(command_value)), 216 13 => Ok(NoteCommand::SetChannelVol(command_value)), 217 14 => Ok(NoteCommand::ChannelVolumeSlideDown(command_value)), 218 15 => Ok(NoteCommand::SetSampleOffset(command_value)), 219 16 => Ok(NoteCommand::PanningSlide(command_value)), 220 17 => Ok(NoteCommand::RetriggerNote(command_value)), 221 18 => Ok(NoteCommand::Tremolo(command_value)), 222 19 => Ok(NoteCommand::AlmostEverything(command_value)), 223 20 => Ok(NoteCommand::TempoChange(command_value)), 224 21 => Ok(NoteCommand::FineVibrato(command_value)), 225 22 => Ok(NoteCommand::SetGlobalVolume(command_value)), 226 23 => Ok(NoteCommand::GlobalVolumeSlide(command_value)), 227 24 => Ok(NoteCommand::SetPanning(command_value)), 228 25 => Ok(NoteCommand::Panbrello(command_value)), 229 26 => Ok(NoteCommand::MIDIMacros(command_value)), 230 _ => Err(UnknownNoteCommand), 231 } 232} 233 234pub struct PatternParser { 235 length: u64, 236 num_rows: u16, 237 // changed while parsing 238 pattern: Pattern, 239 curren_row: u16, 240 last_mask: [u8; 64], 241 last_event: [NoteEvent; 64], 242} 243 244impl PatternParser { 245 const PATTERN_HEADER_SIZE: usize = 8; 246 247 pub fn new(header: &[u8; Self::PATTERN_HEADER_SIZE]) -> Result<Self, err::LoadErr2> { 248 let (length, num_rows) = ( 249 u64::from(u16::from_le_bytes([header[0], header[1]])) 250 + Self::PATTERN_HEADER_SIZE as u64, 251 u16::from_le_bytes([header[2], header[3]]), 252 ); 253 254 // a guarantee given by the impulse tracker "specs" 255 if length >= 64_000 { 256 return Err(err::LoadErr2::Invalid); 257 } 258 259 if !(32..=200).contains(&num_rows) { 260 return Err(err::LoadErr2::Invalid); 261 } 262 263 Ok(Self { 264 length, 265 num_rows, 266 pattern: Pattern::new(num_rows), 267 curren_row: 0, 268 last_mask: [0; _], 269 last_event: [NoteEvent::default(); _], 270 }) 271 } 272 273 /// needs at most 7 bytes at once 274 pub fn parse(&mut self, mut buf: &[u8]) -> SansIO<Pattern> { 275 let mut read = 0; 276 while self.curren_row < self.num_rows { 277 let Some(&channel_variable) = buf.split_off_first() else { 278 return SansIO::Pending(read); 279 }; 280 read += 1; 281 if channel_variable == 0 { 282 self.curren_row += 1; 283 continue; 284 } 285 let channel = (channel_variable - 1) & 63; // 64 channels, 0 based 286 let channel_id = usize::from(channel); 287 288 let maskvar = if (channel_variable & 0b10000000) != 0 { 289 let Some(&val) = buf.split_off_first() else { 290 return SansIO::Pending(read); 291 }; 292 read += 1; 293 self.last_mask[channel_id] = val; 294 val 295 } else { 296 self.last_mask[channel_id] 297 }; 298 299 let mut event = NoteEvent::default(); 300 } 301 let finished = mem::replace(&mut self.pattern, Pattern::new(self.num_rows)); 302 SansIO::Finished(finished, read) 303 } 304}