use serde::{Deserialize, Serialize};
use crate::instrument::Instrument;
use crate::period_helper::FrequencyType;
use crate::prelude::TrackUnit;
use alloc::string::String;
use alloc::string::ToString;
use alloc::{vec, vec::Vec};
#[cfg(target_pointer_width = "16")]
pub const MAX_NUM_ROWS: usize = 255;
#[cfg(target_pointer_width = "32")]
pub const MAX_NUM_ROWS: usize = 4095;
#[cfg(target_pointer_width = "64")]
pub const MAX_NUM_ROWS: usize = 4095;
pub type Row = Vec<TrackUnit>;
pub type Pattern = Vec<Row>;
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum ModuleFormat {
#[default]
Unknown,
Mod,
S3m,
Xm,
It,
}
impl ModuleFormat {
#[inline]
pub fn is_xm(&self) -> bool {
matches!(self, ModuleFormat::Xm)
}
#[inline]
pub fn is_s3m(&self) -> bool {
matches!(self, ModuleFormat::S3m)
}
#[inline]
pub fn is_it(&self) -> bool {
matches!(self, ModuleFormat::It)
}
#[inline]
pub fn is_mod(&self) -> bool {
matches!(self, ModuleFormat::Mod)
}
}
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Default)]
pub struct PlaybackQuirks {
pub ft2_pitch_slide_overflow: bool,
pub period_clamp: Option<(f32, f32)>,
pub allow_zero_period: bool,
pub ft2_arpeggio_lut: bool,
pub ft2_arpeggio_note_clamp: bool,
pub keyoff_cuts_without_vol_env: bool,
pub k00_eats_note: bool,
pub volcol_b_advances_vibrato: bool,
pub e60_leaks_to_next_pattern: bool,
pub pattern_loop_resumes: bool,
pub tremor_state_persists: bool,
pub it_old_effects: bool,
pub it_link_gxx_memory: bool,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct Module {
pub name: String,
pub comment: String,
pub format: ModuleFormat,
pub quirks: PlaybackQuirks,
pub frequency_type: FrequencyType,
pub restart_position: usize,
pub default_tempo: usize,
pub default_bpm: usize,
pub pattern_order: Vec<Vec<usize>>,
pub pattern: Vec<Pattern>,
pub pattern_names: Vec<String>,
pub channel_names: Vec<String>,
pub instrument: Vec<Instrument>,
pub midi_macros: Option<MidiMacros>,
pub mix_volume: f32,
}
#[derive(Serialize, Deserialize, Debug, Clone, Default)]
pub struct MidiMacros {
pub global: Vec<Vec<u8>>,
pub parametric: Vec<Vec<u8>>,
pub fixed: Vec<Vec<u8>>,
}
impl Default for Module {
fn default() -> Self {
Module {
name: "".to_string(),
comment: "".to_string(),
format: ModuleFormat::Unknown,
quirks: PlaybackQuirks::default(),
frequency_type: FrequencyType::LinearFrequencies,
restart_position: 0,
default_tempo: 6,
default_bpm: 125,
pattern_order: vec![],
pattern: vec![],
pattern_names: vec![],
channel_names: vec![],
instrument: vec![],
midi_macros: None,
mix_volume: 1.0,
}
}
}
impl Module {
pub fn get_song_length(&self, song: usize) -> usize {
self.pattern_order[song].len()
}
pub fn get_num_channels(&self) -> usize {
if let Some(first_row) = self.pattern.first().and_then(|p| p.first()) {
first_row.len()
} else {
0
}
}
pub fn get_num_rows(&self, pat_idx: usize) -> usize {
if pat_idx < self.pattern.len() {
self.pattern[pat_idx].len()
} else {
0
}
}
}