From c78cc8c676e58cb11a5df0aa89773bec4b28a498 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 27 May 2021 05:06:43 -0500 Subject: [PATCH] finally output envelopes apparently emulating the timers was necessary after all... --- CMakeLists.txt | 1 + src/engine/platform/gb.cpp | 13 +- src/engine/platform/sound/gb/apu.c | 4 +- src/engine/platform/sound/gb/apu.h | 10 +- src/engine/platform/sound/gb/gb.h | 12 ++ src/engine/platform/sound/gb/timing.c | 278 +------------------------- src/engine/platform/sound/gb/timing.h | 2 - 7 files changed, 20 insertions(+), 300 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1aee7572..8db40853 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -27,6 +27,7 @@ src/log.cpp extern/Nuked-OPN2/ym3438.c src/engine/platform/sound/sn76496.cpp src/engine/platform/sound/gb/apu.c +src/engine/platform/sound/gb/timing.c src/engine/blip_buf.c src/engine/safeReader.cpp diff --git a/src/engine/platform/gb.cpp b/src/engine/platform/gb.cpp index 4a04c8df..44eafeff 100644 --- a/src/engine/platform/gb.cpp +++ b/src/engine/platform/gb.cpp @@ -8,16 +8,9 @@ #define FREQ_BASE 7943.75f void DivPlatformGB::acquire(int& l, int& r) { - gb->apu.apu_cycles=4; - GB_apu_run(gb); - l=(gb->apu_output.current_sample[0].left+ - gb->apu_output.current_sample[1].left+ - gb->apu_output.current_sample[2].left+ - gb->apu_output.current_sample[3].left)<<6; - r=(gb->apu_output.current_sample[0].right+ - gb->apu_output.current_sample[1].right+ - gb->apu_output.current_sample[2].right+ - gb->apu_output.current_sample[3].right)<<6; + GB_advance_cycles(gb,2); + l=gb->apu_output.final_sample.left<<3; + r=gb->apu_output.final_sample.right<<3; } void DivPlatformGB::tick() { diff --git a/src/engine/platform/sound/gb/apu.c b/src/engine/platform/sound/gb/apu.c index badf3fbc..8c56a1a2 100644 --- a/src/engine/platform/sound/gb/apu.c +++ b/src/engine/platform/sound/gb/apu.c @@ -4,7 +4,6 @@ #include #include "gb.h" -#define CGB 0 #define GB_CLOCK_RATE 0x400000 #define likely(x) __builtin_expect((x), 1) @@ -277,8 +276,7 @@ static void render(GB_gameboy_t *gb) filtered_output.left = MAX(MIN(filtered_output.left + interference_bias, 0x7FFF), -0x8000); filtered_output.right = MAX(MIN(filtered_output.right + interference_bias, 0x7FFF), -0x8000); } - assert(gb->apu_output.sample_callback); - gb->apu_output.sample_callback(gb, &filtered_output); + gb->apu_output.final_sample=filtered_output; } static void update_square_sample(GB_gameboy_t *gb, unsigned index) diff --git a/src/engine/platform/sound/gb/apu.h b/src/engine/platform/sound/gb/apu.h index a9447ea0..3c07b46f 100644 --- a/src/engine/platform/sound/gb/apu.h +++ b/src/engine/platform/sound/gb/apu.h @@ -5,10 +5,6 @@ #include #include "gb_struct_def.h" -#ifdef __cplusplus -extern "C" { -#endif - /* Speed = 1 / Length (in seconds) */ #define DAC_DECAY_SPEED 20000 #define DAC_ATTACK_SPEED 20000 @@ -164,6 +160,8 @@ typedef struct { GB_double_sample_t highpass_diff; GB_sample_callback_t sample_callback; + + GB_sample_t final_sample; bool rate_set_in_clocks; double interference_volume; @@ -186,8 +184,4 @@ void GB_apu_run(GB_gameboy_t *gb); void GB_apu_update_cycles_per_sample(GB_gameboy_t *gb); void GB_borrow_sgb_border(GB_gameboy_t *gb); -#ifdef __cplusplus -} -#endif - #endif /* apu_h */ diff --git a/src/engine/platform/sound/gb/gb.h b/src/engine/platform/sound/gb/gb.h index 0a2baa6a..7128ecab 100644 --- a/src/engine/platform/sound/gb/gb.h +++ b/src/engine/platform/sound/gb/gb.h @@ -6,6 +6,10 @@ #include #include +#ifdef __cplusplus +extern "C" { +#endif + #include "gb_struct_def.h" #include "apu.h" @@ -13,6 +17,8 @@ #define GB_STRUCT_VERSION 13 +#define CGB 0 + #define GB_MODEL_FAMILY_MASK 0xF00 #define GB_MODEL_DMG_FAMILY 0x000 #define GB_MODEL_MGB_FAMILY 0x100 @@ -357,7 +363,9 @@ struct GB_gameboy_s { bool stopped; uint8_t io_registers[0x80]; + GB_UNIT(div); uint16_t div_counter; + uint8_t tima_reload_state; GB_apu_t apu; GB_apu_output_t apu_output; }; @@ -382,4 +390,8 @@ typedef enum { GB_DIRECT_ACCESS_IE, } GB_direct_access_t; +#ifdef __cplusplus +} +#endif + #endif /* GB_h */ diff --git a/src/engine/platform/sound/gb/timing.c b/src/engine/platform/sound/gb/timing.c index 7b79b725..03385aee 100644 --- a/src/engine/platform/sound/gb/timing.c +++ b/src/engine/platform/sound/gb/timing.c @@ -10,118 +10,10 @@ static const unsigned GB_TAC_TRIGGER_BITS[] = {512, 8, 32, 128}; -#ifndef GB_DISABLE_TIMEKEEPING -static int64_t get_nanoseconds(void) -{ -#ifndef _WIN32 - struct timeval now; - gettimeofday(&now, NULL); - return (now.tv_usec) * 1000 + now.tv_sec * 1000000000L; -#else - FILETIME time; - GetSystemTimeAsFileTime(&time); - return (((int64_t)time.dwHighDateTime << 32) | time.dwLowDateTime) * 100L; -#endif -} - -static void nsleep(uint64_t nanoseconds) -{ -#ifndef _WIN32 - struct timespec sleep = {0, nanoseconds}; - nanosleep(&sleep, NULL); -#else - HANDLE timer; - LARGE_INTEGER time; - timer = CreateWaitableTimer(NULL, true, NULL); - time.QuadPart = -(nanoseconds / 100L); - SetWaitableTimer(timer, &time, 0, NULL, NULL, false); - WaitForSingleObject(timer, INFINITE); - CloseHandle(timer); -#endif -} - -bool GB_timing_sync_turbo(GB_gameboy_t *gb) -{ - if (!gb->turbo_dont_skip) { - int64_t nanoseconds = get_nanoseconds(); - if (nanoseconds <= gb->last_sync + (1000000000LL * LCDC_PERIOD / GB_get_clock_rate(gb))) { - return true; - } - gb->last_sync = nanoseconds; - } - return false; -} - -void GB_timing_sync(GB_gameboy_t *gb) -{ - if (gb->turbo) { - gb->cycles_since_last_sync = 0; - return; - } - /* Prevent syncing if not enough time has passed.*/ - if (gb->cycles_since_last_sync < LCDC_PERIOD / 3) return; - - uint64_t target_nanoseconds = gb->cycles_since_last_sync * 1000000000LL / 2 / GB_get_clock_rate(gb); /* / 2 because we use 8MHz units */ - int64_t nanoseconds = get_nanoseconds(); - int64_t time_to_sleep = target_nanoseconds + gb->last_sync - nanoseconds; - if (time_to_sleep > 0 && time_to_sleep < LCDC_PERIOD * 1200000000LL / GB_get_clock_rate(gb)) { // +20% to be more forgiving - nsleep(time_to_sleep); - gb->last_sync += target_nanoseconds; - } - else { - if (time_to_sleep < 0 && -time_to_sleep < LCDC_PERIOD * 1200000000LL / GB_get_clock_rate(gb)) { - // We're running a bit too slow, but the difference is small enough, - // just skip this sync and let it even out - return; - } - gb->last_sync = nanoseconds; - } - - gb->cycles_since_last_sync = 0; - if (gb->update_input_hint_callback) { - gb->update_input_hint_callback(gb); - } -} -#else - -bool GB_timing_sync_turbo(GB_gameboy_t *gb) -{ - return false; -} - -void GB_timing_sync(GB_gameboy_t *gb) -{ -} - -#endif - #define IR_DECAY 31500 #define IR_THRESHOLD 19900 #define IR_MAX IR_THRESHOLD * 2 + IR_DECAY -static void GB_ir_run(GB_gameboy_t *gb, uint32_t cycles) -{ - if (gb->model == GB_MODEL_AGB) return; - if (gb->infrared_input || gb->cart_ir || (gb->io_registers[GB_IO_RP] & 1)) { - gb->ir_sensor += cycles; - if (gb->ir_sensor > IR_MAX) { - gb->ir_sensor = IR_MAX; - } - - gb->effective_ir_input = gb->ir_sensor >= IR_THRESHOLD && gb->ir_sensor <= IR_THRESHOLD + IR_DECAY; - } - else { - if (gb->ir_sensor <= cycles) { - gb->ir_sensor = 0; - } - else { - gb->ir_sensor -= cycles; - } - gb->effective_ir_input = false; - } - -} - static void advance_tima_state_machine(GB_gameboy_t *gb) { if (gb->tima_reload_state == GB_TIMA_RELOADED) { @@ -170,7 +62,7 @@ static void GB_set_internal_div_counter(GB_gameboy_t *gb, uint16_t value) static void GB_timers_run(GB_gameboy_t *gb, uint8_t cycles) { if (gb->stopped) { - if (GB_is_cgb(gb)) { + if (CGB) { gb->apu.apu_cycles += 4 << !gb->cgb_double_speed; } return; @@ -201,187 +93,19 @@ main: } } -static void advance_serial(GB_gameboy_t *gb, uint8_t cycles) -{ - if (gb->printer.command_state || gb->printer.bits_received) { - gb->printer.idle_time += cycles; - } - if (gb->serial_length == 0) { - gb->serial_cycles += cycles; - return; - } - - while (cycles > gb->serial_length) { - advance_serial(gb, gb->serial_length); - cycles -= gb->serial_length; - } - - uint16_t previous_serial_cycles = gb->serial_cycles; - gb->serial_cycles += cycles; - if ((gb->serial_cycles & gb->serial_length) != (previous_serial_cycles & gb->serial_length)) { - gb->serial_count++; - if (gb->serial_count == 8) { - gb->serial_length = 0; - gb->serial_count = 0; - gb->io_registers[GB_IO_SC] &= ~0x80; - gb->io_registers[GB_IO_IF] |= 8; - } - - gb->io_registers[GB_IO_SB] <<= 1; - - if (gb->serial_transfer_bit_end_callback) { - gb->io_registers[GB_IO_SB] |= gb->serial_transfer_bit_end_callback(gb); - } - else { - gb->io_registers[GB_IO_SB] |= 1; - } - - if (gb->serial_length) { - /* Still more bits to send */ - if (gb->serial_transfer_bit_start_callback) { - gb->serial_transfer_bit_start_callback(gb, gb->io_registers[GB_IO_SB] & 0x80); - } - } - - } - return; - -} - -static void GB_rtc_run(GB_gameboy_t *gb, uint8_t cycles) -{ - if (gb->cartridge_type->mbc_type != GB_HUC3 && !gb->cartridge_type->has_rtc) return; - gb->rtc_cycles += cycles; - time_t current_time = 0; - - switch (gb->rtc_mode) { - case GB_RTC_MODE_SYNC_TO_HOST: - // Sync in a 1/32s resolution - if (gb->rtc_cycles < GB_get_unmultiplied_clock_rate(gb) / 16) return; - gb->rtc_cycles -= GB_get_unmultiplied_clock_rate(gb) / 16; - current_time = time(NULL); - break; - case GB_RTC_MODE_ACCURATE: - if (gb->cartridge_type->mbc_type != GB_HUC3 && (gb->rtc_real.high & 0x40)) { - gb->rtc_cycles -= cycles; - return; - } - if (gb->rtc_cycles < GB_get_unmultiplied_clock_rate(gb) * 2) return; - gb->rtc_cycles -= GB_get_unmultiplied_clock_rate(gb) * 2; - current_time = gb->last_rtc_second + 1; - break; - } - - if (gb->cartridge_type->mbc_type == GB_HUC3) { - while (gb->last_rtc_second / 60 < current_time / 60) { - gb->last_rtc_second += 60; - gb->huc3_minutes++; - if (gb->huc3_minutes == 60 * 24) { - gb->huc3_days++; - gb->huc3_minutes = 0; - } - } - return; - } - bool running = false; - if (gb->cartridge_type->mbc_type == GB_TPP1) { - running = gb->tpp1_mr4 & 0x4; - } - else { - running = (gb->rtc_real.high & 0x40) == 0; - } - - if (running) { /* is timer running? */ - while (gb->last_rtc_second + 60 * 60 * 24 < current_time) { - gb->last_rtc_second += 60 * 60 * 24; - if (gb->cartridge_type->mbc_type == GB_TPP1) { - if (++gb->rtc_real.tpp1.weekday == 7) { - gb->rtc_real.tpp1.weekday = 0; - if (++gb->rtc_real.tpp1.weeks == 0) { - gb->tpp1_mr4 |= 8; /* Overflow bit */ - } - } - } - else if (++gb->rtc_real.days == 0) { - if (gb->rtc_real.high & 1) { /* Bit 8 of days*/ - gb->rtc_real.high |= 0x80; /* Overflow bit */ - } - - gb->rtc_real.high ^= 1; - } - } - - while (gb->last_rtc_second < current_time) { - gb->last_rtc_second++; - if (++gb->rtc_real.seconds != 60) continue; - gb->rtc_real.seconds = 0; - - if (++gb->rtc_real.minutes != 60) continue; - gb->rtc_real.minutes = 0; - - if (gb->cartridge_type->mbc_type == GB_TPP1) { - if (++gb->rtc_real.tpp1.hours != 24) continue; - gb->rtc_real.tpp1.hours = 0; - if (++gb->rtc_real.tpp1.weekday != 7) continue; - gb->rtc_real.tpp1.weekday = 0; - if (++gb->rtc_real.tpp1.weeks == 0) { - gb->tpp1_mr4 |= 8; /* Overflow bit */ - } - } - else { - if (++gb->rtc_real.hours != 24) continue; - gb->rtc_real.hours = 0; - - if (++gb->rtc_real.days != 0) continue; - - if (gb->rtc_real.high & 1) { /* Bit 8 of days*/ - gb->rtc_real.high |= 0x80; /* Overflow bit */ - } - - gb->rtc_real.high ^= 1; - } - } - } -} - - 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; GB_timers_run(gb, cycles); - if (!gb->stopped) { - advance_serial(gb, cycles); // TODO: Verify what happens in STOP mode - } - - gb->debugger_ticks += cycles; if (!gb->cgb_double_speed) { cycles <<= 1; } - // Not affected by speed boost - if (gb->io_registers[GB_IO_LCDC] & 0x80) { - gb->double_speed_alignment += cycles; - } - gb->hdma_cycles += cycles; gb->apu_output.sample_cycles += cycles; - gb->cycles_since_last_sync += cycles; - gb->cycles_since_run += cycles; - gb->rumble_on_cycles += gb->rumble_strength & 3; - gb->rumble_off_cycles += (gb->rumble_strength & 3) ^ 3; - - if (!gb->stopped) { // TODO: Verify what happens in STOP mode - GB_dma_run(gb); - GB_hdma_run(gb); - } GB_apu_run(gb); - GB_display_run(gb, cycles); - GB_ir_run(gb, cycles); - GB_rtc_run(gb, cycles); } /* diff --git a/src/engine/platform/sound/gb/timing.h b/src/engine/platform/sound/gb/timing.h index 07e04734..f813b758 100644 --- a/src/engine/platform/sound/gb/timing.h +++ b/src/engine/platform/sound/gb/timing.h @@ -2,7 +2,6 @@ #define timing_h #include "gb_struct_def.h" -#ifdef GB_INTERNAL void GB_advance_cycles(GB_gameboy_t *gb, uint8_t cycles); void GB_emulate_timer_glitch(GB_gameboy_t *gb, uint8_t old_tac, uint8_t new_tac); bool GB_timing_sync_turbo(GB_gameboy_t *gb); /* Returns true if should skip frame */ @@ -31,7 +30,6 @@ if ((gb)->unit##_cycles <= 0) {\ return;\ }\ switch ((gb)->unit##_state) -#endif #define GB_STATE(gb, unit, state) case state: goto unit##state