1use crate::{reader::*, ReferenceTemplating};
2use crate::remapper::{EqMapping, InstrumentMapping, TableMapping};
3use crate::version::*;
4use crate::writer::Writer;
5use crate::CommandPack;
6use array_concat::*;
7
8#[derive(Copy, Clone)]
9pub struct FxCommands {
10 pub commands: &'static [&'static str],
11}
12
13impl FxCommands {
14 pub fn find_indices(&self, to_find: &[&str]) -> Vec<u8> {
15 let mut out = vec![];
16
17 for (i, cmd) in self.commands.iter().enumerate() {
18 if to_find.contains(cmd) {
19 out.push(i as u8)
20 }
21 }
22
23 out
24 }
25
26 pub fn try_render(self, cmd: u8) -> Option<&'static str> {
27 let cmd = cmd as usize;
28
29 if cmd < self.commands.len() {
30 Some(self.commands[cmd])
31 } else {
32 None
33 }
34 }
35}
36
37#[derive(PartialEq, Debug, Clone, Copy)]
38pub struct FX {
39 pub command: u8,
40 pub value: u8,
41}
42
43impl FX {
44 pub fn map_instr(
45 self,
46 instrument_mapping: &InstrumentMapping,
47 table_mapping: &TableMapping,
48 eq_mapping: &EqMapping,
49 ) -> Self {
50 let uval = self.value as usize;
51
52 if instrument_mapping
53 .instrument_tracking_commands
54 .contains(&self.command)
55 && uval < instrument_mapping.mapping.len()
56 {
57 Self {
58 command: self.command,
59 value: instrument_mapping.mapping[uval],
60 }
61 } else if table_mapping
62 .table_tracking_commands
63 .contains(&self.command)
64 && uval < table_mapping.mapping.len()
65 {
66 Self {
67 command: self.command,
68 value: table_mapping.mapping[uval],
69 }
70 } else if eq_mapping.eq_tracking_commands.contains(&self.command)
71 && uval < eq_mapping.mapping.len()
72 {
73 Self {
74 command: self.command,
75 value: eq_mapping.mapping[uval],
76 }
77 } else {
78 self
79 }
80 }
81}
82
83impl Default for FX {
84 fn default() -> Self {
85 Self {
86 command: 0xFF,
87 value: 0,
88 }
89 }
90}
91
92#[rustfmt::skip] const SEQ_COMMAND_V2 : [&'static str; 23] = [
98 "ARP",
99 "CHA",
100 "DEL",
101 "GRV",
102 "HOP",
103 "KIL",
104 "RAN",
105 "RET",
106 "REP",
107 "NTH",
108 "PSL",
109 "PSN",
110 "PVB",
111 "PVX",
112 "SCA",
113 "SCG",
114 "SED",
115 "SNG",
116 "TBL",
117 "THO",
118 "TIC",
119 "TPO",
120 "TSP",
121];
122
123#[rustfmt::skip] const FX_MIXER_COMMAND_V2 : [&'static str; 36] = [
125 "VMV",
126 "XCM",
127 "XCF",
128 "XCW",
129 "XCR",
130 "XDT",
131 "XDF",
132 "XDW",
133 "XDR",
134 "XRS",
135 "XRD",
136 "XRM",
137 "XRF",
138 "XRW",
139 "XRZ",
140 "VCH",
141 "VCD",
142 "VRE",
143 "VT1",
144 "VT2",
145 "VT3",
146 "VT4",
147 "VT5",
148 "VT6",
149 "VT7",
150 "VT8",
151 "DJF",
152 "IVO",
153 "ICH",
154 "IDE",
155 "IRE",
156 "IV2",
157 "IC2",
158 "ID2",
159 "IR2",
160 "USB",
161];
162
163const COMMANDS_V2: [&'static str; concat_arrays_size!(SEQ_COMMAND_V2, FX_MIXER_COMMAND_V2)] =
164 concat_arrays!(SEQ_COMMAND_V2, FX_MIXER_COMMAND_V2);
165
166#[rustfmt::skip] const SEQ_COMMAND_V3 : [&'static str; 27] = [
172 "ARP",
173 "CHA",
174 "DEL",
175 "GRV",
176 "HOP",
177 "KIL",
178 "RND",
179 "RNL",
180 "RET",
181 "REP",
182 "RMX",
183 "NTH",
184 "PSL",
185 "PBN",
186 "PVB",
187 "PVX",
188 "SCA",
189 "SCG",
190 "SED",
191 "SNG",
192 "TBL",
193 "THO",
194 "TIC",
195 "TBX",
196 "TPO",
197 "TSP",
198 "OFF"
199];
200
201#[rustfmt::skip] const FX_MIXER_COMMAND_V3 : [&'static str; 36] = [
203 "VMV",
204 "XCM",
205 "XCF",
206 "XCW",
207 "XCR",
208 "XDT",
209 "XDF",
210 "XDW",
211 "XDR",
212 "XRS",
213 "XRD",
214 "XRM",
215 "XRF",
216 "XRW",
217 "XRZ",
218 "VCH",
219 "VCD",
220 "VRE",
221 "VT1",
222 "VT2",
223 "VT3",
224 "VT4",
225 "VT5",
226 "VT6",
227 "VT7",
228 "VT8",
229 "DJF",
230 "IVO",
231 "ICH",
232 "IDE",
233 "IRE",
234 "IV2",
235 "IC2",
236 "ID2",
237 "IR2",
238 "USB",
239];
240
241const COMMANDS_V3: [&'static str; concat_arrays_size!(SEQ_COMMAND_V3, FX_MIXER_COMMAND_V3)] =
242 concat_arrays!(SEQ_COMMAND_V3, FX_MIXER_COMMAND_V3);
243
244#[rustfmt::skip] const FX_MIXER_COMMAND_V4 : [&'static str; 45] = [
250 "VMV",
251 "XCM",
252 "XCF",
253 "XCW",
254 "XCR",
255 "XDT",
256 "XDF",
257 "XDW",
258 "XDR",
259 "XRS",
260 "XRD",
261 "XRM",
262 "XRF",
263 "XRW",
264 "XRZ",
265 "VCH",
266 "VDE",
267 "VRE",
268 "VT1",
269 "VT2",
270 "VT3",
271 "VT4",
272 "VT5",
273 "VT6",
274 "VT7",
275 "VT8",
276 "DJC",
277 "VIN",
278 "ICH",
279 "IDE",
280 "IRE",
281 "VI2",
282 "IC2",
283 "ID2",
284 "IR2",
285 "USB",
286
287 "DJR", "DJT", "EQM", "EQI", "INS", "RTO", "ARC", "GGR", "NXT", ];
297
298#[rustfmt::skip] const FX_MIXER_COMMAND_V6_2 : [&'static str; 50] = [
300 "VMV",
301 "XMM",
302 "XMF",
303 "XMW",
304 "XMR",
305 "XDT",
306 "XDF",
307 "XDW",
308 "XDR",
309 "XRS",
310 "XRD",
311 "XRM",
312 "XRF",
313 "XRW",
314 "XRZ",
315 "VMX",
316 "VDE",
317 "VRE",
318 "VT1",
319 "VT2",
320 "VT3",
321 "VT4",
322 "VT5",
323 "VT6",
324 "VT7",
325 "VT8",
326 "DJC",
327 "VIN",
328 "IMX",
329 "IDE",
330 "IRE",
331 "VI2",
332 "IM2",
333 "ID2",
334 "IR2",
335 "USB",
336
337 "DJR", "DJT", "EQM", "EQI", "INS", "RTO", "ARC", "GGR", "NXT", "XRH", "XMT", "OTT",
350 "OTC",
351 "OTI",
352];
353
354const COMMANDS_V4: [&'static str; concat_arrays_size!(SEQ_COMMAND_V3, FX_MIXER_COMMAND_V4)] =
355 concat_arrays!(SEQ_COMMAND_V3, FX_MIXER_COMMAND_V4);
356
357const COMMANDS_V6_2: [&'static str; concat_arrays_size!(SEQ_COMMAND_V3, FX_MIXER_COMMAND_V6_2)] =
358 concat_arrays!(SEQ_COMMAND_V3, FX_MIXER_COMMAND_V6_2);
359
360impl FX {
361 pub const V4_SIZE: usize = 2;
362
363 pub(crate) fn from_reader(reader: &mut Reader) -> M8Result<Self> {
364 Ok(Self {
365 command: reader.read(),
366 value: reader.read(),
367 })
368 }
369
370 pub fn write(self, w: &mut Writer) {
371 w.write(self.command);
372 w.write(self.value);
373 }
374
375 pub fn is_empty(self) -> bool {
376 self.command == 0xFF
377 }
378
379 pub fn print(&self, fx: FxCommands, pack: CommandPack, templates: &ReferenceTemplating) -> String {
380 if self.is_empty() {
381 format!("--- ")
382 } else {
383 let c = self.format_command(fx, pack);
384 match templates.try_template(&c, self.value) {
385 Some(templated) => templated,
386 None => format!("{}{:02x}", c, self.value)
387 }
388 }
389 }
390
391 pub fn fx_command_names(ver: Version) -> FxCommands {
393 if ver.at_least(6, 1) {
394 FxCommands {
395 commands: &COMMANDS_V6_2,
396 }
397 } else if ver.at_least(4, 0) {
398 FxCommands {
399 commands: &COMMANDS_V4,
400 }
401 } else if ver.at_least(3, 0) {
402 FxCommands {
403 commands: &COMMANDS_V3,
404 }
405 } else {
406 FxCommands {
407 commands: &COMMANDS_V2,
408 }
409 }
410 }
411
412 fn format_command(&self, fx: FxCommands, instr: CommandPack) -> String {
413 match fx.try_render(self.command) {
414 Some(s) => String::from(s),
415 None => {
416 if instr.accepts(self.command) {
417 match instr.try_render(self.command) {
418 Some(v) => String::from(v),
419 None => format!("I{:02X}", self.command - 0x80),
420 }
421 } else {
422 format!("?{:02x}", self.command)
423 }
424 }
425 }
426 }
427}