/*
SPDX-License-Identifier: GPL-3.0-or-later
Copyright © 2024 Mike Robeson [dijksterhuis]
*/

//! Types for `bank??.*` binary data files.

use crate::parts::Parts;
use crate::patterns::Pattern;
use crate::{
    CalculateChecksum, CheckChecksum, CheckFileVersion, CheckHeader, DefaultsArrayBoxed, Encode,
    IsDefault, RBoxErr,
};
use ot_tools_io_derive::{Decodeable, DefaultsAsBoxedBigArray, IntegrityChecks, OctatrackFile};
use serde::{Deserialize, Serialize};
use serde_big_array::{Array, BigArray};
use std::array::from_fn;

/// Bank header data.
/// ```text
/// FORM....DPS1BANK.....
/// 46 4f 52 4d 00 00 00 00 44 50 53 31 42 41 4e 4b 00 00 00 00 00
/// [70 79 82 77 0 0 0 0 68 80 83 49 66 65 78 75 0 0 0 0 0]
/// ```
pub const BANK_HEADER: [u8; 21] = [
    70, 79, 82, 77, 0, 0, 0, 0, 68, 80, 83, 49, 66, 65, 78, 75, 0, 0, 0, 0, 0,
];

/// Current/supported version of bank files.
pub const BANK_FILE_VERSION: u8 = 23;

/// An Octatrack Bank. Contains data related to Parts and Patterns.
#[derive(
    Debug,
    Serialize,
    Deserialize,
    Clone,
    PartialEq,
    DefaultsAsBoxedBigArray,
    Decodeable,
    OctatrackFile,
    IntegrityChecks,
)]
pub struct BankFile {
    /// Misc header data for Banks.
    /// Always follows the same format.
    #[serde(with = "BigArray")]
    pub header: [u8; 21],

    pub datatype_version: u8,

    /// Pattern data for a Bank.
    // note -- stack overflow if tring to use #[serde(with = "BigArray")]
    pub patterns: Box<Array<Pattern, 16>>,

    /// All part data for this bank, includes currently unsaved and previously saved state
    pub parts: Parts,

    /// Indicates which parts have previously saved state available for reloading.
    #[serde(with = "BigArray")]
    pub parts_saved_state: [u8; 4],

    /// Bit mask indicating which parts are currently in an edited state.
    /// ```text
    /// parts
    /// 1 2 3 4 | mask
    /// --------|------
    /// - - - - | 0
    /// x - - - | 1
    /// - x - - | 2
    /// - - x - | 4
    /// - - - x | 8
    /// --------|------
    /// x x - - | 3
    /// x - x - | 5
    /// - x x - | 6
    /// x x x - | 7
    /// x - - x | 9
    /// - x - x | 10
    /// x x - x | 11
    /// - - x x | 12
    /// - x x x | 14
    /// x x x x | 15
    /// ```
    pub parts_edited_bitmask: u8,

    /// Names for each Part within the Bank.
    /// Maximum 7 character length.
    #[serde(with = "BigArray")]
    pub part_names: [[u8; 7]; 4],

    /// checksum bytes
    pub checksum: u16,
}

/// Default Part names (ONE, TWO, THREE, FOUR) converted to u8 for ease of use.
const DEFAULT_PART_NAMES: [[u8; 7]; 4] = [
    [0x4f, 0x4e, 0x45, 0x00, 0x00, 0x00, 0x00], // "ONE"
    [0x54, 0x57, 0x4f, 0x00, 0x00, 0x00, 0x00], // "TWO"
    [0x54, 0x48, 0x52, 0x45, 0x45, 0x00, 0x00], // "THREE"
    [0x46, 0x4f, 0x55, 0x52, 0x00, 0x00, 0x00], // "FOUR"
];

impl Encode for BankFile {
    fn encode(&self) -> RBoxErr<Vec<u8>> {
        let mut chkd = self.clone();
        chkd.checksum = self.calculate_checksum()?;
        let bytes = bincode::serialize(&chkd)?;
        Ok(bytes)
    }
}

