old school music tracker audio backend
at dev 70 lines 2.6 kB view raw
1//! I currently use generics. This hinges on the idea that in every program only one type of file reader is used 2//! so dynamic dispatch would offer no advantages. Maybe i will / should change this at some point. 3//! 4//! I would probably use BufReader<dyn Read + Seek> as the reader to have the buffer below the vtable. 5//! would need my own trait to have Read and Seek together in one vtable 6//! 7//! I currently only support the schism tracker file format. 8use err::LoadErr; 9 10use crate::project::song::Song; 11 12pub mod err; 13pub mod header; 14pub mod instrument; 15pub mod pattern; 16pub mod sample; 17 18#[derive(Debug, Clone, Copy)] 19pub struct InFilePtr(pub(crate) std::num::NonZeroU32); 20 21impl InFilePtr { 22 /// Move the Read Cursor to the value of the file ptr 23 pub fn move_to_self<S: std::io::Seek>(self, seeker: &mut S) -> Result<(), std::io::Error> { 24 seeker 25 .seek(std::io::SeekFrom::Start(self.0.get().into())) 26 .map(|_| ()) 27 } 28} 29 30/// Default parsing of a song. Should be fine for most usecases. If you want more customization use the different parsing functions directly. 31/// 32/// R should be buffered in some way and not do a syscall on every read. 33/// If you ever find yourself using multiple different reader and/or handlers please open an issue on Github, i will change this to take &dyn. 34pub fn parse_song<R: std::io::Read + std::io::Seek>(reader: &mut R) -> Result<Song, LoadErr> { 35 let header = header::ImpulseHeader::parse(reader)?; 36 let mut song = Song::default(); 37 header.copy_values_into_song(&mut song); 38 39 // parse patterns 40 for (idx, ptr) in header 41 .pattern_offsets 42 .iter() 43 // number the pointer slots 44 .enumerate() 45 // filter out empty pointers. Keep the old slot numbering 46 .flat_map(|(idx, ptr)| ptr.map(|ptr| (idx, ptr))) 47 { 48 ptr.move_to_self(reader)?; 49 let pattern = pattern::parse_pattern(reader)?; 50 song.patterns[idx] = pattern; 51 } 52 53 println!("sample_count: {:?}", header.sample_offsets); 54 // let mut sample_header_buf = [0; ImpulseSampleHeader::SIZE]; 55 for (idx, ptr) in header 56 .sample_offsets 57 .iter() 58 .enumerate() 59 .flat_map(|(idx, ptr)| ptr.map(|ptr| (idx, ptr))) 60 { 61 println!("header {idx} at {ptr:?}"); 62 // ptr.move_to_self(reader)?; 63 // reader.read_exact(&mut sample_header_buf)?; 64 // println!("header {idx} read"); 65 // let sample_header = ImpulseSampleHeader::parse(&sample_header_buf); 66 // println!("sample_header {idx}: {sample_header:?}"); 67 } 68 69 Ok(song) 70}