mirror of
https://github.com/italicsjenga/agb.git
synced 2024-12-23 08:11:33 +11:00
Update tracker to support PatternBreak and PositionJump
This commit is contained in:
parent
4a3792b248
commit
da92ec3b8b
|
@ -29,6 +29,16 @@ pub struct Sample {
|
|||
pub fadeout: Num<i32, 8>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum Jump {
|
||||
/// Jump to the given pattern position `pattern` at row index 0
|
||||
Position { pattern: u8 },
|
||||
/// Jump to the next pattern position, at row index `row`
|
||||
PatternBreak { row: u8 },
|
||||
/// Jump to the pattern position `pattern` at row index `row`
|
||||
Combined { pattern: u8, row: u8 },
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Pattern {
|
||||
pub length: usize,
|
||||
|
@ -82,6 +92,7 @@ pub enum PatternEffect {
|
|||
GlobalVolumeSlide(Num<i32, 8>),
|
||||
/// Increase / decrease the pitch by the specified amount immediately
|
||||
PitchBend(Num<u32, 8>),
|
||||
Jump(Jump),
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
|
@ -92,6 +103,31 @@ pub enum Waveform {
|
|||
Square,
|
||||
}
|
||||
|
||||
#[cfg(feature = "quote")]
|
||||
impl quote::ToTokens for Jump {
|
||||
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
|
||||
use quote::{quote, TokenStreamExt};
|
||||
|
||||
let type_bit = match self {
|
||||
Jump::Position { pattern } => {
|
||||
quote! {Position{pattern: #pattern} }
|
||||
}
|
||||
Jump::PatternBreak { row } => {
|
||||
quote! { PatternBreak{row: #row} }
|
||||
}
|
||||
Jump::Combined { pattern, row } => {
|
||||
quote! {
|
||||
Combined{pattern: #pattern, row: #row }
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
tokens.append_all(quote! {
|
||||
agb_tracker::__private::agb_tracker_interop::Jump::#type_bit
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "quote")]
|
||||
impl quote::ToTokens for Track {
|
||||
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
|
||||
|
@ -286,6 +322,7 @@ impl quote::ToTokens for Pattern {
|
|||
} = self;
|
||||
|
||||
tokens.append_all(quote! {
|
||||
|
||||
agb_tracker::__private::agb_tracker_interop::Pattern {
|
||||
length: #length,
|
||||
start_position: #start_position,
|
||||
|
@ -361,6 +398,9 @@ impl quote::ToTokens for PatternEffect {
|
|||
let amount = amount.to_raw();
|
||||
quote! { Vibrato(#waveform, agb_tracker::__private::Num::from_raw(#amount), #speed) }
|
||||
}
|
||||
PatternEffect::Jump(jump) => {
|
||||
quote! { Jump(#jump) }
|
||||
}
|
||||
};
|
||||
|
||||
tokens.append_all(quote! {
|
||||
|
|
|
@ -68,7 +68,7 @@ extern crate alloc;
|
|||
mod lookups;
|
||||
mod mixer;
|
||||
|
||||
use agb_tracker_interop::{PatternEffect, Sample, Waveform};
|
||||
use agb_tracker_interop::{Jump, PatternEffect, Sample, Waveform};
|
||||
use alloc::vec::Vec;
|
||||
|
||||
pub use mixer::{Mixer, SoundChannel};
|
||||
|
@ -111,6 +111,7 @@ pub struct TrackerInner<'track, TChannelId> {
|
|||
|
||||
current_row: usize,
|
||||
current_pattern: usize,
|
||||
current_jump: Option<Jump>,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
|
@ -204,6 +205,7 @@ impl<'track, TChannelId> TrackerInner<'track, TChannelId> {
|
|||
|
||||
current_pattern: 0,
|
||||
current_row: 0,
|
||||
current_jump: None,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -269,12 +271,14 @@ impl<'track, TChannelId> TrackerInner<'track, TChannelId> {
|
|||
self.tick,
|
||||
&mut self.global_settings,
|
||||
&mut self.envelopes[i],
|
||||
&mut self.current_jump,
|
||||
);
|
||||
channel.apply_effect(
|
||||
&pattern_slot.effect2,
|
||||
self.tick,
|
||||
&mut self.global_settings,
|
||||
&mut self.envelopes[i],
|
||||
&mut self.current_jump,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -373,10 +377,14 @@ impl<'track, TChannelId> TrackerInner<'track, TChannelId> {
|
|||
self.frame -= self.global_settings.frames_per_tick;
|
||||
|
||||
if self.tick >= self.global_settings.ticks_per_step {
|
||||
if let Some(jump) = self.current_jump.take() {
|
||||
self.handle_jump(jump);
|
||||
} else {
|
||||
self.current_row += 1;
|
||||
|
||||
if self.current_row
|
||||
>= self.track.patterns[self.track.patterns_to_play[self.current_pattern]].length
|
||||
>= self.track.patterns[self.track.patterns_to_play[self.current_pattern]]
|
||||
.length
|
||||
{
|
||||
self.current_pattern += 1;
|
||||
self.current_row = 0;
|
||||
|
@ -385,6 +393,7 @@ impl<'track, TChannelId> TrackerInner<'track, TChannelId> {
|
|||
self.current_pattern = self.track.repeat;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.tick = 0;
|
||||
}
|
||||
|
@ -394,6 +403,32 @@ impl<'track, TChannelId> TrackerInner<'track, TChannelId> {
|
|||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_jump(&mut self, jump: Jump) {
|
||||
match jump {
|
||||
Jump::Position { pattern } => {
|
||||
self.current_pattern = pattern as usize;
|
||||
self.current_row = 0;
|
||||
}
|
||||
Jump::PatternBreak { row } => {
|
||||
self.current_pattern += 1;
|
||||
self.current_row = row as usize;
|
||||
}
|
||||
Jump::Combined { pattern, row } => {
|
||||
self.current_pattern = pattern as usize;
|
||||
self.current_row = row as usize;
|
||||
}
|
||||
};
|
||||
if self.current_pattern >= self.track.patterns_to_play.len() {
|
||||
self.current_pattern = self.track.repeat;
|
||||
}
|
||||
if self.current_row
|
||||
>= self.track.patterns[self.track.patterns_to_play[self.current_pattern]].length
|
||||
{
|
||||
// TODO: reconsider this default
|
||||
self.current_row = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TrackerChannel {
|
||||
|
@ -419,6 +454,7 @@ impl TrackerChannel {
|
|||
tick: u32,
|
||||
global_settings: &mut GlobalSettings,
|
||||
envelope_state: &mut Option<EnvelopeState>,
|
||||
current_jump: &mut Option<Jump>,
|
||||
) {
|
||||
match effect {
|
||||
PatternEffect::None => {}
|
||||
|
@ -547,6 +583,9 @@ impl TrackerChannel {
|
|||
self.vibrato.waveform = *waveform;
|
||||
self.vibrato.enable = true;
|
||||
}
|
||||
PatternEffect::Jump(jump) => {
|
||||
*current_jump = Some(jump.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use std::collections::HashMap;
|
||||
|
||||
use agb_fixnum::Num;
|
||||
use agb_tracker_interop::{PatternEffect, Waveform};
|
||||
use agb_tracker_interop::{Jump, PatternEffect, Waveform};
|
||||
|
||||
use xmrs::prelude::*;
|
||||
|
||||
|
@ -101,6 +101,9 @@ pub fn parse_module(module: &Module) -> agb_tracker_interop::Track {
|
|||
let mut note_and_sample = vec![None; module.get_num_channels()];
|
||||
|
||||
for row in pattern.iter() {
|
||||
// the combined jump for each row
|
||||
let mut jump = None;
|
||||
|
||||
for (i, slot) in row.iter().enumerate() {
|
||||
let channel_number = i % module.get_num_channels();
|
||||
|
||||
|
@ -319,6 +322,18 @@ pub fn parse_module(module: &Module) -> agb_tracker_interop::Track {
|
|||
)
|
||||
}
|
||||
}
|
||||
0xB => {
|
||||
let pattern_idx = slot.effect_parameter;
|
||||
|
||||
jump = Some((
|
||||
channel_number,
|
||||
Jump::Position {
|
||||
pattern: pattern_idx,
|
||||
},
|
||||
));
|
||||
|
||||
PatternEffect::None
|
||||
}
|
||||
0xC => {
|
||||
if let Some((_, sample)) = maybe_note_and_sample {
|
||||
PatternEffect::Volume(
|
||||
|
@ -328,6 +343,29 @@ pub fn parse_module(module: &Module) -> agb_tracker_interop::Track {
|
|||
PatternEffect::None
|
||||
}
|
||||
}
|
||||
0xD => {
|
||||
// NOTE: this field is generally interpreted as decimal.
|
||||
let first = slot.effect_parameter >> 4;
|
||||
let second = slot.effect_parameter & 0xF;
|
||||
let row_idx = first * 10 + second;
|
||||
|
||||
let pattern_break = Jump::PatternBreak { row: row_idx };
|
||||
|
||||
// if to the *right* of 0xD effect, make combined
|
||||
if let Some((idx, Jump::Position { pattern })) = jump {
|
||||
jump = Some((
|
||||
idx,
|
||||
Jump::Combined {
|
||||
pattern,
|
||||
row: row_idx,
|
||||
},
|
||||
))
|
||||
} else {
|
||||
jump = Some((channel_number, pattern_break));
|
||||
}
|
||||
|
||||
PatternEffect::None
|
||||
}
|
||||
0xE => match slot.effect_parameter >> 4 {
|
||||
0x1 => {
|
||||
let c4_speed: Num<u32, 12> =
|
||||
|
@ -433,6 +471,16 @@ pub fn parse_module(module: &Module) -> agb_tracker_interop::Track {
|
|||
});
|
||||
}
|
||||
}
|
||||
// At the last channel, evaluate the combined jump,
|
||||
// and place at the first jump effect channel index
|
||||
if let Some((jump_channel, jump)) = jump.take() {
|
||||
let jump_effect = PatternEffect::Jump(jump);
|
||||
let pattern_data_idx =
|
||||
pattern_data.len() - module.get_num_channels() + jump_channel;
|
||||
if let Some(data) = pattern_data.get_mut(pattern_data_idx) {
|
||||
data.effect2 = jump_effect;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
patterns.push(agb_tracker_interop::Pattern {
|
||||
|
|
Loading…
Reference in a new issue