use crate::{header::Header, NbsError, NbsFormat};
use byteorder::LittleEndian;
use instrument::Instrument;
use layer::Layer;
use note::Note;
pub mod instrument;
pub mod layer;
pub mod note;
#[derive(Debug)]
pub struct NoteBlocks {
pub layers: Vec<Layer>,
}
impl NoteBlocks {
pub fn new() -> Self {
NoteBlocks { layers: Vec::new() }
}
}
impl NoteBlocks {
pub fn calculate_length(&self) -> i16 {
let mut length: i16 = 0;
for layer in &self.layers {
if layer.notes.len() > 0 {
let last_note = layer.notes.iter().max_by(|x, y| x.0.cmp(&y.0)).unwrap();
if last_note.0 > &length {
length = *last_note.0;
}
}
}
length
}
pub fn decode<R>(reader: &mut R, header: &Header) -> Result<NoteBlocks, NbsError>
where
R: crate::ReadStringExt,
{
let mut noteblocks = NoteBlocks::new();
for layer_index in 0..header.layer_count {
let layer = Layer::from_format(header.format);
noteblocks.layers.insert(layer_index as usize, layer);
}
let mut tick: i16 = -1;
loop {
let mut jumps = reader.read_i16::<LittleEndian>()?;
if jumps == 0 {
break;
}
tick += jumps;
let mut layer: i16 = -1;
loop {
jumps = reader.read_i16::<LittleEndian>()?;
if jumps == 0 {
break;
}
layer += jumps;
let instrument = reader.read_i8()?;
let instrument = if instrument >= header.vannila_instrument_count()? {
Instrument::Custom(instrument)
} else {
Instrument::Vanilla(instrument)
};
let key = reader.read_i8()?;
let velocity = if header.format.version() >= 4 {
Some(reader.read_i8()?)
} else {
None
};
let panning = if header.format.version() >= 4 {
Some(reader.read_i8()?)
} else {
None
};
let pitch = if header.format.version() >= 4 {
Some(reader.read_i16::<LittleEndian>()?)
} else {
None
};
noteblocks
.layers
.get_mut(layer as usize)
.unwrap()
.notes
.insert(
tick,
Note {
instrument,
key,
velocity,
panning,
pitch,
},
);
}
}
for layer_index in 0..noteblocks.layers.len() {
let mut layer = noteblocks.layers.get_mut(layer_index).unwrap();
(*layer).name = reader.read_string()?;
if header.format.version() >= 4 {
(*layer).locked = Some(reader.read_i8()? == 1);
}
(*layer).volume = reader.read_i8()?;
if header.format.version() >= 2 {
(*layer).stereo = Some(reader.read_i8()?);
}
}
Ok(noteblocks)
}
pub fn encode<W>(&self, format: NbsFormat, writer: &mut W) -> Result<(), NbsError>
where
W: crate::WriteStringExt,
{
let mut h_cursor: i16 = -1;
for note_index in 0..=self.calculate_length() {
let mut v_cursor: i16 = -1;
let h_jumps = note_index - h_cursor;
let mut has_jumped_h = false;
for (layer_index, layer) in self.layers.iter().enumerate() {
if layer.notes.contains_key(¬e_index) {
let v_jumps = (layer_index as i16) - v_cursor;
let note = layer.notes.get(¬e_index).unwrap();
if !has_jumped_h {
writer.write_i16::<LittleEndian>(h_jumps)?;
has_jumped_h = true;
h_cursor += h_jumps;
}
writer.write_i16::<LittleEndian>(v_jumps)?;
v_cursor += v_jumps;
writer.write_i8(note.instrument.into())?;
writer.write_i8(note.key)?;
if format.version() >= 4 {
writer.write_i8(note.velocity.ok_or(NbsError::InvalidFormat)?)?;
writer.write_i8(note.panning.ok_or(NbsError::InvalidFormat)?)?;
writer.write_i16::<LittleEndian>(
note.pitch.ok_or(NbsError::InvalidFormat)?,
)?;
}
}
}
if has_jumped_h {
writer.write_i16::<LittleEndian>(0)?;
}
}
writer.write_i16::<LittleEndian>(0)?;
for layer_index in 0..self.layers.len() {
let layer = self.layers.get(layer_index).unwrap();
writer.write_string(&layer.name)?;
if format.version() >= 4 {
writer.write_i8(if layer.locked.ok_or(NbsError::InvalidFormat)? {
1
} else {
0
})?;
}
writer.write_i8(layer.volume)?;
if format.version() >= 2 {
writer.write_i8(layer.stereo.ok_or(NbsError::InvalidFormat)?)?;
}
}
Ok(())
}
}