# HG changeset patch # User Mike Pavone # Date 1371455654 25200 # Node ID a13a83934ba346027c5915af7bb9036ccd155b67 # Parent c3abc4ada43d026212329bd2acd80f173e2172eb Add primitive vgm player for testing diff -r c3abc4ada43d -r a13a83934ba3 Makefile --- a/Makefile Sun Jun 16 17:57:57 2013 -0700 +++ b/Makefile Mon Jun 17 00:54:14 2013 -0700 @@ -34,6 +34,9 @@ stateview : stateview.o vdp.o render_sdl.o $(CC) -o stateview stateview.o vdp.o render_sdl.o `pkg-config --libs $(LIBS)` +vgmplay : vgmplay.o ym2612.o psg.o render_sdl.o wave.o + $(CC) -o vgmplay vgmplay.o ym2612.o psg.o render_sdl.o wave.o `pkg-config --libs $(LIBS)` + test_x86 : test_x86.o gen_x86.o $(CC) -o test_x86 test_x86.o gen_x86.o diff -r c3abc4ada43d -r a13a83934ba3 vgmplay.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vgmplay.c Mon Jun 17 00:54:14 2013 -0700 @@ -0,0 +1,163 @@ +#include "render.h" +#include "ym2612.h" +#include "psg.h" +#include +#include + +#define MCLKS_NTSC 53693175 +#define MCLKS_PAL 53203395 + +#define MCLKS_PER_68K 7 +#define MCLKS_PER_YM MCLKS_PER_68K +#define MCLKS_PER_Z80 15 +#define MCLKS_PER_PSG (MCLKS_PER_Z80*16) + +#pragma pack(push, 1) +typedef struct { + char ident[4]; + uint32_t eof_offset; + uint32_t version; + uint32_t sn76489_clk; + uint32_t ym2413_clk; + uint32_t gd3_offset; + uint32_t num_samples; + uint32_t loop_offset; + uint32_t loop_count; + uint32_t rate; + uint16_t sn76489_fb; + uint8_t sn76489_shift; + uint8_t sn76489_flags; + uint32_t ym2612_clk; + uint32_t ym2151_clk; + uint32_t data_offset; + uint32_t sega_pcm_clk; + uint32_t sega_pcm_reg; +} vgm_header; + +enum { + CMD_PSG_STEREO = 0x4F, + CMD_PSG, + CMD_YM2413, + CMD_YM2612_0, + CMD_YM2612_1, + CMD_YM2151, + CMD_YM2203, + CMD_YM2608_0, + CMD_YM2608_1, + CMD_YM2610_0, + CMD_YM2610_1, + CMD_YM3812, + CMD_YM3526, + CMD_Y8950, + CMD_YMZ280B, + CMD_YMF262_0, + CMD_YMF262_1, + CMD_WAIT = 0x61, + CMD_WAIT_60, + CMD_WAIT_50, + CMD_END = 0x66, + CMD_DATA, + CMD_PCM_WRITE, + CMD_WAIT_SHORT = 0x70, + CMD_YM2612_DAC = 0x80 +}; + +#pragma pack(pop) + +void handle_keydown(int keycode) +{ +} + +void handle_keyup(int keycode) +{ +} + +void wait(ym2612_context * y_context, psg_context * p_context, uint32_t * current_cycle, uint32_t cycles) +{ + *current_cycle += cycles; + psg_run(p_context, *current_cycle); + ym_run(y_context, *current_cycle); + + if (*current_cycle > 0x1FFFFFFF) { + *current_cycle -= 0x1FFFFFFF; + p_context->cycles -= 0x1FFFFFFF; + y_context->current_cycle -= 0x1FFFFFFF; + } +} + +int main(int argc, char ** argv) +{ + uint32_t fps = 60; + render_init(320, 240, "vgm play", 60); + + + ym2612_context y_context; + ym_init(&y_context, render_sample_rate(), MCLKS_NTSC, MCLKS_PER_YM, render_audio_buffer(), 0); + + psg_context p_context; + psg_init(&p_context, render_sample_rate(), MCLKS_NTSC, MCLKS_PER_PSG, render_audio_buffer()); + + FILE * f = fopen(argv[1], "rb"); + vgm_header header; + fread(&header, sizeof(header), 1, f); + if (header.version < 0x150 || !header.data_offset) { + header.data_offset = 0xC; + } + fseek(f, header.data_offset + 0x34, SEEK_SET); + uint32_t data_size = header.eof_offset + 4 - (header.data_offset + 0x34); + uint8_t * data = malloc(data_size); + fread(data, 1, data_size, f); + fclose(f); + + uint32_t mclks_sample = MCLKS_NTSC / 44100; + + uint8_t * end = data + data_size; + uint8_t * cur = data; + uint32_t current_cycle = 0; + while (cur < end) { + uint8_t cmd = *(cur++); + switch(cmd) + { + case CMD_PSG_STEREO: + //ignore for now + cur++; + break; + case CMD_PSG: + psg_write(&p_context, *(cur++)); + break; + case CMD_YM2612_0: + ym_address_write_part1(&y_context, *(cur++)); + ym_data_write(&y_context, *(cur++)); + break; + case CMD_YM2612_1: + ym_address_write_part2(&y_context, *(cur++)); + ym_data_write(&y_context, *(cur++)); + break; + case CMD_WAIT: { + uint32_t wait_time = *(cur++); + wait_time |= *(cur++) << 8; + wait_time *= mclks_sample; + wait(&y_context, &p_context, ¤t_cycle, wait_time); + break; + } + case CMD_WAIT_60: + wait(&y_context, &p_context, ¤t_cycle, 735 * mclks_sample); + break; + case CMD_WAIT_50: + wait(&y_context, &p_context, ¤t_cycle, 882 * mclks_sample); + break; + case CMD_END: + return 0; + default: + if (cmd >= CMD_WAIT_SHORT && cmd < (CMD_WAIT_SHORT + 0x10)) { + uint32_t wait_time = (cmd & 0xF) + 1; + wait_time *= mclks_sample; + wait(&y_context, &p_context, ¤t_cycle, wait_time); + } else { + printf("unimplemented command: %X at offset %X\n", cmd, cur - data - 1); + exit(1); + } + } + } + return 0; +}