diff --git a/tracker/agb-tracker-interop/src/lib.rs b/tracker/agb-tracker-interop/src/lib.rs index 91dc6125..6bcd6b76 100644 --- a/tracker/agb-tracker-interop/src/lib.rs +++ b/tracker/agb-tracker-interop/src/lib.rs @@ -69,6 +69,7 @@ pub enum PatternEffect { Portamento(Num), /// Slide each tick the first amount to at most the second amount TonePortamento(Num, Num), + Vibrato(Waveform, Num, u8), SetTicksPerStep(u32), SetFramesPerTick(Num), SetGlobalVolume(Num), @@ -77,7 +78,7 @@ pub enum PatternEffect { PitchBend(Num), } -#[derive(Debug, Default, Clone, PartialEq, Eq)] +#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)] pub enum Waveform { #[default] Sine, @@ -334,6 +335,10 @@ impl quote::ToTokens for PatternEffect { let amount = amount.to_raw(); quote! { PitchBend(agb_tracker::__private::Num::from_raw(#amount)) } } + PatternEffect::Vibrato(waveform, amount, speed) => { + let amount = amount.to_raw(); + quote! { Vibrato(#waveform, #amount, #speed) } + } }; tokens.append_all(quote! { diff --git a/tracker/agb-tracker/build.rs b/tracker/agb-tracker/build.rs index f08f522c..5236b62e 100644 --- a/tracker/agb-tracker/build.rs +++ b/tracker/agb-tracker/build.rs @@ -5,17 +5,17 @@ use std::fs; use std::path::Path; fn main() { - let sine = (0..64).map(|i| (Num::::new(i) / 64).sin()); + let sine = (0..64).map(|i| (Num::::new(i) / 64).sin()); let square = (0..64).map(|i| { if i < 32 { - Num::::new(-1) + Num::::new(-1) } else { - Num::::new(1) + Num::::new(1) } }); - let saw = (0..64).map(|i| (Num::::new(i) - 32) / 32); + let saw = (0..64).map(|i| (Num::::new(i) - 32) / 32); let out_dir = env::var_os("OUT_DIR").unwrap(); let dest_path = Path::new(&out_dir).join("lookups.rs"); @@ -24,9 +24,9 @@ fn main() { &dest_path, format!( " - pub(crate) static SINE_LOOKUP: [agb_fixnum::Num; 64] = [{sine_lookup}]; - pub(crate) static SQUARE_LOOKUP: [agb_fixnum::Num; 64] = [{square_lookup}]; - pub(crate) static SAW_LOOKUP: [agb_fixnum::Num; 64] = [{saw_lookup}]; + pub(crate) static SINE_LOOKUP: [agb_fixnum::Num; 64] = [{sine_lookup}]; + pub(crate) static SQUARE_LOOKUP: [agb_fixnum::Num; 64] = [{square_lookup}]; + pub(crate) static SAW_LOOKUP: [agb_fixnum::Num; 64] = [{saw_lookup}]; ", sine_lookup = gen_lookup(sine), square_lookup = gen_lookup(square), @@ -38,7 +38,7 @@ fn main() { println!("cargo::rerun-if-changed=build.rs"); } -fn gen_lookup(input: impl IntoIterator>) -> String { +fn gen_lookup(input: impl IntoIterator>) -> String { let output: Vec<_> = input .into_iter() .map(|v| format!("agb_fixnum::Num::from_raw({})", v.to_raw())) diff --git a/tracker/agb-tracker/src/lib.rs b/tracker/agb-tracker/src/lib.rs index 199da58f..5b5fa932 100644 --- a/tracker/agb-tracker/src/lib.rs +++ b/tracker/agb-tracker/src/lib.rs @@ -132,7 +132,7 @@ struct Waves { waveform: Waveform, frame: usize, speed: usize, - amount: Num, + amount: Num, } impl Waves { @@ -281,6 +281,7 @@ impl<'track, TChannelId> TrackerInner<'track, TChannelId> { .and_then(|channel_id| mixer.channel(channel_id)) { let mut current_speed = tracker_channel.current_speed; + if tracker_channel.vibrato.speed != 0 { current_speed *= tracker_channel.vibrato.value().change_base(); } @@ -498,6 +499,11 @@ impl TrackerChannel { global_settings.volume = (global_settings.volume + *volume_delta).clamp(0.into(), 1.into()); } + PatternEffect::Vibrato(waveform, amount, speed) => { + self.vibrato.waveform = *waveform; + self.vibrato.amount = amount.change_base(); + self.vibrato.speed = *speed as usize; + } } } diff --git a/tracker/agb-xm-core/src/lib.rs b/tracker/agb-xm-core/src/lib.rs index e64f5cf4..c44636cb 100644 --- a/tracker/agb-xm-core/src/lib.rs +++ b/tracker/agb-xm-core/src/lib.rs @@ -1,7 +1,7 @@ use std::collections::HashMap; use agb_fixnum::Num; -use agb_tracker_interop::PatternEffect; +use agb_tracker_interop::{PatternEffect, Waveform}; use xmrs::prelude::*; @@ -277,6 +277,22 @@ pub fn parse_module(module: &Module) -> agb_tracker_interop::Track { PatternEffect::None } } + 0x4 => { + let vibrato_speed = effect_parameter >> 4; + let depth = effect_parameter & 0xF; + + let c4_speed = note_to_speed(Note::C4, 0.0, 0, module.frequency_type); + let speed = + note_to_speed(Note::C4, depth as f64 * 8.0, 0, module.frequency_type); + + let amount = speed / c4_speed - 1; + + PatternEffect::Vibrato( + Waveform::Sine, + amount.try_change_base().unwrap(), + vibrato_speed, + ) + } 0x8 => { PatternEffect::Panning(Num::new(slot.effect_parameter as i16 - 128) / 128) }