m8_files/
fx.rs

1use crate::reader::*;
2use crate::version::*;
3use crate::writer::Writer;
4use crate::CommandPack;
5use array_concat::*;
6
7#[derive(Copy, Clone)]
8pub struct FxCommands {
9    pub commands: &'static [&'static str],
10}
11
12impl FxCommands {
13    pub fn try_render(self, cmd: u8) -> Option<&'static str> {
14        let cmd = cmd as usize;
15
16        if cmd < self.commands.len() {
17            Some(self.commands[cmd])
18        } else {
19            None
20        }
21    }
22}
23
24#[derive(PartialEq, Debug, Clone, Copy)]
25pub struct FX {
26    pub command: u8,
27    pub value: u8,
28}
29
30impl Default for FX {
31    fn default() -> Self {
32        Self {
33            command: 0xFF,
34            value: 0,
35        }
36    }
37}
38
39//////////////////////////////////////////
40// MARK: V2 commands
41//////////////////////////////////////////
42
43#[rustfmt::skip] // Keep constants with important order vertical for maintenance
44const SEQ_COMMAND_V2 : [&'static str; 23] = [
45    "ARP",
46    "CHA",
47    "DEL",
48    "GRV",
49    "HOP",
50    "KIL",
51    "RAN",
52    "RET",
53    "REP",
54    "NTH",
55    "PSL",
56    "PSN",
57    "PVB",
58    "PVX",
59    "SCA",
60    "SCG",
61    "SED",
62    "SNG",
63    "TBL",
64    "THO",
65    "TIC",
66    "TPO",
67    "TSP",
68];
69
70#[rustfmt::skip] // Keep constants with important order vertical for maintenance
71const FX_MIXER_COMMAND_V2 : [&'static str; 36] = [
72    "VMV",
73    "XCM",
74    "XCF",
75    "XCW",
76    "XCR",
77    "XDT",
78    "XDF",
79    "XDW",
80    "XDR",
81    "XRS",
82    "XRD",
83    "XRM",
84    "XRF",
85    "XRW",
86    "XRZ",
87    "VCH",
88    "VCD",
89    "VRE",
90    "VT1",
91    "VT2",
92    "VT3",
93    "VT4",
94    "VT5",
95    "VT6",
96    "VT7",
97    "VT8",
98    "DJF",
99    "IVO",
100    "ICH",
101    "IDE",
102    "IRE",
103    "IV2",
104    "IC2",
105    "ID2",
106    "IR2",
107    "USB",
108];
109
110const COMMANDS_V2: [&'static str; concat_arrays_size!(SEQ_COMMAND_V2, FX_MIXER_COMMAND_V2)] =
111    concat_arrays!(SEQ_COMMAND_V2, FX_MIXER_COMMAND_V2);
112
113//////////////////////////////////////////
114// MARK: V3 commands
115//////////////////////////////////////////
116
117#[rustfmt::skip] // Keep constants with important order vertical for maintenance
118const SEQ_COMMAND_V3 : [&'static str; 27] = [
119    "ARP",
120    "CHA",
121    "DEL",
122    "GRV",
123    "HOP",
124    "KIL",
125    "RND",
126    "RNL",
127    "RET",
128    "REP",
129    "RMX",
130    "NTH",
131    "PSL",
132    "PBN",
133    "PVB",
134    "PVX",
135    "SCA",
136    "SCG",
137    "SED",
138    "SNG",
139    "TBL",
140    "THO",
141    "TIC",
142    "TBX",
143    "TPO",
144    "TSP",
145    "OFF",
146];
147
148#[rustfmt::skip] // Keep constants with important order vertical for maintenance
149const FX_MIXER_COMMAND_V3 : [&'static str; 36] = [
150    "VMV",
151    "XCM",
152    "XCF",
153    "XCW",
154    "XCR",
155    "XDT",
156    "XDF",
157    "XDW",
158    "XDR",
159    "XRS",
160    "XRD",
161    "XRM",
162    "XRF",
163    "XRW",
164    "XRZ",
165    "VCH",
166    "VCD",
167    "VRE",
168    "VT1",
169    "VT2",
170    "VT3",
171    "VT4",
172    "VT5",
173    "VT6",
174    "VT7",
175    "VT8",
176    "DJF",
177    "IVO",
178    "ICH",
179    "IDE",
180    "IRE",
181    "IV2",
182    "IC2",
183    "ID2",
184    "IR2",
185    "USB",
186];
187
188const COMMANDS_V3: [&'static str; concat_arrays_size!(SEQ_COMMAND_V3, FX_MIXER_COMMAND_V3)] =
189    concat_arrays!(SEQ_COMMAND_V3, FX_MIXER_COMMAND_V3);
190
191//////////////////////////////////////////
192// MARK: V4 commands
193//////////////////////////////////////////
194
195#[rustfmt::skip] // Keep constants with important order vertical for maintenance
196const FX_MIXER_COMMAND_V4 : [&'static str; 44] = [
197    "VMV",
198    "XCM",
199    "XCF",
200    "XCW",
201    "XCR",
202    "XDT",
203    "XDF",
204    "XDW",
205    "XDR",
206    "XRS",
207    "XRD",
208    "XRM",
209    "XRF",
210    "XRW",
211    "XRZ",
212    "VCH",
213    "VDE",
214    "VRE",
215    "VT1",
216    "VT2",
217    "VT3",
218    "VT4",
219    "VT5",
220    "VT6",
221    "VT7",
222    "VT8",
223    "DJC",
224    "VIN",
225    "ICH",
226    "IDE",
227    "IRE",
228    "VI2",
229    "IC2",
230    "ID2",
231    "IR2",
232    "USB",
233
234    "DJR", // 0x3F
235    "DJT", // 0x40
236    "EQM", // 0x41
237    "EQI", // 0x42
238    "INS", // 0x43
239    "RTO", // 0x44
240    "ARC", // 0x45
241    "GGR", // 0x46
242];
243
244const COMMANDS_V4: [&'static str; concat_arrays_size!(SEQ_COMMAND_V3, FX_MIXER_COMMAND_V4)] =
245    concat_arrays!(SEQ_COMMAND_V3, FX_MIXER_COMMAND_V4);
246
247impl FX {
248    pub const V4_SIZE: usize = 2;
249
250    pub(crate) fn from_reader(reader: &mut Reader) -> M8Result<Self> {
251        Ok(Self {
252            command: reader.read(),
253            value: reader.read(),
254        })
255    }
256
257    pub fn write(self, w: &mut Writer) {
258        w.write(self.command);
259        w.write(self.value);
260    }
261
262    pub fn is_empty(self) -> bool {
263        self.command == 0xFF
264    }
265
266    pub fn print(&self, fx: FxCommands, pack: CommandPack) -> String {
267        if self.is_empty() {
268            format!("---  ")
269        } else {
270            let c = self.format_command(fx, pack);
271            format!("{}{:02x}", c, self.value)
272        }
273    }
274
275    /// Retrieve command names for a given version
276    pub fn fx_command_names(ver: Version) -> FxCommands {
277        if ver.at_least(4, 0) {
278            FxCommands {
279                commands: &COMMANDS_V4,
280            }
281        } else if ver.at_least(3, 0) {
282            FxCommands {
283                commands: &COMMANDS_V3,
284            }
285        } else {
286            FxCommands {
287                commands: &COMMANDS_V2,
288            }
289        }
290    }
291
292    fn format_command(&self, fx: FxCommands, instr: CommandPack) -> String {
293        match fx.try_render(self.command) {
294            Some(s) => String::from(s),
295            None => {
296                if instr.accepts(self.command) {
297                    match instr.try_render(self.command) {
298                        Some(v) => String::from(v),
299                        None => format!("I{:02X}", self.command - 0x80),
300                    }
301                } else {
302                    format!("?{:02x}", self.command)
303                }
304            }
305        }
306    }
307}