Skip to content
Snippets Groups Projects
Verified Commit 92abbbf0 authored by João Magalhães's avatar João Magalhães :rocket:
Browse files

chore: pass length trigger tests (03-trigger.gb)

There are many quirks to how this works but the unfreeze and thre length clock on enable are the most important ones.
For more information on these options check https://github.com/retrio/gb-test-roms/blob/master/dmg_sound/source/03-trigger.s.
parent d559847e
No related branches found
No related tags found
1 merge request!26Make dmg-audio tests pass
Pipeline #3029 passed
...@@ -719,7 +719,7 @@ struct Args { ...@@ -719,7 +719,7 @@ struct Args {
)] )]
cycles: u64, cycles: u64,
#[arg(short, long, default_value_t = String::from("C:/Users/joamag/Desktop/gb-test-roms/dmg_sound/rom_singles/02-len ctr.gb"), help = "Path to the ROM file to be loaded")] #[arg(short, long, default_value_t = String::from("C:/Users/joamag/Desktop/gb-test-roms/dmg_sound/rom_singles/03-trigger.gb"), help = "Path to the ROM file to be loaded")]
rom_path: String, rom_path: String,
} }
......
...@@ -468,7 +468,7 @@ impl Apu { ...@@ -468,7 +468,7 @@ impl Apu {
} }
// 0xFF11 — NR11: Channel 1 length timer & duty cycle // 0xFF11 — NR11: Channel 1 length timer & duty cycle
0xff11 => { 0xff11 => {
self.ch1_length_timer = value & 0x3f; self.ch1_length_timer = 64 - (value & 0x3f);
self.ch1_wave_duty = (value & 0xc0) >> 6; self.ch1_wave_duty = (value & 0xc0) >> 6;
} }
// 0xFF12 — NR12: Channel 1 volume & envelope // 0xFF12 — NR12: Channel 1 volume & envelope
...@@ -491,14 +491,18 @@ impl Apu { ...@@ -491,14 +491,18 @@ impl Apu {
0xff14 => { 0xff14 => {
let length_trigger = value & 0x40 == 0x40; let length_trigger = value & 0x40 == 0x40;
let trigger = value & 0x80 == 0x80; let trigger = value & 0x80 == 0x80;
let length_edge = length_trigger && !self.ch1_length_enabled;
self.ch1_wave_length = self.ch1_wave_length =
(self.ch1_wave_length & 0x00ff) | (((value & 0x07) as u16) << 8); (self.ch1_wave_length & 0x00ff) | (((value & 0x07) as u16) << 8);
self.ch1_length_enabled = value & 0x40 == 0x40; self.ch1_length_enabled = value & 0x40 == 0x40;
self.ch1_enabled |= value & 0x80 == 0x80; self.ch1_enabled |= value & 0x80 == 0x80;
if length_edge && self.sequencer_step % 2 == 1 {
self.tick_length(Channel::Ch1);
}
if trigger { if trigger {
self.trigger_ch1(); self.trigger_ch1();
} }
if length_trigger && self.ch1_length_timer >= 64 { if length_trigger && self.ch1_length_timer == 0 {
self.ch1_enabled = false; self.ch1_enabled = false;
} }
} }
...@@ -507,7 +511,7 @@ impl Apu { ...@@ -507,7 +511,7 @@ impl Apu {
0xff15 => (), 0xff15 => (),
// 0xFF16 — NR21: Channel 2 length timer & duty cycle // 0xFF16 — NR21: Channel 2 length timer & duty cycle
0xff16 => { 0xff16 => {
self.ch2_length_timer = value & 0x3f; self.ch2_length_timer = 64 - (value & 0x3f);
self.ch2_wave_duty = (value & 0xc0) >> 6; self.ch2_wave_duty = (value & 0xc0) >> 6;
} }
// 0xFF17 — NR22: Channel 2 volume & envelope // 0xFF17 — NR22: Channel 2 volume & envelope
...@@ -530,14 +534,18 @@ impl Apu { ...@@ -530,14 +534,18 @@ impl Apu {
0xff19 => { 0xff19 => {
let length_trigger = value & 0x40 == 0x40; let length_trigger = value & 0x40 == 0x40;
let trigger = value & 0x80 == 0x80; let trigger = value & 0x80 == 0x80;
let length_edge = length_trigger && !self.ch2_length_enabled;
self.ch2_wave_length = self.ch2_wave_length =
(self.ch2_wave_length & 0x00ff) | (((value & 0x07) as u16) << 8); (self.ch2_wave_length & 0x00ff) | (((value & 0x07) as u16) << 8);
self.ch2_length_enabled = length_trigger; self.ch2_length_enabled = length_trigger;
self.ch2_enabled |= trigger; self.ch2_enabled |= trigger;
if length_edge && self.sequencer_step % 2 == 1 {
self.tick_length(Channel::Ch2);
}
if trigger { if trigger {
self.trigger_ch2(); self.trigger_ch2();
} }
if length_trigger && self.ch2_length_timer >= 64 { if length_trigger && self.ch2_length_timer == 0 {
self.ch2_enabled = false; self.ch2_enabled = false;
} }
} }
...@@ -551,7 +559,7 @@ impl Apu { ...@@ -551,7 +559,7 @@ impl Apu {
} }
// 0xFF1B — NR31: Channel 3 length timer // 0xFF1B — NR31: Channel 3 length timer
0xff1b => { 0xff1b => {
self.ch3_length_timer = value as u16; self.ch3_length_timer = 256 - (value as u16);
} }
// 0xFF1C — NR32: Channel 3 output level // 0xFF1C — NR32: Channel 3 output level
0xff1c => { 0xff1c => {
...@@ -565,14 +573,18 @@ impl Apu { ...@@ -565,14 +573,18 @@ impl Apu {
0xff1e => { 0xff1e => {
let length_trigger = value & 0x40 == 0x40; let length_trigger = value & 0x40 == 0x40;
let trigger = value & 0x80 == 0x80; let trigger = value & 0x80 == 0x80;
let length_edge = length_trigger && !self.ch3_length_enabled;
self.ch3_wave_length = self.ch3_wave_length =
(self.ch3_wave_length & 0x00ff) | (((value & 0x07) as u16) << 8); (self.ch3_wave_length & 0x00ff) | (((value & 0x07) as u16) << 8);
self.ch3_length_enabled = length_trigger; self.ch3_length_enabled = length_trigger;
self.ch3_enabled |= trigger; self.ch3_enabled |= trigger;
if length_edge && self.sequencer_step % 2 == 1 {
self.tick_length(Channel::Ch3);
}
if trigger { if trigger {
self.trigger_ch3(); self.trigger_ch3();
} }
if length_trigger && self.ch3_length_timer >= 256 { if length_trigger && self.ch3_length_timer == 0 {
self.ch3_enabled = false; self.ch3_enabled = false;
} }
} }
...@@ -581,7 +593,7 @@ impl Apu { ...@@ -581,7 +593,7 @@ impl Apu {
0xff1f => (), 0xff1f => (),
// 0xFF20 — NR41: Channel 4 length timer // 0xFF20 — NR41: Channel 4 length timer
0xff20 => { 0xff20 => {
self.ch4_length_timer = value & 0x3f; self.ch4_length_timer = 64 - (value & 0x3f);
} }
// 0xFF21 — NR42: Channel 4 volume & envelope // 0xFF21 — NR42: Channel 4 volume & envelope
0xff21 => { 0xff21 => {
...@@ -605,12 +617,16 @@ impl Apu { ...@@ -605,12 +617,16 @@ impl Apu {
0xff23 => { 0xff23 => {
let length_trigger = value & 0x40 == 0x40; let length_trigger = value & 0x40 == 0x40;
let trigger = value & 0x80 == 0x80; let trigger = value & 0x80 == 0x80;
let length_edge = length_trigger && !self.ch4_length_enabled;
self.ch4_length_enabled = length_trigger; self.ch4_length_enabled = length_trigger;
self.ch4_enabled |= trigger; self.ch4_enabled |= trigger;
if length_edge && self.sequencer_step % 2 == 1 {
self.tick_length(Channel::Ch4);
}
if trigger { if trigger {
self.trigger_ch4(); self.trigger_ch4();
} }
if length_trigger && self.ch4_length_timer >= 64 { if length_trigger && self.ch4_length_timer == 0 {
self.ch4_enabled = false; self.ch4_enabled = false;
} }
} }
...@@ -746,43 +762,39 @@ impl Apu { ...@@ -746,43 +762,39 @@ impl Apu {
fn tick_length(&mut self, channel: Channel) { fn tick_length(&mut self, channel: Channel) {
match channel { match channel {
Channel::Ch1 => { Channel::Ch1 => {
if !self.ch1_length_enabled { if !self.ch1_length_enabled || self.ch1_length_timer == 0 {
return; return;
} }
self.ch1_length_timer = self.ch1_length_timer.saturating_add(1); self.ch1_length_timer = self.ch1_length_timer.saturating_sub(1);
if self.ch1_length_timer >= 64 { if self.ch1_length_timer == 0 {
self.ch1_enabled = false; self.ch1_enabled = false;
self.ch1_length_timer = 0;
} }
} }
Channel::Ch2 => { Channel::Ch2 => {
if !self.ch2_length_enabled { if !self.ch2_length_enabled || self.ch2_length_timer == 0 {
return; return;
} }
self.ch2_length_timer = self.ch2_length_timer.saturating_add(1); self.ch2_length_timer = self.ch2_length_timer.saturating_sub(1);
if self.ch2_length_timer >= 64 { if self.ch2_length_timer == 0 {
self.ch2_enabled = false; self.ch2_enabled = false;
self.ch2_length_timer = 0;
} }
} }
Channel::Ch3 => { Channel::Ch3 => {
if !self.ch3_length_enabled { if !self.ch3_length_enabled || self.ch3_length_timer == 0 {
return; return;
} }
self.ch3_length_timer = self.ch3_length_timer.saturating_add(1); self.ch3_length_timer = self.ch3_length_timer.saturating_sub(1);
if self.ch3_length_timer >= 256 { if self.ch3_length_timer == 0 {
self.ch3_enabled = false; self.ch3_enabled = false;
self.ch3_length_timer = 0;
} }
} }
Channel::Ch4 => { Channel::Ch4 => {
if !self.ch4_length_enabled { if !self.ch4_length_enabled || self.ch4_length_timer == 0 {
return; return;
} }
self.ch4_length_timer = self.ch4_length_timer.saturating_add(1); self.ch4_length_timer = self.ch4_length_timer.saturating_sub(1);
if self.ch4_length_timer >= 64 { if self.ch4_length_timer == 0 {
self.ch4_enabled = false; self.ch4_enabled = false;
self.ch4_length_timer = 0;
} }
} }
} }
...@@ -994,18 +1006,42 @@ impl Apu { ...@@ -994,18 +1006,42 @@ impl Apu {
self.ch1_timer = ((2048 - self.ch1_wave_length) << 2) as i16; self.ch1_timer = ((2048 - self.ch1_wave_length) << 2) as i16;
self.ch1_envelope_sequence = 0; self.ch1_envelope_sequence = 0;
self.ch1_sweep_sequence = 0; self.ch1_sweep_sequence = 0;
let unfreeze = self.ch1_length_timer == 0;
if unfreeze {
self.ch1_length_timer = 64;
if self.ch1_length_enabled && self.sequencer_step % 2 == 1 {
self.tick_length(Channel::Ch1);
}
}
} }
#[inline(always)] #[inline(always)]
fn trigger_ch2(&mut self) { fn trigger_ch2(&mut self) {
self.ch2_timer = ((2048 - self.ch2_wave_length) << 2) as i16; self.ch2_timer = ((2048 - self.ch2_wave_length) << 2) as i16;
self.ch2_envelope_sequence = 0; self.ch2_envelope_sequence = 0;
let unfreeze = self.ch2_length_timer == 0;
if unfreeze {
self.ch2_length_timer = 64;
if self.ch2_length_enabled && self.sequencer_step % 2 == 1 {
self.tick_length(Channel::Ch2);
}
}
} }
#[inline(always)] #[inline(always)]
fn trigger_ch3(&mut self) { fn trigger_ch3(&mut self) {
self.ch3_timer = 3; self.ch3_timer = 3;
self.ch3_position = 0; self.ch3_position = 0;
let unfreeze = self.ch3_length_timer == 0;
if unfreeze {
self.ch3_length_timer = 256;
if self.ch3_length_enabled && self.sequencer_step % 2 == 1 {
self.tick_length(Channel::Ch3);
}
}
} }
#[inline(always)] #[inline(always)]
...@@ -1014,6 +1050,14 @@ impl Apu { ...@@ -1014,6 +1050,14 @@ impl Apu {
((CH4_DIVISORS[self.ch4_divisor as usize] as u16) << self.ch4_clock_shift) as i32; ((CH4_DIVISORS[self.ch4_divisor as usize] as u16) << self.ch4_clock_shift) as i32;
self.ch4_lfsr = 0x7ff1; self.ch4_lfsr = 0x7ff1;
self.ch4_envelope_sequence = 0; self.ch4_envelope_sequence = 0;
let unfreeze = self.ch4_length_timer == 0;
if unfreeze {
self.ch4_length_timer = 64;
if self.ch4_length_enabled && self.sequencer_step % 2 == 1 {
self.tick_length(Channel::Ch4);
}
}
} }
} }
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment