From 559367f6075ee1ad8981cdbfa83f881a76cf14fc Mon Sep 17 00:00:00 2001 From: Gwilym Inzani Date: Wed, 28 Aug 2024 16:32:28 +0100 Subject: [PATCH] Add sample offset command support --- tracker/agb-tracker-interop/src/lib.rs | 2 ++ tracker/agb-tracker/src/lib.rs | 16 ++++++++++++++++ tracker/agb-tracker/src/mixer.rs | 2 ++ tracker/agb-xm-core/src/lib.rs | 1 + tracker/desktop-player/src/mixer.rs | 5 +++++ tracker/desktop-player/tests/delay.xm | Bin 0 -> 15092 bytes 6 files changed, 26 insertions(+) create mode 100644 tracker/desktop-player/tests/delay.xm diff --git a/tracker/agb-tracker-interop/src/lib.rs b/tracker/agb-tracker-interop/src/lib.rs index f31509c0..eee21c00 100644 --- a/tracker/agb-tracker-interop/src/lib.rs +++ b/tracker/agb-tracker-interop/src/lib.rs @@ -93,6 +93,7 @@ pub enum PatternEffect { /// Increase / decrease the pitch by the specified amount immediately PitchBend(Num), Jump(Jump), + SampleOffset(u16), } #[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)] @@ -401,6 +402,7 @@ impl quote::ToTokens for PatternEffect { PatternEffect::Jump(jump) => { quote! { Jump(#jump) } } + PatternEffect::SampleOffset(offset) => quote! { SampleOffset(#offset) }, }; tokens.append_all(quote! { diff --git a/tracker/agb-tracker/src/lib.rs b/tracker/agb-tracker/src/lib.rs index 9edd20fa..527766bf 100644 --- a/tracker/agb-tracker/src/lib.rs +++ b/tracker/agb-tracker/src/lib.rs @@ -126,6 +126,9 @@ struct TrackerChannel { current_speed: Num, current_panning: Num, is_playing: bool, + + // if some, should set the current position to this + current_pos: Option, } #[derive(Default)] @@ -337,6 +340,10 @@ impl<'track, TChannelId> TrackerInner<'track, TChannelId> { channel.volume(tracker_channel.current_volume.try_change_base().unwrap()); channel.panning(tracker_channel.current_panning.try_change_base().unwrap()); + if let Some(offset) = tracker_channel.current_pos.take() { + channel.set_pos(offset as u32); + } + if tracker_channel.is_playing { channel.resume(); } else { @@ -601,6 +608,11 @@ impl TrackerChannel { PatternEffect::Jump(jump) => { *current_jump = Some(jump.clone()); } + PatternEffect::SampleOffset(offset) => { + if tick == 0 { + self.current_pos = Some(*offset); + } + } } } @@ -677,6 +689,10 @@ impl SoundChannel for agb::sound::mixer::SoundChannel { fn panning(&mut self, panning: impl Into>) -> &mut Self { self.panning(panning) } + + fn set_pos(&mut self, pos: impl Into>) -> &mut Self { + self.set_pos(pos) + } } #[cfg(feature = "agb")] diff --git a/tracker/agb-tracker/src/mixer.rs b/tracker/agb-tracker/src/mixer.rs index 110627e9..dcb1cc60 100644 --- a/tracker/agb-tracker/src/mixer.rs +++ b/tracker/agb-tracker/src/mixer.rs @@ -17,6 +17,8 @@ pub trait SoundChannel { fn restart_point(&mut self, value: impl Into>) -> &mut Self; fn playback(&mut self, playback_speed: impl Into>) -> &mut Self; fn panning(&mut self, panning: impl Into>) -> &mut Self; + + fn set_pos(&mut self, pos: impl Into>) -> &mut Self; } pub trait Mixer { diff --git a/tracker/agb-xm-core/src/lib.rs b/tracker/agb-xm-core/src/lib.rs index 8b5d1aab..018aa540 100644 --- a/tracker/agb-xm-core/src/lib.rs +++ b/tracker/agb-xm-core/src/lib.rs @@ -324,6 +324,7 @@ pub fn parse_module(module: &Module) -> agb_tracker_interop::Track { ) } } + 0x9 => PatternEffect::SampleOffset(effect_parameter as u16 * 256), 0xB => { let pattern_idx = slot.effect_parameter; diff --git a/tracker/desktop-player/src/mixer.rs b/tracker/desktop-player/src/mixer.rs index 990e56e9..69a928fd 100644 --- a/tracker/desktop-player/src/mixer.rs +++ b/tracker/desktop-player/src/mixer.rs @@ -171,6 +171,11 @@ impl agb_tracker::SoundChannel for SoundChannel { self.panning = panning.into(); self } + + fn set_pos(&mut self, pos: impl Into>) -> &mut Self { + self.pos = pos.into(); + self + } } impl agb_tracker::Mixer for Mixer { diff --git a/tracker/desktop-player/tests/delay.xm b/tracker/desktop-player/tests/delay.xm new file mode 100644 index 0000000000000000000000000000000000000000..a41345a388a1509d486572b8621cfb3ac8b8c458 GIT binary patch literal 15092 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