Skip to main content

nbs/noteblocks/
mod.rs

1use crate::{header::Header, NbsError, NbsFormat};
2use byteorder::LittleEndian;
3use instrument::Instrument;
4use layer::Layer;
5use note::Note;
6
7pub mod instrument;
8pub mod layer;
9pub mod note;
10
11#[derive(Debug)]
12pub struct NoteBlocks {
13    /// Layers of the File.
14    pub layers: Vec<Layer>,
15}
16
17impl NoteBlocks {
18    pub fn new() -> Self {
19        NoteBlocks { layers: Vec::new() }
20    }
21}
22
23impl NoteBlocks {
24    pub fn calculate_length(&self) -> i16 {
25        let mut length: i16 = 0;
26        for layer in &self.layers {
27            if layer.notes.len() > 0 {
28                let last_note = layer.notes.iter().max_by(|x, y| x.0.cmp(&y.0)).unwrap();
29                if last_note.0 > &length {
30                    length = *last_note.0;
31                }
32            }
33        }
34        length
35    }
36
37    pub fn decode<R>(reader: &mut R, header: &Header) -> Result<NoteBlocks, NbsError>
38    where
39        R: crate::ReadStringExt,
40    {
41        let mut noteblocks = NoteBlocks::new();
42        // If the layer count differs from the encoded layers, NoteBlockStudio crashes.
43        for layer_index in 0..header.layer_count {
44            let layer = Layer::from_format(header.format);
45            noteblocks.layers.insert(layer_index as usize, layer);
46        }
47
48        let mut tick: i16 = -1;
49        loop {
50            let mut jumps = reader.read_i16::<LittleEndian>()?;
51            if jumps == 0 {
52                break;
53            }
54            tick += jumps;
55            let mut layer: i16 = -1;
56            loop {
57                jumps = reader.read_i16::<LittleEndian>()?;
58                if jumps == 0 {
59                    break;
60                }
61                layer += jumps;
62                let instrument = reader.read_i8()?;
63
64                let instrument = if instrument >= header.vannila_instrument_count()? {
65                    Instrument::Custom(instrument)
66                } else {
67                    Instrument::Vanilla(instrument)
68                };
69                let key = reader.read_i8()?;
70                let velocity = if header.format.version() >= 4 {
71                    Some(reader.read_i8()?)
72                } else {
73                    None
74                };
75                let panning = if header.format.version() >= 4 {
76                    Some(reader.read_i8()?)
77                } else {
78                    None
79                };
80                let pitch = if header.format.version() >= 4 {
81                    Some(reader.read_i16::<LittleEndian>()?)
82                } else {
83                    None
84                };
85                noteblocks
86                    .layers
87                    .get_mut(layer as usize)
88                    .unwrap()
89                    .notes
90                    .insert(
91                        tick,
92                        Note {
93                            instrument,
94                            key,
95                            velocity,
96                            panning,
97                            pitch,
98                        },
99                    );
100            }
101        }
102        for layer_index in 0..noteblocks.layers.len() {
103            let mut layer = noteblocks.layers.get_mut(layer_index).unwrap();
104            (*layer).name = reader.read_string()?;
105            if header.format.version() >= 4 {
106                (*layer).locked = Some(reader.read_i8()? == 1);
107            }
108            (*layer).volume = reader.read_i8()?;
109            if header.format.version() >= 2 {
110                (*layer).stereo = Some(reader.read_i8()?);
111            }
112        }
113        Ok(noteblocks)
114    }
115    pub fn encode<W>(&self, format: NbsFormat, writer: &mut W) -> Result<(), NbsError>
116    where
117        W: crate::WriteStringExt,
118    {
119        let mut h_cursor: i16 = -1;
120        for note_index in 0..=self.calculate_length() {
121            let mut v_cursor: i16 = -1;
122            let h_jumps = note_index - h_cursor;
123            let mut has_jumped_h = false;
124            for (layer_index, layer) in self.layers.iter().enumerate() {
125                if layer.notes.contains_key(&note_index) {
126                    let v_jumps = (layer_index as i16) - v_cursor;
127                    let note = layer.notes.get(&note_index).unwrap();
128                    if !has_jumped_h {
129                        writer.write_i16::<LittleEndian>(h_jumps)?;
130                        has_jumped_h = true;
131                        h_cursor += h_jumps;
132                    }
133                    writer.write_i16::<LittleEndian>(v_jumps)?;
134                    v_cursor += v_jumps;
135                    writer.write_i8(note.instrument.into())?;
136                    writer.write_i8(note.key)?;
137                    if format.version() >= 4 {
138                        writer.write_i8(note.velocity.ok_or(NbsError::InvalidFormat)?)?;
139                        writer.write_i8(note.panning.ok_or(NbsError::InvalidFormat)?)?;
140                        writer.write_i16::<LittleEndian>(
141                            note.pitch.ok_or(NbsError::InvalidFormat)?,
142                        )?;
143                    }
144                }
145            }
146            if has_jumped_h {
147                // If this row actually had notes in it, that means we jumped at least 1 time, we indicate that its finished.
148                writer.write_i16::<LittleEndian>(0)?;
149            }
150        }
151        writer.write_i16::<LittleEndian>(0)?;
152        for layer_index in 0..self.layers.len() {
153            let layer = self.layers.get(layer_index).unwrap();
154            writer.write_string(&layer.name)?;
155            if format.version() >= 4 {
156                writer.write_i8(if layer.locked.ok_or(NbsError::InvalidFormat)? {
157                    1
158                } else {
159                    0
160                })?;
161            }
162            writer.write_i8(layer.volume)?;
163            if format.version() >= 2 {
164                writer.write_i8(layer.stereo.ok_or(NbsError::InvalidFormat)?)?;
165            }
166        }
167        Ok(())
168    }
169}