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>,
|
frame: Num<u16, 8>,
|
||||||
tick: u16,
|
tick: u16,
|
||||||
|
first: bool,
|
||||||
|
|
||||||
current_row: usize,
|
current_row: usize,
|
||||||
current_pattern: usize,
|
current_pattern: usize,
|
||||||
|
@ -38,18 +39,23 @@ pub struct Tracker {
|
||||||
|
|
||||||
struct TrackerChannel {
|
struct TrackerChannel {
|
||||||
channel_id: Option<ChannelId>,
|
channel_id: Option<ChannelId>,
|
||||||
|
base_speed: Num<u32, 8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Tracker {
|
impl Tracker {
|
||||||
pub fn new(track: &'static Track<'static>) -> Self {
|
pub fn new(track: &'static Track<'static>) -> Self {
|
||||||
let mut channels = Vec::new();
|
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 {
|
Self {
|
||||||
track,
|
track,
|
||||||
channels,
|
channels,
|
||||||
|
|
||||||
frame: 0.into(),
|
frame: 0.into(),
|
||||||
|
first: true,
|
||||||
tick: 0,
|
tick: 0,
|
||||||
|
|
||||||
current_row: 0,
|
current_row: 0,
|
||||||
|
@ -58,9 +64,8 @@ impl Tracker {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn step(&mut self, mixer: &mut Mixer) {
|
pub fn step(&mut self, mixer: &mut Mixer) {
|
||||||
if self.tick != 0 {
|
if !self.increment_frame() {
|
||||||
self.increment_step();
|
return;
|
||||||
return; // TODO: volume / pitch slides
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let pattern_to_play = self.track.patterns_to_play[self.current_pattern];
|
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];
|
&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) {
|
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];
|
let sample = &self.track.samples[pattern_slot.sample - 1];
|
||||||
channel.play_sound(mixer, sample);
|
channel.play_sound(mixer, sample);
|
||||||
}
|
}
|
||||||
|
@ -84,13 +89,17 @@ impl Tracker {
|
||||||
self.increment_step();
|
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;
|
self.frame += 1;
|
||||||
|
|
||||||
if self.frame >= self.track.frames_per_tick {
|
if self.frame >= self.track.frames_per_tick {
|
||||||
self.tick += 1;
|
self.tick += 1;
|
||||||
self.frame -= self.track.frames_per_tick;
|
self.frame -= self.track.frames_per_tick;
|
||||||
}
|
|
||||||
|
|
||||||
if self.tick == self.track.ticks_per_step {
|
if self.tick == self.track.ticks_per_step {
|
||||||
self.current_row += 1;
|
self.current_row += 1;
|
||||||
|
@ -108,7 +117,14 @@ impl Tracker {
|
||||||
|
|
||||||
self.tick = 0;
|
self.tick = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn increment_step(&mut self) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TrackerChannel {
|
impl TrackerChannel {
|
||||||
|
@ -143,6 +159,7 @@ impl TrackerChannel {
|
||||||
{
|
{
|
||||||
if speed != 0.into() {
|
if speed != 0.into() {
|
||||||
channel.playback(speed);
|
channel.playback(speed);
|
||||||
|
self.base_speed = speed;
|
||||||
}
|
}
|
||||||
|
|
||||||
match effect {
|
match effect {
|
||||||
|
@ -150,7 +167,17 @@ impl TrackerChannel {
|
||||||
PatternEffect::Stop => {
|
PatternEffect::Stop => {
|
||||||
channel.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) => {
|
PatternEffect::Panning(panning) => {
|
||||||
channel.panning(*panning);
|
channel.panning(*panning);
|
||||||
}
|
}
|
||||||
|
|
|
@ -104,7 +104,11 @@ pub fn parse_module(module: &Module) -> TokenStream {
|
||||||
let start_pos = pattern_data.len();
|
let start_pos = pattern_data.len();
|
||||||
|
|
||||||
for row in pattern.iter() {
|
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 {
|
let sample = if slot.instrument == 0 {
|
||||||
0
|
0
|
||||||
} else {
|
} else {
|
||||||
|
@ -133,7 +137,54 @@ pub fn parse_module(module: &Module) -> TokenStream {
|
||||||
_ => PatternEffect::None,
|
_ => 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 {
|
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 => {
|
0x8 => {
|
||||||
PatternEffect::Panning(Num::new(slot.effect_parameter as i16 - 128) / 128)
|
PatternEffect::Panning(Num::new(slot.effect_parameter as i16 - 128) / 128)
|
||||||
}
|
}
|
||||||
|
@ -141,10 +192,6 @@ pub fn parse_module(module: &Module) -> TokenStream {
|
||||||
_ => PatternEffect::None,
|
_ => PatternEffect::None,
|
||||||
};
|
};
|
||||||
|
|
||||||
if matches!(slot.note, Note::KeyOff) {
|
|
||||||
effect1 = PatternEffect::Stop;
|
|
||||||
}
|
|
||||||
|
|
||||||
if sample == 0 {
|
if sample == 0 {
|
||||||
pattern_data.push(agb_tracker_interop::PatternSlot {
|
pattern_data.push(agb_tracker_interop::PatternSlot {
|
||||||
speed: 0.into(),
|
speed: 0.into(),
|
||||||
|
|
Loading…
Reference in a new issue