Emulate CGB-C’s quirky LFSR function

This commit is contained in:
Lior Halphon 2018-07-04 21:55:12 +03:00
parent f3437d7cc0
commit dc5cb71c22
2 changed files with 16 additions and 5 deletions

View File

@ -365,7 +365,7 @@ void GB_apu_run(GB_gameboy_t *gb)
/* Step LFSR */ /* Step LFSR */
unsigned high_bit_mask = gb->apu.noise_channel.narrow ? 0x4040 : 0x4000; unsigned high_bit_mask = gb->apu.noise_channel.narrow ? 0x4040 : 0x4000;
// This formula is different on a GBA! /* Todo: is this formula is different on a GBA? */
bool new_high_bit = (gb->apu.noise_channel.lfsr ^ (gb->apu.noise_channel.lfsr >> 1) ^ 1) & 1; bool new_high_bit = (gb->apu.noise_channel.lfsr ^ (gb->apu.noise_channel.lfsr >> 1) ^ 1) & 1;
gb->apu.noise_channel.lfsr >>= 1; gb->apu.noise_channel.lfsr >>= 1;
@ -377,8 +377,17 @@ void GB_apu_run(GB_gameboy_t *gb)
gb->apu.noise_channel.lfsr &= ~high_bit_mask; gb->apu.noise_channel.lfsr &= ~high_bit_mask;
} }
gb->apu.current_lfsr_sample = gb->apu.noise_channel.lfsr & 1;
if (gb->model == GB_MODEL_CGB_C) {
/* Todo: This was confirmed to happen on a CGB-C. This may or may not happen on pre-CGB models.
Because this degrades audio quality, and testing this on a pre-CGB device requires audio records,
I'll assume these devices are innocent until proven guilty. */
gb->apu.current_lfsr_sample &= gb->apu.previous_lfsr_sample;
}
gb->apu.previous_lfsr_sample = gb->apu.noise_channel.lfsr & 1;
update_sample(gb, GB_NOISE, update_sample(gb, GB_NOISE,
(gb->apu.noise_channel.lfsr & 1) ? gb->apu.current_lfsr_sample ?
gb->apu.noise_channel.current_volume : 0, gb->apu.noise_channel.current_volume : 0,
0); 0);
} }
@ -776,7 +785,7 @@ void GB_apu_write(GB_gameboy_t *gb, uint8_t reg, uint8_t value)
else if (gb->apu.is_active[GB_NOISE]){ else if (gb->apu.is_active[GB_NOISE]){
nrx2_glitch(&gb->apu.noise_channel.current_volume, value, gb->io_registers[reg]); nrx2_glitch(&gb->apu.noise_channel.current_volume, value, gb->io_registers[reg]);
update_sample(gb, GB_NOISE, update_sample(gb, GB_NOISE,
(gb->apu.noise_channel.lfsr & 1) ? gb->apu.current_lfsr_sample ?
gb->apu.noise_channel.current_volume : 0, gb->apu.noise_channel.current_volume : 0,
0); 0);
} }
@ -821,11 +830,12 @@ void GB_apu_write(GB_gameboy_t *gb, uint8_t reg, uint8_t value)
cases. */ cases. */
if (gb->apu.is_active[GB_NOISE]) { if (gb->apu.is_active[GB_NOISE]) {
update_sample(gb, GB_NOISE, update_sample(gb, GB_NOISE,
(gb->apu.noise_channel.lfsr & 1) ? gb->apu.current_lfsr_sample ?
gb->apu.noise_channel.current_volume : 0, gb->apu.noise_channel.current_volume : 0,
0); 0);
} }
gb->apu.noise_channel.lfsr = 0; gb->apu.noise_channel.lfsr = 0;
gb->apu.current_lfsr_sample = false;
gb->apu.noise_channel.volume_countdown = gb->io_registers[GB_IO_NR42] & 7; gb->apu.noise_channel.volume_countdown = gb->io_registers[GB_IO_NR42] & 7;
if (!gb->apu.is_active[GB_NOISE] && (gb->io_registers[GB_IO_NR42] & 0xF8) != 0) { if (!gb->apu.is_active[GB_NOISE] && (gb->io_registers[GB_IO_NR42] & 0xF8) != 0) {

View File

@ -109,7 +109,8 @@ typedef struct
} noise_channel; } noise_channel;
bool skip_div_event; bool skip_div_event;
bool current_lfsr_sample;
bool previous_lfsr_sample;
} GB_apu_t; } GB_apu_t;
typedef enum { typedef enum {