ot_tools_io/banks/
parts.rs

1/*
2SPDX-License-Identifier: GPL-3.0-or-later
3Copyright © 2024 Mike Robeson [dijksterhuis]
4*/
5
6//! Model for part data within a bank.
7use crate::{CheckHeader, DefaultsArray};
8use ot_tools_io_derive::DefaultsAsArray;
9use serde::{Deserialize, Serialize};
10use serde_big_array::{Array, BigArray};
11use std::array::from_fn;
12
13/// Header data for Parts, indicating when a new Part data section starts in binary data files:
14/// `PART`
15const PART_HEADER: [u8; 4] = [0x50, 0x41, 0x52, 0x54];
16
17#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
18pub enum OnOrOff {
19    On = 1,
20    Off = 0,
21}
22
23/// Audio Track MAIN and CUE volume.
24/// Both are 108 by default.
25#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Copy, DefaultsAsArray)]
26pub struct AudioTrackVolume {
27    pub main: u8,
28    pub cue: u8,
29}
30
31// TODO: Double check values
32impl Default for AudioTrackVolume {
33    fn default() -> Self {
34        Self {
35            main: 0x6c, // 108
36            cue: 0x6c,  // 108
37        }
38    }
39}
40
41/// Scenes currently selected in the Part.
42/// Whether Scenes are muted or not are controlled at the Project level.
43#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
44pub struct ActiveScenes {
45    pub scene_a: u8,
46    pub scene_b: u8,
47}
48
49impl Default for ActiveScenes {
50    fn default() -> Self {
51        Self {
52            scene_a: 0,
53            scene_b: 8,
54        }
55    }
56}
57
58/// An Audio Track's Setup values for the Static machine on the track (loop setting/slice setting/len setting etc.).
59#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Copy)]
60pub struct AudioTrackMachineParamsSetupStatic {
61    pub xloop: u8,
62    pub slic: u8,
63    pub len: u8,
64    pub rate: u8,
65    pub tstr: u8,
66    pub tsns: u8,
67}
68
69/// An Audio Track's Setup values for the Flex machine on the track (loop setting/slice setting/len setting etc.).
70#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Copy)]
71pub struct AudioTrackMachineParamsSetupFlex {
72    pub xloop: u8,
73    pub slic: u8,
74    pub len: u8,
75    pub rate: u8,
76    pub tstr: u8,
77    pub tsns: u8,
78}
79
80/// An Audio Track's Setup values for the Thru machine on the track. Should not contain any data.
81#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Copy)]
82pub struct AudioTrackMachineParamsSetupThru {
83    unused_1: u8,
84    unused_2: u8,
85    unused_3: u8,
86    unused_4: u8,
87    unused_5: u8,
88    unused_6: u8,
89}
90
91/// An Audio Track's Setup values for the Neighbor machine on the track. Should not contain any data.
92#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Copy)]
93pub struct AudioTrackMachineParamsSetupNeighbor {
94    unused_1: u8,
95    unused_2: u8,
96    unused_3: u8,
97    unused_4: u8,
98    unused_5: u8,
99    unused_6: u8,
100}
101
102/// An Audio Track's Setup values for the Pickup machine on the track.
103#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Copy)]
104pub struct AudioTrackMachineParamsSetupPickup {
105    unused_1: u8,
106    unused_2: u8,
107    unused_3: u8,
108    unused_4: u8,
109    pub tstr: u8,
110    pub tsns: u8,
111}
112
113/// Audio Tracks Machine Setup pages.
114/// As before, separate from other Audio Track parameter fields to be persisted,
115/// allowing safer audio triggering.
116#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Copy, DefaultsAsArray)]
117pub struct AudioTrackMachinesParamsSetup {
118    pub static_machine: AudioTrackMachineParamsSetupStatic,
119    pub flex_machine: AudioTrackMachineParamsSetupFlex,
120    pub thru_machine: AudioTrackMachineParamsSetupThru,
121    pub neighbor_machine: AudioTrackMachineParamsSetupNeighbor,
122    pub pickup_machine: AudioTrackMachineParamsSetupPickup,
123}
124
125impl Default for AudioTrackMachinesParamsSetup {
126    fn default() -> Self {
127        Self {
128            static_machine: AudioTrackMachineParamsSetupStatic {
129                xloop: 1,
130                slic: 0,
131                len: 0,
132                rate: 0,
133                tstr: 1,
134                tsns: 64,
135            },
136            flex_machine: AudioTrackMachineParamsSetupFlex {
137                xloop: 1,
138                slic: 0,
139                len: 0,
140                rate: 0,
141                tstr: 1,
142                tsns: 64,
143            },
144            thru_machine: AudioTrackMachineParamsSetupThru {
145                unused_1: 0,
146                unused_2: 0,
147                unused_3: 0,
148                unused_4: 0,
149                unused_5: 0,
150                unused_6: 0,
151            },
152            neighbor_machine: AudioTrackMachineParamsSetupNeighbor {
153                unused_1: 0,
154                unused_2: 0,
155                unused_3: 0,
156                unused_4: 0,
157                unused_5: 0,
158                unused_6: 0,
159            },
160            pickup_machine: AudioTrackMachineParamsSetupPickup {
161                unused_1: 0,
162                unused_2: 0,
163                unused_3: 0,
164                unused_4: 0,
165                tstr: 1,
166                tsns: 64,
167            },
168        }
169    }
170}
171
172/// Audio Tracks Machine Slot assignments.
173/// Sample Slots assigned for each machine.
174/// Also tracks the recording buffer sample slot assignment.
175#[derive(Debug, Serialize, Deserialize, Clone, Copy, PartialEq)]
176pub struct AudioTrackMachineSlot {
177    pub static_slot_id: u8,
178    pub flex_slot_id: u8,
179    unused_1: u8,
180    unused_2: u8,
181    pub recorder_slot_id: u8,
182}
183
184impl AudioTrackMachineSlot {
185    /// WARNING: This `defaults` method is not from the `Defaults` trait, as we
186    /// cannot use a default struct instance to create an array/vector of
187    /// machine slots data --> the individual default depends on their position
188    /// in the final array!
189    ///
190    /// In the future, maybe it might be worth creating `default_with` and
191    /// `defaults_with` methods to deal with this. But it's not clear they are
192    /// needed just yet. 80/20.
193    pub fn defaults<const N: usize>() -> [Self; N] {
194        from_fn(|x| {
195            let x_u8 = x as u8;
196            Self {
197                static_slot_id: x_u8,
198                flex_slot_id: x_u8,
199                unused_1: 0,
200                unused_2: 0,
201                recorder_slot_id: 128 + x_u8,
202            }
203        })
204    }
205}
206
207/// Values of an Audio Track's parameters page for the Static machine on the track (pitch/slice/len etc).
208#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Copy)]
209pub struct AudioTrackMachineParamsValuesStatic {
210    pub ptch: u8,
211    pub strt: u8,
212    pub len: u8,
213    pub rate: u8,
214    pub rtrg: u8,
215    pub rtim: u8,
216}
217
218/// Values of an Audio Track's parameters page for the Flex machine on the track (pitch/slice/len etc).
219#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Copy)]
220pub struct AudioTrackMachineParamsValuesFlex {
221    pub ptch: u8,
222    pub strt: u8,
223    pub len: u8,
224    pub rate: u8,
225    pub rtrg: u8,
226    pub rtim: u8,
227}
228
229/// Values of an Audio Track's parameters page for the Flex machine on the track (in/vol etc).
230#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Copy)]
231pub struct AudioTrackMachineParamsValuesThru {
232    pub in_ab: u8,
233    pub vol_ab: u8,
234    pub unused_1: u8,
235    pub in_cd: u8,
236    pub vol_cd: u8,
237    pub unused_2: u8,
238}
239
240/// Values of an Audio Track's parameters page for the Neighbor machine on the track. Should not contain any data.
241#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Copy)]
242pub struct AudioTrackMachineParamsValuesNeighbor {
243    unused_1: u8,
244    unused_2: u8,
245    unused_3: u8,
246    unused_4: u8,
247    unused_5: u8,
248    unused_6: u8,
249}
250
251/// Values of an Audio Track's parameters page for the Pickup machine on the track. (pitch/dir/len etc).
252#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Copy)]
253pub struct AudioTrackMachineParamsValuesPickup {
254    pub ptch: u8,
255    pub dir: u8,
256    pub len: u8,
257    unused_1: u8,
258    pub gain: u8,
259    pub op: u8,
260}
261
262/// Audio Tracks Machine Parameter pages.
263/// Machine parameter values persist after the machine type is changed,
264/// meaning audio keeps playing until the new machine is triggered to play new audio.
265#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Copy, DefaultsAsArray)]
266pub struct AudioTrackMachinesParamsValues {
267    pub static_machine: AudioTrackMachineParamsValuesStatic,
268    pub flex_machine: AudioTrackMachineParamsValuesFlex,
269    pub thru_machine: AudioTrackMachineParamsValuesThru,
270    pub neighbor_machine: AudioTrackMachineParamsValuesNeighbor,
271    pub pickup_machine: AudioTrackMachineParamsValuesPickup,
272}
273
274// TODO: Set defaults
275impl Default for AudioTrackMachinesParamsValues {
276    fn default() -> Self {
277        Self {
278            static_machine: AudioTrackMachineParamsValuesStatic {
279                ptch: 64,
280                strt: 0,
281                len: 0,
282                rate: 127,
283                rtrg: 0,
284                rtim: 79,
285            },
286            flex_machine: AudioTrackMachineParamsValuesFlex {
287                ptch: 64,
288                strt: 0,
289                len: 0,
290                rate: 127,
291                rtrg: 0,
292                rtim: 79,
293            },
294            thru_machine: AudioTrackMachineParamsValuesThru {
295                in_ab: 0,
296                vol_ab: 64,
297                unused_1: 0,
298                in_cd: 0,
299                vol_cd: 64,
300                unused_2: 0,
301            },
302            neighbor_machine: AudioTrackMachineParamsValuesNeighbor {
303                unused_1: 0,
304                unused_2: 0,
305                unused_3: 0,
306                unused_4: 0,
307                unused_5: 0,
308                unused_6: 0,
309            },
310            pickup_machine: AudioTrackMachineParamsValuesPickup {
311                ptch: 64,
312                dir: 2,
313                len: 1,
314                unused_1: 127,
315                gain: 64,
316                op: 1,
317            },
318        }
319    }
320}
321
322/// Values of a Track's main LFO parameters page.
323/// Note that the speed and depth settings in the LFO Setup menu are looking at these values too.
324#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Copy)]
325pub struct LfoParamsValues {
326    pub spd1: u8,
327    pub spd2: u8,
328    pub spd3: u8,
329    pub dep1: u8,
330    pub dep2: u8,
331    pub dep3: u8,
332}
333
334/// Values of a Track's main AMP parameters page.
335#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Copy)]
336pub struct AudioTrackAmpParamsValues {
337    pub atk: u8,
338    pub hold: u8,
339    pub rel: u8,
340    pub vol: u8,
341    pub bal: u8,
342    /// Reserved space for the \<F\> parameter used by Scenes and LFOs
343    pub unused: u8,
344}
345
346// allow the verbose implementation to keep things
347// - (a) standardised across all types
348// - (b) easier for non-rustaceans to follow when reading through data structures
349#[allow(clippy::derivable_impls)]
350impl Default for AudioTrackAmpParamsValues {
351    fn default() -> Self {
352        Self {
353            atk: 0,
354            hold: 127,
355            rel: 127,
356            vol: 64,
357            bal: 64,
358            unused: 127,
359        }
360    }
361}
362
363/// Values of a Track's FX parameters page.
364#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Copy)]
365pub struct AudioTrackFxParamsValues {
366    pub param_1: u8,
367    pub param_2: u8,
368    pub param_3: u8,
369    pub param_4: u8,
370    pub param_5: u8,
371    pub param_6: u8,
372}
373
374/// Audio Tracks Paramater Page values. LFO, Amp, FX etc.
375#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Copy, DefaultsAsArray)]
376pub struct AudioTrackParamsValues {
377    pub lfo: LfoParamsValues,
378    pub amp: AudioTrackAmpParamsValues,
379    pub fx1: AudioTrackFxParamsValues,
380    pub fx2: AudioTrackFxParamsValues,
381}
382
383impl Default for AudioTrackParamsValues {
384    fn default() -> Self {
385        Self {
386            lfo: LfoParamsValues {
387                spd1: 32,
388                spd2: 32,
389                spd3: 32,
390                dep1: 0,
391                dep2: 0,
392                dep3: 0,
393            },
394            amp: AudioTrackAmpParamsValues::default(),
395            fx1: AudioTrackFxParamsValues {
396                param_1: 0,
397                param_2: 127,
398                param_3: 0,
399                param_4: 64,
400                param_5: 0,
401                param_6: 64,
402            },
403            fx2: AudioTrackFxParamsValues {
404                param_1: 47,
405                param_2: 0,
406                param_3: 127,
407                param_4: 0,
408                param_5: 127,
409                param_6: 0,
410            },
411        }
412    }
413}
414
415/// First set of values for a Track's LFO Setup page.
416#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Copy)]
417pub struct LfoParamsSetup1 {
418    pub lfo1_pmtr: u8,
419    pub lfo2_pmtr: u8,
420    pub lfo3_pmtr: u8,
421    pub lfo1_wave: u8,
422    pub lfo2_wave: u8,
423    pub lfo3_wave: u8,
424}
425
426/// Second set of values for a Track's LFO Setup page.
427#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Copy)]
428pub struct LfoParamsSetup2 {
429    pub lfo1_mult: u8,
430    pub lfo2_mult: u8,
431    pub lfo3_mult: u8,
432    pub lfo1_trig: u8,
433    pub lfo2_trig: u8,
434    pub lfo3_trig: u8,
435}
436
437/// Values for a Track's AMP Setup page.
438#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Copy)]
439pub struct AudioTrackAmpParamsSetup {
440    pub amp: u8,
441    pub sync: u8,
442    pub atck: u8,
443    pub fx1: u8,
444    pub fx2: u8,
445    // This is the hidden <F> parameter used in LFOs and Scenes etc.
446    unused: u8,
447}
448
449/// Values for a Track's FX Setup page.
450#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Copy)]
451pub struct AudioTrackFxParamsSetup {
452    pub setting1: u8,
453    pub setting2: u8,
454    pub setting3: u8,
455    pub setting4: u8,
456    pub setting5: u8,
457    pub setting6: u8,
458}
459
460/// Audio Tracks Paramater Setup pages for LFO, Amp, FX etc.
461#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Copy, DefaultsAsArray)]
462pub struct AudioTrackParamsSetup {
463    /// Parameter Target and Wave selection for the 3x LFOs on this Audio Track.
464    pub lfo_setup_1: LfoParamsSetup1,
465    /// Amplitude setup page
466    pub amp: AudioTrackAmpParamsSetup,
467    /// FX #1 setup page
468    pub fx1: AudioTrackFxParamsSetup,
469    /// FX #2 setup page
470    pub fx2: AudioTrackFxParamsSetup,
471    /// Multiplier and Trigger type selection for the 3x LFOs on this Audio Track.
472    pub lfo_setup_2: LfoParamsSetup2,
473}
474
475impl Default for AudioTrackParamsSetup {
476    fn default() -> Self {
477        Self {
478            lfo_setup_1: LfoParamsSetup1 {
479                lfo1_pmtr: 0,
480                lfo2_pmtr: 0,
481                lfo3_pmtr: 0,
482                lfo1_wave: 0,
483                lfo2_wave: 0,
484                lfo3_wave: 0,
485            },
486            amp: AudioTrackAmpParamsSetup {
487                amp: 1,
488                sync: 1,
489                atck: 0,
490                fx1: 0,
491                fx2: 0,
492                unused: 0,
493            },
494            fx1: AudioTrackFxParamsSetup {
495                setting1: 0,
496                setting2: 0,
497                setting3: 1,
498                setting4: 0,
499                setting5: 3,
500                setting6: 0,
501            },
502            fx2: AudioTrackFxParamsSetup {
503                setting1: 0,
504                setting2: 1,
505                setting3: 127,
506                setting4: 1,
507                setting5: 0,
508                setting6: 0,
509            },
510            lfo_setup_2: LfoParamsSetup2 {
511                lfo1_mult: 0,
512                lfo2_mult: 0,
513                lfo3_mult: 0,
514                lfo1_trig: 0,
515                lfo2_trig: 0,
516                lfo3_trig: 0,
517            },
518        }
519    }
520}
521
522/// Values for a MIDI Track's MIDI parameter page.
523#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Copy)]
524pub struct MidiTrackMidiParamsValues {
525    pub note: u8,
526    pub vel: u8,
527    pub len: u8,
528    pub not2: u8,
529    pub not3: u8,
530    pub not4: u8,
531}
532
533/// Values for a MIDI Track's LFO parameter page.
534/// todo: combine with lfo params?
535#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Copy)]
536pub struct MidiTrackLfoParamsValues {
537    pub spd1: u8,
538    pub spd2: u8,
539    pub spd3: u8,
540    pub dep1: u8,
541    pub dep2: u8,
542    pub dep3: u8,
543}
544
545/// Values for a MIDI Track's Arp parameter page.
546#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Copy)]
547pub struct MidiTrackArpParamsValues {
548    pub tran: u8,
549    pub leg: u8,
550    pub mode: u8,
551    pub spd: u8,
552    pub rnge: u8,
553    pub nlen: u8,
554}
555
556/// Values for a MIDI Track's CC1 parameter page.
557#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Copy)]
558pub struct MidiTrackCc1ParamsValues {
559    pub pb: u8,
560    pub at: u8,
561    pub cc1: u8,
562    pub cc2: u8,
563    pub cc3: u8,
564    pub cc4: u8,
565}
566
567/// Values for a MIDI Track's CC2 parameter page.
568#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Copy)]
569pub struct MidiTrackCc2ParamsValues {
570    pub cc5: u8,
571    pub cc6: u8,
572    pub cc7: u8,
573    pub cc8: u8,
574    pub cc9: u8,
575    pub cc10: u8,
576}
577
578/// MIDI Tracks Paramater values. LFO, Amp, FX etc.
579#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Copy, DefaultsAsArray)]
580pub struct MidiTrackParamsValues {
581    pub midi: MidiTrackMidiParamsValues,
582    pub arp: MidiTrackLfoParamsValues,
583    pub lfo: MidiTrackArpParamsValues,
584    pub ctrl1: MidiTrackCc1ParamsValues,
585    pub ctrl2: MidiTrackCc2ParamsValues,
586    #[serde(with = "BigArray")]
587    pub unknown: [u8; 2],
588}
589
590impl Default for MidiTrackParamsValues {
591    fn default() -> Self {
592        Self {
593            midi: MidiTrackMidiParamsValues {
594                note: 48,
595                vel: 100,
596                len: 6,
597                not2: 64,
598                not3: 64,
599                not4: 64,
600            },
601            arp: MidiTrackLfoParamsValues {
602                spd1: 32,
603                spd2: 32,
604                spd3: 32,
605                dep1: 0,
606                dep2: 0,
607                dep3: 0,
608            },
609            lfo: MidiTrackArpParamsValues {
610                tran: 64,
611                leg: 0,
612                mode: 0,
613                spd: 5,
614                rnge: 0,
615                nlen: 6,
616            },
617            ctrl1: MidiTrackCc1ParamsValues {
618                pb: 64,
619                at: 0,
620                cc1: 127,
621                cc2: 0,
622                cc3: 0,
623                cc4: 64,
624            },
625            ctrl2: MidiTrackCc2ParamsValues {
626                cc5: 0,
627                cc6: 0,
628                cc7: 0,
629                cc8: 0,
630                cc9: 0,
631                cc10: 0,
632            },
633            unknown: [0, 0],
634        }
635    }
636}
637
638/// Values for a MIDI Track's Note Setup page.
639#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Copy)]
640pub struct MidiTrackNoteParamsSetup {
641    pub chan: u8,
642    pub bank: u8,
643    pub prog: u8,
644    unused_1: u8,
645    pub sbank: u8,
646    unused_2: u8,
647}
648
649/// Values for a MIDI Track's Arp Setup page.
650#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Copy)]
651pub struct MidiTrackArpParamsSetup {
652    unused_1: u8,
653    unused_2: u8,
654    /// Length of the arp sequence
655    pub len: u8,
656    unused_3: u8,
657    unused_4: u8,
658    /// maximum 24 -- B Min
659    /// mininim 0 -- Off
660    pub key: u8,
661}
662
663/// Values for a MIDI Track's CC1 Setup page.
664#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Copy)]
665pub struct MidiTrackCc1ParamsSetup {
666    unused_1: u8,
667    unused_2: u8,
668    pub cc1: u8,
669    pub cc2: u8,
670    pub cc3: u8,
671    pub cc4: u8,
672}
673
674/// Values for a MIDI Track's CC2 Setup page.
675#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Copy)]
676pub struct MidiTrackCc2ParamsSetup {
677    pub cc5: u8,
678    pub cc6: u8,
679    pub cc7: u8,
680    pub cc8: u8,
681    pub cc9: u8,
682    pub cc10: u8,
683}
684
685/// MIDI Tracks Paramater Setup pages for LFO, Amp, FX etc.
686#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Copy, DefaultsAsArray)]
687pub struct MidiTrackParamsSetup {
688    pub note: MidiTrackNoteParamsSetup,
689    pub lfo1: LfoParamsSetup1,
690    pub arp: MidiTrackArpParamsSetup,
691    pub ctrl1: MidiTrackCc1ParamsSetup,
692    pub ctrl2: MidiTrackCc2ParamsSetup,
693    pub lfo2: LfoParamsSetup2,
694}
695
696impl Default for MidiTrackParamsSetup {
697    fn default() -> Self {
698        Self {
699            note: MidiTrackNoteParamsSetup {
700                chan: 0,
701                bank: 128,
702                prog: 128,
703                unused_1: 0,
704                sbank: 128,
705                unused_2: 0,
706            },
707            lfo1: LfoParamsSetup1 {
708                lfo1_pmtr: 0,
709                lfo2_pmtr: 0,
710                lfo3_pmtr: 0,
711                lfo1_wave: 0,
712                lfo2_wave: 0,
713                lfo3_wave: 0,
714            },
715            arp: MidiTrackArpParamsSetup {
716                unused_1: 0,
717                unused_2: 0,
718                len: 7,
719                unused_3: 0,
720                unused_4: 0,
721                key: 0,
722            },
723            ctrl1: MidiTrackCc1ParamsSetup {
724                unused_1: 0,
725                unused_2: 0,
726                cc1: 7,
727                cc2: 1,
728                cc3: 2,
729                cc4: 10,
730            },
731            ctrl2: MidiTrackCc2ParamsSetup {
732                cc5: 71,
733                cc6: 72,
734                cc7: 73,
735                cc8: 74,
736                cc9: 75,
737                cc10: 76,
738            },
739            lfo2: LfoParamsSetup2 {
740                lfo1_mult: 0,
741                lfo2_mult: 0,
742                lfo3_mult: 0,
743                lfo1_trig: 0,
744                lfo2_trig: 0,
745                lfo3_trig: 0,
746            },
747        }
748    }
749}
750
751/// A custom LFO Design -- array of 16 values.
752/// 0 -> 127 values (above line) maps to 0 -> 127.
753/// -1 -> -127 values (above line) seems to map to 255 -> 128.
754#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, DefaultsAsArray)]
755pub struct CustomLfoDesign(pub [u8; 16]);
756
757/// Default is a 16 length array with zero values
758impl Default for CustomLfoDesign {
759    fn default() -> Self {
760        Self(from_fn(|_| 0))
761    }
762}
763
764/// LFO Interpolation mask.
765/// Indicates which LFO steps should have values interpolated when LFO is triggered.
766/// Not sure exactly how the calculation works yet.
767#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, DefaultsAsArray)]
768pub struct CustomLfoInterpolationMask(pub [u8; 2]);
769
770impl Default for CustomLfoInterpolationMask {
771    fn default() -> Self {
772        Self(from_fn(|_| 0))
773    }
774}
775
776/// First page of settings controlling an Audio Track's Recording Buffer configuration.
777#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Copy)]
778pub struct RecorderSetupSources {
779    pub in_ab: u8,
780    pub in_cd: u8,
781    /// `64` is MAX. `63` and lower are actual values.
782    pub rlen: u8,
783    pub trig: u8,
784    /// internal recording source
785    pub src3: u8,
786    pub xloop: u8,
787}
788
789/// Second page of settings controlling an Audio Track's Recording Buffer configuration.
790#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Copy)]
791pub struct RecorderSetupProcessing {
792    pub fin: u8,
793    pub fout: u8,
794    pub ab: u8,
795    pub qrec: u8,
796    pub qpl: u8,
797    pub cd: u8,
798}
799
800/// Recorder Setup Pages
801#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Copy, DefaultsAsArray)]
802pub struct RecorderSetup {
803    pub src: RecorderSetupSources,
804    pub proc: RecorderSetupProcessing,
805}
806
807impl Default for RecorderSetup {
808    fn default() -> Self {
809        Self {
810            src: RecorderSetupSources {
811                in_ab: 1,
812                in_cd: 1,
813                rlen: 64,
814                trig: 0,
815                src3: 0,
816                xloop: 1,
817            },
818            proc: RecorderSetupProcessing {
819                fin: 0,
820                fout: 0,
821                ab: 0,
822                qrec: 255,
823                qpl: 255,
824                cd: 0,
825            },
826        }
827    }
828}
829
830// todo: merge with the Pattern Plock variant of this?
831/// A scene's parameter assignments on the Playback/Machine page for an Audio Track.
832#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Copy)]
833pub struct AudioTrackSceneLockPlayback {
834    pub param1: u8,
835    pub param2: u8,
836    pub param3: u8,
837    pub param4: u8,
838    pub param5: u8,
839    pub param6: u8,
840}
841
842/// Scene parameter assignments for a single audio track.
843///
844/// 255 is no assignment on the scene for that specific audio track's parameter
845/// value.
846///
847/// Any other value is the Scene's assigned value for that control.
848#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Copy, DefaultsAsArray)]
849pub struct AudioTrackScenesParamsAssignments {
850    /// Scene assignments for the Audio Track's active playback machine
851    pub machine: AudioTrackSceneLockPlayback,
852    /// Scene assignments for the Audio Track's LFO parameters
853    pub lfo: LfoParamsValues,
854    /// Scene assignments for the Audio Track's AMP parameters
855    pub amp: AudioTrackAmpParamsValues,
856    /// Scene assignments for the Audio Track's FX1 parameters
857    pub fx1: AudioTrackFxParamsValues,
858    /// Scene assignments for the Audio Track's FX2 parameters
859    pub fx2: AudioTrackFxParamsValues,
860    /// Unknown, likely leftover sample slot assignment (it
861    /// seems the underlying machine OS code re-uses the same
862    /// data structure in several places).
863    unknown_1: u8,
864    /// Unknown, likely leftover sample slot assignment (it
865    /// seems the underlying machine OS code re-uses the same
866    /// data structure in several places).
867    unknown_2: u8,
868}
869
870impl Default for AudioTrackScenesParamsAssignments {
871    fn default() -> Self {
872        Self {
873            machine: AudioTrackSceneLockPlayback {
874                param1: 255,
875                param2: 255,
876                param3: 255,
877                param4: 255,
878                param5: 255,
879                param6: 255,
880            },
881            lfo: LfoParamsValues {
882                spd1: 255,
883                spd2: 255,
884                spd3: 255,
885                dep1: 255,
886                dep2: 255,
887                dep3: 255,
888            },
889            amp: AudioTrackAmpParamsValues {
890                atk: 255,
891                hold: 255,
892                rel: 255,
893                vol: 255,
894                bal: 255,
895                unused: 255,
896            },
897            fx1: AudioTrackFxParamsValues {
898                param_1: 255,
899                param_2: 255,
900                param_3: 255,
901                param_4: 255,
902                param_5: 255,
903                param_6: 255,
904            },
905            fx2: AudioTrackFxParamsValues {
906                param_1: 255,
907                param_2: 255,
908                param_3: 255,
909                param_4: 255,
910                param_5: 255,
911                param_6: 255,
912            },
913            unknown_1: 255,
914            unknown_2: 255,
915        }
916    }
917}
918
919/// Parameters for a specified Scene can be configured across all 8 tracks
920#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, DefaultsAsArray)]
921pub struct SceneParams(pub [AudioTrackScenesParamsAssignments; 8]);
922
923impl Default for SceneParams {
924    fn default() -> Self {
925        Self(from_fn(|_| AudioTrackScenesParamsAssignments::default()))
926    }
927}
928
929/// XLV Scene Parameter assignments for an Audio Track,
930/// plus two other parameters i don't know yet
931#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Copy, DefaultsAsArray)]
932pub struct SceneXlvAssignments {
933    /// Main Volume fade control (XLV) for each Audio Track
934    /// `MAX` -> `127`.
935    /// `MIN` -> `0`.
936    #[serde(with = "BigArray")]
937    pub track_xlvs: [u8; 8],
938
939    /// Don't know what this data block is for yet.
940    /// Possibly leftover from using the same struct in the machine code
941    /// as for audio track parameter values.
942    #[serde(with = "BigArray")]
943    unknown: [u8; 2],
944}
945
946impl Default for SceneXlvAssignments {
947    fn default() -> Self {
948        Self {
949            track_xlvs: from_fn(|_| 255),
950            unknown: from_fn(|_| 255),
951        }
952    }
953}
954
955/// A MIDI Track's custom Arp sequence.
956/// `0` -> `+63` values (above line) maps to `0` -> `63`.
957/// `-1` -> `-63` values (below line) map to `255` -> `192`.
958#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, DefaultsAsArray)]
959pub struct MidiArpSequence(pub [u8; 16]);
960
961impl Default for MidiArpSequence {
962    fn default() -> Self {
963        Self(from_fn(|_| 0))
964    }
965}
966
967/// Parts in the bank, containing track data.
968#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
969pub struct Part {
970    #[serde(with = "BigArray")]
971    pub header: [u8; 4],
972
973    /// All 0 values.
974    #[serde(with = "BigArray")]
975    pub data_block_1: [u8; 4],
976
977    /// Zero-indexed part number
978    pub part_id: u8,
979
980    /// Audio Tracks active FX for FX1.
981    /// ```text
982    /// OFF -> 0
983    /// FILTER -> 4
984    /// EQ -> 12
985    /// DJ EQ -> 13
986    /// PHASER -> 16
987    /// FLANGER -> 17
988    /// CHORUS -> 18
989    /// SPATIALIZER -> 5
990    /// COMB FILTER -> 19
991    /// COMPRESSOR -> 24
992    /// LOFI -> 24
993    /// ```
994    #[serde(with = "BigArray")]
995    pub audio_track_fx1: [u8; 8],
996
997    /// Audio Tracks active FX for FX2.
998    /// ```text
999    /// OFF -> 0
1000    /// FILTER -> 4
1001    /// EQ -> 12
1002    /// DJ EQ -> 13
1003    /// PHASER -> 16
1004    /// FLANGER -> 17
1005    /// CHORUS -> 18
1006    /// SPATIALIZER -> 5
1007    /// COMB FILTER -> 19
1008    /// COMPRESSOR -> 24
1009    /// LOFI -> 24
1010    /// DELAY -> 8
1011    /// PLATE REVERB -> 20
1012    /// SPRING REVERB -> 21
1013    /// DARK REVERB -> 22
1014    /// ```
1015    #[serde(with = "BigArray")]
1016    pub audio_track_fx2: [u8; 8],
1017
1018    /// Currently selected Scenes for a Part.
1019    pub active_scenes: ActiveScenes,
1020
1021    /// Volumes for Audio Tracks.
1022    #[serde(with = "BigArray")]
1023    pub audio_track_volumes: [AudioTrackVolume; 8],
1024
1025    /// Audio Tracks Machine types.
1026    /// Static = 0, Flex = 1, Thru = 2, Neighbour = 3, Pickup = 4.
1027    #[serde(with = "BigArray")]
1028    pub audio_track_machine_types: [u8; 8],
1029
1030    /// Parameters for Audio Track machines:
1031    /// Static, Flex, Thru, Neighbor and Pickup machines.
1032    #[serde(with = "BigArray")]
1033    pub audio_track_machine_params: [AudioTrackMachinesParamsValues; 8],
1034
1035    /// Audio Track audio processing parameter values:
1036    /// Amplitude, LFOs, fx1 and fx2.
1037    #[serde(with = "BigArray")]
1038    pub audio_track_params_values: [AudioTrackParamsValues; 8],
1039
1040    /// Setup values for Audio Track machines:
1041    /// Static, Flex, Thru, Neighbor and Pickup machines.
1042    #[serde(with = "BigArray")]
1043    pub audio_track_machine_setup: [AudioTrackMachinesParamsSetup; 8],
1044
1045    /// Audio Track sample slot assignments.
1046    #[serde(with = "BigArray")]
1047    pub audio_track_machine_slots: [AudioTrackMachineSlot; 8],
1048
1049    /// Audio Track audio processing setup values:
1050    /// Amplitude, LFOs, fx1 and fx2.
1051    #[serde(with = "BigArray")]
1052    pub audio_track_params_setup: [AudioTrackParamsSetup; 8],
1053
1054    /// MIDI Track processing values:
1055    /// Amplitude, LFOs, fx1 and fx2.
1056    #[serde(with = "BigArray")]
1057    pub midi_track_params_values: [MidiTrackParamsValues; 8],
1058
1059    /// MIDI Track processing setup values:
1060    /// Amplitude, LFOs, fx1 and fx2.
1061    #[serde(with = "BigArray")]
1062    pub midi_track_params_setup: [MidiTrackParamsSetup; 8],
1063
1064    /// Audio Track Recorder settings.
1065    #[serde(with = "BigArray")]
1066    pub recorder_setup: [RecorderSetup; 8],
1067
1068    /// Scene parameter assignments. There are 16 Scenes in a bank. Each scene
1069    /// can be used to modify parameter page values across any of the audio
1070    /// tracks.
1071    #[serde(with = "BigArray")]
1072    pub scenes: [SceneParams; 16],
1073
1074    #[serde(with = "BigArray")]
1075    pub scene_xlvs: [SceneXlvAssignments; 16],
1076
1077    /// Custom LFO designs for Audio Tracks.
1078    #[serde(with = "BigArray")]
1079    pub audio_tracks_custom_lfo_designs: [CustomLfoDesign; 8],
1080
1081    /// Interpolation of steps in custom LFOs for Audio Tracks.
1082    /// Indicates which LFO steps should have values interpolated when LFO is triggered.
1083    /// Not sure exactly how the calculation works yet.
1084    #[serde(with = "BigArray")]
1085    pub audio_tracks_custom_lfos_interpolation_masks: [CustomLfoInterpolationMask; 8],
1086
1087    /// Custom LFO designs for MIDI Tracks.
1088    #[serde(with = "BigArray")]
1089    pub midi_tracks_custom_lfos: [CustomLfoDesign; 8],
1090
1091    /// Interpolation of steps in custom LFOs for MIDI Tracks.
1092    /// Indicates which LFO steps should have values interpolated when LFO is triggered.
1093    /// Not sure exactly how the calculation works yet.
1094    #[serde(with = "BigArray")]
1095    pub midi_tracks_custom_lfos_interpolation_masks: [CustomLfoInterpolationMask; 8],
1096
1097    /// Arp Sequence Mutes for MIDI tracks.
1098    /// Not sure how these work.
1099    /// Muting some of the notes on M-TR-8 has the last array element set to 7 instead of 255.
1100    #[serde(with = "BigArray")]
1101    pub midi_tracks_arp_mute_masks: [u8; 16],
1102
1103    /// Arp Sequence Notes for MIDI tracks.
1104    pub midi_tracks_arp_seqs: [MidiArpSequence; 8],
1105}
1106
1107impl Part {
1108    /// WARNING: This `default` method is not from the `Default` trait, as we
1109    /// cannot use a default struct instance to create an array/vector of
1110    /// part data --> the individual default depends on their position
1111    /// in the final array!
1112    ///
1113    /// In the future, maybe it might be worth creating `default_with` and
1114    /// `defaults_with` methods to deal with this. But it's not clear they are
1115    /// needed just yet. 80/20.
1116    fn default(part_id: u8) -> Self {
1117        // TODO: create an ot-tools error
1118        assert!(part_id < 4);
1119        Self {
1120            header: PART_HEADER,
1121            data_block_1: from_fn(|_| 0),
1122            part_id,
1123            audio_track_fx1: from_fn(|_| 4),
1124            audio_track_fx2: from_fn(|_| 8),
1125            active_scenes: ActiveScenes::default(),
1126            audio_track_volumes: AudioTrackVolume::defaults(),
1127            audio_track_machine_types: from_fn(|_| 0),
1128            audio_track_machine_params: AudioTrackMachinesParamsValues::defaults(),
1129            audio_track_params_values: AudioTrackParamsValues::defaults(),
1130            audio_track_machine_setup: AudioTrackMachinesParamsSetup::defaults(),
1131            audio_track_machine_slots: AudioTrackMachineSlot::defaults(),
1132            audio_track_params_setup: AudioTrackParamsSetup::defaults(),
1133            midi_track_params_values: MidiTrackParamsValues::defaults(),
1134            midi_track_params_setup: MidiTrackParamsSetup::defaults(),
1135            recorder_setup: RecorderSetup::defaults(),
1136            scenes: SceneParams::defaults(),
1137            scene_xlvs: SceneXlvAssignments::defaults(),
1138            audio_tracks_custom_lfo_designs: CustomLfoDesign::defaults(),
1139            audio_tracks_custom_lfos_interpolation_masks: CustomLfoInterpolationMask::defaults(),
1140            midi_tracks_custom_lfos: CustomLfoDesign::defaults(),
1141            midi_tracks_custom_lfos_interpolation_masks: CustomLfoInterpolationMask::defaults(),
1142            midi_tracks_arp_mute_masks: from_fn(|_| 255),
1143            midi_tracks_arp_seqs: MidiArpSequence::defaults(),
1144        }
1145    }
1146
1147    /// WARNING: This `defaults` method is not from the `Defaults` trait, as we
1148    /// cannot use a default struct instance to create an array/vector of
1149    /// machine slots data --> the individual default depends on their position
1150    /// in the final array!
1151    ///
1152    /// In the future, maybe it might be worth creating `default_with` and
1153    /// `defaults_with` methods to deal with this. But it's not clear they are
1154    /// needed just yet. 80/20.
1155    pub fn defaults<const N: usize>() -> Box<Array<Self, N>> {
1156        Array(from_fn(|x| Self::default(x as u8))).into()
1157    }
1158}
1159
1160impl CheckHeader for Part {
1161    fn check_header(&self) -> bool {
1162        self.header == PART_HEADER
1163    }
1164}
1165
1166/// Contains the two different types of Part data
1167#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
1168pub struct Parts {
1169    /// Unsaved Part data for a Bank.
1170    ///
1171    /// Part state prior to saving a Part via the Part menu (but after SYNC TO CARD).
1172    pub unsaved: Box<Array<Part, 4>>,
1173    /// Saved Part data for a Bank.
1174    ///
1175    /// Part state once the Part has been saved via the Part menu is stored here.
1176    pub saved: Box<Array<Part, 4>>,
1177}
1178
1179impl CheckHeader for Parts {
1180    fn check_header(&self) -> bool {
1181        self.unsaved.iter().all(|x| x.check_header())
1182    }
1183}
1184
1185impl Default for Parts {
1186    fn default() -> Self {
1187        Self {
1188            unsaved: Part::defaults(),
1189            saved: Part::defaults(),
1190        }
1191    }
1192}
1193
1194#[cfg(test)]
1195mod test {
1196    mod integrity_check {
1197        mod part {}
1198
1199        mod parts {}
1200    }
1201}