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