1pub(crate) mod instrument;
4pub(crate) mod wave;
5
6use std::io::{self, Read, Write};
7use thiserror::Error;
8
9pub struct SongMemory {
14 bytes: [u8; Self::LEN],
16}
17
18impl SongMemory {
19 pub const LEN: usize = 0x8000;
21
22 pub fn new() -> Self {
26 Self {
27 bytes: *include_bytes!("92L_empty.raw"),
28 }
29 }
30
31 pub fn from_bytes(bytes: &[u8]) -> Result<Self, FromBytesError> {
33 let bytes: [u8; Self::LEN] = bytes
34 .try_into()
35 .map_err(|_| FromBytesError::IncorrectSize)?;
36
37 let check = |offset| bytes[offset] == 0x72 && bytes[offset + 1] == 0x62;
38
39 if check(0x1E78) || check(0x3E80) || check(0x7FF0) {
40 Ok(Self { bytes })
41 } else {
42 Err(FromBytesError::InitializationCheckIncorrect)
43 }
44 }
45
46 pub fn from_reader<R>(mut reader: R) -> Result<Self, FromReaderError>
48 where
49 R: Read,
50 {
51 let mut bytes = [0; Self::LEN];
52 reader.read_exact(bytes.as_mut_slice())?;
53
54 let song = Self::from_bytes(&bytes)?;
55
56 Ok(song)
57 }
58
59 pub fn to_writer<W>(&self, mut writer: W) -> Result<(), io::Error>
61 where
62 W: Write,
63 {
64 writer.write_all(&self.bytes)
65 }
66
67 pub fn format_version(&self) -> u8 {
69 self.bytes[0x7FFF]
70 }
71
72 pub fn as_slice(&self) -> &[u8] {
74 &self.bytes
75 }
76
77 pub fn as_mut_slice(&mut self) -> &mut [u8] {
79 &mut self.bytes
80 }
81}
82
83impl Default for SongMemory {
84 fn default() -> Self {
85 Self::new()
86 }
87}
88
89#[derive(Debug, Error)]
91pub enum FromBytesError {
92 #[error("The slice isn't of the correct size")]
94 IncorrectSize,
95
96 #[error("The initialization check failed")]
101 InitializationCheckIncorrect,
102}
103
104#[derive(Debug, Error)]
106pub enum FromReaderError {
107 #[error("Something failed with I/O")]
109 Read(#[from] io::Error),
110
111 #[error("Deserialiazation from the read bytes failed")]
113 FromBytes(#[from] FromBytesError),
114}
115
116#[cfg(test)]
117mod tests {
118 use super::*;
119
120 #[test]
121 fn empty_92l() {
122 use std::io::Cursor;
123
124 let song = {
125 let bytes = Cursor::new(include_bytes!("../../test/92L_empty.sav"));
126 SongMemory::from_reader(bytes).expect("could not parse song")
127 };
128
129 assert_eq!(song.format_version(), 0x16);
130 }
131}