m8_file_parser/instruments/
external_inst.rs

1use array_concat::concat_arrays;
2
3use super::common::SynthParams;
4use super::common::TranspEq;
5use super::dests;
6use super::midi::ControlChange;
7use super::params;
8use super::CommandPack;
9use super::Version;
10use crate::reader::*;
11use crate::writer::Writer;
12use crate::FIRMWARE_6_2_SONG_VERSION;
13use crate::SEND_COMMAND_NAMES;
14use crate::SEND_COMMAND_NAMES_6_2;
15
16#[derive(PartialEq, Debug, Clone)]
17pub struct ExternalInst {
18    pub number: u8,
19    pub name: String,
20    pub transpose: bool,
21    pub table_tick: u8,
22    pub synth_params: SynthParams,
23
24    pub input: u8,
25    pub port: u8,
26    pub channel: u8,
27    pub bank: u8,
28    pub program: u8,
29    pub cca: ControlChange,
30    pub ccb: ControlChange,
31    pub ccc: ControlChange,
32    pub ccd: ControlChange,
33}
34
35#[rustfmt::skip] // Keep constants with important order vertical for maintenance
36const EXTERNAL_INST_BASE_COMMANDS : [&'static str; CommandPack::BASE_INSTRUMENT_COMMAND_COUNT - 3] = [
37    "VOL",
38    "PIT",
39    "MPB",
40    "MPG",
41    "CCA",
42    "CCB",
43    "CCC",
44    "CCD",
45    "FLT",
46    "CUT",
47    "RES",
48    "AMP",
49    "LIM",
50    "PAN",
51    "DRY",
52];
53
54#[rustfmt::skip] // Keep constants with important order vertical for maintenance
55const EXTERNAL_INST_EXTRA_COMMANDS : [&'static str; 2] = [
56    // EXTRA
57    "ADD",
58    "CHD"
59];
60
61const EXTERNAL_INST_COMMANDS : [&'static str; CommandPack::BASE_INSTRUMENT_COMMAND_COUNT + 2] =
62    concat_arrays!(EXTERNAL_INST_BASE_COMMANDS, SEND_COMMAND_NAMES, EXTERNAL_INST_EXTRA_COMMANDS);
63
64const EXTERNAL_INST_COMMANDS_6_2 : [&'static str; CommandPack::BASE_INSTRUMENT_COMMAND_COUNT + 2] =
65    concat_arrays!(EXTERNAL_INST_BASE_COMMANDS, SEND_COMMAND_NAMES_6_2, EXTERNAL_INST_EXTRA_COMMANDS);
66
67#[rustfmt::skip] // Keep constants with important order vertical for maintenance
68const DESTINATIONS : [&'static str; 14] = [
69    dests::OFF,
70    dests::VOLUME,
71    dests::CUTOFF,
72    dests::RES,
73    dests::AMP,
74    dests::PAN,
75    params::CCA,
76    params::CCB,
77    params::CCC,
78    params::CCD,
79    dests::MOD_AMT,
80    dests::MOD_RATE,
81    dests::MOD_BOTH,
82    dests::MOD_BINV,
83];
84
85impl ExternalInst {
86    const MOD_OFFSET: usize = 22;
87
88    pub fn command_name(&self, ver: Version) -> &'static [&'static str] {
89        if ver.after(&FIRMWARE_6_2_SONG_VERSION) {
90            &EXTERNAL_INST_COMMANDS_6_2
91        } else {
92            &EXTERNAL_INST_COMMANDS
93        }
94    }
95
96    pub fn destination_names(&self, _ver: Version) -> &'static [&'static str] {
97        &DESTINATIONS
98    }
99
100    /// List of all the applyable filter types for the instrument
101    pub fn filter_types(&self, _ver: Version) -> &'static [&'static str] {
102        &super::common::COMMON_FILTER_TYPES
103    }
104
105    /// Return human readable name of the port.
106    pub fn human_readable_port(&self) -> &'static str {
107        crate::instruments::midi::PORTS[self.port as usize]
108    }
109
110    pub fn write(&self, ver: Version, w: &mut Writer) {
111        w.write_string(&self.name, 12);
112        w.write(TranspEq::from(ver, self.transpose, self.synth_params.associated_eq).into());
113        w.write(self.table_tick);
114        w.write(self.synth_params.volume);
115        w.write(self.synth_params.pitch);
116        w.write(self.synth_params.fine_tune);
117
118        w.write(self.input);
119        w.write(self.port);
120        w.write(self.channel);
121        w.write(self.bank);
122        w.write(self.program);
123
124        self.cca.write(w);
125        self.ccb.write(w);
126        self.ccc.write(w);
127        self.ccd.write(w);
128
129        self.synth_params.write(ver, w, ExternalInst::MOD_OFFSET);
130    }
131
132    pub fn from_reader(ver: Version, reader: &mut Reader, number: u8) -> M8Result<Self> {
133        let name = reader.read_string(12);
134        let transp_eq = TranspEq::from_version(ver, reader.read());
135
136        let table_tick = reader.read();
137        let volume = reader.read();
138        let pitch = reader.read();
139        let fine_tune = reader.read();
140
141        let input = reader.read();
142        let port = reader.read();
143        let channel = reader.read();
144        let bank = reader.read();
145        let program = reader.read();
146        let cca = ControlChange::from_reader(reader)?;
147        let ccb = ControlChange::from_reader(reader)?;
148        let ccc = ControlChange::from_reader(reader)?;
149        let ccd = ControlChange::from_reader(reader)?;
150
151        let synth_params = SynthParams::from_reader3(
152            ver,
153            reader,
154            volume,
155            pitch,
156            fine_tune,
157            transp_eq.eq,
158            ExternalInst::MOD_OFFSET,
159        )?;
160
161        Ok(ExternalInst {
162            number,
163            name,
164            transpose: transp_eq.transpose,
165            table_tick,
166            synth_params,
167
168            input,
169            port,
170            channel,
171            bank,
172            program,
173            cca,
174            ccb,
175            ccc,
176            ccd,
177        })
178    }
179}