impl Default for BankFile {
    fn default() -> Self {
        Self {
            header: BANK_HEADER,
            datatype_version: BANK_FILE_VERSION,
            patterns: Pattern::defaults(),
            parts: Parts::default(),
            parts_saved_state: from_fn(|_| 0),
            parts_edited_bitmask: 0,
            part_names: DEFAULT_PART_NAMES,
            // WARN: mutated during encode! do not calculate checksum in this
            // method until i've refactored `get_checksum` to not use Bank::default()
            // (end up with a never ending recursive loop of calling default)
            // TODO: Hardcoded
            checksum: 48022,
        }
    }
}

impl IsDefault for BankFile {
    fn is_default(&self) -> bool {
        &BankFile::default() == self
    }
}

impl CalculateChecksum for BankFile {
    fn calculate_checksum(&self) -> RBoxErr<u16> {
        let bytes = bincode::serialize(&self)?;
        let bytes_no_header_no_chk = &bytes[16..bytes.len() - 2];
        let default_bytes = &bincode::serialize(&BankFile::default())?;
        let def_important_bytes = &default_bytes[16..bytes.len() - 2];
        let default_checksum: i32 = 48022;
        let mut byte_diffs: i32 = 0;
        for (byte, def_byte) in bytes_no_header_no_chk.iter().zip(def_important_bytes) {
            let byte_diff = (*byte as i32) - (*def_byte as i32);
            if byte_diff != 0 {
                byte_diffs += byte_diff;
            }
        }
        let check = byte_diffs * 256 + default_checksum;
        let modded = check.rem_euclid(65535);
        Ok(modded as u16)
    }
}

impl CheckHeader for BankFile {
    fn check_header(&self) -> bool {
        self.header == BANK_HEADER
    }
}

impl CheckChecksum for BankFile {
    fn check_checksum(&self) -> RBoxErr<bool> {
        Ok(self.checksum == self.calculate_checksum()?)
    }
}

impl CheckFileVersion for BankFile {
    fn check_file_version(&self) -> RBoxErr<bool> {
        Ok(BANK_FILE_VERSION == self.datatype_version)
    }
}

#[cfg(test)]
mod checksum {
    use crate::banks::BankFile;
    use crate::test_utils::{get_bank_dirpath, get_blank_proj_dirpath};
    use crate::{CalculateChecksum, Encode, OctatrackFileIO};
    use std::path::Path;

    fn helper_test_chksum(fp: &Path) {
        let valid = BankFile::from_data_file(fp).unwrap();
        let mut test = valid.clone();
        test.checksum = 0;
        let encoded = test.encode().unwrap();
        let def_encoded = BankFile::default().encode().unwrap();

        let r = test.calculate_checksum();

        //let bytes = bincode::serialize(&test).unwrap();
        //let r = get_checksum(&bytes);
        assert!(r.is_ok());
        let res = r.unwrap();

        let s_attr_chk: u32 = encoded[16..encoded.len() - 2]
            .iter()
            .map(|x| *x as u32)
            .sum::<u32>()
            .rem_euclid(u16::MAX as u32 + 1);

        let non_zero_bytes = encoded.iter().filter(|b| b > &&0).count();
        let non_zero_sum = encoded
            .iter()
            .cloned()
            .filter(|b| b > &0)
            .map(|x| x as u32)
            .sum::<u32>();

        let default_byte_sum = def_encoded
            .iter()
            .cloned()
            .filter(|b| b > &0)
            .map(|x| x as u32)
            .sum::<u32>();

        println!(
            "l: {} r: {} non_zero_bytes {} sum total: {} def sum: {}, s-attr {} diff {} (or {})",
            res,
            valid.checksum,
            non_zero_bytes,
            non_zero_sum,
            default_byte_sum,
            s_attr_chk,
            res.wrapping_sub(valid.checksum),
            valid.checksum.wrapping_sub(res)
        );

        assert_eq!(res, valid.checksum);
    }

    #[test]
    fn default_bank1() {
        helper_test_chksum(&get_blank_proj_dirpath().join("bank01.work"));
    }

