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#[rustfmt::skip] const 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] const 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#[rustfmt::skip] const 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] const 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#[rustfmt::skip] const 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", "DJT", "EQM", "EQI", "INS", "RTO", "ARC", "GGR", ];
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 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}