Skip to main content

ot_tools_io/parts/tracks/
audio.rs

1/*
2SPDX-License-Identifier: GPL-3.0-or-later
3Copyright © 2026 Mike Robeson [dijksterhuis]
4*/
5
6use crate::parts::lfos::{LfoParamsSetup1, LfoParamsSetup2, LfoParamsValues};
7use crate::Defaults;
8use ot_tools_io_derive::{ArrayDefaults, AsMutDerive, AsRefDerive, BoxedArrayDefaults};
9use serde::{Deserialize, Serialize};
10use std::array::from_fn;
11
12/// Audio Track MAIN and CUE volume.
13/// Both are 108 by default.
14#[derive(
15    Copy,
16    Clone,
17    Debug,
18    Eq,
19    Hash,
20    Ord,
21    PartialEq,
22    PartialOrd,
23    Serialize,
24    Deserialize,
25    AsMutDerive,
26    AsRefDerive,
27    ArrayDefaults,
28    BoxedArrayDefaults,
29)]
30pub struct AudioTrackVolume {
31    pub main: u8,
32    pub cue: u8,
33}
34
35// TODO: Double check values
36impl Default for AudioTrackVolume {
37    fn default() -> Self {
38        Self {
39            main: 0x6c, // 108
40            cue: 0x6c,  // 108
41        }
42    }
43}
44
45#[cfg(test)]
46mod audio_track_volume {
47    use crate::parts::test_helper::get_default_test_bank;
48    use crate::{parts::tracks::audio::AudioTrackVolume, OtToolsIoError};
49    #[test]
50    fn default() -> Result<(), OtToolsIoError> {
51        let b = get_default_test_bank()?;
52        for x in b.parts_unsaved[0].audio_track_volumes.iter() {
53            assert_eq!(x, &AudioTrackVolume::default());
54        }
55        Ok(())
56    }
57}
58
59/// An Audio Track's Setup values for the Static and Flex machine on the track (loop setting/slice setting/len setting etc.).
60#[derive(
61    Copy,
62    Clone,
63    Debug,
64    Eq,
65    Hash,
66    Ord,
67    PartialEq,
68    PartialOrd,
69    Serialize,
70    Deserialize,
71    AsMutDerive,
72    AsRefDerive,
73)]
74pub struct AudioTrackMachineParamsSetupStd {
75    pub xloop: u8,
76    pub slic: u8,
77    pub len: u8,
78    pub rate: u8,
79    pub tstr: u8,
80    pub tsns: u8,
81}
82
83impl Default for AudioTrackMachineParamsSetupStd {
84    fn default() -> Self {
85        Self {
86            xloop: 1,
87            slic: 0,
88            len: 0,
89            rate: 0,
90            tstr: 1,
91            tsns: 64,
92        }
93    }
94}
95
96#[cfg(test)]
97mod audio_track_machines_params_setup_std {
98    use crate::parts::test_helper::get_default_test_bank;
99    use crate::{parts::tracks::audio::AudioTrackMachineParamsSetupStd, OtToolsIoError};
100    #[test]
101    fn default() -> Result<(), OtToolsIoError> {
102        let b = get_default_test_bank()?;
103        for x in b.parts_unsaved[0].audio_track_machine_setup.iter() {
104            assert_eq!(x.static_machine, AudioTrackMachineParamsSetupStd::default());
105            assert_eq!(x.flex_machine, AudioTrackMachineParamsSetupStd::default());
106        }
107        Ok(())
108    }
109}
110
111/// An Audio Track's Setup values for the Thru machine on the track. Should not contain any data.
112#[derive(
113    Copy,
114    Clone,
115    Debug,
116    Default,
117    Eq,
118    Hash,
119    Ord,
120    PartialEq,
121    PartialOrd,
122    Serialize,
123    Deserialize,
124    AsMutDerive,
125    AsRefDerive,
126)]
127pub struct AudioTrackMachineParamsSetupThru {
128    pub unused_1: u8,
129    pub unused_2: u8,
130    pub unused_3: u8,
131    pub unused_4: u8,
132    pub unused_5: u8,
133    pub unused_6: u8,
134}
135
136#[cfg(test)]
137mod audio_track_machines_params_setup_thru {
138    use crate::parts::test_helper::get_default_test_bank;
139    use crate::{parts::tracks::audio::AudioTrackMachineParamsSetupThru, OtToolsIoError};
140    #[test]
141    fn default() -> Result<(), OtToolsIoError> {
142        let b = get_default_test_bank()?;
143        for x in b.parts_unsaved[0].audio_track_machine_setup.iter() {
144            assert_eq!(x.thru_machine, AudioTrackMachineParamsSetupThru::default());
145        }
146        Ok(())
147    }
148}
149
150/// An Audio Track's Setup values for the Neighbor machine on the track. Should not contain any data.
151#[derive(
152    Copy,
153    Clone,
154    Debug,
155    Default,
156    Eq,
157    Hash,
158    Ord,
159    PartialEq,
160    PartialOrd,
161    Serialize,
162    Deserialize,
163    AsMutDerive,
164    AsRefDerive,
165)]
166pub struct AudioTrackMachineParamsSetupNeighbor {
167    pub unused_1: u8,
168    pub unused_2: u8,
169    pub unused_3: u8,
170    pub unused_4: u8,
171    pub unused_5: u8,
172    pub unused_6: u8,
173}
174
175#[cfg(test)]
176mod audio_track_machines_params_setup_neigh {
177    use crate::parts::test_helper::get_default_test_bank;
178    use crate::{parts::tracks::audio::AudioTrackMachineParamsSetupNeighbor, OtToolsIoError};
179    #[test]
180    fn default() -> Result<(), OtToolsIoError> {
181        let b = get_default_test_bank()?;
182        for x in b.parts_unsaved[0].audio_track_machine_setup.iter() {
183            assert_eq!(
184                x.neighbor_machine,
185                AudioTrackMachineParamsSetupNeighbor::default()
186            );
187        }
188        Ok(())
189    }
190}
191
192/// An Audio Track's Setup values for the Pickup machine on the track.
193#[derive(
194    Copy,
195    Clone,
196    Debug,
197    Eq,
198    Hash,
199    Ord,
200    PartialEq,
201    PartialOrd,
202    Serialize,
203    Deserialize,
204    AsMutDerive,
205    AsRefDerive,
206)]
207pub struct AudioTrackMachineParamsSetupPickup {
208    pub unused_1: u8,
209    pub unused_2: u8,
210    pub unused_3: u8,
211    pub unused_4: u8,
212    pub tstr: u8,
213    pub tsns: u8,
214}
215
216impl Default for AudioTrackMachineParamsSetupPickup {
217    fn default() -> Self {
218        AudioTrackMachineParamsSetupPickup {
219            unused_1: 0,
220            unused_2: 0,
221            unused_3: 0,
222            unused_4: 0,
223            tstr: 1,
224            tsns: 64,
225        }
226    }
227}
228
229#[cfg(test)]
230mod audio_track_machines_params_setup_pickup {
231    use crate::parts::test_helper::get_default_test_bank;
232    use crate::{parts::tracks::audio::AudioTrackMachineParamsSetupPickup, OtToolsIoError};
233    #[test]
234    fn default() -> Result<(), OtToolsIoError> {
235        let b = get_default_test_bank()?;
236        for x in b.parts_unsaved[0].audio_track_machine_setup.iter() {
237            assert_eq!(
238                x.pickup_machine,
239                AudioTrackMachineParamsSetupPickup::default()
240            );
241        }
242        Ok(())
243    }
244}
245
246/// Audio Tracks Machine Setup pages.
247/// As before, separate from other Audio Track parameter fields to be persisted,
248/// allowing safer audio triggering.
249
250#[derive(
251    Copy,
252    Clone,
253    Debug,
254    Default,
255    Eq,
256    Hash,
257    Ord,
258    PartialEq,
259    PartialOrd,
260    Serialize,
261    Deserialize,
262    AsMutDerive,
263    AsRefDerive,
264    ArrayDefaults,
265    BoxedArrayDefaults,
266)]
267pub struct AudioTrackMachinesParamsSetup {
268    pub static_machine: AudioTrackMachineParamsSetupStd,
269    pub flex_machine: AudioTrackMachineParamsSetupStd,
270    pub thru_machine: AudioTrackMachineParamsSetupThru,
271    pub neighbor_machine: AudioTrackMachineParamsSetupNeighbor,
272    pub pickup_machine: AudioTrackMachineParamsSetupPickup,
273}
274
275#[cfg(test)]
276mod audio_track_machines_params_setup {
277    use crate::parts::test_helper::get_default_test_bank;
278    use crate::{parts::tracks::audio::AudioTrackMachinesParamsSetup, OtToolsIoError};
279    #[test]
280    fn default() -> Result<(), OtToolsIoError> {
281        let b = get_default_test_bank()?;
282        for x in b.parts_unsaved[0].audio_track_machine_setup.iter() {
283            assert_eq!(x, &AudioTrackMachinesParamsSetup::default());
284        }
285        Ok(())
286    }
287}
288
289/// Audio Tracks Machine Slot assignments.
290/// Sample Slots assigned for each machine.
291/// Also tracks the recording buffer sample slot assignment.
292#[derive(
293    Copy,
294    Clone,
295    Debug,
296    Eq,
297    Hash,
298    Ord,
299    PartialEq,
300    PartialOrd,
301    Serialize,
302    Deserialize,
303    AsMutDerive,
304    AsRefDerive,
305    BoxedArrayDefaults,
306)]
307pub struct AudioTrackMachineSlot {
308    pub static_slot_id: u8,
309    pub flex_slot_id: u8,
310    pub unused_1: u8,
311    pub unused_2: u8,
312    pub recorder_slot_id: u8,
313}
314
315impl Default for AudioTrackMachineSlot {
316    fn default() -> Self {
317        Self {
318            static_slot_id: 0,
319            flex_slot_id: 0,
320            unused_1: 0,
321            unused_2: 0,
322            recorder_slot_id: 128,
323        }
324    }
325}
326
327// need to implement manually to handle id fields
328impl<const N: usize> Defaults<[Self; N]> for AudioTrackMachineSlot {
329    fn defaults() -> [Self; N]
330    where
331        Self: Default,
332    {
333        from_fn(|i| Self {
334            static_slot_id: i as u8,
335            flex_slot_id: i as u8,
336            recorder_slot_id: 128 + i as u8,
337            ..Default::default()
338        })
339    }
340}
341
342#[cfg(test)]
343mod audio_track_machines_slot {
344    use crate::generics::Tracks;
345    use crate::parts::test_helper::get_default_test_bank;
346    use crate::{parts::tracks::audio::AudioTrackMachineSlot, OtToolsIoError};
347
348    #[test]
349    #[ignore]
350    fn default() -> Result<(), OtToolsIoError> {
351        // this test doesn't make sense to run -- each track will have a different values, so
352        // testing the default method doesn't really help
353        // todo: maybe manually implement a check using emumerate?
354        unimplemented!();
355    }
356
357    #[test]
358    fn defaults() -> Result<(), OtToolsIoError> {
359        let b = get_default_test_bank()?;
360        let slots = b.parts_unsaved[0].audio_track_machine_slots;
361        let valid: Tracks<AudioTrackMachineSlot> = Tracks::<AudioTrackMachineSlot>::default();
362        assert_eq!(slots, valid);
363        Ok(())
364    }
365}
366
367/// Values of an Audio Track's parameters page for the Static or FLex machine on the track (pitch/slice/len etc).
368#[derive(
369    Copy,
370    Clone,
371    Debug,
372    Eq,
373    Hash,
374    Ord,
375    PartialEq,
376    PartialOrd,
377    Serialize,
378    Deserialize,
379    AsMutDerive,
380    AsRefDerive,
381)]
382pub struct AudioTrackMachineParamsValuesStd {
383    pub ptch: u8,
384    pub strt: u8,
385    pub len: u8,
386    pub rate: u8,
387    pub rtrg: u8,
388    pub rtim: u8,
389}
390
391impl Default for AudioTrackMachineParamsValuesStd {
392    fn default() -> Self {
393        Self {
394            ptch: 64,
395            strt: 0,
396            len: 0,
397            rate: 127,
398            rtrg: 0,
399            rtim: 79,
400        }
401    }
402}
403
404#[cfg(test)]
405mod audio_track_machines_params_values_std {
406    use crate::parts::test_helper::get_default_test_bank;
407    use crate::{parts::tracks::audio::AudioTrackMachineParamsValuesStd, OtToolsIoError};
408    #[test]
409    fn default() -> Result<(), OtToolsIoError> {
410        let b = get_default_test_bank()?;
411        for x in b.parts_unsaved[0].audio_track_machine_params.iter() {
412            assert_eq!(
413                x.static_machine,
414                AudioTrackMachineParamsValuesStd::default()
415            );
416            assert_eq!(x.flex_machine, AudioTrackMachineParamsValuesStd::default());
417        }
418        Ok(())
419    }
420}
421
422/// Values of an Audio Track's parameters page for the Flex machine on the track (in/vol etc).
423#[derive(
424    Copy,
425    Clone,
426    Debug,
427    Eq,
428    Hash,
429    Ord,
430    PartialEq,
431    PartialOrd,
432    Serialize,
433    Deserialize,
434    AsMutDerive,
435    AsRefDerive,
436)]
437pub struct AudioTrackMachineParamsValuesThru {
438    pub in_ab: u8,
439    pub vol_ab: u8,
440    pub unused_1: u8,
441    pub in_cd: u8,
442    pub vol_cd: u8,
443    pub unused_2: u8,
444}
445
446impl Default for AudioTrackMachineParamsValuesThru {
447    fn default() -> Self {
448        Self {
449            in_ab: 0,
450            vol_ab: 64,
451            unused_1: 0,
452            in_cd: 0,
453            vol_cd: 64,
454            unused_2: 0,
455        }
456    }
457}
458
459#[cfg(test)]
460mod audio_track_machines_params_values_thru {
461    use crate::parts::test_helper::get_default_test_bank;
462    use crate::{parts::tracks::audio::AudioTrackMachineParamsValuesThru, OtToolsIoError};
463    #[test]
464    fn default() -> Result<(), OtToolsIoError> {
465        let b = get_default_test_bank()?;
466        for x in b.parts_unsaved[0].audio_track_machine_params.iter() {
467            assert_eq!(x.thru_machine, AudioTrackMachineParamsValuesThru::default());
468        }
469        Ok(())
470    }
471}
472
473/// Values of an Audio Track's parameters page for the Neighbor machine on the track. Should not contain any data.
474#[derive(
475    Copy,
476    Clone,
477    Debug,
478    Default,
479    Eq,
480    Hash,
481    Ord,
482    PartialEq,
483    PartialOrd,
484    Serialize,
485    Deserialize,
486    AsMutDerive,
487    AsRefDerive,
488)]
489pub struct AudioTrackMachineParamsValuesNeighbor {
490    pub unused_1: u8,
491    pub unused_2: u8,
492    pub unused_3: u8,
493    pub unused_4: u8,
494    pub unused_5: u8,
495    pub unused_6: u8,
496}
497
498#[cfg(test)]
499mod audio_track_machines_params_values_neigh {
500    use crate::parts::test_helper::get_default_test_bank;
501    use crate::{parts::tracks::audio::AudioTrackMachineParamsValuesNeighbor, OtToolsIoError};
502    #[test]
503    fn default() -> Result<(), OtToolsIoError> {
504        let b = get_default_test_bank()?;
505        for x in b.parts_unsaved[0].audio_track_machine_params.iter() {
506            assert_eq!(
507                x.neighbor_machine,
508                AudioTrackMachineParamsValuesNeighbor::default()
509            );
510        }
511        Ok(())
512    }
513}
514
515/// Values of an Audio Track's parameters page for the Pickup machine on the track. (pitch/dir/len etc).
516#[derive(
517    Copy,
518    Clone,
519    Debug,
520    Eq,
521    Hash,
522    Ord,
523    PartialEq,
524    PartialOrd,
525    Serialize,
526    Deserialize,
527    AsMutDerive,
528    AsRefDerive,
529)]
530pub struct AudioTrackMachineParamsValuesPickup {
531    pub ptch: u8,
532    pub dir: u8,
533    pub len: u8,
534    pub unused_1: u8,
535    pub gain: u8,
536    pub op: u8,
537}
538
539impl Default for AudioTrackMachineParamsValuesPickup {
540    fn default() -> Self {
541        Self {
542            ptch: 64,
543            dir: 2,
544            len: 1,
545            unused_1: 127,
546            gain: 64,
547            op: 1,
548        }
549    }
550}
551
552#[cfg(test)]
553mod audio_track_machines_params_values_pickup {
554    use crate::parts::test_helper::get_default_test_bank;
555    use crate::{parts::tracks::audio::AudioTrackMachineParamsValuesPickup, OtToolsIoError};
556    #[test]
557    fn default() -> Result<(), OtToolsIoError> {
558        let b = get_default_test_bank()?;
559        for x in b.parts_unsaved[0].audio_track_machine_params.iter() {
560            assert_eq!(
561                x.pickup_machine,
562                AudioTrackMachineParamsValuesPickup::default()
563            );
564        }
565        Ok(())
566    }
567}
568
569/// Audio Tracks Machine Parameter pages.
570/// Machine parameter values persist after the machine type is changed,
571/// meaning audio keeps playing until the new machine is triggered to play new audio.
572#[derive(
573    Copy,
574    Clone,
575    Debug,
576    Default,
577    Eq,
578    Hash,
579    Ord,
580    PartialEq,
581    PartialOrd,
582    Serialize,
583    Deserialize,
584    AsMutDerive,
585    AsRefDerive,
586    ArrayDefaults,
587    BoxedArrayDefaults,
588)]
589pub struct AudioTrackMachinesParamsValues {
590    pub static_machine: AudioTrackMachineParamsValuesStd,
591    pub flex_machine: AudioTrackMachineParamsValuesStd,
592    pub thru_machine: AudioTrackMachineParamsValuesThru,
593    pub neighbor_machine: AudioTrackMachineParamsValuesNeighbor,
594    pub pickup_machine: AudioTrackMachineParamsValuesPickup,
595}
596
597#[cfg(test)]
598mod audio_track_machines_params_values {
599    use crate::parts::test_helper::get_default_test_bank;
600    use crate::{parts::tracks::audio::AudioTrackMachinesParamsValues, OtToolsIoError};
601    #[test]
602    fn default() -> Result<(), OtToolsIoError> {
603        let b = get_default_test_bank()?;
604        for x in b.parts_unsaved[0].audio_track_machine_params.iter() {
605            assert_eq!(x, &AudioTrackMachinesParamsValues::default());
606        }
607        Ok(())
608    }
609}
610
611#[cfg(test)]
612mod audio_track_params_values_lfo {
613    use crate::parts::lfos::LfoParamsValues;
614    use crate::parts::test_helper::get_default_test_bank;
615    use crate::OtToolsIoError;
616
617    #[test]
618    fn default() -> Result<(), OtToolsIoError> {
619        let b = get_default_test_bank()?;
620        for x in b.parts_unsaved[0].audio_track_params_values.iter() {
621            assert_eq!(x.lfo, LfoParamsValues::default());
622        }
623        Ok(())
624    }
625}
626
627/// Values of a Track's main AMP parameters page.
628#[derive(
629    Copy,
630    Clone,
631    Debug,
632    Eq,
633    Hash,
634    Ord,
635    PartialEq,
636    PartialOrd,
637    Serialize,
638    Deserialize,
639    AsMutDerive,
640    AsRefDerive,
641)]
642pub struct AudioTrackAmpParamsValues {
643    pub atk: u8,
644    pub hold: u8,
645    pub rel: u8,
646    pub vol: u8,
647    pub bal: u8,
648    /// Reserved space for the \<F\> parameter used by Scenes and LFOs
649    pub f: u8,
650}
651
652// allow the verbose implementation to keep things
653// - (a) standardised across all types
654// - (b) easier for non-rustaceans to follow when reading through data structures
655#[allow(clippy::derivable_impls)]
656impl Default for AudioTrackAmpParamsValues {
657    fn default() -> Self {
658        Self {
659            atk: 0,
660            hold: 127,
661            rel: 127,
662            vol: 64,
663            bal: 64,
664            f: 127,
665        }
666    }
667}
668
669#[cfg(test)]
670mod audio_track_params_values_amp {
671    use crate::parts::test_helper::get_default_test_bank;
672    use crate::{parts::tracks::audio::AudioTrackAmpParamsValues, OtToolsIoError};
673    #[test]
674    fn default() -> Result<(), OtToolsIoError> {
675        let b = get_default_test_bank()?;
676        for x in b.parts_unsaved[0].audio_track_params_values.iter() {
677            assert_eq!(x.amp, AudioTrackAmpParamsValues::default());
678        }
679        Ok(())
680    }
681}
682
683/// Values of a Track's FX parameters page.
684#[derive(
685    Copy,
686    Clone,
687    Debug,
688    Default,
689    Eq,
690    Hash,
691    Ord,
692    PartialEq,
693    PartialOrd,
694    Serialize,
695    Deserialize,
696    AsMutDerive,
697    AsRefDerive,
698)]
699pub struct AudioTrackFxParamsValues {
700    pub param_1: u8,
701    pub param_2: u8,
702    pub param_3: u8,
703    pub param_4: u8,
704    pub param_5: u8,
705    pub param_6: u8,
706}
707
708#[cfg(test)]
709mod audio_track_params_values_fx {
710    use crate::parts::test_helper::get_default_test_bank;
711    use crate::{parts::tracks::audio::AudioTrackFxParamsValues, OtToolsIoError};
712    #[test]
713    fn default_fx1() -> Result<(), OtToolsIoError> {
714        let b = get_default_test_bank()?;
715        for x in b.parts_unsaved[0].audio_track_params_values.iter() {
716            assert_eq!(
717                x.fx1,
718                AudioTrackFxParamsValues {
719                    param_1: 0,
720                    param_2: 127,
721                    param_3: 0,
722                    param_4: 64,
723                    param_5: 0,
724                    param_6: 64,
725                }
726            );
727        }
728        Ok(())
729    }
730    #[test]
731    fn default_fx2() -> Result<(), OtToolsIoError> {
732        let b = get_default_test_bank()?;
733        for x in b.parts_unsaved[0].audio_track_params_values.iter() {
734            assert_eq!(
735                x.fx2,
736                AudioTrackFxParamsValues {
737                    param_1: 47,
738                    param_2: 0,
739                    param_3: 127,
740                    param_4: 0,
741                    param_5: 127,
742                    param_6: 0,
743                }
744            );
745        }
746        Ok(())
747    }
748}
749
750/// Audio Tracks Parameter Page values. LFO, Amp, FX etc.
751#[derive(
752    Copy,
753    Clone,
754    Debug,
755    Eq,
756    Hash,
757    Ord,
758    PartialEq,
759    PartialOrd,
760    Serialize,
761    Deserialize,
762    AsMutDerive,
763    AsRefDerive,
764    ArrayDefaults,
765    BoxedArrayDefaults,
766)]
767pub struct AudioTrackParamsValues {
768    pub lfo: LfoParamsValues,
769    pub amp: AudioTrackAmpParamsValues,
770    pub fx1: AudioTrackFxParamsValues,
771    pub fx2: AudioTrackFxParamsValues,
772}
773
774impl Default for AudioTrackParamsValues {
775    fn default() -> Self {
776        Self {
777            lfo: LfoParamsValues::default(),
778            amp: AudioTrackAmpParamsValues::default(),
779            fx1: AudioTrackFxParamsValues {
780                param_1: 0,
781                param_2: 127,
782                param_3: 0,
783                param_4: 64,
784                param_5: 0,
785                param_6: 64,
786            },
787            fx2: AudioTrackFxParamsValues {
788                param_1: 47,
789                param_2: 0,
790                param_3: 127,
791                param_4: 0,
792                param_5: 127,
793                param_6: 0,
794            },
795        }
796    }
797}
798
799#[cfg(test)]
800mod audio_track_params_values {
801    use crate::parts::test_helper::get_default_test_bank;
802    use crate::{parts::tracks::audio::AudioTrackParamsValues, OtToolsIoError};
803    #[test]
804    fn default() -> Result<(), OtToolsIoError> {
805        let b = get_default_test_bank()?;
806        for x in b.parts_unsaved[0].audio_track_params_values.iter() {
807            assert_eq!(x, &AudioTrackParamsValues::default());
808        }
809        Ok(())
810    }
811}
812
813#[cfg(test)]
814mod audio_track_params_setup_lfo_1 {
815    use crate::parts::lfos::LfoParamsSetup1;
816    use crate::parts::test_helper::get_default_test_bank;
817    use crate::OtToolsIoError;
818
819    #[test]
820    fn default() -> Result<(), OtToolsIoError> {
821        let b = get_default_test_bank()?;
822        for x in b.parts_unsaved[0].audio_track_params_setup.iter() {
823            assert_eq!(x.lfo_setup_1, LfoParamsSetup1::default());
824        }
825        Ok(())
826    }
827}
828
829#[cfg(test)]
830mod audio_track_params_setup_lfo_2 {
831    use crate::parts::lfos::LfoParamsSetup2;
832    use crate::parts::test_helper::get_default_test_bank;
833    use crate::OtToolsIoError;
834
835    #[test]
836    fn default() -> Result<(), OtToolsIoError> {
837        let b = get_default_test_bank()?;
838        for x in b.parts_unsaved[0].audio_track_params_setup.iter() {
839            assert_eq!(x.lfo_setup_2, LfoParamsSetup2::default());
840        }
841        Ok(())
842    }
843}
844
845/// Values for a Track's AMP Setup page.
846#[derive(
847    Copy,
848    Clone,
849    Debug,
850    Eq,
851    Hash,
852    Ord,
853    PartialEq,
854    PartialOrd,
855    Serialize,
856    Deserialize,
857    AsMutDerive,
858    AsRefDerive,
859)]
860pub struct AudioTrackAmpParamsSetup {
861    pub amp: u8,
862    pub sync: u8,
863    pub atck: u8,
864    pub fx1: u8,
865    pub fx2: u8,
866    // This is the hidden <F> parameter used in LFOs and Scenes etc.
867    pub unused: u8,
868}
869
870impl Default for AudioTrackAmpParamsSetup {
871    fn default() -> Self {
872        Self {
873            amp: 1,
874            sync: 1,
875            atck: 0,
876            fx1: 0,
877            fx2: 0,
878            unused: 0,
879        }
880    }
881}
882
883#[cfg(test)]
884mod audio_track_params_setup_amp {
885    use crate::parts::test_helper::get_default_test_bank;
886    use crate::{parts::tracks::audio::AudioTrackAmpParamsSetup, OtToolsIoError};
887    #[test]
888    fn default() -> Result<(), OtToolsIoError> {
889        let b = get_default_test_bank()?;
890        for x in b.parts_unsaved[0].audio_track_params_setup.iter() {
891            assert_eq!(x.amp, AudioTrackAmpParamsSetup::default());
892        }
893        Ok(())
894    }
895}
896
897/// Values for a Track's FX Setup page.
898///
899/// # Default
900///
901/// There is no `Default` trait implemented for this type as it is shared for both FX1 and FX2,
902/// which both have different default settings.
903#[derive(
904    Copy,
905    Clone,
906    Debug,
907    Default,
908    Eq,
909    Hash,
910    Ord,
911    PartialEq,
912    PartialOrd,
913    Serialize,
914    Deserialize,
915    AsMutDerive,
916    AsRefDerive,
917)]
918pub struct AudioTrackFxParamsSetup {
919    pub setting1: u8,
920    pub setting2: u8,
921    pub setting3: u8,
922    pub setting4: u8,
923    pub setting5: u8,
924    pub setting6: u8,
925}
926
927#[cfg(test)]
928mod audio_track_params_setup_fx {
929    use crate::parts::test_helper::get_default_test_bank;
930    use crate::{parts::tracks::audio::AudioTrackFxParamsSetup, OtToolsIoError};
931    #[test]
932    fn default_fx1() -> Result<(), OtToolsIoError> {
933        let b = get_default_test_bank()?;
934        for x in b.parts_unsaved[0].audio_track_params_setup.iter() {
935            assert_eq!(
936                x.fx1,
937                AudioTrackFxParamsSetup {
938                    setting1: 0,
939                    setting2: 0,
940                    setting3: 1,
941                    setting4: 0,
942                    setting5: 3,
943                    setting6: 0,
944                }
945            );
946        }
947        Ok(())
948    }
949    #[test]
950    fn default_fx2() -> Result<(), OtToolsIoError> {
951        let b = get_default_test_bank()?;
952        for x in b.parts_unsaved[0].audio_track_params_setup.iter() {
953            assert_eq!(
954                x.fx2,
955                AudioTrackFxParamsSetup {
956                    setting1: 0,
957                    setting2: 1,
958                    setting3: 127,
959                    setting4: 1,
960                    setting5: 0,
961                    setting6: 0,
962                }
963            );
964        }
965        Ok(())
966    }
967}
968
969/// Audio Tracks Parameter Setup pages for LFO, Amp, FX etc.
970///
971/// # Field ordering
972///
973/// yes, `lfo_setup_2` comes after fx data fields in the binary data...
974#[derive(
975    Copy,
976    Clone,
977    Debug,
978    Eq,
979    Hash,
980    Ord,
981    PartialEq,
982    PartialOrd,
983    Serialize,
984    Deserialize,
985    AsMutDerive,
986    AsRefDerive,
987    ArrayDefaults,
988    BoxedArrayDefaults,
989)]
990pub struct AudioTrackParamsSetup {
991    /// Parameter Target and Wave selection for the 3x LFOs on this Audio Track.
992    pub lfo_setup_1: LfoParamsSetup1,
993    /// Amplitude setup page
994    pub amp: AudioTrackAmpParamsSetup,
995    /// FX #1 setup page
996    pub fx1: AudioTrackFxParamsSetup,
997    /// FX #2 setup page
998    pub fx2: AudioTrackFxParamsSetup,
999    /// Multiplier and Trigger type selection for the 3x LFOs on this Audio Track.
1000    pub lfo_setup_2: LfoParamsSetup2,
1001}
1002
1003impl Default for AudioTrackParamsSetup {
1004    fn default() -> Self {
1005        Self {
1006            lfo_setup_1: LfoParamsSetup1::default(),
1007            amp: AudioTrackAmpParamsSetup::default(),
1008            fx1: AudioTrackFxParamsSetup {
1009                setting1: 0,
1010                setting2: 0,
1011                setting3: 1,
1012                setting4: 0,
1013                setting5: 3,
1014                setting6: 0,
1015            },
1016            fx2: AudioTrackFxParamsSetup {
1017                setting1: 0,
1018                setting2: 1,
1019                setting3: 127,
1020                setting4: 1,
1021                setting5: 0,
1022                setting6: 0,
1023            },
1024            lfo_setup_2: LfoParamsSetup2::default(),
1025        }
1026    }
1027}
1028
1029#[cfg(test)]
1030mod audio_track_params_setup {
1031    use crate::parts::test_helper::get_default_test_bank;
1032    use crate::{parts::tracks::audio::AudioTrackParamsSetup, OtToolsIoError};
1033    #[test]
1034    fn default() -> Result<(), OtToolsIoError> {
1035        let b = get_default_test_bank()?;
1036        for x in b.parts_unsaved[0].audio_track_params_setup.iter() {
1037            assert_eq!(x, &AudioTrackParamsSetup::default());
1038        }
1039        Ok(())
1040    }
1041}
1042
1043// todo: merge with the Pattern parameter-lock variant of this?
1044/// A scene's parameter assignments on the Playback/Machine page for an Audio Track.
1045#[derive(
1046    Copy,
1047    Clone,
1048    Debug,
1049    Eq,
1050    Hash,
1051    Ord,
1052    PartialEq,
1053    PartialOrd,
1054    Serialize,
1055    Deserialize,
1056    AsMutDerive,
1057    AsRefDerive,
1058)]
1059pub struct AudioTrackSceneLockPlayback {
1060    pub param1: u8,
1061    pub param2: u8,
1062    pub param3: u8,
1063    pub param4: u8,
1064    pub param5: u8,
1065    pub param6: u8,
1066}
1067
1068impl Default for AudioTrackSceneLockPlayback {
1069    fn default() -> Self {
1070        Self {
1071            param1: 255,
1072            param2: 255,
1073            param3: 255,
1074            param4: 255,
1075            param5: 255,
1076            param6: 255,
1077        }
1078    }
1079}
1080
1081#[cfg(test)]
1082mod audio_track_scene_lock_playback {
1083    use crate::parts::test_helper::get_default_test_bank;
1084    use crate::{parts::tracks::audio::AudioTrackSceneLockPlayback, OtToolsIoError};
1085    #[test]
1086    fn default() -> Result<(), OtToolsIoError> {
1087        let b = get_default_test_bank()?;
1088        for arr in b.parts_unsaved[0].scenes.iter() {
1089            for x in arr.iter() {
1090                assert_eq!(x.machine, AudioTrackSceneLockPlayback::default());
1091            }
1092        }
1093        Ok(())
1094    }
1095}