Mercurial > repos > blastem
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, ¤t_cycle, wait_time); | |
141 break; | |
142 } | |
143 case CMD_WAIT_60: | |
144 wait(&y_context, &p_context, ¤t_cycle, 735 * mclks_sample); | |
145 break; | |
146 case CMD_WAIT_50: | |
147 wait(&y_context, &p_context, ¤t_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, ¤t_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 } |