ot_tools_io/lib.rs
1/*
2SPDX-License-Identifier: GPL-3.0-or-later
3Copyright © 2024 Mike Robeson [dijksterhuis]
4*/
5
6//! Serialization and Deserialization library for Elektron Octatrack data files.
7//!
8//! ## Important types
9//!
10//! | rust type | octatrack filename pattern | description |
11//! | ------------ | -------------------------- | ------------|
12//! | [`ArrangementFile`] | `arr??.*` | data for arrangements |
13//! | [`BankFile`] | `bank??.*` | data for parts and patterns |
14//! | [`MarkersFile`] | `markers.*` | start trim/end trim/slices/loop points for sample slots |
15//! | [`ProjectFile`] | `project.*` | project level settings; state; sample slots |
16//! | [`SampleSettingsFile`] | `*.ot` | saved sample settings data, loops slices etc. |
17//!
18//!
19//! Only the above types implement the [`OctatrackFileIO`] super trait, meaning
20//! only these types can be read from / written to the filesystem using the
21//! functions in this library.
22//!
23//! Read the relevant modules in this library for more detailed information on
24//! the data contained in each file.
25//!
26//! ## How do different Octatrack data files relate to each other?
27//!
28//! - A Bank stores zero-indexed sample slot IDs to indicate which sample should be played when on a given track
29//! (part machine data and/or track p-lock trigs).
30//! - Changing the sample loaded into a sample slot updates both the `project.*` file (change the trig quantization
31//! settings, file path etc) and the `markers.*` file (change the trim settings based on either initial load,
32//! or any data in a relevant `*.ot` sample settings file).
33//! - Data from `project.*`and `markers.*` is written to an `*.ot` file when saving sample attributes data from the
34//! octatrack's audio editing menu.
35//! - Loading a sample into a project sample slot (`project.*` and `markers.*` files) reads any data in an `*.ot` files
36//! and configures the sample slot accordingly.
37//!
38//! ## When do `*.work` and `*.strd` files get modified by the Octatrack?
39//!
40//! - `*.work` files are created when creating a new project `PROJECT MENU -> CHANGE PROJECT -> CREATE NEW`.
41//! - `*.work` files are updated by using the `PROJECT MENU -> SYNC TO CARD` operation.
42//! - `*.work` files are updated when the user performs a `PROJECT MENU -> SAVE PROJECT` operation.
43//! - `*.strd` files are created/updated when the user performs a `PROJECT MENU -> SAVE PROJECT` operation.
44//! - `*.strd` files are not changed by the `PROJECT -> SYNC TO CARD` operation.
45//! - `arr??.strd` files can also be saved via the `ARRANGER MENU -> SAVE ARRANGEMENT` operation.
46//!
47//! ## Notable 'gotcha's
48//! - Project sample slots (`project.*` files) are one-indexed, but their references everywhere else are zero-indexed
49//! (`bank??.*` and `markers.*` files).
50//! - A 'Disabled' loop point in either `markers.*` or `*.ot` files is a `0xFFFFFFFF` value, but the default
51//! loop point when creating new `markers.*` file is always `0_u32`. The 'Disabled' value setting is only set
52//! when a sample is loaded into a sample slot, and an `.ot` file is generated from that sample slot data.
53//!
54//! ## Example code
55//! ```rust
56//! /*
57//! reading, mutating and writing a bank file
58//! */
59//!
60//! use std::path::PathBuf;
61//! use ot_tools_io::{OctatrackFileIO, BankFile};
62//!
63//! let path = PathBuf::from("test-data")
64//! .join("blank-project")
65//! .join("bank01.work");
66//!
67//! // read an editable version of the bank file
68//! let mut bank = BankFile::from_data_file(&path).unwrap();
69//!
70//! // change active scenes on the working copy of Part 4
71//! bank.parts.unsaved[3].active_scenes.scene_a = 2;
72//! bank.parts.unsaved[3].active_scenes.scene_b = 6;
73//!
74//! // write to a new bank file
75//! let outfpath = std::env::temp_dir()
76//! .join("ot-tools-io")
77//! .join("doctest")
78//! .join("main_example_1");
79//!
80//! # // when running in cicd env the /tmp/ot-tools-io directory doesn't exist yet
81//! # let _ = std::fs::create_dir_all(outfpath.parent().unwrap());
82//!
83//! BankFile::to_data_file(&bank, &outfpath).unwrap();
84//! ```
85
86pub mod arrangements;
87pub mod banks;
88mod common_options;
89mod err;
90pub mod markers;
91pub mod parts;
92pub mod patterns;
93pub mod projects;
94pub mod samples;
95pub mod slices;
96#[cfg(test)]
97#[allow(dead_code)]
98mod test_utils;
99mod traits;
100
101pub use crate::common_options::*;
102pub use crate::err::*;
103pub use crate::traits::*;
104use std::error::Error;
105
106pub use crate::arrangements::ArrangementFile;
107pub use crate::banks::BankFile;
108pub use crate::markers::MarkersFile;
109pub use crate::projects::ProjectFile;
110pub use crate::samples::SampleSettingsFile;
111
112// todo: sized errors so not necessary to keep Boxing error enum varients
113/// Shorthand type alias for a Result with a Boxed Error
114type RBoxErr<T> = Result<T, Box<dyn Error>>;
115
116fn u8_bytes_to_u16(bytes: &[u8; 2]) -> u16 {
117 ((bytes[0] as u16) << 8) | bytes[1] as u16
118}