ot-tools-io 0.9.0

A library crate for reading/writing binary data files used by the Elektron Octatrack DPS-1.
Documentation
/*
SPDX-License-Identifier: GPL-3.0-or-later
Copyright © 2024 Mike Robeson [dijksterhuis]
*/
use crate::parts::lfos::LfoParamsValues;
use crate::parts::tracks::audio::{
    AudioTrackAmpParamsValues, AudioTrackFxParamsValues, AudioTrackSceneLockPlayback,
};

use crate::traits::Defaults;
use ot_tools_io_derive::{
    ArrayDefaults, AsMutDerive, AsRefDerive, BoxedArrayDefaults, IsDefaultCheck,
};
use serde::{Deserialize, Serialize};
use serde_big_array::BigArray;
use std::array::from_fn;

/// Scenes currently selected in the Part.
/// Whether Scenes are muted or not are controlled at the Project level.
#[derive(
    Copy,
    Clone,
    Debug,
    Eq,
    Hash,
    Ord,
    PartialEq,
    PartialOrd,
    Serialize,
    Deserialize,
    AsMutDerive,
    AsRefDerive,
)]
pub struct ActiveScenes {
    pub scene_a: u8,
    pub scene_b: u8,
}

impl Default for ActiveScenes {
    fn default() -> Self {
        Self {
            scene_a: 0,
            scene_b: 8,
        }
    }
}

#[cfg(test)]
mod active_scenes {
    use crate::parts::scenes::ActiveScenes;
    use crate::parts::test_helper::get_default_test_bank;
    use crate::OtToolsIoError;

    #[test]
    fn default() -> Result<(), OtToolsIoError> {
        let b = get_default_test_bank()?;
        assert_eq!(b.parts_unsaved[0].active_scenes, ActiveScenes::default());
        Ok(())
    }
}

/// Scene parameter assignments for a single audio track.
///
/// 255 is no assignment on the scene for that specific audio track's parameter
/// value.
///
/// Any other value is the Scene's assigned value for that control.
#[derive(
    Copy,
    Clone,
    Debug,
    Eq,
    Hash,
    Ord,
    PartialEq,
    PartialOrd,
    Serialize,
    Deserialize,
    AsMutDerive,
    AsRefDerive,
    ArrayDefaults,
    BoxedArrayDefaults,
    IsDefaultCheck,
)]
pub struct SceneParams {
    /// Scene assignments for the Audio Track's active playback machine
    pub machine: AudioTrackSceneLockPlayback,
    /// Scene assignments for the Audio Track's LFO parameters
    pub lfo: LfoParamsValues,
    /// Scene assignments for the Audio Track's AMP parameters
    pub amp: AudioTrackAmpParamsValues,
    /// Scene assignments for the Audio Track's FX1 parameters
    pub fx1: AudioTrackFxParamsValues,
    /// Scene assignments for the Audio Track's FX2 parameters
    pub fx2: AudioTrackFxParamsValues,
    /// Unknown, likely leftover sample slot assignment (it
    /// seems the underlying machine OS code re-uses the same
    /// data structure in several places).
    pub unknown_1: u8,
    /// Unknown, likely leftover sample slot assignment (it
    /// seems the underlying machine OS code re-uses the same
    /// data structure in several places).
    pub unknown_2: u8,
}

impl Default for SceneParams {
    fn default() -> Self {
        Self {
            machine: AudioTrackSceneLockPlayback::default(),
            lfo: LfoParamsValues {
                // DO NOT USE STANDARD DEFAULT METHOD
                spd1: 255,
                spd2: 255,
                spd3: 255,
                dep1: 255,
                dep2: 255,
                dep3: 255,
            },
            amp: AudioTrackAmpParamsValues {
                // DO NOT USE STANDARD DEFAULT METHOD
                atk: 255,
                hold: 255,
                rel: 255,
                vol: 255,
                bal: 255,
                f: 255,
            },
            fx1: AudioTrackFxParamsValues {
                param_1: 255,
                param_2: 255,
                param_3: 255,
                param_4: 255,
                param_5: 255,
                param_6: 255,
            },
            fx2: AudioTrackFxParamsValues {
                param_1: 255,
                param_2: 255,
                param_3: 255,
                param_4: 255,
                param_5: 255,
                param_6: 255,
            },
            unknown_1: 255,
            unknown_2: 255,
        }
    }
}

#[cfg(test)]
mod scene_params {
    use crate::parts::scenes::SceneParams;
    use crate::parts::test_helper::get_default_test_bank;
    use crate::OtToolsIoError;

    #[test]
    fn default() -> Result<(), OtToolsIoError> {
        let b = get_default_test_bank()?;
        for arr in b.parts_unsaved[0].scenes.iter() {
            for x in arr.iter() {
                assert_eq!(x, &SceneParams::default());
            }
        }
        Ok(())
    }
}

#[cfg(test)]
mod scene_params_array {
    use crate::generics::Tracks;
    use crate::parts::test_helper::get_default_test_bank;
    use crate::OtToolsIoError;

    #[test]
    fn default() -> Result<(), OtToolsIoError> {
        let b = get_default_test_bank()?;
        for x in b.parts_unsaved[0].scenes.iter() {
            assert_eq!(x, &Tracks::default());
        }
        Ok(())
    }
}

/// XLV Scene Parameter assignments for an Audio Track,
/// plus two other parameters i don't know yet
#[derive(
    Copy,
    Clone,
    Debug,
    Eq,
    Hash,
    Ord,
    PartialEq,
    PartialOrd,
    Serialize,
    Deserialize,
    AsMutDerive,
    AsRefDerive,
    ArrayDefaults,
    BoxedArrayDefaults,
)]
pub struct SceneXlvAssignments {
    /// Main Volume fade control (XLV) for each Audio Track
    /// `MAX` -> `127`.
    /// `MIN` -> `0`.
    #[serde(with = "BigArray")]
    pub track_xlvs: [u8; 8],

    /// Don't know what this data block is for yet.
    /// Possibly leftover from using the same struct in the machine code
    /// as for audio track parameter values.
    #[serde(with = "BigArray")]
    pub unknown: [u8; 2],
}

impl Default for SceneXlvAssignments {
    fn default() -> Self {
        Self {
            track_xlvs: from_fn(|_| 255),
            unknown: from_fn(|_| 255),
        }
    }
}

#[cfg(test)]
mod scene_xlv {
    use crate::parts::scenes::SceneXlvAssignments;
    use crate::parts::test_helper::get_default_test_bank;
    use crate::OtToolsIoError;

    #[test]
    fn default() -> Result<(), OtToolsIoError> {
        let b = get_default_test_bank()?;
        for x in b.parts_unsaved[0].scene_xlvs.iter() {
            assert_eq!(x, &SceneXlvAssignments::default());
        }
        Ok(())
    }
}