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 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 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(¬e_index) {
126 let v_jumps = (layer_index as i16) - v_cursor;
127 let note = layer.notes.get(¬e_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 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}