1use crate::slices::{Slice, SLICE_LOOP_POINT_DEFAULT};
22use crate::{
23 CalculateChecksum, CheckChecksum, CheckFileVersion, CheckHeader, Decode, Encode, IsDefault,
24 OtToolsIoErrors, RBoxErr, SwapBytes,
25};
26use ot_tools_io_derive::{Decodeable, IntegrityChecks, OctatrackFile};
27use serde::{Deserialize, Serialize};
28use serde_big_array::{Array, BigArray};
29use std::array::from_fn;
30pub const MARKERS_HEADER: [u8; 21] = [
42 0x46, 0x4f, 0x52, 0x4d, 0x00, 0x00, 0x00, 0x00, 0x44, 0x50, 0x53, 0x31, 0x53, 0x41, 0x4d, 0x50,
43 0x00, 0x00, 0x00, 0x00, 0x00,
44];
45
46pub const MARKERS_FILE_VERSION: u8 = 4;
48
49#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize, Decodeable, Hash)]
60pub struct SlotMarkers {
61 pub trim_offset: u32,
63
64 pub trim_end: u32,
66
67 pub loop_point: u32,
69
70 #[serde(with = "BigArray")]
72 pub slices: [Slice; 64],
73
74 pub slice_count: u32,
76}
77
78impl SlotMarkers {
79 fn validate(&self) -> RBoxErr<bool> {
80 for slice in self.slices.iter() {
81 slice.validate()?;
82 }
83 let trim_ok = self.trim_offset < self.trim_end;
84 let slice_count_ok = self.slice_count == self.slices.len() as u32;
85 let loop_start_ok = self.loop_point >= self.trim_offset;
86 let loop_end_ok =
87 self.loop_point <= self.trim_end || self.loop_point == SLICE_LOOP_POINT_DEFAULT;
88
89 if !(trim_ok && slice_count_ok && loop_start_ok && loop_end_ok) {
90 return Err(OtToolsIoErrors::TodoError.into());
91 }
92
93 Ok(true)
94 }
95}
96
97impl SwapBytes for SlotMarkers {
98 fn swap_bytes(self) -> RBoxErr<Self> {
99 let mut slices: [Slice; 64] = self.slices;
100
101 for (i, slice) in self.slices.iter().enumerate() {
102 slices[i] = slice.swap_bytes()?;
103 }
104
105 let bswapped = Self {
106 trim_offset: self.trim_offset.swap_bytes(),
107 trim_end: self.trim_end.swap_bytes(),
108 loop_point: self.loop_point.swap_bytes(),
109 slices,
110 slice_count: self.slice_count.swap_bytes(),
111 };
112
113 Ok(bswapped)
114 }
115}
116
117impl Default for SlotMarkers {
118 fn default() -> Self {
119 Self {
120 trim_offset: 0,
121 trim_end: 0,
122 loop_point: 0,
123 slices: from_fn(|_| Slice::default()),
124 slice_count: 0,
125 }
126 }
127}
128
129#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize, OctatrackFile, IntegrityChecks)]
131pub struct MarkersFile {
132 #[serde(with = "BigArray")]
133 pub header: [u8; 21],
134
135 pub datatype_version: u8,
154
155 pub flex_slots: Box<Array<SlotMarkers, 136>>,
157
158 pub static_slots: Box<Array<SlotMarkers, 128>>,
160
161 pub checksum: u16,
163}
164
165impl MarkersFile {
166 #[allow(dead_code)]
167 fn validate(&self) -> RBoxErr<bool> {
168 for slot in self.flex_slots.iter() {
169 slot.validate()?;
170 }
171 for slot in self.static_slots.iter() {
172 slot.validate()?;
173 }
174
175 Ok(true)
176 }
177}
178
179impl SwapBytes for MarkersFile {
180 fn swap_bytes(self) -> RBoxErr<Self> {
181 let mut flex_slots = self.flex_slots.clone();
182 for (i, slot) in self.flex_slots.iter().enumerate() {
183 flex_slots[i] = slot.clone().swap_bytes()?;
184 }
185
186 let mut static_slots = self.static_slots.clone();
187 for (i, slot) in self.static_slots.iter().enumerate() {
188 static_slots[i] = slot.clone().swap_bytes()?;
189 }
190
191 let bswapped = Self {
192 header: self.header,
193 datatype_version: self.datatype_version,
194 flex_slots,
195 static_slots,
196 checksum: self.checksum.swap_bytes(),
197 };
198
199 Ok(bswapped)
200 }
201}
202
203impl Decode for MarkersFile {
204 fn decode(bytes: &[u8]) -> RBoxErr<Self>
205 where
206 Self: Sized,
207 Self: for<'a> Deserialize<'a>,
208 {
209 let mut x: Self = bincode::deserialize(bytes)?;
210 #[cfg(target_endian = "little")]
211 {
212 x = x.swap_bytes()?;
213 }
214
215 Ok(x)
216 }
217}
218
219impl Encode for MarkersFile {
220 fn encode(&self) -> RBoxErr<Vec<u8>> {
221 let mut chkd = self.clone();
222 chkd.checksum = self.calculate_checksum()?;
223 let encoded = if cfg!(target_endian = "little") {
224 bincode::serialize(&chkd.swap_bytes()?)?
225 } else {
226 bincode::serialize(&chkd)?
227 };
228 Ok(encoded)
229 }
230}
231
232impl MarkersFile {
233 fn new(flex_slots: [SlotMarkers; 136], static_slots: [SlotMarkers; 128]) -> RBoxErr<Self> {
234 let mut init = Self {
235 header: MARKERS_HEADER,
236 datatype_version: MARKERS_FILE_VERSION,
237 flex_slots: Array(flex_slots).into(),
238 static_slots: Array(static_slots).into(),
239 checksum: 0,
240 };
241
242 init.checksum = init.calculate_checksum()?;
243 Ok(init)
244 }
245}
246
247impl Default for MarkersFile {
248 fn default() -> Self {
249 Self::new(
250 from_fn(|_| SlotMarkers::default()),
251 from_fn(|_| SlotMarkers::default()),
252 )
253 .unwrap()
254 }
255}
256
257impl IsDefault for MarkersFile {
258 fn is_default(&self) -> bool {
259 let default = &mut MarkersFile::default();
260 default == self
261 }
262}
263
264impl CalculateChecksum for MarkersFile {
265 fn calculate_checksum(&self) -> RBoxErr<u16> {
266 let bytes = bincode::serialize(self)?;
267 let mut chk: u16 = 0;
268 for byte in &bytes[16..bytes.len() - 2] {
269 chk = chk.wrapping_add(*byte as u16);
270 }
271 Ok(chk)
272 }
273}
274
275impl CheckHeader for MarkersFile {
276 fn check_header(&self) -> bool {
277 self.header == MARKERS_HEADER
278 }
279}
280
281impl CheckChecksum for MarkersFile {
282 fn check_checksum(&self) -> RBoxErr<bool> {
283 Ok(self.checksum == self.calculate_checksum()?)
284 }
285}
286
287impl CheckFileVersion for MarkersFile {
288 fn check_file_version(&self) -> RBoxErr<bool> {
289 Ok(self.datatype_version == MARKERS_FILE_VERSION)
290 }
291}