torque_tracker_engine/file/
mod.rs

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}