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