ot_tools_io/
banks.rs

1/*
2SPDX-License-Identifier: GPL-3.0-or-later
3Copyright © 2024 Mike Robeson [dijksterhuis]
4*/
5
6//! Types for `bank??.*` binary data files.
7
8use crate::parts::Parts;
9use crate::patterns::PatternArray;
10
11use crate::{
12    Defaults, HasChecksumField, HasFileVersionField, HasHeaderField, OctatrackFileIO,
13    OtToolsIoError,
14};
15use ot_tools_io_derive::{ArrayDefaults, BoxedBigArrayDefaults, IntegrityChecks, IsDefaultCheck};
16use serde::{Deserialize, Serialize};
17use serde_big_array::{Array, BigArray};
18use std::array::from_fn;
19
20/// Bank header data.
21/// ```text
22/// FORM....DPS1BANK.....
23/// 46 4f 52 4d 00 00 00 00 44 50 53 31 42 41 4e 4b 00 00 00 00 00
24/// [70 79 82 77 0 0 0 0 68 80 83 49 66 65 78 75 0 0 0 0 0]
25/// ```
26pub const BANK_HEADER: [u8; 21] = [
27    70, 79, 82, 77, 0, 0, 0, 0, 68, 80, 83, 49, 66, 65, 78, 75, 0, 0, 0, 0, 0,
28];
29
30/// Current/supported version of bank files.
31pub const BANK_FILE_VERSION: u8 = 23;
32
33/// An Octatrack Bank. Contains data related to Parts and Patterns.
34#[derive(
35    Debug,
36    Serialize,
37    Deserialize,
38    Clone,
39    PartialEq,
40    ArrayDefaults,
41    BoxedBigArrayDefaults,
42    IsDefaultCheck,
43    IntegrityChecks,
44)]
45pub struct BankFile {
46    /// Misc header data for Banks.
47    /// Always follows the same format.
48    #[serde(with = "BigArray")]
49    pub header: [u8; 21],
50
51    pub datatype_version: u8,
52
53    /// Pattern data for a Bank.
54    // note -- stack overflow if trying to use #[serde(with = "BigArray")]
55    pub patterns: PatternArray,
56
57    /// All part data for this bank, includes currently unsaved and previously saved state
58    pub parts: Parts,
59
60    /// Indicates which parts have previously saved state available for reloading.
61    #[serde(with = "BigArray")]
62    pub parts_saved_state: [u8; 4],
63
64    /// Bit mask indicating which parts are currently in an edited state.
65    /// ```text
66    /// parts
67    /// 1 2 3 4 | mask
68    /// --------|------
69    /// - - - - | 0
70    /// x - - - | 1
71    /// - x - - | 2
72    /// - - x - | 4
73    /// - - - x | 8
74    /// --------|------
75    /// x x - - | 3
76    /// x - x - | 5
77    /// - x x - | 6
78    /// x x x - | 7
79    /// x - - x | 9
80    /// - x - x | 10
81    /// x x - x | 11
82    /// - - x x | 12
83    /// - x x x | 14
84    /// x x x x | 15
85    /// ```
86    pub parts_edited_bitmask: u8,
87
88    /// Names for each Part within the Bank.
89    /// Maximum 7 character length.
90    #[serde(with = "BigArray")]
91    pub part_names: [[u8; 7]; 4],
92
93    /// checksum bytes
94    pub checksum: u16,
95}
96
97/// Default Part names (ONE, TWO, THREE, FOUR) converted to u8 for ease of use.
98const DEFAULT_PART_NAMES: [[u8; 7]; 4] = [
99    [0x4f, 0x4e, 0x45, 0x00, 0x00, 0x00, 0x00], // "ONE"
100    [0x54, 0x57, 0x4f, 0x00, 0x00, 0x00, 0x00], // "TWO"
101    [0x54, 0x48, 0x52, 0x45, 0x45, 0x00, 0x00], // "THREE"
102    [0x46, 0x4f, 0x55, 0x52, 0x00, 0x00, 0x00], // "FOUR"
103];
104
105impl OctatrackFileIO for BankFile {
106    fn encode(&self) -> Result<Vec<u8>, OtToolsIoError>
107    where
108        Self: Serialize,
109    {
110        let mut chkd = self.clone();
111        chkd.checksum = self.calculate_checksum()?;
112        let bytes = bincode::serialize(&chkd)?;
113        Ok(bytes)
114    }
115}
116
117impl Default for BankFile {
118    fn default() -> Self {
119        Self {
120            header: BANK_HEADER,
121            datatype_version: BANK_FILE_VERSION,
122            patterns: PatternArray::default(),
123            parts: Parts::default(),
124            parts_saved_state: from_fn(|_| 0),
125            parts_edited_bitmask: 0,
126            part_names: DEFAULT_PART_NAMES,
127            // WARN: mutated during encode! do not calculate checksum in this
128            // method until i've refactored `get_checksum` to not use Bank::default()
129            // (end up with a never ending recursive loop of calling default)
130            // TODO: Hardcoded
131            checksum: 48022,
132        }
133    }
134}
135
136#[cfg(test)]
137mod decode {
138    use crate::{
139        read_bin_file, test_utils::get_blank_proj_dirpath, BankFile, OctatrackFileIO,
140        OtToolsIoError,
141    };
142    #[test]
143    fn valid() -> Result<(), OtToolsIoError> {
144        let path = get_blank_proj_dirpath().join("bank01.work");
145        let bytes = read_bin_file(&path)?;
146        let s = BankFile::decode(&bytes)?;
147        assert_eq!(s, BankFile::default());
148        Ok(())
149    }
150}
151
152#[cfg(test)]
153mod encode {
154    use crate::{
155        read_bin_file, test_utils::get_blank_proj_dirpath, BankFile, OctatrackFileIO,
156        OtToolsIoError,
157    };
158    #[test]
159    fn valid() -> Result<(), OtToolsIoError> {
160        let path = get_blank_proj_dirpath().join("bank01.work");
161        let bytes = read_bin_file(&path)?;
162        let b = BankFile::default().encode()?;
163        assert_eq!(b, bytes);
164        Ok(())
165    }
166}
167
168impl HasChecksumField for BankFile {
169    fn calculate_checksum(&self) -> Result<u16, OtToolsIoError> {
170        let bytes = bincode::serialize(&self)?;
171        let bytes_no_header_no_chk = &bytes[16..bytes.len() - 2];
172        let default_bytes = &bincode::serialize(&BankFile::default())?;
173        let def_important_bytes = &default_bytes[16..bytes.len() - 2];
174        let default_checksum: i32 = 48022;
175        let mut byte_diffs: i32 = 0;
176        for (byte, def_byte) in bytes_no_header_no_chk.iter().zip(def_important_bytes) {
177            let byte_diff = (*byte as i32) - (*def_byte as i32);
178            if byte_diff != 0 {
179                byte_diffs += byte_diff;
180            }
181        }
182        let check = byte_diffs * 256 + default_checksum;
183        let modded = check.rem_euclid(65535);
184        Ok(modded as u16)
185    }
186
187    fn check_checksum(&self) -> Result<bool, OtToolsIoError> {
188        Ok(self.checksum == self.calculate_checksum()?)
189    }
190}
191
192#[cfg(test)]
193mod checksum_field {
194    use crate::{BankFile, HasChecksumField, OtToolsIoError};
195    #[test]
196    fn valid() -> Result<(), OtToolsIoError> {
197        let mut x = BankFile::default();
198        x.checksum = x.calculate_checksum()?;
199        assert!(x.check_checksum()?);
200        Ok(())
201    }
202
203    #[test]
204    fn invalid() -> Result<(), OtToolsIoError> {
205        let x = BankFile {
206            checksum: u16::MAX,
207            ..Default::default()
208        };
209        assert!(!x.check_checksum()?);
210        Ok(())
211    }
212
213    mod files {
214        use crate::test_utils::{get_bank_dirpath, get_blank_proj_dirpath};
215        use crate::{BankFile, HasChecksumField, OctatrackFileIO, OtToolsIoError};
216        use std::path::Path;
217
218        fn helper_test_chksum(fp: &Path) -> Result<(u16, u16), OtToolsIoError> {
219            let valid = BankFile::from_data_file(fp)?;
220            let mut test = valid.clone();
221            test.checksum = 0;
222            let chk = test.calculate_checksum()?;
223            Ok((chk, valid.checksum))
224        }
225
226        #[allow(clippy::field_reassign_with_default)]
227        #[test]
228        fn default_method() -> Result<(), OtToolsIoError> {
229            let (_, valid) = helper_test_chksum(&get_blank_proj_dirpath().join("bank01.work"))?;
230            let mut x = BankFile::default();
231            x.checksum = 0;
232            let test = x.calculate_checksum()?;
233            assert_eq!(test, valid);
234            Ok(())
235        }
236
237        #[test]
238        fn default_bank1_file() -> Result<(), OtToolsIoError> {
239            let (test, valid) = helper_test_chksum(&get_blank_proj_dirpath().join("bank01.work"))?;
240            assert_eq!(test, valid);
241            Ok(())
242        }
243
244        #[test]
245        fn default_bank2_file() -> Result<(), OtToolsIoError> {
246            let (test, valid) = helper_test_chksum(&get_blank_proj_dirpath().join("bank02.work"))?;
247            assert_eq!(test, valid);
248            Ok(())
249        }
250
251        #[test]
252        fn one_scene_zero_val() -> Result<(), OtToolsIoError> {
253            // start value incremented by 127 (max) and len incremented by 127 (max) on the machine
254            let (test, valid) = helper_test_chksum(
255                &get_bank_dirpath()
256                    .join("checksum")
257                    .join("scene1-atrack1-lfo-dep1-zero.work"),
258            )?;
259            assert_eq!(test, valid);
260            Ok(())
261        }
262
263        #[test]
264        fn one_scene_127_val() -> Result<(), OtToolsIoError> {
265            // start value incremented by 127 (max) and len incremented by 127 (max) on the machine
266            let (test, valid) = helper_test_chksum(
267                &get_bank_dirpath()
268                    .join("checksum")
269                    .join("scene1-atrack1-lfo-dep1-127.work"),
270            )?;
271            assert_eq!(test, valid);
272            Ok(())
273        }
274
275        #[test]
276        fn scene_params_decr_lots() -> Result<(), OtToolsIoError> {
277            // all scenes have assignments on the LFO parameters for track 1 - sets everything tp 0
278            let (test, valid) = helper_test_chksum(
279                &get_bank_dirpath()
280                    .join("checksum")
281                    .join("all-scenes-lfo-params-zeroed.work"),
282            )?;
283            assert_eq!(test, valid);
284            Ok(())
285        }
286
287        mod static_strt_only {
288            use super::helper_test_chksum;
289            use crate::test_utils::get_bank_dirpath;
290            use crate::OtToolsIoError;
291
292            #[test]
293            fn static_strt_1() -> Result<(), OtToolsIoError> {
294                // start value incremented by one on the machine
295                let (test, valid) = helper_test_chksum(
296                    &get_bank_dirpath()
297                        .join("checksum")
298                        .join("static-strt-1.work"),
299                )?;
300                assert_eq!(test, valid);
301                Ok(())
302            }
303
304            #[test]
305            fn static_strt_2() -> Result<(), OtToolsIoError> {
306                // start value incremented by two on the machine
307                let (test, valid) = helper_test_chksum(
308                    &get_bank_dirpath()
309                        .join("checksum")
310                        .join("static-strt-2.work"),
311                )?;
312                assert_eq!(test, valid);
313                Ok(())
314            }
315
316            #[test]
317            fn static_strt_10() -> Result<(), OtToolsIoError> {
318                // start value incremented by ten on the machine
319                let (test, valid) = helper_test_chksum(
320                    &get_bank_dirpath()
321                        .join("checksum")
322                        .join("static-strt-10.work"),
323                )?;
324                assert_eq!(test, valid);
325                Ok(())
326            }
327
328            // off by one -- this is why we have so many of these test examples
329            #[test]
330            fn static_strt_127() -> Result<(), OtToolsIoError> {
331                // start value incremented by 127 (max) on the machine
332                let (test, valid) = helper_test_chksum(
333                    &get_bank_dirpath()
334                        .join("checksum")
335                        .join("static-strt-127.work"),
336                )?;
337                assert_eq!(test, valid);
338                Ok(())
339            }
340
341            #[test]
342            fn static_strt_126() -> Result<(), OtToolsIoError> {
343                let (test, valid) = helper_test_chksum(
344                    &get_bank_dirpath()
345                        .join("checksum")
346                        .join("static-strt-126.work"),
347                )?;
348                assert_eq!(test, valid);
349                Ok(())
350            }
351
352            #[test]
353            fn static_strt_125() -> Result<(), OtToolsIoError> {
354                let (test, valid) = helper_test_chksum(
355                    &get_bank_dirpath()
356                        .join("checksum")
357                        .join("static-strt-125.work"),
358                )?;
359                assert_eq!(test, valid);
360                Ok(())
361            }
362
363            #[test]
364            fn static_strt_124() -> Result<(), OtToolsIoError> {
365                let (test, valid) = helper_test_chksum(
366                    &get_bank_dirpath()
367                        .join("checksum")
368                        .join("static-strt-124.work"),
369                )?;
370                assert_eq!(test, valid);
371                Ok(())
372            }
373
374            #[test]
375            fn static_strt_123() -> Result<(), OtToolsIoError> {
376                let (test, valid) = helper_test_chksum(
377                    &get_bank_dirpath()
378                        .join("checksum")
379                        .join("static-strt-123.work"),
380                )?;
381                assert_eq!(test, valid);
382                Ok(())
383            }
384
385            #[test]
386            fn static_strt_122() -> Result<(), OtToolsIoError> {
387                let (test, valid) = helper_test_chksum(
388                    &get_bank_dirpath()
389                        .join("checksum")
390                        .join("static-strt-122.work"),
391                )?;
392                assert_eq!(test, valid);
393                Ok(())
394            }
395
396            #[test]
397            fn static_strt_121() -> Result<(), OtToolsIoError> {
398                let (test, valid) = helper_test_chksum(
399                    &get_bank_dirpath()
400                        .join("checksum")
401                        .join("static-strt-121.work"),
402                )?;
403                assert_eq!(test, valid);
404                Ok(())
405            }
406
407            #[test]
408            fn static_strt_120() -> Result<(), OtToolsIoError> {
409                let (test, valid) = helper_test_chksum(
410                    &get_bank_dirpath()
411                        .join("checksum")
412                        .join("static-strt-120.work"),
413                )?;
414                assert_eq!(test, valid);
415                Ok(())
416            }
417
418            #[test]
419            fn static_strt_119() -> Result<(), OtToolsIoError> {
420                let (test, valid) = helper_test_chksum(
421                    &get_bank_dirpath()
422                        .join("checksum")
423                        .join("static-strt-119.work"),
424                )?;
425                assert_eq!(test, valid);
426                Ok(())
427            }
428
429            #[test]
430            fn static_strt_118() -> Result<(), OtToolsIoError> {
431                let (test, valid) = helper_test_chksum(
432                    &get_bank_dirpath()
433                        .join("checksum")
434                        .join("static-strt-118.work"),
435                )?;
436                assert_eq!(test, valid);
437                Ok(())
438            }
439
440            #[test]
441            fn static_strt_117() -> Result<(), OtToolsIoError> {
442                let (test, valid) = helper_test_chksum(
443                    &get_bank_dirpath()
444                        .join("checksum")
445                        .join("static-strt-117.work"),
446                )?;
447                assert_eq!(test, valid);
448                Ok(())
449            }
450
451            #[test]
452            fn static_strt_116() -> Result<(), OtToolsIoError> {
453                let (test, valid) = helper_test_chksum(
454                    &get_bank_dirpath()
455                        .join("checksum")
456                        .join("static-strt-116.work"),
457                )?;
458                assert_eq!(test, valid);
459                Ok(())
460            }
461
462            #[test]
463            fn static_strt_115() -> Result<(), OtToolsIoError> {
464                let (test, valid) = helper_test_chksum(
465                    &get_bank_dirpath()
466                        .join("checksum")
467                        .join("static-strt-115.work"),
468                )?;
469                assert_eq!(test, valid);
470                Ok(())
471            }
472
473            #[test]
474            fn static_strt_114() -> Result<(), OtToolsIoError> {
475                let (test, valid) = helper_test_chksum(
476                    &get_bank_dirpath()
477                        .join("checksum")
478                        .join("static-strt-114.work"),
479                )?;
480                assert_eq!(test, valid);
481                Ok(())
482            }
483
484            #[test]
485            fn static_strt_113() -> Result<(), OtToolsIoError> {
486                let (test, valid) = helper_test_chksum(
487                    &get_bank_dirpath()
488                        .join("checksum")
489                        .join("static-strt-113.work"),
490                )?;
491                assert_eq!(test, valid);
492                Ok(())
493            }
494
495            #[test]
496            fn static_strt_112() -> Result<(), OtToolsIoError> {
497                let (test, valid) = helper_test_chksum(
498                    &get_bank_dirpath()
499                        .join("checksum")
500                        .join("static-strt-112.work"),
501                )?;
502                assert_eq!(test, valid);
503                Ok(())
504            }
505
506            #[test]
507            fn static_strt_111() -> Result<(), OtToolsIoError> {
508                let (test, valid) = helper_test_chksum(
509                    &get_bank_dirpath()
510                        .join("checksum")
511                        .join("static-strt-111.work"),
512                )?;
513                assert_eq!(test, valid);
514                Ok(())
515            }
516
517            #[test]
518            fn static_strt_71() -> Result<(), OtToolsIoError> {
519                let (test, valid) = helper_test_chksum(
520                    &get_bank_dirpath()
521                        .join("checksum")
522                        .join("static-strt-71.work"),
523                )?;
524                assert_eq!(test, valid);
525                Ok(())
526            }
527
528            #[test]
529            fn static_strt_70() -> Result<(), OtToolsIoError> {
530                let (test, valid) = helper_test_chksum(
531                    &get_bank_dirpath()
532                        .join("checksum")
533                        .join("static-strt-70.work"),
534                )?;
535                assert_eq!(test, valid);
536                Ok(())
537            }
538
539            #[test]
540            fn static_strt_69() -> Result<(), OtToolsIoError> {
541                let (test, valid) = helper_test_chksum(
542                    &get_bank_dirpath()
543                        .join("checksum")
544                        .join("static-strt-69.work"),
545                )?;
546                assert_eq!(test, valid);
547                Ok(())
548            }
549
550            #[test]
551            fn static_strt_68() -> Result<(), OtToolsIoError> {
552                let (test, valid) = helper_test_chksum(
553                    &get_bank_dirpath()
554                        .join("checksum")
555                        .join("static-strt-68.work"),
556                )?;
557                assert_eq!(test, valid);
558                Ok(())
559            }
560
561            #[test]
562            fn static_strt_67() -> Result<(), OtToolsIoError> {
563                let (test, valid) = helper_test_chksum(
564                    &get_bank_dirpath()
565                        .join("checksum")
566                        .join("static-strt-67.work"),
567                )?;
568                assert_eq!(test, valid);
569                Ok(())
570            }
571
572            #[test]
573            fn static_strt_66() -> Result<(), OtToolsIoError> {
574                let (test, valid) = helper_test_chksum(
575                    &get_bank_dirpath()
576                        .join("checksum")
577                        .join("static-strt-66.work"),
578                )?;
579                assert_eq!(test, valid);
580                Ok(())
581            }
582
583            #[test]
584            fn static_strt_65() -> Result<(), OtToolsIoError> {
585                let (test, valid) = helper_test_chksum(
586                    &get_bank_dirpath()
587                        .join("checksum")
588                        .join("static-strt-65.work"),
589                )?;
590                assert_eq!(test, valid);
591                Ok(())
592            }
593
594            #[test]
595            fn static_strt_64() -> Result<(), OtToolsIoError> {
596                let (test, valid) = helper_test_chksum(
597                    &get_bank_dirpath()
598                        .join("checksum")
599                        .join("static-strt-64.work"),
600                )?;
601                assert_eq!(test, valid);
602                Ok(())
603            }
604
605            #[test]
606            fn static_strt_63() -> Result<(), OtToolsIoError> {
607                let (test, valid) = helper_test_chksum(
608                    &get_bank_dirpath()
609                        .join("checksum")
610                        .join("static-strt-63.work"),
611                )?;
612                assert_eq!(test, valid);
613                Ok(())
614            }
615
616            #[test]
617            fn static_strt_62() -> Result<(), OtToolsIoError> {
618                let (test, valid) = helper_test_chksum(
619                    &get_bank_dirpath()
620                        .join("checksum")
621                        .join("static-strt-62.work"),
622                )?;
623                assert_eq!(test, valid);
624                Ok(())
625            }
626
627            #[test]
628            fn static_strt_61() -> Result<(), OtToolsIoError> {
629                let (test, valid) = helper_test_chksum(
630                    &get_bank_dirpath()
631                        .join("checksum")
632                        .join("static-strt-61.work"),
633                )?;
634                assert_eq!(test, valid);
635                Ok(())
636            }
637
638            #[test]
639            fn static_strt_60() -> Result<(), OtToolsIoError> {
640                let (test, valid) = helper_test_chksum(
641                    &get_bank_dirpath()
642                        .join("checksum")
643                        .join("static-strt-60.work"),
644                )?;
645                assert_eq!(test, valid);
646                Ok(())
647            }
648
649            #[test]
650            fn static_strt_59() -> Result<(), OtToolsIoError> {
651                let (test, valid) = helper_test_chksum(
652                    &get_bank_dirpath()
653                        .join("checksum")
654                        .join("static-strt-59.work"),
655                )?;
656                assert_eq!(test, valid);
657                Ok(())
658            }
659
660            #[test]
661            fn static_strt_58() -> Result<(), OtToolsIoError> {
662                let (test, valid) = helper_test_chksum(
663                    &get_bank_dirpath()
664                        .join("checksum")
665                        .join("static-strt-58.work"),
666                )?;
667                assert_eq!(test, valid);
668                Ok(())
669            }
670
671            #[test]
672            fn static_strt_57() -> Result<(), OtToolsIoError> {
673                let (test, valid) = helper_test_chksum(
674                    &get_bank_dirpath()
675                        .join("checksum")
676                        .join("static-strt-57.work"),
677                )?;
678                assert_eq!(test, valid);
679                Ok(())
680            }
681
682            #[test]
683            fn static_strt_56() -> Result<(), OtToolsIoError> {
684                let (test, valid) = helper_test_chksum(
685                    &get_bank_dirpath()
686                        .join("checksum")
687                        .join("static-strt-56.work"),
688                )?;
689                assert_eq!(test, valid);
690                Ok(())
691            }
692        }
693
694        mod static_strt_mult {
695            use super::helper_test_chksum;
696            use crate::test_utils::get_bank_dirpath;
697            use crate::OtToolsIoError;
698
699            #[test]
700            fn static_strt_127_len_128() -> Result<(), OtToolsIoError> {
701                // start value incremented by 127 (max) and len incremented by 127 (max) on the machine
702                let (test, valid) = helper_test_chksum(
703                    &get_bank_dirpath()
704                        .join("checksum")
705                        .join("static-strt-127-len-128.work"),
706                )?;
707                assert_eq!(test, valid);
708                Ok(())
709            }
710
711            #[test]
712            fn static_strt_67_len_67() -> Result<(), OtToolsIoError> {
713                let (test, valid) = helper_test_chksum(
714                    &get_bank_dirpath()
715                        .join("checksum")
716                        .join("static-strt-67-len-67.work"),
717                )?;
718                assert_eq!(test, valid);
719                Ok(())
720            }
721
722            #[test]
723            fn static_strt_67_len_68() -> Result<(), OtToolsIoError> {
724                let (test, valid) = helper_test_chksum(
725                    &get_bank_dirpath()
726                        .join("checksum")
727                        .join("static-strt-67-len-68.work"),
728                )?;
729                assert_eq!(test, valid);
730                Ok(())
731            }
732
733            #[test]
734            fn static_strt_68_len_68() -> Result<(), OtToolsIoError> {
735                let (test, valid) = helper_test_chksum(
736                    &get_bank_dirpath()
737                        .join("checksum")
738                        .join("static-strt-68-len-68.work"),
739                )?;
740                assert_eq!(test, valid);
741                Ok(())
742            }
743
744            #[test]
745            fn static_strt_67_len_66() -> Result<(), OtToolsIoError> {
746                let (test, valid) = helper_test_chksum(
747                    &get_bank_dirpath()
748                        .join("checksum")
749                        .join("static-strt-67-len-66.work"),
750                )?;
751                assert_eq!(test, valid);
752                Ok(())
753            }
754
755            #[test]
756            fn static_strt_66_len_66() -> Result<(), OtToolsIoError> {
757                let (test, valid) = helper_test_chksum(
758                    &get_bank_dirpath()
759                        .join("checksum")
760                        .join("static-strt-66-len-66.work"),
761                )?;
762                assert_eq!(test, valid);
763                Ok(())
764            }
765
766            #[test]
767            fn static_strt_32_len_32() -> Result<(), OtToolsIoError> {
768                let (test, valid) = helper_test_chksum(
769                    &get_bank_dirpath()
770                        .join("checksum")
771                        .join("static-strt-32-len-32.work"),
772                )?;
773                assert_eq!(test, valid);
774                Ok(())
775            }
776
777            #[test]
778            fn static_strt_32_len_33() -> Result<(), OtToolsIoError> {
779                let (test, valid) = helper_test_chksum(
780                    &get_bank_dirpath()
781                        .join("checksum")
782                        .join("static-strt-32-len-33.work"),
783                )?;
784                assert_eq!(test, valid);
785                Ok(())
786            }
787
788            #[test]
789            fn static_strt_33_len_33() -> Result<(), OtToolsIoError> {
790                let (test, valid) = helper_test_chksum(
791                    &get_bank_dirpath()
792                        .join("checksum")
793                        .join("static-strt-33-len-33.work"),
794                )?;
795                assert_eq!(test, valid);
796                Ok(())
797            }
798
799            #[test]
800            fn static_strt_32_len_31() -> Result<(), OtToolsIoError> {
801                let (test, valid) = helper_test_chksum(
802                    &get_bank_dirpath()
803                        .join("checksum")
804                        .join("static-strt-32-len-31.work"),
805                )?;
806                assert_eq!(test, valid);
807                Ok(())
808            }
809
810            #[test]
811            fn static_strt_31_len_31() -> Result<(), OtToolsIoError> {
812                let (test, valid) = helper_test_chksum(
813                    &get_bank_dirpath()
814                        .join("checksum")
815                        .join("static-strt-31-len-31.work"),
816                )?;
817                assert_eq!(test, valid);
818                Ok(())
819            }
820
821            #[test]
822            fn static_strt_67_len_67_rtrg_68() -> Result<(), OtToolsIoError> {
823                let (test, valid) = helper_test_chksum(
824                    &get_bank_dirpath()
825                        .join("checksum")
826                        .join("static-strt-67-len-67-rtrg-68.work"),
827                )?;
828                assert_eq!(test, valid);
829                Ok(())
830            }
831
832            #[test]
833            fn static_strt_67_len_68_rtrg_68() -> Result<(), OtToolsIoError> {
834                let (test, valid) = helper_test_chksum(
835                    &get_bank_dirpath()
836                        .join("checksum")
837                        .join("static-strt-67-len-68-rtrg-68.work"),
838                )?;
839                assert_eq!(test, valid);
840                Ok(())
841            }
842
843            #[test]
844            fn static_strt_67_len_69_rtrg_68() -> Result<(), OtToolsIoError> {
845                let (test, valid) = helper_test_chksum(
846                    &get_bank_dirpath()
847                        .join("checksum")
848                        .join("static-strt-67-len-69-rtrg-68.work"),
849                )?;
850                assert_eq!(test, valid);
851                Ok(())
852            }
853
854            #[test]
855            fn static_strt_67_len_69_rtrg_69() -> Result<(), OtToolsIoError> {
856                let (test, valid) = helper_test_chksum(
857                    &get_bank_dirpath()
858                        .join("checksum")
859                        .join("static-strt-67-len-69-rtrg-69.work"),
860                )?;
861                assert_eq!(test, valid);
862                Ok(())
863            }
864
865            #[test]
866            fn static_strt_67_len_69_rtrg_67() -> Result<(), OtToolsIoError> {
867                let (test, valid) = helper_test_chksum(
868                    &get_bank_dirpath()
869                        .join("checksum")
870                        .join("static-strt-67-len-69-rtrg-67.work"),
871                )?;
872                assert_eq!(test, valid);
873                Ok(())
874            }
875
876            #[test]
877            fn static_strt_67_len_67_rtrg_67() -> Result<(), OtToolsIoError> {
878                let (test, valid) = helper_test_chksum(
879                    &get_bank_dirpath()
880                        .join("checksum")
881                        .join("static-strt-67-len-67-rtrg-67.work"),
882                )?;
883                assert_eq!(test, valid);
884                Ok(())
885            }
886        }
887
888        mod flex_strt {
889            use super::helper_test_chksum;
890            use crate::test_utils::get_bank_dirpath;
891            use crate::OtToolsIoError;
892
893            #[test]
894            fn flex_strt_126() -> Result<(), OtToolsIoError> {
895                let (test, valid) = helper_test_chksum(
896                    &get_bank_dirpath()
897                        .join("checksum")
898                        .join("flex-strt-126.work"),
899                )?;
900                assert_eq!(test, valid);
901                Ok(())
902            }
903
904            #[test]
905            fn flex_strt_125() -> Result<(), OtToolsIoError> {
906                let (test, valid) = helper_test_chksum(
907                    &get_bank_dirpath()
908                        .join("checksum")
909                        .join("flex-strt-125.work"),
910                )?;
911                assert_eq!(test, valid);
912                Ok(())
913            }
914
915            #[test]
916            fn flex_strt_124() -> Result<(), OtToolsIoError> {
917                let (test, valid) = helper_test_chksum(
918                    &get_bank_dirpath()
919                        .join("checksum")
920                        .join("flex-strt-124.work"),
921                )?;
922                assert_eq!(test, valid);
923                Ok(())
924            }
925
926            #[test]
927            fn flex_strt_123() -> Result<(), OtToolsIoError> {
928                let (test, valid) = helper_test_chksum(
929                    &get_bank_dirpath()
930                        .join("checksum")
931                        .join("flex-strt-123.work"),
932                )?;
933                assert_eq!(test, valid);
934                Ok(())
935            }
936
937            #[test]
938            fn flex_strt_122() -> Result<(), OtToolsIoError> {
939                let (test, valid) = helper_test_chksum(
940                    &get_bank_dirpath()
941                        .join("checksum")
942                        .join("flex-strt-122.work"),
943                )?;
944                assert_eq!(test, valid);
945                Ok(())
946            }
947
948            #[test]
949            fn flex_strt_121() -> Result<(), OtToolsIoError> {
950                let (test, valid) = helper_test_chksum(
951                    &get_bank_dirpath()
952                        .join("checksum")
953                        .join("flex-strt-121.work"),
954                )?;
955                assert_eq!(test, valid);
956                Ok(())
957            }
958
959            #[test]
960            fn flex_strt_120() -> Result<(), OtToolsIoError> {
961                let (test, valid) = helper_test_chksum(
962                    &get_bank_dirpath()
963                        .join("checksum")
964                        .join("flex-strt-120.work"),
965                )?;
966                assert_eq!(test, valid);
967                Ok(())
968            }
969
970            #[test]
971            fn flex_strt_119() -> Result<(), OtToolsIoError> {
972                let (test, valid) = helper_test_chksum(
973                    &get_bank_dirpath()
974                        .join("checksum")
975                        .join("flex-strt-119.work"),
976                )?;
977                assert_eq!(test, valid);
978                Ok(())
979            }
980
981            #[test]
982            fn flex_strt_118() -> Result<(), OtToolsIoError> {
983                let (test, valid) = helper_test_chksum(
984                    &get_bank_dirpath()
985                        .join("checksum")
986                        .join("flex-strt-118.work"),
987                )?;
988                assert_eq!(test, valid);
989                Ok(())
990            }
991
992            #[test]
993            fn flex_strt_117() -> Result<(), OtToolsIoError> {
994                let (test, valid) = helper_test_chksum(
995                    &get_bank_dirpath()
996                        .join("checksum")
997                        .join("flex-strt-117.work"),
998                )?;
999                assert_eq!(test, valid);
1000                Ok(())
1001            }
1002
1003            #[test]
1004            fn flex_strt_116() -> Result<(), OtToolsIoError> {
1005                let (test, valid) = helper_test_chksum(
1006                    &get_bank_dirpath()
1007                        .join("checksum")
1008                        .join("flex-strt-116.work"),
1009                )?;
1010                assert_eq!(test, valid);
1011                Ok(())
1012            }
1013
1014            #[test]
1015            fn flex_strt_115() -> Result<(), OtToolsIoError> {
1016                let (test, valid) = helper_test_chksum(
1017                    &get_bank_dirpath()
1018                        .join("checksum")
1019                        .join("flex-strt-115.work"),
1020                )?;
1021                assert_eq!(test, valid);
1022                Ok(())
1023            }
1024
1025            #[test]
1026            fn flex_strt_114() -> Result<(), OtToolsIoError> {
1027                let (test, valid) = helper_test_chksum(
1028                    &get_bank_dirpath()
1029                        .join("checksum")
1030                        .join("flex-strt-114.work"),
1031                )?;
1032                assert_eq!(test, valid);
1033                Ok(())
1034            }
1035
1036            #[test]
1037            fn flex_strt_113() -> Result<(), OtToolsIoError> {
1038                let (test, valid) = helper_test_chksum(
1039                    &get_bank_dirpath()
1040                        .join("checksum")
1041                        .join("flex-strt-113.work"),
1042                )?;
1043                assert_eq!(test, valid);
1044                Ok(())
1045            }
1046
1047            #[test]
1048            fn flex_strt_112() -> Result<(), OtToolsIoError> {
1049                let (test, valid) = helper_test_chksum(
1050                    &get_bank_dirpath()
1051                        .join("checksum")
1052                        .join("flex-strt-112.work"),
1053                )?;
1054                assert_eq!(test, valid);
1055                Ok(())
1056            }
1057
1058            #[test]
1059            fn flex_strt_111() -> Result<(), OtToolsIoError> {
1060                let (test, valid) = helper_test_chksum(
1061                    &get_bank_dirpath()
1062                        .join("checksum")
1063                        .join("flex-strt-111.work"),
1064                )?;
1065                assert_eq!(test, valid);
1066                Ok(())
1067            }
1068        }
1069
1070        mod track_parameters {
1071            use super::helper_test_chksum;
1072            use crate::test_utils::get_bank_dirpath;
1073            use crate::OtToolsIoError;
1074
1075            #[test]
1076            fn track_params_attack_127() -> Result<(), OtToolsIoError> {
1077                let (test, valid) = helper_test_chksum(
1078                    &get_bank_dirpath()
1079                        .join("checksum")
1080                        .join("tparams-attack-127.work"),
1081                )?;
1082                assert_eq!(test, valid);
1083                Ok(())
1084            }
1085
1086            #[test]
1087            fn track_params_hold_0() -> Result<(), OtToolsIoError> {
1088                let (test, valid) = helper_test_chksum(
1089                    &get_bank_dirpath()
1090                        .join("checksum")
1091                        .join("tparams-hold-0.work"),
1092                )?;
1093                assert_eq!(test, valid);
1094                Ok(())
1095            }
1096
1097            #[test]
1098            fn track_params_release_0() -> Result<(), OtToolsIoError> {
1099                let (test, valid) = helper_test_chksum(
1100                    &get_bank_dirpath()
1101                        .join("checksum")
1102                        .join("tparams-rel-0.work"),
1103                )?;
1104                assert_eq!(test, valid);
1105                Ok(())
1106            }
1107            #[test]
1108            fn track_params_vol_neg64() -> Result<(), OtToolsIoError> {
1109                let (test, valid) = helper_test_chksum(
1110                    &get_bank_dirpath()
1111                        .join("checksum")
1112                        .join("tparams-vol-neg64.work"),
1113                )?;
1114                assert_eq!(test, valid);
1115                Ok(())
1116            }
1117
1118            #[test]
1119            fn track_params_vol_pos63() -> Result<(), OtToolsIoError> {
1120                let (test, valid) = helper_test_chksum(
1121                    &get_bank_dirpath()
1122                        .join("checksum")
1123                        .join("tparams-vol-pos63.work"),
1124                )?;
1125                assert_eq!(test, valid);
1126                Ok(())
1127            }
1128
1129            #[test]
1130            fn track_params_balance_neg64() -> Result<(), OtToolsIoError> {
1131                let (test, valid) = helper_test_chksum(
1132                    &get_bank_dirpath()
1133                        .join("checksum")
1134                        .join("tparams-bal-neg64.work"),
1135                )?;
1136                assert_eq!(test, valid);
1137                Ok(())
1138            }
1139
1140            #[test]
1141            fn track_params_balance_pos63() -> Result<(), OtToolsIoError> {
1142                let (test, valid) = helper_test_chksum(
1143                    &get_bank_dirpath()
1144                        .join("checksum")
1145                        .join("tparams-bal-pos63.work"),
1146                )?;
1147                assert_eq!(test, valid);
1148                Ok(())
1149            }
1150
1151            #[test]
1152            fn track_params_lfo1_spd_0() -> Result<(), OtToolsIoError> {
1153                let (test, valid) = helper_test_chksum(
1154                    &get_bank_dirpath()
1155                        .join("checksum")
1156                        .join("tparams-lfo1-spd-0.work"),
1157                )?;
1158                assert_eq!(test, valid);
1159                Ok(())
1160            }
1161
1162            #[test]
1163            fn track_params_lfo1_spd_127() -> Result<(), OtToolsIoError> {
1164                let (test, valid) = helper_test_chksum(
1165                    &get_bank_dirpath()
1166                        .join("checksum")
1167                        .join("tparams-lfo1-spd-127.work"),
1168                )?;
1169                assert_eq!(test, valid);
1170                Ok(())
1171            }
1172
1173            #[test]
1174            fn track_params_lfo1_amt_64() -> Result<(), OtToolsIoError> {
1175                let (test, valid) = helper_test_chksum(
1176                    &get_bank_dirpath()
1177                        .join("checksum")
1178                        .join("tparams-lfo1-amt-64.work"),
1179                )?;
1180                assert_eq!(test, valid);
1181                Ok(())
1182            }
1183
1184            #[test]
1185            fn track_params_lfo1_amt_127() -> Result<(), OtToolsIoError> {
1186                let (test, valid) = helper_test_chksum(
1187                    &get_bank_dirpath()
1188                        .join("checksum")
1189                        .join("tparams-lfo1-amt-127.work"),
1190                )?;
1191                assert_eq!(test, valid);
1192                Ok(())
1193            }
1194
1195            #[test]
1196            fn track_params_fx1_filter_base_127() -> Result<(), OtToolsIoError> {
1197                let (test, valid) = helper_test_chksum(
1198                    &get_bank_dirpath()
1199                        .join("checksum")
1200                        .join("tparams-fx1-filt-base-127.work"),
1201                )?;
1202                assert_eq!(test, valid);
1203                Ok(())
1204            }
1205
1206            #[test]
1207            fn track_params_fx1_filter_width_0() -> Result<(), OtToolsIoError> {
1208                let (test, valid) = helper_test_chksum(
1209                    &get_bank_dirpath()
1210                        .join("checksum")
1211                        .join("tparams-fx1-filt-wid-0.work"),
1212                )?;
1213                assert_eq!(test, valid);
1214                Ok(())
1215            }
1216
1217            #[test]
1218            fn track_params_fx1_filter_q_127() -> Result<(), OtToolsIoError> {
1219                let (test, valid) = helper_test_chksum(
1220                    &get_bank_dirpath()
1221                        .join("checksum")
1222                        .join("tparams-fx1-filt-q-127.work"),
1223                )?;
1224                assert_eq!(test, valid);
1225                Ok(())
1226            }
1227
1228            #[test]
1229            fn track_params_fx1_filter_depth_neg64() -> Result<(), OtToolsIoError> {
1230                let (test, valid) = helper_test_chksum(
1231                    &get_bank_dirpath()
1232                        .join("checksum")
1233                        .join("tparams-fx1-filt-dep-neg64.work"),
1234                )?;
1235                assert_eq!(test, valid);
1236                Ok(())
1237            }
1238
1239            #[test]
1240            fn track_params_fx1_filter_depth_pos63() -> Result<(), OtToolsIoError> {
1241                let (test, valid) = helper_test_chksum(
1242                    &get_bank_dirpath()
1243                        .join("checksum")
1244                        .join("tparams-fx1-filt-dep-pos63.work"),
1245                )?;
1246                assert_eq!(test, valid);
1247                Ok(())
1248            }
1249
1250            #[test]
1251            fn track_params_fx2_delay_snd_127() -> Result<(), OtToolsIoError> {
1252                // start value incremented by 127 (max) and len incremented by 127 (max) on the machine
1253                let (test, valid) = helper_test_chksum(
1254                    &get_bank_dirpath()
1255                        .join("checksum")
1256                        .join("atrack1-delay-snd-127.work"),
1257                )?;
1258                assert_eq!(test, valid);
1259                Ok(())
1260            }
1261        }
1262
1263        mod lfo_designer {
1264            use super::helper_test_chksum;
1265            use crate::test_utils::get_bank_dirpath;
1266            use crate::OtToolsIoError;
1267
1268            #[test]
1269            fn lfo_design_atr1_step1_pos64() -> Result<(), OtToolsIoError> {
1270                let (test, valid) = helper_test_chksum(
1271                    &get_bank_dirpath()
1272                        .join("checksum")
1273                        .join("lfo-design-step1-64.work"),
1274                )?;
1275                assert_eq!(test, valid);
1276                Ok(())
1277            }
1278
1279            #[test]
1280            fn lfo_design_atr1_step1_pos127() -> Result<(), OtToolsIoError> {
1281                let (test, valid) = helper_test_chksum(
1282                    &get_bank_dirpath()
1283                        .join("checksum")
1284                        .join("lfo-design-step1-127.work"),
1285                )?;
1286                assert_eq!(test, valid);
1287                Ok(())
1288            }
1289
1290            #[test]
1291            fn lfo_design_atr1_step1_neg64() -> Result<(), OtToolsIoError> {
1292                let (test, valid) = helper_test_chksum(
1293                    &get_bank_dirpath()
1294                        .join("checksum")
1295                        .join("lfo-design-step1-neg64.work"),
1296                )?;
1297                assert_eq!(test, valid);
1298                Ok(())
1299            }
1300
1301            #[test]
1302            fn lfo_design_atr1_step1_neg128() -> Result<(), OtToolsIoError> {
1303                let (test, valid) = helper_test_chksum(
1304                    &get_bank_dirpath()
1305                        .join("checksum")
1306                        .join("lfo-design-step1-neg128.work"),
1307                )?;
1308                assert_eq!(test, valid);
1309                Ok(())
1310            }
1311
1312            #[test]
1313            fn lfo_design_atr1_randomised() -> Result<(), OtToolsIoError> {
1314                let (test, valid) = helper_test_chksum(
1315                    &get_bank_dirpath()
1316                        .join("checksum")
1317                        .join("lfo-design-randomised.work"),
1318                )?;
1319                assert_eq!(test, valid);
1320                Ok(())
1321            }
1322        }
1323    }
1324}
1325
1326impl HasHeaderField for BankFile {
1327    fn check_header(&self) -> Result<bool, OtToolsIoError> {
1328        Ok(self.header == BANK_HEADER)
1329    }
1330}
1331
1332#[cfg(test)]
1333mod header_field {
1334    use crate::{BankFile, HasHeaderField, OtToolsIoError};
1335    #[test]
1336    fn valid() -> Result<(), OtToolsIoError> {
1337        assert!(BankFile::default().check_header()?);
1338        Ok(())
1339    }
1340
1341    #[test]
1342    fn invalid() -> Result<(), OtToolsIoError> {
1343        let mut mutated = BankFile::default();
1344        mutated.header[0] = 0x00;
1345        mutated.header[20] = 111;
1346        assert!(!mutated.check_header()?);
1347        Ok(())
1348    }
1349}
1350
1351impl HasFileVersionField for BankFile {
1352    fn check_file_version(&self) -> Result<bool, OtToolsIoError> {
1353        Ok(BANK_FILE_VERSION == self.datatype_version)
1354    }
1355}
1356
1357#[cfg(test)]
1358mod file_version_field {
1359    use crate::{BankFile, HasFileVersionField, OtToolsIoError};
1360    #[test]
1361    fn valid() -> Result<(), OtToolsIoError> {
1362        assert!(BankFile::default().check_file_version()?);
1363        Ok(())
1364    }
1365
1366    #[test]
1367    fn invalid() -> Result<(), OtToolsIoError> {
1368        let x = BankFile {
1369            datatype_version: 0,
1370            ..BankFile::default()
1371        };
1372        assert!(!x.check_file_version()?);
1373        Ok(())
1374    }
1375}