Implement vibrato correctly and add a small test case

This commit is contained in:
Gwilym Inzani 2024-07-10 14:15:04 +01:00
parent 431833b216
commit d15063373d
4 changed files with 38 additions and 16 deletions

View file

@ -62,7 +62,8 @@ pub enum PatternEffect {
Arpeggio(Num<u16, 8>, Num<u16, 8>), Arpeggio(Num<u16, 8>, Num<u16, 8>),
Panning(Num<i16, 4>), Panning(Num<i16, 4>),
Volume(Num<i16, 8>), Volume(Num<i16, 8>),
VolumeSlide(Num<i16, 8>), // bool = maintain vibrato?
VolumeSlide(Num<i16, 8>, bool),
FineVolumeSlide(Num<i16, 8>), FineVolumeSlide(Num<i16, 8>),
NoteCut(u32), NoteCut(u32),
NoteDelay(u32), NoteDelay(u32),
@ -298,9 +299,9 @@ impl quote::ToTokens for PatternEffect {
let volume = volume.to_raw(); let volume = volume.to_raw();
quote! { Volume(agb_tracker::__private::Num::from_raw(#volume))} quote! { Volume(agb_tracker::__private::Num::from_raw(#volume))}
} }
PatternEffect::VolumeSlide(amount) => { PatternEffect::VolumeSlide(amount, vibrato) => {
let amount = amount.to_raw(); let amount = amount.to_raw();
quote! { VolumeSlide(agb_tracker::__private::Num::from_raw(#amount))} quote! { VolumeSlide(agb_tracker::__private::Num::from_raw(#amount), #vibrato)}
} }
PatternEffect::FineVolumeSlide(amount) => { PatternEffect::FineVolumeSlide(amount) => {
let amount = amount.to_raw(); let amount = amount.to_raw();

View file

@ -133,6 +133,8 @@ struct Waves {
frame: usize, frame: usize,
speed: usize, speed: usize,
amount: Num<i32, 12>, amount: Num<i32, 12>,
enable: bool,
} }
impl Waves { impl Waves {
@ -254,6 +256,8 @@ impl<'track, TChannelId> TrackerInner<'track, TChannelId> {
channel.set_speed(pattern_slot.speed.change_base()); channel.set_speed(pattern_slot.speed.change_base());
} }
channel.vibrato.enable = false;
channel.apply_effect( channel.apply_effect(
&pattern_slot.effect1, &pattern_slot.effect1,
self.tick, self.tick,
@ -282,7 +286,7 @@ impl<'track, TChannelId> TrackerInner<'track, TChannelId> {
{ {
let mut current_speed = tracker_channel.current_speed; let mut current_speed = tracker_channel.current_speed;
if tracker_channel.vibrato.speed != 0 { if tracker_channel.vibrato.speed != 0 && tracker_channel.vibrato.enable {
current_speed *= tracker_channel.vibrato.value().change_base(); current_speed *= tracker_channel.vibrato.value().change_base();
} }
@ -419,13 +423,15 @@ impl TrackerChannel {
self.volume = volume.change_base(); self.volume = volume.change_base();
} }
PatternEffect::VolumeSlide(amount) => { PatternEffect::VolumeSlide(amount, keep_vibrato) => {
if tick != 0 { if tick != 0 {
self.volume = (self.volume + amount.change_base()).max(0.into()); self.volume = (self.volume + amount.change_base()).max(0.into());
self.current_volume = (self.volume * global_settings.volume) self.current_volume = (self.volume * global_settings.volume)
.try_change_base() .try_change_base()
.unwrap(); .unwrap();
} }
self.vibrato.enable = *keep_vibrato;
} }
PatternEffect::FineVolumeSlide(amount) => { PatternEffect::FineVolumeSlide(amount) => {
if tick == 0 { if tick == 0 {
@ -506,10 +512,17 @@ impl TrackerChannel {
(global_settings.volume + *volume_delta).clamp(0.into(), 1.into()); (global_settings.volume + *volume_delta).clamp(0.into(), 1.into());
} }
PatternEffect::Vibrato(waveform, amount, speed) => { PatternEffect::Vibrato(waveform, amount, speed) => {
self.vibrato.waveform = *waveform; if *amount != 0.into() {
self.vibrato.amount = amount.change_base(); self.vibrato.amount = amount.change_base();
}
if *speed != 0 {
self.vibrato.speed = *speed as usize; self.vibrato.speed = *speed as usize;
} }
self.vibrato.waveform = *waveform;
self.vibrato.enable = true;
}
} }
} }

View file

@ -147,12 +147,14 @@ pub fn parse_module(module: &Module) -> agb_tracker_interop::Track {
.map(|note_and_sample| note_and_sample.1.volume) .map(|note_and_sample| note_and_sample.1.volume)
.unwrap_or(1.into()), .unwrap_or(1.into()),
), ),
0x60..=0x6F => { 0x60..=0x6F => PatternEffect::VolumeSlide(
PatternEffect::VolumeSlide(-Num::new((slot.volume - 0x60) as i16) / 64) -Num::new((slot.volume - 0x60) as i16) / 64,
} false,
0x70..=0x7F => { ),
PatternEffect::VolumeSlide(Num::new((slot.volume - 0x70) as i16) / 64) 0x70..=0x7F => PatternEffect::VolumeSlide(
} Num::new((slot.volume - 0x70) as i16) / 64,
false,
),
0x80..=0x8F => PatternEffect::FineVolumeSlide( 0x80..=0x8F => PatternEffect::FineVolumeSlide(
-Num::new((slot.volume - 0x80) as i16) / 128, -Num::new((slot.volume - 0x80) as i16) / 128,
), ),
@ -283,7 +285,7 @@ pub fn parse_module(module: &Module) -> agb_tracker_interop::Track {
let c4_speed = note_to_speed(Note::C4, 0.0, 0, module.frequency_type); let c4_speed = note_to_speed(Note::C4, 0.0, 0, module.frequency_type);
let speed = let speed =
note_to_speed(Note::C4, depth as f64 * 8.0, 0, module.frequency_type); note_to_speed(Note::C4, depth as f64 * 16.0, 0, module.frequency_type);
let amount = speed / c4_speed - 1; let amount = speed / c4_speed - 1;
@ -301,9 +303,15 @@ pub fn parse_module(module: &Module) -> agb_tracker_interop::Track {
let second = effect_parameter & 0xF; let second = effect_parameter & 0xF;
if first == 0 { if first == 0 {
PatternEffect::VolumeSlide(-Num::new(second as i16) / 64) PatternEffect::VolumeSlide(
-Num::new(second as i16) / 64,
slot.effect_type == 0x6,
)
} else { } else {
PatternEffect::VolumeSlide(Num::new(first as i16) / 64) PatternEffect::VolumeSlide(
Num::new(first as i16) / 64,
slot.effect_type == 0x6,
)
} }
} }
0xC => { 0xC => {

Binary file not shown.