mirror of
https://github.com/italicsjenga/agb.git
synced 2024-12-23 08:11:33 +11:00
Actually make arpeggios work
This commit is contained in:
parent
9b94b2a2cb
commit
203b1a4026
|
@ -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,9 +117,16 @@ impl Tracker {
|
|||
|
||||
self.tick = 0;
|
||||
}
|
||||
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn increment_step(&mut self) {}
|
||||
}
|
||||
|
||||
impl TrackerChannel {
|
||||
fn play_sound(&mut self, mixer: &mut Mixer<'_>, sample: &Sample<'static>) {
|
||||
self.channel_id
|
||||
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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(),
|
||||
|
|
Loading…
Reference in a new issue