comparison vgmplay.c @ 2081:cfd53c94fffb

Initial stab at RF5C164 emulation
author Michael Pavone <pavone@retrodev.com>
date Thu, 03 Feb 2022 23:15:42 -0800
parents 460e14497120
children
comparison
equal deleted inserted replaced
2080:bafb757e1cd2 2081:cfd53c94fffb
12 #include <stdio.h> 12 #include <stdio.h>
13 #include <stdlib.h> 13 #include <stdlib.h>
14 #include <string.h> 14 #include <string.h>
15 #include "vgm.h" 15 #include "vgm.h"
16 #include "system.h" 16 #include "system.h"
17 #include "rf5c164.h"
17 18
18 #define MCLKS_NTSC 53693175 19 #define MCLKS_NTSC 53693175
19 #define MCLKS_PAL 53203395 20 #define MCLKS_PAL 53203395
20 21
21 #define MCLKS_PER_68K 7 22 #define MCLKS_PER_68K 7
88 { 89 {
89 } 90 }
90 91
91 int headless = 0; 92 int headless = 0;
92 93
93 #define CYCLE_LIMIT MCLKS_NTSC/60 94 #include <limits.h>
94 #define MAX_SOUND_CYCLES 100000 95 #define ADJUST_BUFFER (12500000)
96 #define MAX_NO_ADJUST (UINT_MAX-ADJUST_BUFFER)
97 #define MAX_RUN_SAMPLES 128
95 tern_node * config; 98 tern_node * config;
96 99
97 void vgm_wait(ym2612_context * y_context, psg_context * p_context, uint32_t * current_cycle, uint32_t cycles) 100 typedef struct chip_info chip_info;
98 { 101 typedef void (*run_fun)(void *context, uint32_t cycle);
99 while (cycles > MAX_SOUND_CYCLES) 102 typedef void (*adjust_fun)(chip_info *chip);
103 struct chip_info {
104 void *context;
105 run_fun run;
106 adjust_fun adjust;
107 uint32_t clock;
108 uint32_t samples;
109 };
110
111 uint32_t cycles_to_samples(uint32_t clock_rate, uint32_t cycles)
112 {
113 return ((uint64_t)cycles) * ((uint64_t)44100) / ((uint64_t)clock_rate);
114 }
115
116 uint32_t samples_to_cycles(uint32_t clock_rate, uint32_t cycles)
117 {
118 return ((uint64_t)cycles) * ((uint64_t)clock_rate) / ((uint64_t)44100);
119 }
120
121 void ym_adjust(chip_info *chip)
122 {
123 ym2612_context *ym = chip->context;
124 if (ym->current_cycle >= MAX_NO_ADJUST) {
125 uint32_t deduction = ym->current_cycle - ADJUST_BUFFER;
126 chip->samples -= cycles_to_samples(chip->clock, deduction);
127 ym->current_cycle -= deduction;
128 }
129 }
130
131 void psg_adjust(chip_info *chip)
132 {
133 psg_context *psg = chip->context;
134 if (psg->cycles >= MAX_NO_ADJUST) {
135 uint32_t deduction = psg->cycles - ADJUST_BUFFER;
136 chip->samples -= cycles_to_samples(chip->clock, deduction);
137 psg->cycles -= deduction;
138 }
139 }
140
141 void pcm_adjust(chip_info *chip)
142 {
143 rf5c164 *pcm = chip->context;
144 if (pcm->cycle >= MAX_NO_ADJUST) {
145 uint32_t deduction = pcm->cycle - ADJUST_BUFFER;
146 chip->samples -= cycles_to_samples(chip->clock, deduction);
147 pcm->cycle -= deduction;
148 }
149 }
150
151 void vgm_wait(chip_info *chips, uint32_t num_chips, uint32_t *completed_samples, uint32_t samples)
152 {
153 while (samples > MAX_RUN_SAMPLES)
100 { 154 {
101 vgm_wait(y_context, p_context, current_cycle, MAX_SOUND_CYCLES); 155 vgm_wait(chips, num_chips, completed_samples, MAX_RUN_SAMPLES);
102 cycles -= MAX_SOUND_CYCLES; 156 samples -= MAX_RUN_SAMPLES;
103 } 157 }
104 *current_cycle += cycles; 158 *completed_samples += samples;
105 psg_run(p_context, *current_cycle); 159 for (uint32_t i = 0; i < num_chips; i++)
106 ym_run(y_context, *current_cycle); 160 {
107 161 chips[i].samples += samples;
108 if (*current_cycle > CYCLE_LIMIT) { 162 chips[i].run(chips[i].context, samples_to_cycles(chips[i].clock, chips[i].samples));
109 *current_cycle -= CYCLE_LIMIT; 163 chips[i].adjust(chips + i);
110 p_context->cycles -= CYCLE_LIMIT; 164 }
111 y_context->current_cycle -= CYCLE_LIMIT; 165 if (*completed_samples > 44100/60) {
112 process_events(); 166 process_events();
113 } 167 }
168 }
169
170 chip_info chips[64];
171
172 uint8_t *find_block(data_block *head, uint32_t offset, uint32_t size)
173 {
174 if (!head) {
175 return NULL;
176 }
177 while (head->size < offset) {
178 offset -= head->size;
179 head = head->next;
180 }
181 if (head->size - offset < size) {
182 return NULL;
183 }
184 return head->data + offset;
114 } 185 }
115 186
116 int main(int argc, char ** argv) 187 int main(int argc, char ** argv)
117 { 188 {
118 set_exe_str(argv[0]); 189 set_exe_str(argv[0]);
119 data_block *blocks = NULL; 190 data_block *blocks = NULL;
120 data_block *seek_block = NULL; 191 data_block *seek_block = NULL;
192 data_block *pcm68_blocks = NULL;
193 data_block *pcm164_blocks = NULL;
121 uint32_t seek_offset; 194 uint32_t seek_offset;
122 uint32_t block_offset; 195 uint32_t block_offset;
123 196
124 uint32_t fps = 60; 197 uint32_t fps = 60;
125 config = load_config(argv[0]); 198 config = load_config(argv[0]);
127 200
128 uint32_t opts = 0; 201 uint32_t opts = 0;
129 if (argc >= 3 && !strcmp(argv[2], "-y")) { 202 if (argc >= 3 && !strcmp(argv[2], "-y")) {
130 opts |= YM_OPT_WAVE_LOG; 203 opts |= YM_OPT_WAVE_LOG;
131 } 204 }
132 205
133 char * lowpass_cutoff_str = tern_find_path(config, "audio\0lowpass_cutoff\0", TVAL_PTR).ptrval; 206 char * lowpass_cutoff_str = tern_find_path(config, "audio\0lowpass_cutoff\0", TVAL_PTR).ptrval;
134 uint32_t lowpass_cutoff = lowpass_cutoff_str ? atoi(lowpass_cutoff_str) : 3390; 207 uint32_t lowpass_cutoff = lowpass_cutoff_str ? atoi(lowpass_cutoff_str) : 3390;
135 208
136 ym2612_context y_context; 209 VGMFILE f = vgmopen(argv[1], "rb");
137 ym_init(&y_context, MCLKS_NTSC, MCLKS_PER_YM, opts);
138
139 psg_context p_context;
140 psg_init(&p_context, MCLKS_NTSC, MCLKS_PER_PSG);
141
142 VGMFILE * f = vgmopen(argv[1], "rb");
143 vgm_header header; 210 vgm_header header;
144 vgmread(&header, sizeof(header), 1, f); 211 vgmread(&header, sizeof(header), 1, f);
145 if (header.version < 0x150 || !header.data_offset) { 212 if (header.version < 0x150 || !header.data_offset) {
146 header.data_offset = 0xC; 213 header.data_offset = 0xC;
147 } 214 }
215 if (header.version <= 0x101) {
216 header.ym2612_clk = header.ym2413_clk;
217 }
218 uint32_t num_chips = 0;
219 rf5c164 *pcm68 = NULL;
220 if ((header.data_offset + 0x34) >= 0x44) {
221 uint32_t pcm68_clock = 0;
222 vgmseek(f, 0x40, SEEK_SET);
223 vgmread(&pcm68_clock, sizeof(pcm68_clock), 1, f);
224 if (pcm68_clock) {
225 pcm68 = calloc(sizeof(*pcm68), 1);
226 rf5c164_init(pcm68, pcm68_clock, 1);
227 chips[num_chips++] = (chip_info) {
228 .context = pcm68,
229 .run = (run_fun)rf5c164_run,
230 .adjust = pcm_adjust,
231 .clock = pcm68_clock,
232 .samples = 0
233 };
234 }
235 }
236 rf5c164 *pcm164 = NULL;
237 if ((header.data_offset + 0x34) >= 0x70) {
238 uint32_t pcm164_clock = 0;
239 vgmseek(f, 0x6C, SEEK_SET);
240 vgmread(&pcm164_clock, sizeof(pcm164_clock), 1, f);
241 if (pcm164_clock) {
242 pcm164 = calloc(sizeof(*pcm164), 1);
243 rf5c164_init(pcm164, pcm164_clock, 1);
244 chips[num_chips++] = (chip_info) {
245 .context = pcm164,
246 .run = (run_fun)rf5c164_run,
247 .adjust = pcm_adjust,
248 .clock = pcm164_clock,
249 .samples = 0
250 };
251 }
252 }
253
254 ym2612_context y_context;
255 if (header.ym2612_clk) {
256 ym_init(&y_context, header.ym2612_clk, 1, opts);
257 chips[num_chips++] = (chip_info) {
258 .context = &y_context,
259 .run = (run_fun)ym_run,
260 .adjust = ym_adjust,
261 .clock = header.ym2612_clk,
262 .samples = 0
263 };
264 }
265
266 psg_context p_context;
267 if (header.sn76489_clk) {
268 psg_init(&p_context, header.sn76489_clk, 1);
269 chips[num_chips++] = (chip_info) {
270 .context = &p_context,
271 .run = (run_fun)psg_run,
272 .adjust = psg_adjust,
273 .clock = header.sn76489_clk,
274 .samples = 0
275 };
276 }
277
148 vgmseek(f, header.data_offset + 0x34, SEEK_SET); 278 vgmseek(f, header.data_offset + 0x34, SEEK_SET);
149 uint32_t data_size = header.eof_offset + 4 - (header.data_offset + 0x34); 279 uint32_t data_size = header.eof_offset + 4 - (header.data_offset + 0x34);
150 uint8_t * data = malloc(data_size); 280 uint8_t * data = malloc(data_size);
151 vgmread(data, 1, data_size, f); 281 vgmread(data, 1, data_size, f);
152 vgmclose(f); 282 vgmclose(f);
153 283
154 uint32_t mclks_sample = MCLKS_NTSC / 44100;
155 uint32_t loop_count = 2; 284 uint32_t loop_count = 2;
156 285
157 uint8_t * end = data + data_size; 286 uint8_t * end = data + data_size;
158 uint8_t * cur = data; 287 uint8_t * cur = data;
159 uint32_t current_cycle = 0; 288 uint32_t completed_samples = 0;
160 while (cur < end) { 289 while (cur < end) {
161 uint8_t cmd = *(cur++); 290 uint8_t cmd = *(cur++);
162 switch(cmd) 291 switch(cmd)
163 { 292 {
164 case CMD_PSG_STEREO: 293 case CMD_PSG_STEREO:
177 ym_data_write(&y_context, *(cur++)); 306 ym_data_write(&y_context, *(cur++));
178 break; 307 break;
179 case CMD_WAIT: { 308 case CMD_WAIT: {
180 uint32_t wait_time = *(cur++); 309 uint32_t wait_time = *(cur++);
181 wait_time |= *(cur++) << 8; 310 wait_time |= *(cur++) << 8;
182 wait_time *= mclks_sample; 311 vgm_wait(chips, num_chips, &completed_samples, wait_time);
183 vgm_wait(&y_context, &p_context, &current_cycle, wait_time);
184 break; 312 break;
185 } 313 }
186 case CMD_WAIT_60: 314 case CMD_WAIT_60:
187 vgm_wait(&y_context, &p_context, &current_cycle, 735 * mclks_sample); 315 vgm_wait(chips, num_chips, &completed_samples, 735);
188 break; 316 break;
189 case CMD_WAIT_50: 317 case CMD_WAIT_50:
190 vgm_wait(&y_context, &p_context, &current_cycle, 882 * mclks_sample); 318 vgm_wait(chips, num_chips, &completed_samples, 882);
191 break; 319 break;
192 case CMD_END: 320 case CMD_END:
193 if (header.loop_offset && --loop_count) { 321 if (header.loop_offset && --loop_count) {
194 cur = data + header.loop_offset + 0x1C - (header.data_offset + 0x34); 322 cur = data + header.loop_offset + 0x1C - (header.data_offset + 0x34);
195 } else { 323 } else {
196 //TODO: fade out 324 //TODO: fade out
197 return 0; 325 return 0;
326 }
327 break;
328 case CMD_PCM_WRITE:
329 if (end - cur < 11) {
330 fatal_error("early end of stream at offset %X\n", data-cur);
331 }
332 cur++;
333 {
334 uint8_t chip_type = *(cur++);
335 uint32_t read_offset = *(cur++);
336 read_offset |= *(cur++) << 8;
337 read_offset |= *(cur++) << 16;
338 uint32_t write_offset = *(cur++);
339 write_offset |= *(cur++) << 8;
340 write_offset |= *(cur++) << 16;
341 uint32_t size = *(cur++);
342 size |= *(cur++) << 8;
343 size |= *(cur++) << 16;
344 if (chip_type == DATA_RF5C68) {
345 uint8_t *src = find_block(pcm68_blocks, read_offset, size);
346 if (!src) {
347 printf("Failed to find RF6C68 data offset %X with size %X\n", read_offset, size);
348 }
349 write_offset |= pcm68->ram_bank;
350 write_offset &= 0xFFFF;
351 if (size + write_offset > 0x10000) {
352 size = 0x10000 - write_offset;
353 }
354 memcpy(pcm68->ram + write_offset, src, size);
355 printf("rf5c68 PCM write read_offset %X, write_offset %X, size %X\n", read_offset, write_offset, size);
356 } else if (chip_type == DATA_RF5C164) {
357 uint8_t *src = find_block(pcm164_blocks, read_offset, size);
358 if (!src) {
359 printf("Failed to find RF6C68 data offset %X with size %X\n", read_offset, size);
360 }
361 write_offset |= pcm164->ram_bank;
362 write_offset &= 0xFFFF;
363 if (size + write_offset > 0x10000) {
364 size = 0x10000 - write_offset;
365 }
366 memcpy(pcm164->ram + write_offset, src, size);
367 printf("rf5c164 PCM write read_offset %X, write_offset %X, size %X\n", read_offset, write_offset, size);
368 } else {
369 printf("unknown PCM write read_offset %X, write_offset %X, size %X\n", read_offset, write_offset, size);
370 }
371 }
372 break;
373 case CMD_PCM68_REG:
374 if (pcm68) {
375 uint8_t reg = *(cur++);
376 uint8_t value = *(cur++);
377
378 rf5c164_write(pcm68, reg, value);
379 } else {
380 printf("CMD_PCM68_REG without rf5c68 clock\n");
381 cur += 2;
382 }
383 break;
384 case CMD_PCM164_REG:
385 if (pcm164) {
386 uint8_t reg = *(cur++);
387 uint8_t value = *(cur++);
388 rf5c164_write(pcm164, reg, value);
389 } else {
390 printf("CMD_PCM164_REG without rf5c164 clock\n");
391 cur += 2;
392 }
393 break;
394 case CMD_PCM68_RAM:
395 if (pcm68) {
396 uint16_t address = *(cur++);
397 address |= *(cur++) << 8;
398 address &= 0xFFF;
399 address |= 0x1000;
400 uint8_t value = *(cur++);
401 rf5c164_write(pcm68, address, value);
402 }
403 break;
404 case CMD_PCM164_RAM:
405 if (pcm164) {
406 uint16_t address = *(cur++);
407 address |= *(cur++) << 8;
408 address &= 0xFFF;
409 address |= 0x1000;
410 uint8_t value = *(cur++);
411 rf5c164_write(pcm164, address, value);
198 } 412 }
199 break; 413 break;
200 case CMD_DATA: { 414 case CMD_DATA: {
201 cur++; //skip compat command 415 cur++; //skip compat command
202 uint8_t data_type = *(cur++); 416 uint8_t data_type = *(cur++);
203 uint32_t data_size = *(cur++); 417 uint32_t data_size = *(cur++);
204 data_size |= *(cur++) << 8; 418 data_size |= *(cur++) << 8;
205 data_size |= *(cur++) << 16; 419 data_size |= *(cur++) << 16;
206 data_size |= *(cur++) << 24; 420 data_size |= *(cur++) << 24;
421 data_block **curblock = NULL;
207 if (data_type == DATA_YM2612_PCM) { 422 if (data_type == DATA_YM2612_PCM) {
208 data_block ** curblock = &blocks; 423 curblock = &blocks;
424 } else if (data_type == DATA_RF5C68) {
425 curblock = &pcm68_blocks;
426 } else if (data_type == DATA_RF5C164) {
427 curblock = &pcm164_blocks;
428 }
429
430 if (curblock) {
209 while(*curblock) 431 while(*curblock)
210 { 432 {
211 curblock = &((*curblock)->next); 433 curblock = &((*curblock)->next);
212 } 434 }
213 *curblock = malloc(sizeof(data_block)); 435 *curblock = malloc(sizeof(data_block));
243 } 465 }
244 466
245 default: 467 default:
246 if (cmd >= CMD_WAIT_SHORT && cmd < (CMD_WAIT_SHORT + 0x10)) { 468 if (cmd >= CMD_WAIT_SHORT && cmd < (CMD_WAIT_SHORT + 0x10)) {
247 uint32_t wait_time = (cmd & 0xF) + 1; 469 uint32_t wait_time = (cmd & 0xF) + 1;
248 wait_time *= mclks_sample; 470 vgm_wait(chips, num_chips, &completed_samples, wait_time);
249 vgm_wait(&y_context, &p_context, &current_cycle, wait_time);
250 } else if (cmd >= CMD_YM2612_DAC && cmd < CMD_DAC_STREAM_SETUP) { 471 } else if (cmd >= CMD_YM2612_DAC && cmd < CMD_DAC_STREAM_SETUP) {
251 if (seek_block) { 472 if (seek_block) {
252 ym_address_write_part1(&y_context, 0x2A); 473 ym_address_write_part1(&y_context, 0x2A);
253 ym_data_write(&y_context, seek_block->data[block_offset++]); 474 ym_data_write(&y_context, seek_block->data[block_offset++]);
254 seek_offset++; 475 seek_offset++;
260 fputs("Encountered DAC write command but data seek pointer is invalid!\n", stderr); 481 fputs("Encountered DAC write command but data seek pointer is invalid!\n", stderr);
261 } 482 }
262 uint32_t wait_time = (cmd & 0xF); 483 uint32_t wait_time = (cmd & 0xF);
263 if (wait_time) 484 if (wait_time)
264 { 485 {
265 wait_time *= mclks_sample; 486 vgm_wait(chips, num_chips, &completed_samples, wait_time);
266 vgm_wait(&y_context, &p_context, &current_cycle, wait_time);
267 } 487 }
268 } else { 488 } else {
269 fatal_error("unimplemented command: %X at offset %X\n", cmd, (unsigned int)(cur - data - 1)); 489 fatal_error("unimplemented command: %X at offset %X\n", cmd, (unsigned int)(cur - data - 1));
270 } 490 }
271 } 491 }