mirror of
https://github.com/italicsjenga/agb.git
synced 2024-12-23 08:11:33 +11:00
Add note delay and fix envelopes (#698)
Adds support for the effect EDx (note delay) although it isn't completely correct. And envelopes were too short so I've fixed that too. - [x] no changelog update needed
This commit is contained in:
commit
bcafe7be75
|
@ -62,6 +62,7 @@ pub enum PatternEffect {
|
|||
VolumeSlide(Num<i16, 8>),
|
||||
FineVolumeSlide(Num<i16, 8>),
|
||||
NoteCut(u32),
|
||||
NoteDelay(u32),
|
||||
Portamento(Num<u16, 12>),
|
||||
/// Slide each tick the first amount to at most the second amount
|
||||
TonePortamento(Num<u16, 12>, Num<u16, 12>),
|
||||
|
@ -289,6 +290,7 @@ impl quote::ToTokens for PatternEffect {
|
|||
quote! { FineVolumeSlide(agb_tracker::__private::Num::from_raw(#amount))}
|
||||
}
|
||||
PatternEffect::NoteCut(wait) => quote! { NoteCut(#wait) },
|
||||
PatternEffect::NoteDelay(wait) => quote! { NoteDelay(#wait) },
|
||||
PatternEffect::Portamento(amount) => {
|
||||
let amount = amount.to_raw();
|
||||
quote! { Portamento(agb_tracker::__private::Num::from_raw(#amount))}
|
||||
|
|
|
@ -405,6 +405,20 @@ impl TrackerChannel {
|
|||
}
|
||||
}
|
||||
}
|
||||
PatternEffect::NoteDelay(wait) => {
|
||||
if tick < *wait {
|
||||
channel.pause();
|
||||
}
|
||||
|
||||
if tick == *wait {
|
||||
channel.resume();
|
||||
channel.volume(
|
||||
(self.volume * global_settings.volume)
|
||||
.try_change_base()
|
||||
.unwrap(),
|
||||
);
|
||||
}
|
||||
}
|
||||
PatternEffect::Portamento(amount) => {
|
||||
if tick != 0 {
|
||||
self.base_speed *= amount.change_base();
|
||||
|
|
|
@ -71,7 +71,7 @@ pub fn parse_module(module: &Module) -> TokenStream {
|
|||
|
||||
let envelope = &instrument.volume_envelope;
|
||||
let envelope_id = if envelope.enabled {
|
||||
let envelope: EnvelopeData = envelope.as_ref().into();
|
||||
let envelope = EnvelopeData::new(envelope, module.default_bpm as u32);
|
||||
let id = existing_envelopes
|
||||
.entry(envelope)
|
||||
.or_insert_with_key(|envelope| {
|
||||
|
@ -347,6 +347,7 @@ pub fn parse_module(module: &Module) -> TokenStream {
|
|||
-Num::new((slot.effect_parameter & 0xf) as i16) / 128,
|
||||
),
|
||||
0xC => PatternEffect::NoteCut((slot.effect_parameter & 0xf).into()),
|
||||
0xD => PatternEffect::NoteDelay((slot.effect_parameter & 0xf).into()),
|
||||
_ => PatternEffect::None,
|
||||
},
|
||||
0xF => match slot.effect_parameter {
|
||||
|
@ -519,13 +520,12 @@ struct EnvelopeData {
|
|||
loop_end: Option<usize>,
|
||||
}
|
||||
|
||||
impl From<&xmrs::envelope::Envelope> for EnvelopeData {
|
||||
fn from(e: &xmrs::envelope::Envelope) -> Self {
|
||||
impl EnvelopeData {
|
||||
fn new(e: &xmrs::envelope::Envelope, bpm: u32) -> Self {
|
||||
let mut amounts = vec![];
|
||||
|
||||
// it should be sampled at 50fps, but we're sampling at 60fps, so need to do a bit of cheating here.
|
||||
for frame in 0..(e.point.last().unwrap().frame * 60 / 50) {
|
||||
let xm_frame = frame * 50 / 60;
|
||||
for frame in 0..=(Self::envelope_frame_to_gba_frame(e.point.last().unwrap().frame, bpm)) {
|
||||
let xm_frame = Self::gba_frame_to_envelope_frame(frame, bpm);
|
||||
let index = e
|
||||
.point
|
||||
.iter()
|
||||
|
@ -542,14 +542,23 @@ impl From<&xmrs::envelope::Envelope> for EnvelopeData {
|
|||
}
|
||||
|
||||
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 {
|
||||
None
|
||||
};
|
||||
let (loop_start, loop_end) = if e.loop_enabled {
|
||||
(
|
||||
Some(e.point[e.loop_start_point as usize].frame as usize * 60 / 50),
|
||||
Some(e.point[e.loop_end_point as usize].frame as usize * 60 / 50),
|
||||
Some(Self::envelope_frame_to_gba_frame(
|
||||
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 {
|
||||
(None, None)
|
||||
|
@ -562,4 +571,14 @@ impl From<&xmrs::envelope::Envelope> for EnvelopeData {
|
|||
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
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue