use std::io; use byteorder::{LE, ReadBytesExt}; use crate::framework::error::{GameError, GameResult}; #[repr(u8)] #[derive(Debug, Copy, Clone, Eq, PartialEq)] pub enum Version { // Can't find any files with this signature, // But apparently these files had no Pi flag. Beta = b'1', Main = b'2', // OrgMaker 2.05 Extended Drums Extended = b'3', } #[derive(Debug, Copy, Clone)] pub struct LoopRange { // inclusive pub start: i32, // exclusive pub end: i32, } #[derive(Debug, Copy, Clone)] pub struct Display { pub beats: u8, pub steps: u8, } #[derive(Debug, Copy, Clone)] pub struct Timing { pub wait: u16, pub loop_range: LoopRange, } #[derive(Debug, Copy, Clone)] pub struct Instrument { pub freq: u16, pub inst: u8, pub pipi: u8, pub notes: u16, } #[derive(Clone)] pub struct Track { pub inst: Instrument, pub notes: Vec, } impl std::fmt::Debug for Track { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { self.inst.fmt(f) } } #[repr(C)] #[derive(Debug, Copy, Clone)] pub struct Note { pub pos: i32, pub key: u8, pub len: u8, pub vol: u8, pub pan: u8, } #[derive(Debug, Clone)] pub struct Song { pub version: Version, pub time: Timing, pub tracks: [Track; 16], } impl Song { pub fn empty() -> Song { Song { version: Version::Main, time: Timing { wait: 8, loop_range: LoopRange { start: 0, end: 1 } }, tracks: [ Track { inst: Instrument { freq: 1000, inst: 0, pipi: 0, notes: 0 }, notes: vec![] }, Track { inst: Instrument { freq: 1000, inst: 0, pipi: 0, notes: 0 }, notes: vec![] }, Track { inst: Instrument { freq: 1000, inst: 0, pipi: 0, notes: 0 }, notes: vec![] }, Track { inst: Instrument { freq: 1000, inst: 0, pipi: 0, notes: 0 }, notes: vec![] }, Track { inst: Instrument { freq: 1000, inst: 0, pipi: 0, notes: 0 }, notes: vec![] }, Track { inst: Instrument { freq: 1000, inst: 0, pipi: 0, notes: 0 }, notes: vec![] }, Track { inst: Instrument { freq: 1000, inst: 0, pipi: 0, notes: 0 }, notes: vec![] }, Track { inst: Instrument { freq: 1000, inst: 0, pipi: 0, notes: 0 }, notes: vec![] }, Track { inst: Instrument { freq: 1000, inst: 0, pipi: 0, notes: 0 }, notes: vec![] }, Track { inst: Instrument { freq: 1000, inst: 0, pipi: 0, notes: 0 }, notes: vec![] }, Track { inst: Instrument { freq: 1000, inst: 0, pipi: 0, notes: 0 }, notes: vec![] }, Track { inst: Instrument { freq: 1000, inst: 0, pipi: 0, notes: 0 }, notes: vec![] }, Track { inst: Instrument { freq: 1000, inst: 0, pipi: 0, notes: 0 }, notes: vec![] }, Track { inst: Instrument { freq: 1000, inst: 0, pipi: 0, notes: 0 }, notes: vec![] }, Track { inst: Instrument { freq: 1000, inst: 0, pipi: 0, notes: 0 }, notes: vec![] }, Track { inst: Instrument { freq: 1000, inst: 0, pipi: 0, notes: 0 }, notes: vec![] }, ], } } pub fn load_from(mut f: R) -> GameResult { let mut magic = [0; 6]; f.read_exact(&mut magic)?; let version = match &magic { b"Org-01" => Version::Beta, b"Org-02" => Version::Main, b"Org-03" => Version::Extended, _ => return Err(GameError::ResourceLoadError("Invalid magic number".to_string())) }; let wait = f.read_u16::()?; let _bpm = f.read_u8()?; let _spb = f.read_u8()?; let start = f.read_i32::()?; let end = f.read_i32::()?; use std::mem::MaybeUninit as Mu; let mut insts: [Mu; 16] = unsafe { Mu::uninit().assume_init() }; for i in &mut insts { let freq = f.read_u16::()?; let inst = f.read_u8()?; let pipi = f.read_u8()?; let notes = f.read_u16::()?; *i = Mu::new(Instrument { freq, inst, pipi, notes, }); } let insts: [Instrument; 16] = unsafe { std::mem::transmute(insts) }; let mut tracks: [Mu; 16] = unsafe { Mu::uninit().assume_init() }; for (i, t) in tracks.iter_mut().enumerate() { let count = insts[i].notes as usize; #[repr(C)] #[derive(Copy, Clone)] struct UninitNote { pos: Mu, key: Mu, len: Mu, vol: Mu, pan: Mu, } let mut notes: Vec = unsafe { vec![Mu::uninit().assume_init(); count] }; for note in &mut notes { note.pos = Mu::new(f.read_i32::()?); } for note in &mut notes { note.key = Mu::new(f.read_u8()?); } for note in &mut notes { note.len = Mu::new(f.read_u8()?); } for note in &mut notes { note.vol = Mu::new(f.read_u8()?); } for note in &mut notes { note.pan = Mu::new(f.read_u8()?); } *t = Mu::new(Track { inst: insts[i], notes: unsafe { std::mem::transmute(notes) }, }); } let tracks = unsafe { std::mem::transmute(tracks) }; let song = Song { version, time: Timing { wait, loop_range: LoopRange { start, end, }, }, tracks, }; Ok(song) } }