diff --git a/Core/apu.c b/Core/apu.c index afb970c..7e7ab31 100644 --- a/Core/apu.c +++ b/Core/apu.c @@ -283,6 +283,15 @@ static void tick_square_envelope(GB_gameboy_t *gb, enum GB_CHANNELS index) if (gb->apu.square_channels[index].volume_countdown || (nrx2 & 7)) { if (!gb->apu.square_channels[index].volume_countdown || !--gb->apu.square_channels[index].volume_countdown) { + if (gb->cgb_double_speed) { + if (index == GB_SQUARE_1) { + gb->apu.pcm_mask[0] &= gb->apu.square_channels[GB_SQUARE_1].current_volume | 0xF1; + } + else { + gb->apu.pcm_mask[0] &= (gb->apu.square_channels[GB_SQUARE_2].current_volume << 2) | 0x1F; + } + } + if ((nrx2 & 8) && gb->apu.square_channels[index].current_volume < 0xF) { gb->apu.square_channels[index].current_volume++; } @@ -305,7 +314,10 @@ static void tick_noise_envelope(GB_gameboy_t *gb) uint8_t nr42 = gb->io_registers[GB_IO_NR42]; if (gb->apu.noise_channel.volume_countdown || (nr42 & 7)) { - if (!--gb->apu.noise_channel.volume_countdown) { + if (!gb->apu.noise_channel.volume_countdown || !--gb->apu.noise_channel.volume_countdown) { + if (gb->cgb_double_speed) { + gb->apu.pcm_mask[0] &= (gb->apu.noise_channel.current_volume << 2) | 0x1F; + } if ((nr42 & 8) && gb->apu.noise_channel.current_volume < 0xF) { gb->apu.noise_channel.current_volume++; } @@ -423,7 +435,7 @@ void GB_apu_run(GB_gameboy_t *gb) uint8_t cycles = gb->apu.apu_cycles >> 2; gb->apu.apu_cycles = 0; if (!cycles) return; - + if (likely(!gb->stopped || GB_is_cgb(gb))) { /* To align the square signal to 1MHz */ gb->apu.lf_div ^= cycles & 1; @@ -455,6 +467,9 @@ void GB_apu_run(GB_gameboy_t *gb) gb->apu.square_channels[i].sample_countdown = (gb->apu.square_channels[i].sample_length ^ 0x7FF) * 2 + 1; gb->apu.square_channels[i].current_sample_index++; gb->apu.square_channels[i].current_sample_index &= 0x7; + if (cycles_left == 0 && gb->apu.samples[i] == 0) { + gb->apu.pcm_mask[0] &= i == GB_SQUARE_1? 0xF0 : 0x0F; + } update_square_sample(gb, i); } @@ -506,6 +521,10 @@ void GB_apu_run(GB_gameboy_t *gb) gb->apu.current_lfsr_sample = gb->apu.noise_channel.lfsr & 1; + if (cycles_left == 0 && gb->apu.samples[GB_NOISE] == 0) { + gb->apu.pcm_mask[1] &= 0x0F; + } + update_sample(gb, GB_NOISE, gb->apu.current_lfsr_sample ? gb->apu.noise_channel.current_volume : 0, diff --git a/Core/apu.h b/Core/apu.h index 398b903..a3a36a6 100644 --- a/Core/apu.h +++ b/Core/apu.h @@ -119,6 +119,7 @@ typedef struct #define GB_SKIP_DIV_EVENT_SKIP 2 uint8_t skip_div_event; bool current_lfsr_sample; + uint8_t pcm_mask[2]; // For CGB-0 to CGB-C PCM read glitch } GB_apu_t; typedef enum { diff --git a/Core/memory.c b/Core/memory.c index 49296dd..9f52af5 100644 --- a/Core/memory.c +++ b/Core/memory.c @@ -303,12 +303,12 @@ static uint8_t read_high_memory(GB_gameboy_t *gb, uint16_t addr) case GB_IO_PCM_12: if (!GB_is_cgb(gb)) return 0xFF; - return (gb->apu.is_active[GB_SQUARE_2] ? (gb->apu.samples[GB_SQUARE_2] << 4) : 0) | - (gb->apu.is_active[GB_SQUARE_1] ? (gb->apu.samples[GB_SQUARE_1]) : 0); + return ((gb->apu.is_active[GB_SQUARE_2] ? (gb->apu.samples[GB_SQUARE_2] << 4) : 0) | + (gb->apu.is_active[GB_SQUARE_1] ? (gb->apu.samples[GB_SQUARE_1]) : 0)) & (gb->model <= GB_MODEL_CGB_C? gb->apu.pcm_mask[0] : 0xFF); case GB_IO_PCM_34: if (!GB_is_cgb(gb)) return 0xFF; - return (gb->apu.is_active[GB_NOISE] ? (gb->apu.samples[GB_NOISE] << 4) : 0) | - (gb->apu.is_active[GB_WAVE] ? (gb->apu.samples[GB_WAVE]) : 0); + return ((gb->apu.is_active[GB_NOISE] ? (gb->apu.samples[GB_NOISE] << 4) : 0) | + (gb->apu.is_active[GB_WAVE] ? (gb->apu.samples[GB_WAVE]) : 0)) & (gb->model <= GB_MODEL_CGB_C? gb->apu.pcm_mask[1] : 0xFF); case GB_IO_JOYP: GB_timing_sync(gb); case GB_IO_TMA: diff --git a/Core/timing.c b/Core/timing.c index f79727c..f734caf 100644 --- a/Core/timing.c +++ b/Core/timing.c @@ -214,7 +214,8 @@ static void advance_serial(GB_gameboy_t *gb, uint8_t cycles) } void GB_advance_cycles(GB_gameboy_t *gb, uint8_t cycles) -{ +{ + gb->apu.pcm_mask[0] = gb->apu.pcm_mask[1] = 0xFF; // Sort of hacky, but too many cross-component interactions to do it right // Affected by speed boost gb->dma_cycles += cycles;