Properly implement delay and envelopes

This commit is contained in:
Gwilym Inzani 2024-05-16 00:27:20 +01:00
parent 5494ae29e1
commit 352b352b27
2 changed files with 30 additions and 11 deletions

View file

@ -406,11 +406,12 @@ impl TrackerChannel {
} }
} }
PatternEffect::NoteDelay(wait) => { PatternEffect::NoteDelay(wait) => {
if tick <= *wait { if tick < *wait {
channel.volume(0); channel.pause();
} }
if tick == *wait + 1 { if tick == *wait {
channel.resume();
channel.volume((self.volume * global_settings.volume).try_change_base().unwrap()); channel.volume((self.volume * global_settings.volume).try_change_base().unwrap());
} }
} }

View file

@ -524,33 +524,41 @@ impl EnvelopeData {
fn new(e: &xmrs::envelope::Envelope, bpm: u32) -> Self { fn new(e: &xmrs::envelope::Envelope, bpm: u32) -> Self {
let mut amounts = vec![]; let mut amounts = vec![];
// FT2 manual says number of ticks / second = BPM * 0.4 = BPM * 4 / 10. GBA runs at 60Hz for frame in 0..=(Self::envelope_frame_to_gba_frame(e.point.last().unwrap().frame, bpm)) {
for frame in 0..(e.point.last().unwrap().frame as u32 * 60 * 10 / bpm / 4) { let xm_frame = Self::gba_frame_to_envelope_frame(frame, bpm);
let xm_frame = frame * bpm * 4 / 60 / 10;
let index = e let index = e
.point .point
.iter() .iter()
.rposition(|point| point.frame < xm_frame as u16) .rposition(|point| point.frame < xm_frame)
.unwrap_or(0); .unwrap_or(0);
let first_point = &e.point[index]; let first_point = &e.point[index];
let second_point = &e.point[index + 1]; let second_point = &e.point[index + 1];
let amount = EnvelopePoint::lerp(first_point, second_point, xm_frame as u16) / 64.0; let amount = EnvelopePoint::lerp(first_point, second_point, xm_frame) / 64.0;
let amount = Num::from_f32(amount); let amount = Num::from_f32(amount);
amounts.push(amount); amounts.push(amount);
} }
let sustain = if e.sustain_enabled { let sustain = if e.sustain_enabled {
Some(e.point[e.sustain_point as usize].frame as usize * 60 / 50) Some(
Self::envelope_frame_to_gba_frame(e.point[e.sustain_point as usize].frame, bpm)
as usize,
)
} else { } else {
None None
}; };
let (loop_start, loop_end) = if e.loop_enabled { let (loop_start, loop_end) = if e.loop_enabled {
( (
Some(e.point[e.loop_start_point as usize].frame as usize * 60 / 50), Some(Self::envelope_frame_to_gba_frame(
Some(e.point[e.loop_end_point as usize].frame as usize * 60 / 50), e.point[e.loop_start_point as usize].frame,
bpm,
) as usize),
Some(Self::envelope_frame_to_gba_frame(
e.point[e.loop_end_point as usize].frame,
bpm,
) as usize),
) )
} else { } else {
(None, None) (None, None)
@ -563,4 +571,14 @@ impl EnvelopeData {
loop_end, loop_end,
} }
} }
fn envelope_frame_to_gba_frame(envelope_frame: u16, bpm: u32) -> u16 {
// FT2 manual says number of ticks / second = BPM * 0.4
// somehow this works as a good approximation :/
(envelope_frame as u32 * 250 / bpm) as u16
}
fn gba_frame_to_envelope_frame(gba_frame: u16, bpm: u32) -> u16 {
(gba_frame as u32 * bpm / 250) as u16
}
} }