Mercurial > repos > blastem
diff gen_player.c @ 2053:3414a4423de1 segacd
Merge from default
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Sat, 15 Jan 2022 13:15:21 -0800 |
parents | a042e046f7f2 |
children | 01ff005b08f6 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gen_player.c Sat Jan 15 13:15:21 2022 -0800 @@ -0,0 +1,175 @@ +#include <stdlib.h> +#include "gen_player.h" +#include "event_log.h" +#include "render.h" + +#define MCLKS_NTSC 53693175 +#define MCLKS_PAL 53203395 +#define MCLKS_PER_YM 7 +#define MCLKS_PER_Z80 15 +#define MCLKS_PER_PSG (MCLKS_PER_Z80*16) + +#ifdef IS_LIB +#define MAX_SOUND_CYCLES (MCLKS_PER_YM*NUM_OPERATORS*6*4) +#else +#define MAX_SOUND_CYCLES 100000 +#endif + +static void sync_sound(gen_player *gen, uint32_t target) +{ + //printf("YM | Cycle: %d, bpos: %d, PSG | Cycle: %d, bpos: %d\n", gen->ym->current_cycle, gen->ym->buffer_pos, gen->psg->cycles, gen->psg->buffer_pos * 2); + while (target > gen->psg->cycles && target - gen->psg->cycles > MAX_SOUND_CYCLES) { + uint32_t cur_target = gen->psg->cycles + MAX_SOUND_CYCLES; + //printf("Running PSG to cycle %d\n", cur_target); + psg_run(gen->psg, cur_target); + //printf("Running YM-2612 to cycle %d\n", cur_target); + ym_run(gen->ym, cur_target); + } + psg_run(gen->psg, target); + ym_run(gen->ym, target); + + //printf("Target: %d, YM bufferpos: %d, PSG bufferpos: %d\n", target, gen->ym->buffer_pos, gen->psg->buffer_pos * 2); +} + +static void run(gen_player *player) +{ + while(player->reader.socket || player->reader.buffer.cur_pos < player->reader.buffer.size) + { + uint32_t cycle; + uint8_t event = reader_next_event(&player->reader, &cycle); + switch (event) + { + case EVENT_FLUSH: + sync_sound(player, cycle); + vdp_run_context(player->vdp, cycle); + break; + case EVENT_ADJUST: { + sync_sound(player, cycle); + vdp_run_context(player->vdp, cycle); + uint32_t deduction = load_int32(&player->reader.buffer); + ym_adjust_cycles(player->ym, deduction); + vdp_adjust_cycles(player->vdp, deduction); + player->psg->cycles -= deduction; + break; + case EVENT_PSG_REG: + sync_sound(player, cycle); + reader_ensure_data(&player->reader, 1); + psg_write(player->psg, load_int8(&player->reader.buffer)); + break; + case EVENT_YM_REG: { + sync_sound(player, cycle); + reader_ensure_data(&player->reader, 3); + uint8_t part = load_int8(&player->reader.buffer); + uint8_t reg = load_int8(&player->reader.buffer); + uint8_t value = load_int8(&player->reader.buffer); + if (part) { + ym_address_write_part2(player->ym, reg); + } else { + ym_address_write_part1(player->ym, reg); + } + ym_data_write(player->ym, value); + break; + case EVENT_STATE: { + reader_ensure_data(&player->reader, 3); + uint32_t size = load_int8(&player->reader.buffer) << 16; + size |= load_int16(&player->reader.buffer); + reader_ensure_data(&player->reader, size); + deserialize_buffer buffer; + init_deserialize(&buffer, player->reader.buffer.data + player->reader.buffer.cur_pos, size); + register_section_handler(&buffer, (section_handler){.fun = vdp_deserialize, .data = player->vdp}, SECTION_VDP); + register_section_handler(&buffer, (section_handler){.fun = ym_deserialize, .data = player->ym}, SECTION_YM2612); + register_section_handler(&buffer, (section_handler){.fun = psg_deserialize, .data = player->psg}, SECTION_PSG); + while (buffer.cur_pos < buffer.size) + { + load_section(&buffer); + } + player->reader.buffer.cur_pos += size; + free(buffer.handlers); + break; + } + default: + vdp_run_context(player->vdp, cycle); + vdp_replay_event(player->vdp, event, &player->reader); + } + } + + } + if (!player->reader.socket) { + reader_ensure_data(&player->reader, 1); + } + } +} + +static int thread_main(void *player) +{ + run(player); + return 0; +} + +void start_context(system_header *sys, char *statefile) +{ + gen_player *player = (gen_player *)sys; + if (player->reader.socket) { +#ifndef IS_LIB + render_create_thread(&player->thread, "player", thread_main, player); +#endif + } else { + run(player); + } +} + +static void gamepad_down(system_header *system, uint8_t gamepad_num, uint8_t button) +{ + gen_player *player = (gen_player *)system; + reader_send_gamepad_event(&player->reader, gamepad_num, button, 1); +} + +static void gamepad_up(system_header *system, uint8_t gamepad_num, uint8_t button) +{ + gen_player *player = (gen_player *)system; + reader_send_gamepad_event(&player->reader, gamepad_num, button, 0); +} + +static void config_common(gen_player *player) +{ + uint8_t vid_std = load_int8(&player->reader.buffer); + uint8_t name_len = load_int8(&player->reader.buffer); + player->header.info.name = calloc(1, name_len + 1); + load_buffer8(&player->reader.buffer, player->header.info.name, name_len); + + player->vdp = init_vdp_context(vid_std == VID_PAL, 0); + render_set_video_standard(vid_std); + uint32_t master_clock = vid_std == VID_NTSC ? MCLKS_NTSC : MCLKS_PAL; + + player->ym = malloc(sizeof(ym2612_context)); + ym_init(player->ym, master_clock, MCLKS_PER_YM, 0); + + player->psg = malloc(sizeof(psg_context)); + psg_init(player->psg, master_clock, MCLKS_PER_PSG); + + player->header.start_context = start_context; + player->header.gamepad_down = gamepad_down; + player->header.gamepad_up = gamepad_up; + player->header.type = SYSTEM_GENESIS_PLAYER; + player->header.info.save_type = SAVE_NONE; +} + +gen_player *alloc_config_gen_player(void *stream, uint32_t rom_size) +{ + uint8_t *data = stream; + gen_player *player = calloc(1, sizeof(gen_player)); + init_event_reader(&player->reader, data + 9, rom_size - 9); + config_common(player); + return player; +} + +gen_player *alloc_config_gen_player_reader(event_reader *reader) +{ + gen_player *player = calloc(1, sizeof(gen_player)); + player->reader = *reader; + inflateCopy(&player->reader.input_stream, &reader->input_stream); + render_set_external_sync(1); + config_common(player); + return player; +} +