Skip to main content

nbs/noteblocks/
instrument.rs

1use crate::{header::Header, NbsError};
2
3pub const PIANO: Instrument = Instrument::Vanilla(0);
4pub const DOUBLE_BASS: Instrument = Instrument::Vanilla(1);
5pub const BASS_DRUM: Instrument = Instrument::Vanilla(2);
6pub const SNARE_DRUM: Instrument = Instrument::Vanilla(3);
7pub const CLICK: Instrument = Instrument::Vanilla(4);
8pub const GUITAR: Instrument = Instrument::Vanilla(5);
9pub const FLUTE: Instrument = Instrument::Vanilla(6);
10pub const BELL: Instrument = Instrument::Vanilla(7);
11pub const CHIME: Instrument = Instrument::Vanilla(8);
12pub const XYLOPHONE: Instrument = Instrument::Vanilla(9);
13pub const IRON_XYLOPHONE: Instrument = Instrument::Vanilla(10);
14pub const COW_BELL: Instrument = Instrument::Vanilla(11);
15pub const DIDGERIDOO: Instrument = Instrument::Vanilla(12);
16pub const BIT: Instrument = Instrument::Vanilla(13);
17pub const BANJO: Instrument = Instrument::Vanilla(14);
18pub const PLING: Instrument = Instrument::Vanilla(15);
19
20#[derive(Debug, Clone, Copy)]
21pub enum Instrument {
22    Vanilla(i8),
23    Custom(i8),
24}
25
26impl Instrument {
27    pub fn is_custom(&self) -> bool {
28        match self {
29            Instrument::Custom(_) => true,
30            _ => false,
31        }
32    }
33}
34
35impl Into<i8> for Instrument {
36    fn into(self) -> i8 {
37        match self {
38            Instrument::Custom(id) | Instrument::Vanilla(id) => id,
39        }
40    }
41}
42
43pub struct CustomInstruments {
44    instruments: Vec<CustomInstrumentInfo>,
45}
46
47impl CustomInstruments {
48    pub fn new() -> Self {
49        CustomInstruments {
50            instruments: Vec::new(),
51        }
52    }
53
54    pub fn decode<R>(reader: &mut R, header: &Header) -> Result<CustomInstruments, NbsError>
55    where
56        R: crate::ReadStringExt,
57    {
58        let instrument_count = reader.read_i8()?;
59        let mut custom_instruments = CustomInstruments {
60            instruments: Vec::with_capacity(instrument_count as usize),
61        };
62        for id in 0..instrument_count {
63            // We don't want to overlap with vannila instruments.
64            let instrument = Instrument::Custom(id + header.vannila_instrument_count()?);
65            let name = reader.read_string()?;
66            let file_name = reader.read_string()?;
67            let pitch = reader.read_i8()?;
68            let press_key = reader.read_i8()? == 1;
69            custom_instruments.instruments.push(CustomInstrumentInfo {
70                instrument,
71                name,
72                file_name,
73                pitch,
74                press_key,
75            })
76        }
77        Ok(custom_instruments)
78    }
79
80    pub fn encode<W>(&self, writer: &mut W) -> Result<(), NbsError>
81    where
82        W: crate::WriteStringExt,
83    {
84        writer.write_i8(self.instruments.len() as i8)?;
85        for instrument in &self.instruments {
86            writer.write_string(&instrument.name)?;
87            writer.write_string(&instrument.file_name)?;
88            writer.write_i8(instrument.pitch)?;
89            writer.write_i8(if instrument.press_key { 1 } else { 0 })?;
90        }
91        Ok(())
92    }
93}
94
95pub struct CustomInstrumentInfo {
96    pub instrument: Instrument,
97    pub name: String,
98    pub file_name: String,
99    pub pitch: i8,
100    pub press_key: bool,
101}