Retrigger with volume

This commit is contained in:
Gwilym Inzani 2024-08-28 17:38:24 +01:00
parent 48f7020f2c
commit fee2575cb7
4 changed files with 67 additions and 15 deletions

View file

@ -39,6 +39,14 @@ pub enum Jump {
Combined { pattern: u8, row: u8 }, Combined { pattern: u8, row: u8 },
} }
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum RetriggerVolumeChange {
/// Decrease the volume by one each retrigger
DecreaseByOne,
/// Don't change it
NoChange,
}
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Pattern { pub struct Pattern {
pub length: usize, pub length: usize,
@ -94,7 +102,8 @@ pub enum PatternEffect {
PitchBend(Num<u32, 8>), PitchBend(Num<u32, 8>),
Jump(Jump), Jump(Jump),
SampleOffset(u16), SampleOffset(u16),
Retrigger(u8), /// Retrigger the note every u8 ticks with the volume change specified
Retrigger(RetriggerVolumeChange, u8),
} }
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)] #[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
@ -130,6 +139,22 @@ impl quote::ToTokens for Jump {
} }
} }
#[cfg(feature = "quote")]
impl quote::ToTokens for RetriggerVolumeChange {
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
use quote::{quote, TokenStreamExt};
let type_bit = match self {
RetriggerVolumeChange::DecreaseByOne => quote!(DecreaseByOne),
RetriggerVolumeChange::NoChange => quote!(NoChange),
};
tokens.append_all(quote! {
agb_tracker::__private::agb_tracker_interop::RetriggerVolumeChange::#type_bit
});
}
}
#[cfg(feature = "quote")] #[cfg(feature = "quote")]
impl quote::ToTokens for Track { impl quote::ToTokens for Track {
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) { fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
@ -404,7 +429,9 @@ impl quote::ToTokens for PatternEffect {
quote! { Jump(#jump) } quote! { Jump(#jump) }
} }
PatternEffect::SampleOffset(offset) => quote! { SampleOffset(#offset) }, PatternEffect::SampleOffset(offset) => quote! { SampleOffset(#offset) },
PatternEffect::Retrigger(ticks) => quote! { Retrigger(#ticks) }, PatternEffect::Retrigger(retrigger_volume_change, ticks) => {
quote! { Retrigger(#retrigger_volume_change, #ticks) }
}
}; };
tokens.append_all(quote! { tokens.append_all(quote! {

View file

@ -613,8 +613,18 @@ impl TrackerChannel {
self.current_pos = Some(*offset); self.current_pos = Some(*offset);
} }
} }
PatternEffect::Retrigger(ticks) => { PatternEffect::Retrigger(volume_change, ticks) => {
if tick % *ticks as u32 == 0 { if tick % *ticks as u32 == 0 {
match volume_change {
agb_tracker_interop::RetriggerVolumeChange::DecreaseByOne => {
self.volume = (self.volume - Num::new(1) / 64).max(0.into());
self.current_volume = (self.volume * global_settings.volume)
.try_change_base()
.unwrap();
}
agb_tracker_interop::RetriggerVolumeChange::NoChange => {}
}
self.current_pos = Some(0); self.current_pos = Some(0);
} }
} }

View file

@ -1,7 +1,7 @@
use std::collections::HashMap; use std::collections::HashMap;
use agb_fixnum::Num; use agb_fixnum::Num;
use agb_tracker_interop::{Jump, PatternEffect, Waveform}; use agb_tracker_interop::{Jump, PatternEffect, RetriggerVolumeChange, Waveform};
use xmrs::prelude::*; use xmrs::prelude::*;
@ -99,7 +99,8 @@ pub fn parse_module(module: &Module) -> agb_tracker_interop::Track {
let mut effect_parameters: [u8; 255] = [0; u8::MAX as usize]; let mut effect_parameters: [u8; 255] = [0; u8::MAX as usize];
let mut tone_portamento_directions = vec![0; module.get_num_channels()]; let mut tone_portamento_directions = vec![0; module.get_num_channels()];
let mut note_and_sample = vec![None; module.get_num_channels()]; let mut note_and_sample = vec![None; module.get_num_channels()];
let mut previous_retriggers: Vec<Option<u8>> = vec![None; module.get_num_channels()]; let mut previous_retriggers: Vec<Option<(RetriggerVolumeChange, u8)>> =
vec![None; module.get_num_channels()];
for row in pattern.iter() { for row in pattern.iter() {
// the combined jump for each row // the combined jump for each row
@ -411,7 +412,7 @@ pub fn parse_module(module: &Module) -> agb_tracker_interop::Track {
0x9 => { 0x9 => {
let retrigger_amount = slot.effect_parameter & 0xf; let retrigger_amount = slot.effect_parameter & 0xf;
let modified_amount = if retrigger_amount == 0 { let modified_amount = if retrigger_amount == 0 {
if let Some(previous_retrigger) = if let Some((_, previous_retrigger)) =
previous_retriggers[channel_number] previous_retriggers[channel_number]
{ {
previous_retrigger previous_retrigger
@ -419,11 +420,15 @@ pub fn parse_module(module: &Module) -> agb_tracker_interop::Track {
1 1
} }
} else { } else {
previous_retriggers[channel_number] = Some(retrigger_amount); previous_retriggers[channel_number] =
Some((RetriggerVolumeChange::NoChange, retrigger_amount));
retrigger_amount retrigger_amount
}; };
PatternEffect::Retrigger(modified_amount) PatternEffect::Retrigger(
RetriggerVolumeChange::NoChange,
modified_amount,
)
} }
0xA => PatternEffect::FineVolumeSlide( 0xA => PatternEffect::FineVolumeSlide(
Num::new((slot.effect_parameter & 0xf) as i16) / 128, Num::new((slot.effect_parameter & 0xf) as i16) / 128,
@ -465,22 +470,32 @@ pub fn parse_module(module: &Module) -> agb_tracker_interop::Track {
let first = effect_parameter >> 4; let first = effect_parameter >> 4;
let second = effect_parameter & 0xF; let second = effect_parameter & 0xF;
if first != 0 { let previous_retrigger = &mut previous_retriggers[channel_number];
eprintln!("Unsupported retrigger effect volume {first}"); let volume_type = match first {
} 0 => previous_retrigger
.map(|retrigger| retrigger.0)
.unwrap_or(RetriggerVolumeChange::NoChange),
1 => RetriggerVolumeChange::DecreaseByOne,
8 => RetriggerVolumeChange::NoChange,
_ => {
eprintln!("Unsupported retrigger effect volume {first}");
RetriggerVolumeChange::NoChange
}
};
let ticks_between_retriggers = if second == 0 { let ticks_between_retriggers = if second == 0 {
if let Some(previous_retrigger) = previous_retriggers[channel_number] { if let Some((_, previous_retrigger)) = previous_retrigger {
previous_retrigger *previous_retrigger
} else { } else {
1 1
} }
} else { } else {
previous_retriggers[channel_number] = Some(second);
second second
}; };
PatternEffect::Retrigger(ticks_between_retriggers) *previous_retrigger = Some((volume_type, ticks_between_retriggers));
PatternEffect::Retrigger(volume_type, ticks_between_retriggers)
} }
e => { e => {
let effect_char = char::from_digit(e as u32, 36) let effect_char = char::from_digit(e as u32, 36)