    #[test]
    fn default_bank2() {
        helper_test_chksum(&get_blank_proj_dirpath().join("bank02.work"));
    }

    #[test]
    fn one_scene_zero_val() {
        // start value incremented by 127 (max) and len incremented by 127 (max) on the machine
        helper_test_chksum(
            &get_bank_dirpath()
                .join("checksum")
                .join("scene1-atrack1-lfo-dep1-zero.work"),
        );
    }

    #[test]
    fn one_scene_127_val() {
        // start value incremented by 127 (max) and len incremented by 127 (max) on the machine
        helper_test_chksum(
            &get_bank_dirpath()
                .join("checksum")
                .join("scene1-atrack1-lfo-dep1-127.work"),
        );
    }

    #[test]
    fn scene_params_decr_lots() {
        // all scenes have assignments on the LFO parameters for track 1 - sets everything tp 0
        helper_test_chksum(
            &get_bank_dirpath()
                .join("checksum")
                .join("all-scenes-lfo-params-zeroed.work"),
        );
    }

    mod static_strt_only {
        use crate::banks::checksum::helper_test_chksum;
        use crate::test_utils::get_bank_dirpath;

        #[test]
        fn static_strt_1() {
            // start value incremented by one on the machine
            helper_test_chksum(
                &get_bank_dirpath()
                    .join("checksum")
                    .join("static-strt-1.work"),
            );
        }

        #[test]
        fn static_strt_2() {
            // start value incremented by two on the machine
            helper_test_chksum(
                &get_bank_dirpath()
                    .join("checksum")
                    .join("static-strt-2.work"),
            );
        }

        #[test]
        fn static_strt_10() {
            // start value incremented by ten on the machine
            helper_test_chksum(
                &get_bank_dirpath()
                    .join("checksum")
                    .join("static-strt-10.work"),
            );
        }

        // off by one?!
        #[test]
        fn static_strt_127() {
            // start value incremented by 127 (max) on the machine
            helper_test_chksum(
                &get_bank_dirpath()
                    .join("checksum")
                    .join("static-strt-127.work"),
            );
        }

        #[test]
        fn static_strt_126() {
            helper_test_chksum(
                &get_bank_dirpath()
                    .join("checksum")
                    .join("static-strt-126.work"),
            );
        }

        #[test]
        fn static_strt_125() {
            helper_test_chksum(
                &get_bank_dirpath()
                    .join("checksum")
                    .join("static-strt-125.work"),
            );
        }

        #[test]
        fn static_strt_124() {
            helper_test_chksum(
                &get_bank_dirpath()
                    .join("checksum")
                    .join("static-strt-124.work"),
            );
        }

        #[test]
        fn static_strt_123() {
            helper_test_chksum(
                &get_bank_dirpath()
                    .join("checksum")
                    .join("static-strt-123.work"),
            );
        }

        #[test]
        fn static_strt_122() {
            helper_test_chksum(
                &get_bank_dirpath()
                    .join("checksum")
                    .join("static-strt-122.work"),
            );
        }

        #[test]
        fn static_strt_121() {
            helper_test_chksum(
                &get_bank_dirpath()
                    .join("checksum")
                    .join("static-strt-121.work"),
            );
        }

        #[test]
        fn static_strt_120() {
            helper_test_chksum(
                &get_bank_dirpath()
                    .join("checksum")
                    .join("static-strt-120.work"),
            );
        }

        #[test]
        fn static_strt_119() {
            helper_test_chksum(
                &get_bank_dirpath()
                    .join("checksum")
                    .join("static-strt-119.work"),
            );
        }

        #[test]
        fn static_strt_118() {
            helper_test_chksum(
                &get_bank_dirpath()
                    .join("checksum")
                    .join("static-strt-118.work"),
            );
        }

        #[test]
        fn static_strt_117() {
            helper_test_chksum(
                &get_bank_dirpath()
                    .join("checksum")
                    .join("static-strt-117.work"),
            );
        }

        #[test]
        fn static_strt_116() {
            helper_test_chksum(
                &get_bank_dirpath()
                    .join("checksum")
                    .join("static-strt-116.work"),
            );
        }

