use crate::arrangements::ArrangeRow;
use crate::identifiers::{
ArrId, BankId, PartId, PatternId, PlaybackSlotId, RecBufId, SavedState, SceneId, SliceId,
TrackId, TrigId,
};
use crate::macros::*;
use crate::markers::SlotMarkers;
use crate::parts::Part;
use crate::patterns::Pattern;
use crate::projects::SlotAttributes;
use crate::{
ArrangementFile, BankFile, Defaults, HasHeaderField, OctatrackFileIO, OtToolsIoError,
SampleSettingsFile,
};
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use serde_big_array::BigArray;
use std::array::from_fn;
use std::ops::{Deref, DerefMut, Index, IndexMut};
use std::path::PathBuf;
#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct Arrangements<T>(Box<[T; 8]>);
impl<T> Arrangements<T> {
pub fn new(value: [T; 8]) -> Self {
Self(Box::new(value))
}
pub fn new_boxed(value: Box<[T; 8]>) -> Self {
Self(value)
}
}
generic_newtype_id_lookups!(Arrangements, ArrId);
generic_newtype_unbox!(Arrangements, 8);
generic_newtype_asref!(Arrangements);
generic_newtype_asmut!(Arrangements);
generic_newtype_deref!(Arrangements, 8);
generic_newtype_deref_mut!(Arrangements);
impl<T: Defaults<Box<[T; 8]>> + Default> Default for Arrangements<T> {
fn default() -> Self {
Self(T::defaults())
}
}
impl HasHeaderField for Arrangements<ArrangementFile> {
fn check_header(&self) -> Result<bool, OtToolsIoError> {
Ok(self.iter().all(|x| x.check_header().is_ok_and(|x| x)))
}
}
impl Arrangements<ArrangementFile> {
pub fn from_data_files<P>(dirpath: P, state: &SavedState) -> Result<Self, OtToolsIoError>
where
PathBuf: From<P>,
{
let mut new = Self::default();
let path = PathBuf::from(dirpath);
for id in ArrId::iter() {
let data = ArrangementFile::from_data_file(&path.join(id.file_stem(state)))?;
new[id.as_index()] = data;
}
Ok(new)
}
pub fn to_data_files<P>(
&self,
dirpath: P,
state: &SavedState,
skip_unchanged: bool,
) -> Result<(), OtToolsIoError>
where
PathBuf: From<P>,
{
let path = PathBuf::from(dirpath);
for id in ArrId::iter() {
let arr = self.id_ref(&id);
if skip_unchanged {
if let Ok(exists) = ArrangementFile::from_data_file(&path.join(id.file_stem(state)))
{
if &exists != arr {
arr.to_data_file(&path.join(id.file_stem(state)))?;
}
} else {
arr.to_data_file(&path.join(id.file_stem(state)))?;
}
} else {
arr.to_data_file(&path.join(id.file_stem(state)))?;
}
}
Ok(())
}
}
#[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct ArrangeRows<T>([T; 256]);
impl<T> ArrangeRows<T> {
pub fn new(value: [T; 256]) -> Self {
Self(value)
}
}
generic_newtype_asref!(ArrangeRows);
generic_newtype_asmut!(ArrangeRows);
generic_newtype_deref!(ArrangeRows, 256);
generic_newtype_deref_mut!(ArrangeRows);
impl<T: Defaults<[T; 256]> + Default> Default for ArrangeRows<T> {
fn default() -> Self {
Self(T::defaults())
}
}
impl<'de> Deserialize<'de> for ArrangeRows<ArrangeRow> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
Ok(Self(
<[ArrangeRow; 256] as BigArray<ArrangeRow>>::deserialize(deserializer)?,
))
}
}
impl Serialize for ArrangeRows<ArrangeRow> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
<[ArrangeRow; 256] as BigArray<ArrangeRow>>::serialize(&self.0, serializer)
}
}
#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct Banks<T>(Box<[T; 16]>);
impl<T> Banks<T> {
pub fn new(value: [T; 16]) -> Self {
Self(Box::new(value))
}
pub fn new_boxed(value: Box<[T; 16]>) -> Self {
Self(value)
}
}
generic_newtype_id_lookups!(Banks, BankId);
generic_newtype_unbox!(Banks, 16);
generic_newtype_asref!(Banks);
generic_newtype_asmut!(Banks);
generic_newtype_deref!(Banks, 16);
generic_newtype_deref_mut!(Banks);
impl<T: Defaults<Box<[T; 16]>> + Default> Default for Banks<T> {
fn default() -> Self {
Self(T::defaults())
}
}
impl HasHeaderField for Banks<BankFile> {
fn check_header(&self) -> Result<bool, OtToolsIoError> {
Ok(self.iter().all(|x| x.check_header().is_ok_and(|x| x)))
}
}
impl Banks<BankFile> {
pub fn from_data_files<P>(dirpath: P, state: &SavedState) -> Result<Self, OtToolsIoError>
where
PathBuf: From<P>,
{
let mut new = Self::default();
let path = PathBuf::from(dirpath);
for id in BankId::iter() {
let bank = BankFile::from_data_file(&path.join(id.file_stem(state)))?;
new[id.as_index()] = bank;
}
Ok(new)
}
pub fn to_data_files<P>(
&self,
dirpath: P,
state: &SavedState,
skip_unchanged: bool,
) -> Result<(), OtToolsIoError>
where
PathBuf: From<P>,
{
let path = PathBuf::from(dirpath);
for id in BankId::iter() {
let bank = self.id_ref(&id);
if skip_unchanged {
if let Ok(exists) = BankFile::from_data_file(&path.join(id.file_stem(state))) {
if &exists != bank {
bank.to_data_file(&path.join(id.file_stem(state)))?;
}
} else {
bank.to_data_file(&path.join(id.file_stem(state)))?;
}
} else {
bank.to_data_file(&path.join(id.file_stem(state)))?;
}
}
Ok(())
}
}
#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct Parts<T>(Box<[T; 4]>);
impl<T> Parts<T> {
pub fn new(value: [T; 4]) -> Self {
Self(Box::new(value))
}
pub fn new_boxed(value: Box<[T; 4]>) -> Self {
Self(value)
}
}
generic_newtype_id_lookups!(Parts, PartId);
generic_newtype_unbox!(Parts, 4);
generic_newtype_asref!(Parts);
generic_newtype_asmut!(Parts);
generic_newtype_deref!(Parts, 4);
generic_newtype_deref_mut!(Parts);
impl<T: Defaults<Box<[T; 4]>> + Default> Default for Parts<T> {
fn default() -> Self {
Self(T::defaults())
}
}
impl<'de> Deserialize<'de> for Parts<Part> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let boxed = Box::new(<[Part; 4] as BigArray<Part>>::deserialize(deserializer)?);
Ok(Self(boxed))
}
}
impl Serialize for Parts<Part> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
<[Part; 4] as BigArray<Part>>::serialize(&self.0, serializer)
}
}
impl HasHeaderField for Parts<Part> {
fn check_header(&self) -> Result<bool, OtToolsIoError> {
Ok(self.iter().all(|x| x.check_header().is_ok_and(|x| x)))
}
}
#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct Patterns<T>(Box<[T; 16]>);
impl<T> Patterns<T> {
pub fn new(value: [T; 16]) -> Self {
Self(Box::new(value))
}
pub fn new_boxed(value: Box<[T; 16]>) -> Self {
Self(value)
}
}
generic_newtype_id_lookups!(Patterns, PatternId);
generic_newtype_unbox!(Patterns, 16);
generic_newtype_asref!(Patterns);
generic_newtype_asmut!(Patterns);
generic_newtype_deref!(Patterns, 16);
generic_newtype_deref_mut!(Patterns);
impl<T: Defaults<Box<[T; 16]>> + Default> Default for Patterns<T> {
fn default() -> Self {
Self(T::defaults())
}
}
impl<'de> Deserialize<'de> for Patterns<Pattern> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let boxed = Box::new(<[Pattern; 16] as BigArray<Pattern>>::deserialize(
deserializer,
)?);
Ok(Self(boxed))
}
}
impl Serialize for Patterns<Pattern> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
<[Pattern; 16] as BigArray<Pattern>>::serialize(&self.0, serializer)
}
}
impl HasHeaderField for Patterns<Pattern> {
fn check_header(&self) -> Result<bool, OtToolsIoError> {
Ok(self.iter().all(|x| x.check_header().is_ok_and(|x| x)))
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct Tracks<T>([T; 8]);
generic_newtype_id_lookups!(Tracks, TrackId);
generic_newtype_asref!(Tracks);
generic_newtype_asmut!(Tracks);
generic_newtype_deref!(Tracks, 8);
generic_newtype_deref_mut!(Tracks);
generic_newtype_index!(Tracks);
generic_newtype_index_mut!(Tracks);
impl<T: Defaults<[T; 8]> + Default> Default for Tracks<T> {
fn default() -> Self {
Self(T::defaults())
}
}
impl<const N: usize, T: Default> Defaults<[Self; N]> for Tracks<T> {
fn defaults() -> [Self; N]
where
Self: Default,
{
from_fn(|_| Self::default())
}
}
impl<T> Tracks<T> {
pub fn new(value: [T; 8]) -> Self {
Self(value)
}
}
impl<'de, T: Deserialize<'de>> Deserialize<'de> for Tracks<T> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
Ok(Self(<[T; 8] as BigArray<T>>::deserialize(deserializer)?))
}
}
impl<T: Serialize> Serialize for Tracks<T> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
<[T; 8] as BigArray<T>>::serialize(&self.0, serializer)
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct Scenes<T>([T; 16]);
generic_newtype_id_lookups!(Scenes, SceneId);
generic_newtype_asref!(Scenes);
generic_newtype_asmut!(Scenes);
generic_newtype_deref!(Scenes, 16);
generic_newtype_deref_mut!(Scenes);
generic_newtype_index!(Scenes);
generic_newtype_index_mut!(Scenes);
impl<T: Defaults<[T; 16]> + Default> Default for Scenes<T> {
fn default() -> Self {
Self(T::defaults())
}
}
impl<T> Scenes<T> {
pub fn new(value: [T; 16]) -> Self {
Self(value)
}
}
impl<'de, T: Deserialize<'de>> Deserialize<'de> for Scenes<T> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
Ok(Self(<[T; 16] as BigArray<T>>::deserialize(deserializer)?))
}
}
impl<T: Serialize> Serialize for Scenes<T> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
<[T; 16] as BigArray<T>>::serialize(&self.0, serializer)
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct Slices<T>([T; 64]);
generic_newtype_id_lookups!(Slices, SliceId);
generic_newtype_asref!(Slices);
generic_newtype_asmut!(Slices);
generic_newtype_deref!(Slices, 64);
generic_newtype_deref_mut!(Slices);
generic_newtype_index!(Slices);
generic_newtype_index_mut!(Slices);
generic_newtype_into_iter!(Slices, 64);
impl<T: Defaults<[T; 64]> + Default> Default for Slices<T> {
fn default() -> Self {
Self(T::defaults())
}
}
impl<T> Slices<T> {
pub fn new(value: [T; 64]) -> Self {
Self(value)
}
}
impl<'de, T: Deserialize<'de>> Deserialize<'de> for Slices<T> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
Ok(Self(<[T; 64] as BigArray<T>>::deserialize(deserializer)?))
}
}
impl<T: Serialize> Serialize for Slices<T> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
<[T; 64] as BigArray<T>>::serialize(&self.0, serializer)
}
}
#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct Trigs<T>(Box<[T; 64]>);
generic_newtype_id_lookups!(Trigs, TrigId);
generic_newtype_unbox!(Trigs, 64);
generic_newtype_asref!(Trigs);
generic_newtype_asmut!(Trigs);
generic_newtype_deref!(Trigs, 64);
generic_newtype_deref_mut!(Trigs);
impl<T: Defaults<Box<[T; 64]>> + Default> Default for Trigs<T> {
fn default() -> Self {
Self(T::defaults())
}
}
impl<T> Trigs<T> {
pub fn new(value: [T; 64]) -> Self {
Self(Box::new(value))
}
pub fn new_boxed(value: Box<[T; 64]>) -> Self {
Self(value)
}
}
impl<'de, T: Deserialize<'de>> Deserialize<'de> for Trigs<T> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
Ok(Self(Box::new(<[T; 64] as BigArray<T>>::deserialize(
deserializer,
)?)))
}
}
impl<T: Serialize> Serialize for Trigs<T> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
<[T; 64] as BigArray<T>>::serialize(&self.0, serializer)
}
}
impl<T, I> Index<I> for Trigs<T>
where
[T]: Index<I>,
{
type Output = <[T] as Index<I>>::Output;
#[inline]
fn index(&self, index: I) -> &Self::Output {
Index::index(&*self.0 as &[T], index)
}
}
impl<T, I> IndexMut<I> for Trigs<T>
where
[T]: IndexMut<I>,
{
#[inline]
fn index_mut(&mut self, index: I) -> &mut Self::Output {
IndexMut::index_mut(&mut *self.0 as &mut [T], index)
}
}
#[allow(rustdoc::invalid_rust_codeblocks)]
#[derive(Clone, PartialEq, Debug, Hash, PartialOrd, Ord, Eq)]
pub struct PlaybackSlots<T>(Box<[T; 128]>);
generic_newtype_id_lookups!(PlaybackSlots, PlaybackSlotId);
generic_newtype_asref!(PlaybackSlots);
generic_newtype_asmut!(PlaybackSlots);
generic_newtype_deref!(PlaybackSlots, 128);
generic_newtype_deref_mut!(PlaybackSlots);
impl<T: Defaults<Box<[T; 128]>> + Default> Default for PlaybackSlots<T> {
fn default() -> Self {
Self(T::defaults())
}
}
impl<T> PlaybackSlots<T> {
pub fn new(value: [T; 128]) -> Self {
Self(Box::new(value))
}
pub fn new_boxed(value: Box<[T; 128]>) -> Self {
Self(value)
}
}
impl PlaybackSlots<Option<ActiveSlot<SlotAttributes, SlotMarkers>>> {
pub fn insert_or_replace_by_slot_id_field(
&mut self,
value: ActiveSlot<SlotAttributes, SlotMarkers>,
) -> Option<ActiveSlot<SlotAttributes, SlotMarkers>> {
if let Some(slot_id) = PlaybackSlotId::from_id(value.attrs_ref().slot_id) {
let to_replace = self.id_mut(&slot_id);
let old = to_replace.clone();
*to_replace = Some(value);
old
} else {
None
}
}
pub fn take_by_id(
&mut self,
id: &PlaybackSlotId,
) -> Option<ActiveSlot<SlotAttributes, SlotMarkers>> {
if let Some(slot) = self.get_mut(id.as_index()) {
slot.take()
} else {
None
}
}
}
impl Default for PlaybackSlots<Option<ActiveSlot<SlotAttributes, SlotMarkers>>> {
fn default() -> Self {
Self(Box::new(from_fn(|_| None)))
}
}
impl<'de, T: Deserialize<'de>> Deserialize<'de> for PlaybackSlots<T> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
Ok(Self(Box::new(<[T; 128] as BigArray<T>>::deserialize(
deserializer,
)?)))
}
}
impl<T: Serialize> Serialize for PlaybackSlots<T> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
<[T; 128] as BigArray<T>>::serialize(&self.0, serializer)
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct RecordingBufferSlots<T>([T; 8]);
generic_newtype_id_lookups!(RecordingBufferSlots, RecBufId);
generic_newtype_asref!(RecordingBufferSlots);
generic_newtype_asmut!(RecordingBufferSlots);
generic_newtype_deref!(RecordingBufferSlots, 8);
generic_newtype_deref_mut!(RecordingBufferSlots);
generic_newtype_index!(RecordingBufferSlots);
generic_newtype_index_mut!(RecordingBufferSlots);
impl<T: Defaults<[T; 8]> + Default> Default for RecordingBufferSlots<T> {
fn default() -> Self {
Self(T::defaults())
}
}
impl<const N: usize, T: Default> Defaults<[Self; N]> for RecordingBufferSlots<T> {
fn defaults() -> [Self; N]
where
Self: Default,
{
from_fn(|_| Self::default())
}
}
impl<T> RecordingBufferSlots<T> {
pub fn new(value: [T; 8]) -> Self {
Self(value)
}
}
impl<'de, T: Deserialize<'de>> Deserialize<'de> for RecordingBufferSlots<T> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
Ok(Self(<[T; 8] as BigArray<T>>::deserialize(deserializer)?))
}
}
impl<T: Serialize> Serialize for RecordingBufferSlots<T> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
<[T; 8] as BigArray<T>>::serialize(&self.0, serializer)
}
}
#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct Slots<T> {
pub flex_slots: PlaybackSlots<T>,
pub recording_buffers: RecordingBufferSlots<T>,
pub static_slots: PlaybackSlots<T>,
}
impl<T> Slots<T> {
pub fn new(
flex_slots: PlaybackSlots<T>,
recording_buffers: RecordingBufferSlots<T>,
static_slots: PlaybackSlots<T>,
) -> Self {
Self {
flex_slots,
recording_buffers,
static_slots,
}
}
}
#[derive(Default, Clone, Copy, PartialEq, Debug, Hash, PartialOrd, Ord, Eq)]
pub struct ActiveSlot<A, M>
where
A: AsRef<SlotAttributes>,
M: AsRef<SlotMarkers>,
{
pub attrs: A,
pub marks: M,
}
impl AsRef<ActiveSlot<SlotAttributes, SlotMarkers>> for ActiveSlot<SlotAttributes, SlotMarkers> {
fn as_ref(&self) -> &ActiveSlot<SlotAttributes, SlotMarkers> {
self
}
}
impl<A, M> ActiveSlot<A, M>
where
A: AsRef<SlotAttributes>,
M: AsRef<SlotMarkers>,
{
pub fn new(attrs: A, marks: M) -> Self {
Self { attrs, marks }
}
pub fn attrs(self) -> A {
self.attrs
}
pub fn attrs_ref(&self) -> &A {
&self.attrs
}
pub fn marks(self) -> M {
self.marks
}
pub fn marks_ref(&self) -> &M {
&self.marks
}
}
impl<A, M> ActiveSlot<A, M>
where
A: AsRef<SlotAttributes> + AsMut<SlotAttributes>,
M: AsRef<SlotMarkers> + AsMut<SlotMarkers>,
{
pub fn attrs_mut(&mut self) -> &mut A {
&mut self.attrs
}
pub fn marks_mut(&mut self) -> &mut M {
&mut self.marks
}
}
impl<A, M> From<ActiveSlot<A, M>> for SampleSettingsFile
where
A: AsRef<SlotAttributes>,
M: AsRef<SlotMarkers>,
{
fn from(value: ActiveSlot<A, M>) -> Self {
SampleSettingsFile::from((value.attrs_ref(), value.marks_ref()))
}
}
impl<A, M> TryFrom<Option<ActiveSlot<A, M>>> for SampleSettingsFile
where
A: AsRef<SlotAttributes>,
M: AsRef<SlotMarkers>,
{
type Error = OtToolsIoError;
fn try_from(value: Option<ActiveSlot<A, M>>) -> Result<Self, Self::Error> {
let value = value.ok_or(OtToolsIoError::InvalidIndex)?;
Ok(SampleSettingsFile::from((
value.attrs_ref(),
value.marks_ref(),
)))
}
}