diff --git a/Core/apu.c b/Core/apu.c index e98f8044..c337aed9 100644 --- a/Core/apu.c +++ b/Core/apu.c @@ -289,6 +289,19 @@ static void update_square_sample(GB_gameboy_t *gb, unsigned index) 0); } +static inline void update_wave_sample(GB_gameboy_t *gb, unsigned cycles) +{ + if (gb->apu.wave_channel.current_sample_index & 1) { + update_sample(gb, GB_WAVE, + (gb->apu.wave_channel.current_sample_byte & 0xF) >> gb->apu.wave_channel.shift, + cycles); + } + else { + update_sample(gb, GB_WAVE, + (gb->apu.wave_channel.current_sample_byte >> 4) >> gb->apu.wave_channel.shift, + cycles); + } +} /* the effects of NRX2 writes on current volume are not well documented and differ between models and variants. The exact behavior can only be verified on CGB as it @@ -665,11 +678,9 @@ void GB_apu_run(GB_gameboy_t *gb) gb->apu.wave_channel.sample_countdown = gb->apu.wave_channel.sample_length ^ 0x7FF; gb->apu.wave_channel.current_sample_index++; gb->apu.wave_channel.current_sample_index &= 0x1F; - gb->apu.wave_channel.current_sample = - gb->apu.wave_channel.wave_form[gb->apu.wave_channel.current_sample_index]; - update_sample(gb, GB_WAVE, - gb->apu.wave_channel.current_sample >> gb->apu.wave_channel.shift, - cycles - cycles_left); + gb->apu.wave_channel.current_sample_byte = + gb->io_registers[GB_IO_WAV_START + (gb->apu.wave_channel.current_sample_index >> 1)]; + update_wave_sample(gb, cycles - cycles_left); gb->apu.wave_channel.wave_form_just_read = true; } if (cycles_left) { @@ -729,11 +740,6 @@ void GB_apu_run(GB_gameboy_t *gb) void GB_apu_init(GB_gameboy_t *gb) { memset(&gb->apu, 0, sizeof(gb->apu)); - /* Restore the wave form */ - for (unsigned reg = GB_IO_WAV_START; reg <= GB_IO_WAV_END; reg++) { - gb->apu.wave_channel.wave_form[(reg - GB_IO_WAV_START) * 2] = gb->io_registers[reg] >> 4; - gb->apu.wave_channel.wave_form[(reg - GB_IO_WAV_START) * 2 + 1] = gb->io_registers[reg] & 0xF; - } gb->apu.lf_div = 1; gb->apu.wave_channel.shift = 4; /* APU glitch: When turning the APU on while DIV's bit 4 (or 5 in double speed mode) is on, @@ -1150,6 +1156,15 @@ void GB_apu_write(GB_gameboy_t *gb, uint8_t reg, uint8_t value) case GB_IO_NR30: gb->apu.wave_channel.enable = value & 0x80; if (!gb->apu.wave_channel.enable) { + if (gb->apu.is_active[GB_WAVE]) { + // Todo: I assume this happens on pre-CGB models; test this with an audible test + if (gb->apu.wave_channel.sample_countdown == 0 && gb->model < GB_MODEL_AGB) { + gb->apu.wave_channel.current_sample_byte = gb->io_registers[GB_IO_WAV_START + 5]; // what the actual fuck? Why specifically this wave address ? + } + else if (gb->apu.wave_channel.wave_form_just_read && gb->model <= GB_MODEL_CGB_C) { + gb->apu.wave_channel.current_sample_byte = gb->io_registers[GB_IO_WAV_START + 0xA]; // what the actual fuck? Why specifically this wave address? + } + } gb->apu.is_active[GB_WAVE] = false; update_sample(gb, GB_WAVE, 0, 0); } @@ -1160,7 +1175,7 @@ void GB_apu_write(GB_gameboy_t *gb, uint8_t reg, uint8_t value) case GB_IO_NR32: gb->apu.wave_channel.shift = (uint8_t[]){4, 0, 1, 2}[(value >> 5) & 3]; if (gb->apu.is_active[GB_WAVE]) { - update_sample(gb, GB_WAVE, gb->apu.wave_channel.current_sample >> gb->apu.wave_channel.shift, 0); + update_wave_sample(gb, 0); } break; case GB_IO_NR33: @@ -1187,26 +1202,24 @@ void GB_apu_write(GB_gameboy_t *gb, uint8_t reg, uint8_t value) are all deterministic. */ if (offset < 4) { gb->io_registers[GB_IO_WAV_START] = gb->io_registers[GB_IO_WAV_START + offset]; - gb->apu.wave_channel.wave_form[0] = gb->apu.wave_channel.wave_form[offset / 2]; - gb->apu.wave_channel.wave_form[1] = gb->apu.wave_channel.wave_form[offset / 2 + 1]; } else { memcpy(gb->io_registers + GB_IO_WAV_START, gb->io_registers + GB_IO_WAV_START + (offset & ~3), 4); - memcpy(gb->apu.wave_channel.wave_form, - gb->apu.wave_channel.wave_form + (offset & ~3) * 2, - 8); } } - if (!gb->apu.is_active[GB_WAVE] && gb->apu.wave_channel.enable) { + gb->apu.wave_channel.current_sample_index = 0; + if (gb->apu.is_active[GB_WAVE] && gb->apu.wave_channel.sample_countdown == 0) { + gb->apu.wave_channel.current_sample_byte = gb->io_registers[GB_IO_WAV_START]; + } + if (gb->apu.wave_channel.enable) { gb->apu.is_active[GB_WAVE] = true; update_sample(gb, GB_WAVE, - gb->apu.wave_channel.current_sample >> gb->apu.wave_channel.shift, + (gb->apu.wave_channel.current_sample_byte >> 4) >> gb->apu.wave_channel.shift, 0); } gb->apu.wave_channel.sample_countdown = (gb->apu.wave_channel.sample_length ^ 0x7FF) + 3; - gb->apu.wave_channel.current_sample_index = 0; if (gb->apu.wave_channel.pulse_length == 0) { gb->apu.wave_channel.pulse_length = 0x100; gb->apu.wave_channel.length_enabled = false; @@ -1396,12 +1409,6 @@ void GB_apu_write(GB_gameboy_t *gb, uint8_t reg, uint8_t value) gb->apu.noise_channel.length_enabled = value & 0x40; break; } - - default: - if (reg >= GB_IO_WAV_START && reg <= GB_IO_WAV_END) { - gb->apu.wave_channel.wave_form[(reg - GB_IO_WAV_START) * 2] = value >> 4; - gb->apu.wave_channel.wave_form[(reg - GB_IO_WAV_START) * 2 + 1] = value & 0xF; - } } gb->io_registers[reg] = value; } diff --git a/Core/apu.h b/Core/apu.h index e44b0b6f..57c59768 100644 --- a/Core/apu.h +++ b/Core/apu.h @@ -99,9 +99,9 @@ typedef struct uint16_t sample_countdown; // in APU ticks (Reloaded from sample_length, xorred $7FF) uint8_t current_sample_index; - uint8_t current_sample; // Current sample before shifting. + uint8_t current_sample_byte; // Current sample byte. - int8_t wave_form[32]; + GB_PADDING(int8_t, wave_form)[32]; bool wave_form_just_read; } wave_channel; diff --git a/Core/debugger.c b/Core/debugger.c index f7f33358..04327fec 100644 --- a/Core/debugger.c +++ b/Core/debugger.c @@ -1797,8 +1797,9 @@ static bool apu(GB_gameboy_t *gb, char *arguments, char *modifiers, const debugg GB_log(gb, "\nCH3:\n"); GB_log(gb, " Wave:"); - for (uint8_t i = 0; i < 32; i++) { - GB_log(gb, "%s%X", i%4?"":" ", gb->apu.wave_channel.wave_form[i]); + for (uint8_t i = 0; i < 16; i++) { + GB_log(gb, "%s%X", i % 2? "" : " ", gb->io_registers[GB_IO_WAV_START + i] >> 4); + GB_log(gb, "%s%X", i % 2? "" : " ", gb->io_registers[GB_IO_WAV_START + i] & 0xF); } GB_log(gb, "\n"); GB_log(gb, " Current position: %u\n", gb->apu.wave_channel.current_sample_index); @@ -1880,11 +1881,14 @@ static bool wave(GB_gameboy_t *gb, char *arguments, char *modifiers, const debug for (int8_t cur_val = 0xf & mask; cur_val >= 0; cur_val -= shift_amount) { for (uint8_t i = 0; i < 32; i++) { - if ((gb->apu.wave_channel.wave_form[i] & mask) == cur_val) { - GB_log(gb, "%X", gb->apu.wave_channel.wave_form[i]); + uint8_t sample = i & 1? + (gb->io_registers[GB_IO_WAV_START + i / 2] & 0xF) : + (gb->io_registers[GB_IO_WAV_START + i / 2] >> 4); + if ((sample & mask) == cur_val) { + GB_log(gb, "%X", sample); } else { - GB_log(gb, "%c", i%4 == 2 ? '-' : ' '); + GB_log(gb, "%c", i % 4 == 2 ? '-' : ' '); } } GB_log(gb, "\n"); diff --git a/Core/gb.c b/Core/gb.c index 9fbee627..a845797a 100644 --- a/Core/gb.c +++ b/Core/gb.c @@ -1536,18 +1536,13 @@ static void reset_ram(GB_gameboy_t *gb) case GB_MODEL_SGB_PAL_NO_SFC: /* Unverified */ case GB_MODEL_SGB2: case GB_MODEL_SGB2_NO_SFC: { - uint8_t temp; for (unsigned i = 0; i < GB_IO_WAV_END - GB_IO_WAV_START; i++) { if (i & 1) { - temp = GB_random() & GB_random() & GB_random(); + gb->io_registers[GB_IO_WAV_START + i] = GB_random() & GB_random() & GB_random(); } else { - temp = GB_random() | GB_random() | GB_random(); + gb->io_registers[GB_IO_WAV_START + i] = GB_random() | GB_random() | GB_random(); } - gb->apu.wave_channel.wave_form[i * 2] = temp >> 4; - gb->apu.wave_channel.wave_form[i * 2 + 1] = temp & 0xF; - gb->io_registers[GB_IO_WAV_START + i] = temp; - } break; }