        #[test]
        fn static_strt_115() {
            helper_test_chksum(
                &get_bank_dirpath()
                    .join("checksum")
                    .join("static-strt-115.work"),
            );
        }

        #[test]
        fn static_strt_114() {
            helper_test_chksum(
                &get_bank_dirpath()
                    .join("checksum")
                    .join("static-strt-114.work"),
            );
        }

        #[test]
        fn static_strt_113() {
            helper_test_chksum(
                &get_bank_dirpath()
                    .join("checksum")
                    .join("static-strt-113.work"),
            );
        }

        #[test]
        fn static_strt_112() {
            helper_test_chksum(
                &get_bank_dirpath()
                    .join("checksum")
                    .join("static-strt-112.work"),
            );
        }

        #[test]
        fn static_strt_111() {
            helper_test_chksum(
                &get_bank_dirpath()
                    .join("checksum")
                    .join("static-strt-111.work"),
            );
        }

        #[test]
        fn static_strt_71() {
            helper_test_chksum(
                &get_bank_dirpath()
                    .join("checksum")
                    .join("static-strt-71.work"),
            );
        }

        #[test]
        fn static_strt_70() {
            helper_test_chksum(
                &get_bank_dirpath()
                    .join("checksum")
                    .join("static-strt-70.work"),
            );
        }

        #[test]
        fn static_strt_69() {
            helper_test_chksum(
                &get_bank_dirpath()
                    .join("checksum")
                    .join("static-strt-69.work"),
            );
        }

        #[test]
        fn static_strt_68() {
            helper_test_chksum(
                &get_bank_dirpath()
                    .join("checksum")
                    .join("static-strt-68.work"),
            );
        }

        #[test]
        fn static_strt_67() {
            helper_test_chksum(
                &get_bank_dirpath()
                    .join("checksum")
                    .join("static-strt-67.work"),
            );
        }

        #[test]
        fn static_strt_66() {
            helper_test_chksum(
                &get_bank_dirpath()
                    .join("checksum")
                    .join("static-strt-66.work"),
            );
        }

        #[test]
        fn static_strt_65() {
            helper_test_chksum(
                &get_bank_dirpath()
                    .join("checksum")
                    .join("static-strt-65.work"),
            );
        }

        #[test]
        fn static_strt_64() {
            helper_test_chksum(
                &get_bank_dirpath()
                    .join("checksum")
                    .join("static-strt-64.work"),
            );
        }

        #[test]
        fn static_strt_63() {
            helper_test_chksum(
                &get_bank_dirpath()
                    .join("checksum")
                    .join("static-strt-63.work"),
            );
        }

        #[test]
        fn static_strt_62() {
            helper_test_chksum(
                &get_bank_dirpath()
                    .join("checksum")
                    .join("static-strt-62.work"),
            );
        }

        #[test]
        fn static_strt_61() {
            helper_test_chksum(
                &get_bank_dirpath()
                    .join("checksum")
                    .join("static-strt-61.work"),
            );
        }

        #[test]
        fn static_strt_60() {
            helper_test_chksum(
                &get_bank_dirpath()
                    .join("checksum")
                    .join("static-strt-60.work"),
            );
        }

        #[test]
        fn static_strt_59() {
            helper_test_chksum(
                &get_bank_dirpath()
                    .join("checksum")
                    .join("static-strt-59.work"),
            );
        }

        #[test]
        fn static_strt_58() {
            helper_test_chksum(
                &get_bank_dirpath()
                    .join("checksum")
                    .join("static-strt-58.work"),
            );
        }

        #[test]
        fn static_strt_57() {
            helper_test_chksum(
                &get_bank_dirpath()
                    .join("checksum")
                    .join("static-strt-57.work"),
            );
        }

        #[test]
        fn static_strt_56() {
            helper_test_chksum(
                &get_bank_dirpath()
                    .join("checksum")
                    .join("static-strt-56.work"),
            );
        }
    }

    mod static_strt_mult {
        use crate::banks::checksum::helper_test_chksum;
        use crate::test_utils::get_bank_dirpath;

