From 594aea2d5a48fe621327b9a9ba4d9ab68250fdf1 Mon Sep 17 00:00:00 2001 From: Lior Halphon Date: Tue, 13 Sep 2016 17:33:48 +0300 Subject: [PATCH] APU is now being run lazily --- Core/apu.c | 116 ++++++++++++++++++++++++++------------------------ Core/gb.c | 2 +- Core/memory.c | 5 ++- 3 files changed, 65 insertions(+), 58 deletions(-) diff --git a/Core/apu.c b/Core/apu.c index b6bf9f9..ae15c56 100755 --- a/Core/apu.c +++ b/Core/apu.c @@ -58,60 +58,6 @@ static int16_t step_lfsr(uint16_t lfsr, bool uses_7_bit) return lfsr; } -void GB_apu_get_samples_and_update_pcm_regs(GB_gameboy_t *gb, GB_sample_t *samples) -{ - samples->left = samples->right = 0; - if (!gb->apu.global_enable) { - return; - } - - gb->io_registers[GB_IO_PCM_12] = 0; - gb->io_registers[GB_IO_PCM_34] = 0; - - { - int16_t sample = generate_square(gb->apu.wave_channels[0].phase, - gb->apu.wave_channels[0].wave_length, - gb->apu.wave_channels[0].amplitude, - gb->apu.wave_channels[0].duty); - if (gb->apu.wave_channels[0].left_on ) samples->left += sample; - if (gb->apu.wave_channels[0].right_on) samples->right += sample; - gb->io_registers[GB_IO_PCM_12] = ((int)sample) * 0xF / MAX_CH_AMP; - } - - { - int16_t sample = generate_square(gb->apu.wave_channels[1].phase, - gb->apu.wave_channels[1].wave_length, - gb->apu.wave_channels[1].amplitude, - gb->apu.wave_channels[1].duty); - if (gb->apu.wave_channels[1].left_on ) samples->left += sample; - if (gb->apu.wave_channels[1].right_on) samples->right += sample; - gb->io_registers[GB_IO_PCM_12] |= (((int)sample) * 0xF / MAX_CH_AMP) << 4; - } - - if (gb->apu.wave_enable) - { - int16_t sample = generate_wave(gb->apu.wave_channels[2].phase, - gb->apu.wave_channels[2].wave_length, - MAX_CH_AMP, - gb->apu.wave_form, - gb->apu.wave_shift); - if (gb->apu.wave_channels[2].left_on ) samples->left += sample; - if (gb->apu.wave_channels[2].right_on) samples->right += sample; - gb->io_registers[GB_IO_PCM_34] = ((int)sample) * 0xF / MAX_CH_AMP; - } - - { - int16_t sample = generate_noise(gb->apu.wave_channels[3].amplitude, - gb->apu.lfsr); - if (gb->apu.wave_channels[3].left_on ) samples->left += sample; - if (gb->apu.wave_channels[3].right_on) samples->right += sample; - gb->io_registers[GB_IO_PCM_34] |= (((int)sample) * 0xF / MAX_CH_AMP) << 4; - } - - samples->left *= gb->apu.left_volume; - samples->right *= gb->apu.right_volume; -} - /* General Todo: The APU emulation seems to fail many accuracy tests. It might require a rewrite with these tests in mind. */ @@ -177,14 +123,69 @@ static void GB_apu_run_internal(GB_gameboy_t *gb) } } +void GB_apu_get_samples_and_update_pcm_regs(GB_gameboy_t *gb, GB_sample_t *samples) +{ + GB_apu_run_internal(gb); + + samples->left = samples->right = 0; + if (!gb->apu.global_enable) { + return; + } + + gb->io_registers[GB_IO_PCM_12] = 0; + gb->io_registers[GB_IO_PCM_34] = 0; + + { + int16_t sample = generate_square(gb->apu.wave_channels[0].phase, + gb->apu.wave_channels[0].wave_length, + gb->apu.wave_channels[0].amplitude, + gb->apu.wave_channels[0].duty); + if (gb->apu.wave_channels[0].left_on ) samples->left += sample; + if (gb->apu.wave_channels[0].right_on) samples->right += sample; + gb->io_registers[GB_IO_PCM_12] = ((int)sample) * 0xF / MAX_CH_AMP; + } + + { + int16_t sample = generate_square(gb->apu.wave_channels[1].phase, + gb->apu.wave_channels[1].wave_length, + gb->apu.wave_channels[1].amplitude, + gb->apu.wave_channels[1].duty); + if (gb->apu.wave_channels[1].left_on ) samples->left += sample; + if (gb->apu.wave_channels[1].right_on) samples->right += sample; + gb->io_registers[GB_IO_PCM_12] |= (((int)sample) * 0xF / MAX_CH_AMP) << 4; + } + + if (gb->apu.wave_enable) + { + int16_t sample = generate_wave(gb->apu.wave_channels[2].phase, + gb->apu.wave_channels[2].wave_length, + MAX_CH_AMP, + gb->apu.wave_form, + gb->apu.wave_shift); + if (gb->apu.wave_channels[2].left_on ) samples->left += sample; + if (gb->apu.wave_channels[2].right_on) samples->right += sample; + gb->io_registers[GB_IO_PCM_34] = ((int)sample) * 0xF / MAX_CH_AMP; + } + + { + int16_t sample = generate_noise(gb->apu.wave_channels[3].amplitude, + gb->apu.lfsr); + if (gb->apu.wave_channels[3].left_on ) samples->left += sample; + if (gb->apu.wave_channels[3].right_on) samples->right += sample; + gb->io_registers[GB_IO_PCM_34] |= (((int)sample) * 0xF / MAX_CH_AMP) << 4; + } + + samples->left *= gb->apu.left_volume; + samples->right *= gb->apu.right_volume; +} + void GB_apu_run(GB_gameboy_t *gb) { + if (gb->sample_rate == 0) return; static bool should_log_overflow = true; while (gb->audio_copy_in_progress); double ticks_per_sample = (double) CPU_FREQUENCY / gb->sample_rate; - GB_apu_run_internal(gb); - if (gb->apu_sample_cycles > ticks_per_sample) { gb->apu_sample_cycles -= ticks_per_sample; if (gb->audio_position == gb->buffer_size) { @@ -239,6 +240,7 @@ void GB_apu_init(GB_gameboy_t *gb) uint8_t GB_apu_read(GB_gameboy_t *gb, uint8_t reg) { /* Todo: what happens when reading from the wave from while it's playing? */ + GB_apu_run_internal(gb); if (reg == GB_IO_NR52) { uint8_t value = 0; @@ -277,6 +279,8 @@ uint8_t GB_apu_read(GB_gameboy_t *gb, uint8_t reg) void GB_apu_write(GB_gameboy_t *gb, uint8_t reg, uint8_t value) { + GB_apu_run_internal(gb); + static const uint8_t duties[] = {1, 2, 4, 6}; /* Values are in 1/8 */ uint8_t channel = 0; diff --git a/Core/gb.c b/Core/gb.c index c504545..dd591d0 100755 --- a/Core/gb.c +++ b/Core/gb.c @@ -491,7 +491,7 @@ void GB_set_sample_rate(GB_gameboy_t *gb, unsigned int sample_rate) free(gb->audio_buffer); } gb->buffer_size = sample_rate / 25; // 40ms delay - gb->audio_buffer = malloc((gb->buffer_size + 1) * sizeof(*gb->audio_buffer)); + gb->audio_buffer = malloc(gb->buffer_size * sizeof(*gb->audio_buffer)); gb->sample_rate = sample_rate; gb->audio_position = 0; } diff --git a/Core/memory.c b/Core/memory.c index 442f7c7..03d043f 100644 --- a/Core/memory.c +++ b/Core/memory.c @@ -141,7 +141,10 @@ static uint8_t read_high_memory(GB_gameboy_t *gb, uint16_t addr) case GB_IO_PCM_12: case GB_IO_PCM_34: - GB_apu_get_samples_and_update_pcm_regs(gb, &gb->audio_buffer[gb->audio_position]); + { + GB_sample_t dummy; + GB_apu_get_samples_and_update_pcm_regs(gb, &dummy); + } case GB_IO_HDMA1: case GB_IO_HDMA2: case GB_IO_HDMA3: