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