        #[test]
        fn static_strt_127_len_128() {
            // start value incremented by 127 (max) and len incremented by 127 (max) on the machine
            helper_test_chksum(
                &get_bank_dirpath()
                    .join("checksum")
                    .join("static-strt-127-len-128.work"),
            );
        }

        #[test]
        fn static_strt_67_len_67() {
            helper_test_chksum(
                &get_bank_dirpath()
                    .join("checksum")
                    .join("static-strt-67-len-67.work"),
            );
        }

        #[test]
        fn static_strt_67_len_68() {
            helper_test_chksum(
                &get_bank_dirpath()
                    .join("checksum")
                    .join("static-strt-67-len-68.work"),
            );
        }

        #[test]
        fn static_strt_68_len_68() {
            helper_test_chksum(
                &get_bank_dirpath()
                    .join("checksum")
                    .join("static-strt-68-len-68.work"),
            );
        }

        #[test]
        fn static_strt_67_len_66() {
            helper_test_chksum(
                &get_bank_dirpath()
                    .join("checksum")
                    .join("static-strt-67-len-66.work"),
            );
        }

        #[test]
        fn static_strt_66_len_66() {
            helper_test_chksum(
                &get_bank_dirpath()
                    .join("checksum")
                    .join("static-strt-66-len-66.work"),
            );
        }

        #[test]
        fn static_strt_32_len_32() {
            helper_test_chksum(
                &get_bank_dirpath()
                    .join("checksum")
                    .join("static-strt-32-len-32.work"),
            );
        }

        #[test]
        fn static_strt_32_len_33() {
            helper_test_chksum(
                &get_bank_dirpath()
                    .join("checksum")
                    .join("static-strt-32-len-33.work"),
            );
        }

        #[test]
        fn static_strt_33_len_33() {
            helper_test_chksum(
                &get_bank_dirpath()
                    .join("checksum")
                    .join("static-strt-33-len-33.work"),
            );
        }

        #[test]
        fn static_strt_32_len_31() {
            helper_test_chksum(
                &get_bank_dirpath()
                    .join("checksum")
                    .join("static-strt-32-len-31.work"),
            );
        }

        #[test]
        fn static_strt_31_len_31() {
            helper_test_chksum(
                &get_bank_dirpath()
                    .join("checksum")
                    .join("static-strt-31-len-31.work"),
            );
        }

        #[test]
        fn static_strt_67_len_67_rtrg_68() {
            helper_test_chksum(
                &get_bank_dirpath()
                    .join("checksum")
                    .join("static-strt-67-len-67-rtrg-68.work"),
            );
        }

        #[test]
        fn static_strt_67_len_68_rtrg_68() {
            helper_test_chksum(
                &get_bank_dirpath()
                    .join("checksum")
                    .join("static-strt-67-len-68-rtrg-68.work"),
            );
        }

        #[test]
        fn static_strt_67_len_69_rtrg_68() {
            helper_test_chksum(
                &get_bank_dirpath()
                    .join("checksum")
                    .join("static-strt-67-len-69-rtrg-68.work"),
            );
        }

        #[test]
        fn static_strt_67_len_69_rtrg_69() {
            helper_test_chksum(
                &get_bank_dirpath()
                    .join("checksum")
                    .join("static-strt-67-len-69-rtrg-69.work"),
            );
        }

        #[test]
        fn static_strt_67_len_69_rtrg_67() {
            helper_test_chksum(
                &get_bank_dirpath()
                    .join("checksum")
                    .join("static-strt-67-len-69-rtrg-67.work"),
            );
        }

        #[test]
        fn static_strt_67_len_67_rtrg_67() {
            helper_test_chksum(
                &get_bank_dirpath()
                    .join("checksum")
                    .join("static-strt-67-len-67-rtrg-67.work"),
            );
        }
    }

    mod flex_strt {
        use crate::banks::checksum::helper_test_chksum;
        use crate::test_utils::get_bank_dirpath;

        #[test]
        fn flex_strt_126() {
            helper_test_chksum(
                &get_bank_dirpath()
                    .join("checksum")
                    .join("flex-strt-126.work"),
            );
        }

