comparison vgmplay.c @ 408:a13a83934ba3

Add primitive vgm player for testing
author Mike Pavone <pavone@retrodev.com>
date Mon, 17 Jun 2013 00:54:14 -0700
parents
children c1bddeadc566
comparison
equal deleted inserted replaced
407:c3abc4ada43d 408:a13a83934ba3
1 #include "render.h"
2 #include "ym2612.h"
3 #include "psg.h"
4 #include <stdint.h>
5 #include <stdio.h>
6
7 #define MCLKS_NTSC 53693175
8 #define MCLKS_PAL 53203395
9
10 #define MCLKS_PER_68K 7
11 #define MCLKS_PER_YM MCLKS_PER_68K
12 #define MCLKS_PER_Z80 15
13 #define MCLKS_PER_PSG (MCLKS_PER_Z80*16)
14
15 #pragma pack(push, 1)
16 typedef struct {
17 char ident[4];
18 uint32_t eof_offset;
19 uint32_t version;
20 uint32_t sn76489_clk;
21 uint32_t ym2413_clk;
22 uint32_t gd3_offset;
23 uint32_t num_samples;
24 uint32_t loop_offset;
25 uint32_t loop_count;
26 uint32_t rate;
27 uint16_t sn76489_fb;
28 uint8_t sn76489_shift;
29 uint8_t sn76489_flags;
30 uint32_t ym2612_clk;
31 uint32_t ym2151_clk;
32 uint32_t data_offset;
33 uint32_t sega_pcm_clk;
34 uint32_t sega_pcm_reg;
35 } vgm_header;
36
37 enum {
38 CMD_PSG_STEREO = 0x4F,
39 CMD_PSG,
40 CMD_YM2413,
41 CMD_YM2612_0,
42 CMD_YM2612_1,
43 CMD_YM2151,
44 CMD_YM2203,
45 CMD_YM2608_0,
46 CMD_YM2608_1,
47 CMD_YM2610_0,
48 CMD_YM2610_1,
49 CMD_YM3812,
50 CMD_YM3526,
51 CMD_Y8950,
52 CMD_YMZ280B,
53 CMD_YMF262_0,
54 CMD_YMF262_1,
55 CMD_WAIT = 0x61,
56 CMD_WAIT_60,
57 CMD_WAIT_50,
58 CMD_END = 0x66,
59 CMD_DATA,
60 CMD_PCM_WRITE,
61 CMD_WAIT_SHORT = 0x70,
62 CMD_YM2612_DAC = 0x80
63 };
64
65 #pragma pack(pop)
66
67 void handle_keydown(int keycode)
68 {
69 }
70
71 void handle_keyup(int keycode)
72 {
73 }
74
75 void wait(ym2612_context * y_context, psg_context * p_context, uint32_t * current_cycle, uint32_t cycles)
76 {
77 *current_cycle += cycles;
78 psg_run(p_context, *current_cycle);
79 ym_run(y_context, *current_cycle);
80
81 if (*current_cycle > 0x1FFFFFFF) {
82 *current_cycle -= 0x1FFFFFFF;
83 p_context->cycles -= 0x1FFFFFFF;
84 y_context->current_cycle -= 0x1FFFFFFF;
85 }
86 }
87
88 int main(int argc, char ** argv)
89 {
90 uint32_t fps = 60;
91 render_init(320, 240, "vgm play", 60);
92
93
94 ym2612_context y_context;
95 ym_init(&y_context, render_sample_rate(), MCLKS_NTSC, MCLKS_PER_YM, render_audio_buffer(), 0);
96
97 psg_context p_context;
98 psg_init(&p_context, render_sample_rate(), MCLKS_NTSC, MCLKS_PER_PSG, render_audio_buffer());
99
100 FILE * f = fopen(argv[1], "rb");
101 vgm_header header;
102 fread(&header, sizeof(header), 1, f);
103 if (header.version < 0x150 || !header.data_offset) {
104 header.data_offset = 0xC;
105 }
106 fseek(f, header.data_offset + 0x34, SEEK_SET);
107 uint32_t data_size = header.eof_offset + 4 - (header.data_offset + 0x34);
108 uint8_t * data = malloc(data_size);
109 fread(data, 1, data_size, f);
110 fclose(f);
111
112 uint32_t mclks_sample = MCLKS_NTSC / 44100;
113
114 uint8_t * end = data + data_size;
115 uint8_t * cur = data;
116 uint32_t current_cycle = 0;
117 while (cur < end) {
118 uint8_t cmd = *(cur++);
119 switch(cmd)
120 {
121 case CMD_PSG_STEREO:
122 //ignore for now
123 cur++;
124 break;
125 case CMD_PSG:
126 psg_write(&p_context, *(cur++));
127 break;
128 case CMD_YM2612_0:
129 ym_address_write_part1(&y_context, *(cur++));
130 ym_data_write(&y_context, *(cur++));
131 break;
132 case CMD_YM2612_1:
133 ym_address_write_part2(&y_context, *(cur++));
134 ym_data_write(&y_context, *(cur++));
135 break;
136 case CMD_WAIT: {
137 uint32_t wait_time = *(cur++);
138 wait_time |= *(cur++) << 8;
139 wait_time *= mclks_sample;
140 wait(&y_context, &p_context, &current_cycle, wait_time);
141 break;
142 }
143 case CMD_WAIT_60:
144 wait(&y_context, &p_context, &current_cycle, 735 * mclks_sample);
145 break;
146 case CMD_WAIT_50:
147 wait(&y_context, &p_context, &current_cycle, 882 * mclks_sample);
148 break;
149 case CMD_END:
150 return 0;
151 default:
152 if (cmd >= CMD_WAIT_SHORT && cmd < (CMD_WAIT_SHORT + 0x10)) {
153 uint32_t wait_time = (cmd & 0xF) + 1;
154 wait_time *= mclks_sample;
155 wait(&y_context, &p_context, &current_cycle, wait_time);
156 } else {
157 printf("unimplemented command: %X at offset %X\n", cmd, cur - data - 1);
158 exit(1);
159 }
160 }
161 }
162 return 0;
163 }