old school music tracker audio backend
1use err::LoadErr;
2use impulse_format::{header, pattern};
3
4use crate::project::song::Song;
5
6pub mod err;
7pub mod impulse_format;
8
9#[derive(Debug, Clone, Copy)]
10pub struct InFilePtr(pub(crate) std::num::NonZeroU32);
11
12impl InFilePtr {
13 /// Move the Read Cursor to the value of the file ptr
14 pub fn move_to_self<S: std::io::Seek>(self, seeker: &mut S) -> Result<(), std::io::Error> {
15 seeker
16 .seek(std::io::SeekFrom::Start(self.0.get().into()))
17 .map(|_| ())
18 }
19}
20
21/// Default parsing of a song. Should be fine for most usecases. If you want more customization use the different parsing functions directly.
22///
23/// R should be buffered in some way and not do a syscall on every read.
24/// 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.
25pub fn parse_song<R: std::io::Read + std::io::Seek>(reader: &mut R) -> Result<Song, LoadErr> {
26 //ignore defects
27 let mut defect_handler = |_| ();
28 let header = header::ImpulseHeader::parse(reader, &mut defect_handler)?;
29 let mut song = Song::default();
30 song.copy_values_from_header(&header);
31
32 // parse patterns
33 for (idx, ptr) in header
34 .pattern_offsets
35 .iter()
36 .enumerate()
37 .flat_map(|(idx, ptr)| ptr.map(|ptr| (idx, ptr)))
38 {
39 ptr.move_to_self(reader)?;
40 let pattern = pattern::parse_pattern(reader, &mut defect_handler)?;
41 song.patterns[idx] = pattern;
42 }
43
44 Ok(song)
45}