        #[test]
        fn flex_strt_125() {
            helper_test_chksum(
                &get_bank_dirpath()
                    .join("checksum")
                    .join("flex-strt-125.work"),
            );
        }

        #[test]
        fn flex_strt_124() {
            helper_test_chksum(
                &get_bank_dirpath()
                    .join("checksum")
                    .join("flex-strt-124.work"),
            );
        }

        #[test]
        fn flex_strt_123() {
            helper_test_chksum(
                &get_bank_dirpath()
                    .join("checksum")
                    .join("flex-strt-123.work"),
            );
        }

        #[test]
        fn flex_strt_122() {
            helper_test_chksum(
                &get_bank_dirpath()
                    .join("checksum")
                    .join("flex-strt-122.work"),
            );
        }

        #[test]
        fn flex_strt_121() {
            helper_test_chksum(
                &get_bank_dirpath()
                    .join("checksum")
                    .join("flex-strt-121.work"),
            );
        }

        #[test]
        fn flex_strt_120() {
            helper_test_chksum(
                &get_bank_dirpath()
                    .join("checksum")
                    .join("flex-strt-120.work"),
            );
        }

        #[test]
        fn flex_strt_119() {
            helper_test_chksum(
                &get_bank_dirpath()
                    .join("checksum")
                    .join("flex-strt-119.work"),
            );
        }

        #[test]
        fn flex_strt_118() {
            helper_test_chksum(
                &get_bank_dirpath()
                    .join("checksum")
                    .join("flex-strt-118.work"),
            );
        }

        #[test]
        fn flex_strt_117() {
            helper_test_chksum(
                &get_bank_dirpath()
                    .join("checksum")
                    .join("flex-strt-117.work"),
            );
        }

        #[test]
        fn flex_strt_116() {
            helper_test_chksum(
                &get_bank_dirpath()
                    .join("checksum")
                    .join("flex-strt-116.work"),
            );
        }

        #[test]
        fn flex_strt_115() {
            helper_test_chksum(
                &get_bank_dirpath()
                    .join("checksum")
                    .join("flex-strt-115.work"),
            );
        }

        #[test]
        fn flex_strt_114() {
            helper_test_chksum(
                &get_bank_dirpath()
                    .join("checksum")
                    .join("flex-strt-114.work"),
            );
        }

        #[test]
        fn flex_strt_113() {
            helper_test_chksum(
                &get_bank_dirpath()
                    .join("checksum")
                    .join("flex-strt-113.work"),
            );
        }

        #[test]
        fn flex_strt_112() {
            helper_test_chksum(
                &get_bank_dirpath()
                    .join("checksum")
                    .join("flex-strt-112.work"),
            );
        }

        #[test]
        fn flex_strt_111() {
            helper_test_chksum(
                &get_bank_dirpath()
                    .join("checksum")
                    .join("flex-strt-111.work"),
            );
        }
    }

    mod track_parameters {
        use crate::banks::checksum::helper_test_chksum;
        use crate::test_utils::get_bank_dirpath;

        #[test]
        fn track_params_attack_127() {
            helper_test_chksum(
                &get_bank_dirpath()
                    .join("checksum")
                    .join("tparams-attack-127.work"),
            );
        }

        #[test]
        fn track_params_hold_0() {
            helper_test_chksum(
                &get_bank_dirpath()
                    .join("checksum")
                    .join("tparams-hold-0.work"),
            );
        }

        #[test]
        fn track_params_release_0() {
            helper_test_chksum(
                &get_bank_dirpath()
                    .join("checksum")
                    .join("tparams-rel-0.work"),
            );
        }
        #[test]
        fn track_params_vol_neg64() {
            helper_test_chksum(
                &get_bank_dirpath()
                    .join("checksum")
                    .join("tparams-vol-neg64.work"),
            );
        }

        #[test]
        fn track_params_vol_pos63() {
            helper_test_chksum(
                &get_bank_dirpath()
                    .join("checksum")
                    .join("tparams-vol-pos63.work"),
            );
        }

