1use crate::reader::*;
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
298const COMMANDS_V4: [&'static str; concat_arrays_size!(SEQ_COMMAND_V3, FX_MIXER_COMMAND_V4)] =
299 concat_arrays!(SEQ_COMMAND_V3, FX_MIXER_COMMAND_V4);
300
301impl FX {
302 pub const V4_SIZE: usize = 2;
303
304 pub(crate) fn from_reader(reader: &mut Reader) -> M8Result<Self> {
305 Ok(Self {
306 command: reader.read(),
307 value: reader.read(),
308 })
309 }
310
311 pub fn write(self, w: &mut Writer) {
312 w.write(self.command);
313 w.write(self.value);
314 }
315
316 pub fn is_empty(self) -> bool {
317 self.command == 0xFF
318 }
319
320 pub fn print(&self, fx: FxCommands, pack: CommandPack) -> String {
321 if self.is_empty() {
322 format!("--- ")
323 } else {
324 let c = self.format_command(fx, pack);
325 format!("{}{:02x}", c, self.value)
326 }
327 }
328
329 pub fn fx_command_names(ver: Version) -> FxCommands {
331 if ver.at_least(4, 0) {
332 FxCommands {
333 commands: &COMMANDS_V4,
334 }
335 } else if ver.at_least(3, 0) {
336 FxCommands {
337 commands: &COMMANDS_V3,
338 }
339 } else {
340 FxCommands {
341 commands: &COMMANDS_V2,
342 }
343 }
344 }
345
346 fn format_command(&self, fx: FxCommands, instr: CommandPack) -> String {
347 match fx.try_render(self.command) {
348 Some(s) => String::from(s),
349 None => {
350 if instr.accepts(self.command) {
351 match instr.try_render(self.command) {
352 Some(v) => String::from(v),
353 None => format!("I{:02X}", self.command - 0x80),
354 }
355 } else {
356 format!("?{:02x}", self.command)
357 }
358 }
359 }
360 }
361}