Actually make arpeggios work

This commit is contained in:
Gwilym Inzani 2023-07-17 00:27:20 +01:00
parent 9b94b2a2cb
commit 203b1a4026
2 changed files with 97 additions and 23 deletions

View file

@ -31,6 +31,7 @@ pub struct Tracker {
frame: Num<u16, 8>,
tick: u16,
first: bool,
current_row: usize,
current_pattern: usize,
@ -38,18 +39,23 @@ pub struct Tracker {
struct TrackerChannel {
channel_id: Option<ChannelId>,
base_speed: Num<u32, 8>,
}
impl Tracker {
pub fn new(track: &'static Track<'static>) -> Self {
let mut channels = Vec::new();
channels.resize_with(track.num_channels, || TrackerChannel { channel_id: None });
channels.resize_with(track.num_channels, || TrackerChannel {
channel_id: None,
base_speed: 0.into(),
});
Self {
track,
channels,
frame: 0.into(),
first: true,
tick: 0,
current_row: 0,
@ -58,9 +64,8 @@ impl Tracker {
}
pub fn step(&mut self, mixer: &mut Mixer) {
if self.tick != 0 {
self.increment_step();
return; // TODO: volume / pitch slides
if !self.increment_frame() {
return;
}
let pattern_to_play = self.track.patterns_to_play[self.current_pattern];
@ -72,7 +77,7 @@ impl Tracker {
&self.track.pattern_data[pattern_data_pos..pattern_data_pos + self.track.num_channels];
for (channel, pattern_slot) in self.channels.iter_mut().zip(pattern_slots) {
if pattern_slot.sample != 0 {
if pattern_slot.sample != 0 && self.tick == 0 {
let sample = &self.track.samples[pattern_slot.sample - 1];
channel.play_sound(mixer, sample);
}
@ -84,13 +89,17 @@ impl Tracker {
self.increment_step();
}
fn increment_step(&mut self) {
fn increment_frame(&mut self) -> bool {
if self.first {
self.first = false;
return true;
}
self.frame += 1;
if self.frame >= self.track.frames_per_tick {
self.tick += 1;
self.frame -= self.track.frames_per_tick;
}
if self.tick == self.track.ticks_per_step {
self.current_row += 1;
@ -108,7 +117,14 @@ impl Tracker {
self.tick = 0;
}
true
} else {
false
}
}
fn increment_step(&mut self) {}
}
impl TrackerChannel {
@ -143,6 +159,7 @@ impl TrackerChannel {
{
if speed != 0.into() {
channel.playback(speed);
self.base_speed = speed;
}
match effect {
@ -150,7 +167,17 @@ impl TrackerChannel {
PatternEffect::Stop => {
channel.stop();
}
PatternEffect::Arpeggio(_, _) => todo!(),
PatternEffect::Arpeggio(first, second) => {
let first: Num<u32, 8> = first.change_base();
let second: Num<u32, 8> = second.change_base();
match tick % 3 {
0 => channel.playback(self.base_speed),
1 => channel.playback(self.base_speed + first),
2 => channel.playback(self.base_speed + second),
_ => unreachable!(),
};
}
PatternEffect::Panning(panning) => {
channel.panning(*panning);
}

View file

@ -104,7 +104,11 @@ pub fn parse_module(module: &Module) -> TokenStream {
let start_pos = pattern_data.len();
for row in pattern.iter() {
for slot in row {
let mut notes = vec![None; module.get_num_channels()];
for (i, slot) in row.iter().enumerate() {
let channel_number = i % module.get_num_channels();
let sample = if slot.instrument == 0 {
0
} else {
@ -133,7 +137,54 @@ pub fn parse_module(module: &Module) -> TokenStream {
_ => PatternEffect::None,
};
if matches!(slot.note, Note::KeyOff) {
effect1 = PatternEffect::Stop;
notes[channel_number] = None;
} else {
notes[channel_number] = Some(slot.note);
}
let effect2 = match slot.effect_type {
0x0 => {
if slot.effect_parameter == 0 {
PatternEffect::None
} else if let Some(note) = notes[channel_number] {
let first_arpeggio = slot.effect_parameter >> 4;
let second_arpeggio = slot.effect_parameter & 0xF;
let note_speed = note_to_speed(note, 0.0, 0, module.frequency_type);
let note = note as u8;
let first_arpeggio: Note = (note + first_arpeggio)
.try_into()
.expect("Note out of bounds");
let second_arpeggio: Note = (note + second_arpeggio)
.try_into()
.expect("Note out of bounds");
let first_arpeggio_speed =
note_to_speed(first_arpeggio, 0.0, 0, module.frequency_type);
let second_arpeggio_speed =
note_to_speed(second_arpeggio, 0.0, 0, module.frequency_type);
let first_arpeggio_difference = first_arpeggio_speed - note_speed;
let second_arpeggio_difference = second_arpeggio_speed - note_speed;
let first_arpeggio_difference = first_arpeggio_difference
.try_change_base()
.expect("Arpeggio difference too large");
let second_arpeggio_difference = second_arpeggio_difference
.try_change_base()
.expect("Arpeggio difference too large");
PatternEffect::Arpeggio(
first_arpeggio_difference,
second_arpeggio_difference,
)
} else {
PatternEffect::None
}
}
0x8 => {
PatternEffect::Panning(Num::new(slot.effect_parameter as i16 - 128) / 128)
}
@ -141,10 +192,6 @@ pub fn parse_module(module: &Module) -> TokenStream {
_ => PatternEffect::None,
};
if matches!(slot.note, Note::KeyOff) {
effect1 = PatternEffect::Stop;
}
if sample == 0 {
pattern_data.push(agb_tracker_interop::PatternSlot {
speed: 0.into(),