        #[test]
        fn track_params_balance_neg64() {
            helper_test_chksum(
                &get_bank_dirpath()
                    .join("checksum")
                    .join("tparams-bal-neg64.work"),
            );
        }

        #[test]
        fn track_params_balance_pos63() {
            helper_test_chksum(
                &get_bank_dirpath()
                    .join("checksum")
                    .join("tparams-bal-pos63.work"),
            );
        }

        #[test]
        fn track_params_lfo1_spd_0() {
            helper_test_chksum(
                &get_bank_dirpath()
                    .join("checksum")
                    .join("tparams-lfo1-spd-0.work"),
            );
        }

        #[test]
        fn track_params_lfo1_spd_127() {
            helper_test_chksum(
                &get_bank_dirpath()
                    .join("checksum")
                    .join("tparams-lfo1-spd-127.work"),
            );
        }

        #[test]
        fn track_params_lfo1_amt_64() {
            helper_test_chksum(
                &get_bank_dirpath()
                    .join("checksum")
                    .join("tparams-lfo1-amt-64.work"),
            );
        }

        #[test]
        fn track_params_lfo1_amt_127() {
            helper_test_chksum(
                &get_bank_dirpath()
                    .join("checksum")
                    .join("tparams-lfo1-amt-127.work"),
            );
        }

        #[test]
        fn track_params_fx1_filter_base_127() {
            helper_test_chksum(
                &get_bank_dirpath()
                    .join("checksum")
                    .join("tparams-fx1-filt-base-127.work"),
            );
        }

        #[test]
        fn track_params_fx1_filter_width_0() {
            helper_test_chksum(
                &get_bank_dirpath()
                    .join("checksum")
                    .join("tparams-fx1-filt-wid-0.work"),
            );
        }

        #[test]
        fn track_params_fx1_filter_q_127() {
            helper_test_chksum(
                &get_bank_dirpath()
                    .join("checksum")
                    .join("tparams-fx1-filt-q-127.work"),
            );
        }

        #[test]
        fn track_params_fx1_filter_depth_neg64() {
            helper_test_chksum(
                &get_bank_dirpath()
                    .join("checksum")
                    .join("tparams-fx1-filt-dep-neg64.work"),
            );
        }

        #[test]
        fn track_params_fx1_filter_depth_pos63() {
            helper_test_chksum(
                &get_bank_dirpath()
                    .join("checksum")
                    .join("tparams-fx1-filt-dep-pos63.work"),
            );
        }

        #[test]
        fn track_params_fx2_delay_snd_127() {
            // start value incremented by 127 (max) and len incremented by 127 (max) on the machine
            helper_test_chksum(
                &get_bank_dirpath()
                    .join("checksum")
                    .join("atrack1-delay-snd-127.work"),
            );
        }
    }

    mod lfo_designer {
        use crate::banks::checksum::helper_test_chksum;
        use crate::test_utils::get_bank_dirpath;

        #[test]
        fn lfo_design_atr1_step1_pos64() {
            helper_test_chksum(
                &get_bank_dirpath()
                    .join("checksum")
                    .join("lfo-design-step1-64.work"),
            );
        }

        #[test]
        fn lfo_design_atr1_step1_pos127() {
            helper_test_chksum(
                &get_bank_dirpath()
                    .join("checksum")
                    .join("lfo-design-step1-127.work"),
            );
        }

        #[test]
        fn lfo_design_atr1_step1_neg64() {
            helper_test_chksum(
                &get_bank_dirpath()
                    .join("checksum")
                    .join("lfo-design-step1-neg64.work"),
            );
        }

        #[test]
        fn lfo_design_atr1_step1_neg128() {
            helper_test_chksum(
                &get_bank_dirpath()
                    .join("checksum")
                    .join("lfo-design-step1-neg128.work"),
            );
        }

        #[test]
        fn lfo_design_atr1_randomised() {
            helper_test_chksum(
                &get_bank_dirpath()
                    .join("checksum")
                    .join("lfo-design-randomised.work"),
            );
        }
    }
}
