use alloc::vec::Vec;
#[cfg(feature = "import_it")]
use crate::import::it::it_effect::ItEffect;
#[cfg(feature = "import_s3m")]
use crate::import::s3m::s3m_effect::S3mEffect;
#[cfg(any(feature = "import_mod", feature = "import_xm"))]
use crate::import::xm::mod_xm_effect::ModXmEffect;
use super::patternslot::PatternSlot;
use super::track_import_effect::TrackImportEffect;
use super::track_import_unit::TrackImportUnit;
use crate::prelude::*;
pub enum MemoryType {
Mod,
Xm,
S3m,
It,
}
const ARPEGGIO: usize = 0;
const PANBRELLO: usize = 1;
const PANNING_SLIDE: usize = 2;
const PORTAMENTO_UP: usize = 3;
const PORTAMENTO_DOWN: usize = 4;
const PORTAMENTO_FINE_UP: usize = 5;
const PORTAMENTO_FINE_DOWN: usize = 6;
const PORTAMENTO_FINE_EXTRA_UP: usize = 7;
const PORTAMENTO_FINE_EXTRA_DOWN: usize = 8;
const NOTE_RETRIG: usize = 9;
const TONE_PORTAMENTO: usize = 10;
const TREMOLO: usize = 11;
const TREMOR: usize = 12;
const SAMPLE_OFFSET: usize = 13;
const VIBRATO: usize = 14;
const VIBRATO_FINE: usize = 15;
const PITCH_VOLUME_SLIDE_0: usize = 16;
const PITCH_VOLUME_SLIDE_N: usize = 17;
const FX_VOLUME_TONE_PORTAMENTO: usize = 18;
const FX_VOLUME_VIBRATO_DEPTH: usize = 19;
const CHANNEL_VOLUME_SLIDE: usize = 20;
const GLOBAL_VOLUME_SLIDE: usize = 21;
const TEMPO_UP: usize = 22;
const TEMPO_DOWN: usize = 23;
const SAMPLE_OFFSET_ADD_HIGH: usize = 24;
const ARRAY_SIZE: usize = 25;
#[derive(Debug, Clone, Copy, Default)]
pub struct S3mImportFlags {
pub fastvolslide: bool,
pub oldstvib: bool,
}
#[derive(Default, Copy, Clone, Debug)]
pub struct ItImportFlags {
pub link_gxx_ef_memory: bool,
}
pub struct ImportMemory {
global: [(f32, f32, usize, usize); ARRAY_SIZE], channel: [[(f32, f32, usize, usize); ARRAY_SIZE]; 64], pub s3m_flags: S3mImportFlags,
pub it_flags: ItImportFlags,
}
impl Default for ImportMemory {
fn default() -> Self {
Self {
global: [(0.0, 0.0, 0, 0); ARRAY_SIZE],
channel: [[(0.0, 0.0, 0, 0); ARRAY_SIZE]; 64],
s3m_flags: S3mImportFlags::default(),
it_flags: ItImportFlags::default(),
}
}
}
impl ImportMemory {
fn update_memory(&mut self, mem: &MemoryType, index: usize, tiu: &mut TrackImportUnit) {
tiu.effects.iter_mut().for_each(|e| {
match e {
TrackImportEffect::Arpeggio(a, b) => {
match mem {
MemoryType::Mod | MemoryType::Xm => {
}
MemoryType::It => {
if *a == 0 {
*a = self.channel[index][ARPEGGIO].2
} else {
self.channel[index][ARPEGGIO].2 = *a;
}
if *b == 0 {
*b = self.channel[index][ARPEGGIO].3
} else {
self.channel[index][ARPEGGIO].3 = *b;
}
}
MemoryType::S3m => {
if *a == 0 {
*a = self.global[ARPEGGIO].2
} else {
self.global[ARPEGGIO].2 = *a;
}
if *b == 0 {
*b = self.global[ARPEGGIO].3
} else {
self.global[ARPEGGIO].3 = *b;
}
}
}
}
TrackImportEffect::Panbrello(a, b) => {
match mem {
MemoryType::Mod => {
}
MemoryType::Xm | MemoryType::It | MemoryType::S3m => {
if *a == 0.0 {
*a = self.channel[index][PANBRELLO].0
} else {
self.channel[index][PANBRELLO].0 = *a;
}
if *b == 0.0 {
*b = self.channel[index][PANBRELLO].1
} else {
self.channel[index][PANBRELLO].1 = *b;
}
}
}
}
TrackImportEffect::PanningSlideN(a) => {
match mem {
MemoryType::Mod => {
}
MemoryType::Xm | MemoryType::It | MemoryType::S3m => {
if *a == 0.0 {
*a = self.channel[index][PANNING_SLIDE].0
} else {
self.channel[index][PANNING_SLIDE].0 = *a;
}
}
}
}
TrackImportEffect::PortamentoUp(a) => {
match mem {
MemoryType::Mod => {
}
MemoryType::Xm => {
if *a == 0.0 {
*a = self.channel[index][PORTAMENTO_UP].0
} else {
self.channel[index][PORTAMENTO_UP].0 = *a;
}
}
MemoryType::It => {
if *a == 0.0 {
*a = self.channel[index][PORTAMENTO_UP].0
} else {
self.channel[index][PORTAMENTO_UP].0 = *a;
}
}
MemoryType::S3m => {
if *a == 0.0 {
*a = self.global[PORTAMENTO_UP].0
} else {
self.global[PORTAMENTO_UP].0 = *a;
}
}
}
}
TrackImportEffect::PortamentoDown(a) => {
match mem {
MemoryType::Mod => {
}
MemoryType::Xm => {
if *a == 0.0 {
*a = self.channel[index][PORTAMENTO_DOWN].0
} else {
self.channel[index][PORTAMENTO_DOWN].0 = *a;
}
}
MemoryType::It => {
if *a == 0.0 {
*a = self.channel[index][PORTAMENTO_UP].0
} else {
self.channel[index][PORTAMENTO_UP].0 = *a;
}
}
MemoryType::S3m => {
if *a == 0.0 {
*a = self.global[PORTAMENTO_DOWN].0
} else {
self.global[PORTAMENTO_DOWN].0 = *a;
}
}
}
}
TrackImportEffect::PortamentoFineUp(a) => {
match mem {
MemoryType::Mod => {
}
MemoryType::Xm | MemoryType::It => {
if *a == 0.0 {
*a = self.channel[index][PORTAMENTO_FINE_UP].0
} else {
self.channel[index][PORTAMENTO_FINE_UP].0 = *a;
}
}
MemoryType::S3m => {
if *a == 0.0 {
*a = self.global[PORTAMENTO_FINE_UP].0
} else {
self.global[PORTAMENTO_FINE_UP].0 = *a;
}
}
}
}
TrackImportEffect::PortamentoFineDown(a) => {
match mem {
MemoryType::Mod => {
}
MemoryType::Xm | MemoryType::It => {
if *a == 0.0 {
*a = self.channel[index][PORTAMENTO_FINE_DOWN].0
} else {
self.channel[index][PORTAMENTO_FINE_DOWN].0 = *a;
}
}
MemoryType::S3m => {
if *a == 0.0 {
*a = self.global[PORTAMENTO_FINE_DOWN].0
} else {
self.global[PORTAMENTO_FINE_DOWN].0 = *a;
}
}
}
}
TrackImportEffect::PortamentoExtraFineUp(a) => {
match mem {
MemoryType::Mod => {
}
MemoryType::Xm | MemoryType::It => {
if *a == 0.0 {
*a = self.channel[index][PORTAMENTO_FINE_EXTRA_UP].0
} else {
self.channel[index][PORTAMENTO_FINE_EXTRA_UP].0 = *a;
}
}
MemoryType::S3m => {
if *a == 0.0 {
*a = self.global[PORTAMENTO_FINE_EXTRA_UP].0
} else {
self.global[PORTAMENTO_FINE_EXTRA_UP].0 = *a;
}
}
}
}
TrackImportEffect::PortamentoExtraFineDown(a) => {
match mem {
MemoryType::Mod => {
}
MemoryType::Xm | MemoryType::It => {
if *a == 0.0 {
*a = self.channel[index][PORTAMENTO_FINE_EXTRA_DOWN].0
} else {
self.channel[index][PORTAMENTO_FINE_EXTRA_DOWN].0 = *a;
}
}
MemoryType::S3m => {
if *a == 0.0 {
*a = self.global[PORTAMENTO_FINE_EXTRA_DOWN].0
} else {
self.global[PORTAMENTO_FINE_EXTRA_DOWN].0 = *a;
}
}
}
}
TrackImportEffect::NoteRetrigExtended(speed, vol) => {
match mem {
MemoryType::Mod => {
}
MemoryType::Xm | MemoryType::It => {
if *speed == 0 {
*speed = self.channel[index][NOTE_RETRIG].2
} else {
self.channel[index][NOTE_RETRIG].2 = *speed;
}
if *vol == 0 {
*vol = self.channel[index][NOTE_RETRIG].3
} else {
self.channel[index][NOTE_RETRIG].3 = *vol;
}
}
MemoryType::S3m => {
if *speed == 0 {
*speed = self.global[NOTE_RETRIG].2
} else {
self.global[NOTE_RETRIG].2 = *speed;
}
if *vol == 0 {
*vol = self.channel[index][NOTE_RETRIG].3
} else {
self.channel[index][NOTE_RETRIG].3 = *vol;
}
}
}
}
TrackImportEffect::TonePortamento(a) => match mem {
MemoryType::Mod | MemoryType::Xm | MemoryType::S3m => {
if *a == 0.0 {
*a = self.channel[index][TONE_PORTAMENTO].0
} else {
self.channel[index][TONE_PORTAMENTO].0 = *a;
}
}
MemoryType::It => {
if self.it_flags.link_gxx_ef_memory {
if *a == 0.0 {
*a = self.channel[index][PORTAMENTO_UP].0
} else {
self.channel[index][PORTAMENTO_UP].0 = *a;
}
} else {
if *a == 0.0 {
*a = self.channel[index][TONE_PORTAMENTO].0
} else {
self.channel[index][TONE_PORTAMENTO].0 = *a;
}
}
}
},
TrackImportEffect::Tremolo(a, b) => match mem {
MemoryType::Mod | MemoryType::Xm | MemoryType::It => {
if *a == 0.0 {
*a = self.channel[index][TREMOLO].0
} else {
self.channel[index][TREMOLO].0 = *a;
}
if *b == 0.0 {
*b = self.channel[index][TREMOLO].1
} else {
self.channel[index][TREMOLO].1 = *b;
}
}
MemoryType::S3m => {
if *a == 0.0 {
*a = self.global[TREMOLO].0
} else {
self.global[TREMOLO].0 = *a;
}
if *b == 0.0 {
*b = self.global[TREMOLO].1
} else {
self.global[TREMOLO].1 = *b;
}
}
},
TrackImportEffect::Tremor(a, b) => {
match mem {
MemoryType::Mod => {
}
MemoryType::Xm | MemoryType::It => {
if *a == 0 {
*a = self.channel[index][TREMOR].2
} else {
self.channel[index][TREMOR].2 = *a;
}
if *b == 0 {
*b = self.channel[index][TREMOR].3
} else {
self.channel[index][TREMOR].3 = *b;
}
}
MemoryType::S3m => {
if *a == 0 {
*a = self.global[TREMOR].2
} else {
self.global[TREMOR].2 = *a;
}
if *b == 0 {
*b = self.global[TREMOR].3
} else {
self.global[TREMOR].3 = *b;
}
}
}
}
TrackImportEffect::InstrumentSampleOffset(a) => match mem {
MemoryType::Mod | MemoryType::Xm | MemoryType::It | MemoryType::S3m => {
if *a == 0 {
*a = self.channel[index][SAMPLE_OFFSET].2
+ self.channel[index][SAMPLE_OFFSET_ADD_HIGH].2;
} else {
self.channel[index][SAMPLE_OFFSET].2 = *a;
*a += self.channel[index][SAMPLE_OFFSET_ADD_HIGH].2;
}
}
},
TrackImportEffect::InstrumentSampleOffsetAddHigh(a) => match mem {
MemoryType::Mod | MemoryType::Xm | MemoryType::S3m => {
}
MemoryType::It => {
self.channel[index][SAMPLE_OFFSET_ADD_HIGH].2 = *a;
}
},
TrackImportEffect::Vibrato(a, b) => match mem {
MemoryType::Mod | MemoryType::Xm | MemoryType::It | MemoryType::S3m => {
if *a == 0.0 {
*a = self.channel[index][VIBRATO].0
} else {
self.channel[index][VIBRATO].0 = *a;
}
if *b == 0.0 {
*b = self.channel[index][VIBRATO].1
} else {
self.channel[index][VIBRATO].1 = *b;
}
}
},
TrackImportEffect::VibratoFine(a, b) => {
match mem {
MemoryType::Mod | MemoryType::Xm | MemoryType::It => {
}
MemoryType::S3m => {
if *a == 0.0 {
*a = self.channel[index][VIBRATO_FINE].0
} else {
self.channel[index][VIBRATO_FINE].0 = *a;
}
if *b == 0.0 {
*b = self.channel[index][VIBRATO_FINE].1
} else {
self.channel[index][VIBRATO_FINE].1 = *b;
}
}
}
}
TrackImportEffect::VolumeSlide0(a) => {
match mem {
MemoryType::Mod => {
}
MemoryType::Xm | MemoryType::It => {
if *a == 0.0 {
*a = self.channel[index][PITCH_VOLUME_SLIDE_0].0
} else {
self.channel[index][PITCH_VOLUME_SLIDE_0].0 = *a;
}
}
MemoryType::S3m => {
if *a == 0.0 {
*a = self.global[PITCH_VOLUME_SLIDE_0].0
} else {
self.global[PITCH_VOLUME_SLIDE_0].0 = *a;
}
}
}
}
TrackImportEffect::VolumeSlideN(a) => {
match mem {
MemoryType::Mod => {
}
MemoryType::Xm | MemoryType::It => {
if *a == 0.0 {
*a = self.channel[index][PITCH_VOLUME_SLIDE_N].0
} else {
self.channel[index][PITCH_VOLUME_SLIDE_N].0 = *a;
}
}
MemoryType::S3m => {
if *a == 0.0 {
*a = self.global[PITCH_VOLUME_SLIDE_N].0
} else {
self.global[PITCH_VOLUME_SLIDE_N].0 = *a;
}
}
}
}
TrackImportEffect::TonePortamentoFxVol(a) => {
match mem {
MemoryType::Mod | MemoryType::S3m => {
}
MemoryType::Xm => {
if *a == 0.0 {
*a = self.channel[index][FX_VOLUME_TONE_PORTAMENTO].0
} else {
self.channel[index][FX_VOLUME_TONE_PORTAMENTO].0 = *a;
}
}
MemoryType::It => {
}
}
}
TrackImportEffect::VibratoDepthFxVol(a) => {
match mem {
MemoryType::Mod | MemoryType::S3m => {
}
MemoryType::Xm => {
if *a == 0.0 {
*a = self.channel[index][FX_VOLUME_VIBRATO_DEPTH].0
} else {
self.channel[index][FX_VOLUME_VIBRATO_DEPTH].0 = *a;
}
}
MemoryType::It => {
}
}
}
TrackImportEffect::ChannelVolumeSlide0(a)
| TrackImportEffect::ChannelVolumeSlideN(a) => {
match mem {
MemoryType::Mod => {
}
MemoryType::Xm | MemoryType::It | MemoryType::S3m => {
if *a == 0.0 {
*a = self.channel[index][CHANNEL_VOLUME_SLIDE].0
} else {
self.channel[index][CHANNEL_VOLUME_SLIDE].0 = *a;
}
}
}
}
_ => {}
}
});
tiu.global_effects.iter_mut().for_each(|e| {
match e {
GlobalEffect::BpmSlide(a) => {
let fx_index = if *a < 0 { TEMPO_DOWN } else { TEMPO_UP };
match mem {
MemoryType::Mod => {
}
MemoryType::Xm | MemoryType::It | MemoryType::S3m => {
if *a == 0 {
*a = self.channel[index][fx_index].2 as isize;
} else {
self.channel[index][fx_index].2 = *a as usize;
}
}
}
}
GlobalEffect::VolumeSlide { speed: a, fine: _b } => {
match mem {
MemoryType::Mod => {
}
MemoryType::Xm | MemoryType::It | MemoryType::S3m => {
if *a == 0.0 {
*a = self.channel[index][CHANNEL_VOLUME_SLIDE].0
} else {
self.channel[index][CHANNEL_VOLUME_SLIDE].0 = *a;
}
}
}
}
_ => {}
}
});
}
fn apply_memory(
&mut self,
freq_type: FrequencyType,
mem: MemoryType,
order: &[Vec<usize>],
patterns: &[Vec<Vec<PatternSlot>>],
) -> Vec<Vec<Vec<TrackImportUnit>>> {
let mut source: Vec<Vec<Vec<TrackImportUnit>>> = patterns
.iter()
.map(|pattern| match mem {
#[cfg(any(feature = "import_mod", feature = "import_xm"))]
MemoryType::Mod | MemoryType::Xm => {
ModXmEffect::mod_xm_unpack_pattern(freq_type, pattern)
}
#[cfg(feature = "import_s3m")]
MemoryType::S3m => {
S3mEffect::s3m_unpack_pattern(freq_type, self.s3m_flags, pattern)
}
#[cfg(feature = "import_it")]
MemoryType::It => ItEffect::it_unpack_pattern(freq_type, pattern),
#[allow(unreachable_patterns)]
_ => unreachable!("MemoryType dispatched to a disabled format importer"),
})
.collect();
order.iter().flat_map(|inner| inner.iter()).for_each(|o| {
if *o >= source.len() {
return;
}
let pattern = &mut source[*o];
pattern.iter_mut().for_each(|row| {
row.iter_mut()
.enumerate()
.for_each(|(index, tiu)| self.update_memory(&mem, index, tiu));
});
});
source
}
pub fn unpack_patterns(
&mut self,
freq_type: FrequencyType,
mem: MemoryType,
order: &[Vec<usize>],
patterns: &[Vec<Vec<PatternSlot>>],
) -> Vec<Vec<Vec<TrackUnit>>> {
let source = self.apply_memory(freq_type, mem, order, patterns);
let mut dest: Vec<Vec<Vec<TrackUnit>>> = source
.iter()
.map(|pattern| {
pattern
.iter()
.map(|row| row.iter().map(|tiu| tiu.prepare_track_unit()).collect())
.collect()
})
.collect();
for ol in order.iter().flat_map(|inner| inner.iter()) {
if *ol >= source.len() || *ol >= dest.len() {
continue;
}
let pattern_s = &source[*ol];
let pattern_d = &mut dest[*ol];
for (index_row, row_s) in pattern_s.iter().enumerate() {
let row_d = &mut pattern_d[index_row];
for (index_ch, ch_s) in row_s.iter().enumerate() {
let ch_d = &mut row_d[index_ch];
ch_d.effects = TrackImportEffect::to_track_effects(&ch_s.effects);
}
}
}
dest
}
}