diff --git a/tracker/agb-tracker-interop/src/lib.rs b/tracker/agb-tracker-interop/src/lib.rs index 6bcd6b76..0edf0bc2 100644 --- a/tracker/agb-tracker-interop/src/lib.rs +++ b/tracker/agb-tracker-interop/src/lib.rs @@ -67,6 +67,7 @@ pub enum PatternEffect { NoteCut(u32), NoteDelay(u32), Portamento(Num), + FinePortamento(Num), /// Slide each tick the first amount to at most the second amount TonePortamento(Num, Num), Vibrato(Waveform, Num, u8), @@ -311,6 +312,10 @@ impl quote::ToTokens for PatternEffect { let amount = amount.to_raw(); quote! { Portamento(agb_tracker::__private::Num::from_raw(#amount))} } + PatternEffect::FinePortamento(amount) => { + let amount = amount.to_raw(); + quote! { FinePortamento(agb_tracker::__private::Num::from_raw(#amount))} + } PatternEffect::TonePortamento(amount, target) => { let amount = amount.to_raw(); let target = target.to_raw(); diff --git a/tracker/agb-tracker/src/lib.rs b/tracker/agb-tracker/src/lib.rs index 5b5fa932..968ab14e 100644 --- a/tracker/agb-tracker/src/lib.rs +++ b/tracker/agb-tracker/src/lib.rs @@ -462,6 +462,12 @@ impl TrackerChannel { self.current_speed = self.base_speed.change_base(); } } + PatternEffect::FinePortamento(amount) => { + if tick == 1 { + self.base_speed *= amount.change_base(); + self.current_speed = self.base_speed.change_base(); + } + } PatternEffect::TonePortamento(amount, target) => { self.current_volume = (self.volume * global_settings.volume) .try_change_base() diff --git a/tracker/agb-xm-core/src/lib.rs b/tracker/agb-xm-core/src/lib.rs index c44636cb..f63088ad 100644 --- a/tracker/agb-xm-core/src/lib.rs +++ b/tracker/agb-xm-core/src/lib.rs @@ -316,6 +316,40 @@ pub fn parse_module(module: &Module) -> agb_tracker_interop::Track { } } 0xE => match slot.effect_parameter >> 4 { + 0x1 => { + let c4_speed: Num = + note_to_speed(Note::C4, 0.0, 0, module.frequency_type) + .change_base(); + let speed: Num = note_to_speed( + Note::C4, + effect_parameter as f64 * 8.0, + 0, + module.frequency_type, + ) + .change_base(); + + let portamento_amount = speed / c4_speed; + + PatternEffect::FinePortamento( + portamento_amount.try_change_base().unwrap(), + ) + } + 0x2 => { + let c4_speed = note_to_speed(Note::C4, 0.0, 0, module.frequency_type); + let speed = note_to_speed( + Note::C4, + effect_parameter as f64 * 8.0, + 0, + module.frequency_type, + ); + + let portamento_amount = c4_speed / speed; + + PatternEffect::FinePortamento( + portamento_amount.try_change_base().unwrap(), + ) + } + 0xA => PatternEffect::FineVolumeSlide( Num::new((slot.effect_parameter & 0xf) as i16) / 128, ), @@ -324,7 +358,10 @@ pub fn parse_module(module: &Module) -> agb_tracker_interop::Track { ), 0xC => PatternEffect::NoteCut((slot.effect_parameter & 0xf).into()), 0xD => PatternEffect::NoteDelay((slot.effect_parameter & 0xf).into()), - _ => PatternEffect::None, + u => { + eprintln!("Unsupported extended effect E{u:X}y"); + PatternEffect::None + } }, 0xF => match slot.effect_parameter { 0 => PatternEffect::SetTicksPerStep(u32::MAX), @@ -348,7 +385,11 @@ pub fn parse_module(module: &Module) -> agb_tracker_interop::Track { PatternEffect::GlobalVolumeSlide(Num::new(first as i32) / 0x40) } } - _ => PatternEffect::None, + e => { + eprintln!("Unsupported effect {e:X}xy"); + + PatternEffect::None + } }; if sample == 0