//! I currently use generics. This hinges on the idea that in every program only one type of file reader is used //! so dynamic dispatch would offer no advantages. Maybe i will / should change this at some point. //! //! I would probably use BufReader as the reader to have the buffer below the vtable. //! would need my own trait to have Read and Seek together in one vtable //! //! I currently only support the schism tracker file format. use err::LoadErr; use crate::project::song::Song; pub mod err; pub mod header; pub mod instrument; pub mod pattern; pub mod sample; #[derive(Debug, Clone, Copy)] pub struct InFilePtr(pub(crate) std::num::NonZeroU32); impl InFilePtr { /// Move the Read Cursor to the value of the file ptr pub fn move_to_self(self, seeker: &mut S) -> Result<(), std::io::Error> { seeker .seek(std::io::SeekFrom::Start(self.0.get().into())) .map(|_| ()) } } /// Default parsing of a song. Should be fine for most usecases. If you want more customization use the different parsing functions directly. /// /// R should be buffered in some way and not do a syscall on every read. /// 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. pub fn parse_song(reader: &mut R) -> Result { let header = header::ImpulseHeader::parse(reader)?; let mut song = Song::default(); header.copy_values_into_song(&mut song); // parse patterns for (idx, ptr) in header .pattern_offsets .iter() // number the pointer slots .enumerate() // filter out empty pointers. Keep the old slot numbering .flat_map(|(idx, ptr)| ptr.map(|ptr| (idx, ptr))) { ptr.move_to_self(reader)?; let pattern = pattern::parse_pattern(reader)?; song.patterns[idx] = pattern; } println!("sample_count: {:?}", header.sample_offsets); // let mut sample_header_buf = [0; ImpulseSampleHeader::SIZE]; for (idx, ptr) in header .sample_offsets .iter() .enumerate() .flat_map(|(idx, ptr)| ptr.map(|ptr| (idx, ptr))) { println!("header {idx} at {ptr:?}"); // ptr.move_to_self(reader)?; // reader.read_exact(&mut sample_header_buf)?; // println!("header {idx} read"); // let sample_header = ImpulseSampleHeader::parse(&sample_header_buf); // println!("sample_header {idx}: {sample_header:?}"); } Ok(song) }