comparison mediaplayer.c @ 2374:97f164d1f0f6

Re-enable VGM looping. Enable oscilloscope in VGM player. Fix VGM player PSG output
author Michael Pavone <pavone@retrodev.com>
date Wed, 15 Nov 2023 23:23:52 -0800
parents 0343f0d5add0
children 02c04196c2da
comparison
equal deleted inserted replaced
2373:f6213de4224c 2374:97f164d1f0f6
44 chip->samples -= cycles_to_samples(chip->clock, deduction); 44 chip->samples -= cycles_to_samples(chip->clock, deduction);
45 ym->current_cycle -= deduction; 45 ym->current_cycle -= deduction;
46 } 46 }
47 } 47 }
48 48
49 void ym_scope(chip_info *chip, oscilloscope *scope)
50 {
51 ym_enable_scope(chip->context, scope, chip->clock);
52 }
53
54 void ym_no_scope(void *context)
55 {
56 ym2612_context *ym = context;
57 ym->scope = NULL;
58 }
59
49 void psg_adjust(chip_info *chip) 60 void psg_adjust(chip_info *chip)
50 { 61 {
51 psg_context *psg = chip->context; 62 psg_context *psg = chip->context;
52 if (psg->cycles >= MAX_NO_ADJUST) { 63 if (psg->cycles >= MAX_NO_ADJUST) {
53 uint32_t deduction = psg->cycles - ADJUST_BUFFER; 64 uint32_t deduction = psg->cycles - ADJUST_BUFFER;
54 chip->samples -= cycles_to_samples(chip->clock, deduction); 65 chip->samples -= cycles_to_samples(chip->clock, deduction);
55 psg->cycles -= deduction; 66 psg->cycles -= deduction;
56 } 67 }
57 } 68 }
58 69
70 void psg_scope(chip_info *chip, oscilloscope *scope)
71 {
72 psg_enable_scope(chip->context, scope, chip->clock);
73 }
74
75 void psg_no_scope(void *context)
76 {
77 psg_context *psg = context;
78 psg->scope = NULL;
79 }
80
59 void pcm_adjust(chip_info *chip) 81 void pcm_adjust(chip_info *chip)
60 { 82 {
61 rf5c164 *pcm = chip->context; 83 rf5c164 *pcm = chip->context;
62 if (pcm->cycle >= MAX_NO_ADJUST) { 84 if (pcm->cycle >= MAX_NO_ADJUST) {
63 uint32_t deduction = pcm->cycle - ADJUST_BUFFER; 85 uint32_t deduction = pcm->cycle - ADJUST_BUFFER;
64 chip->samples -= cycles_to_samples(chip->clock, deduction); 86 chip->samples -= cycles_to_samples(chip->clock, deduction);
65 pcm->cycle -= deduction; 87 pcm->cycle -= deduction;
66 } 88 }
67 } 89 }
68 90
91 void pcm_scope(chip_info *chip, oscilloscope *scope)
92 {
93 rf5c164_enable_scope(chip->context, scope);
94 }
95
96 void pcm_no_scope(void *context)
97 {
98 rf5c164 *pcm = context;
99 pcm->scope = NULL;
100 }
101
69 uint8_t *find_block(data_block *head, uint32_t offset, uint32_t size) 102 uint8_t *find_block(data_block *head, uint32_t offset, uint32_t size)
70 { 103 {
71 if (!head) { 104 if (!head) {
72 return NULL; 105 return NULL;
73 } 106 }
101 void vgm_stop(media_player *player) 134 void vgm_stop(media_player *player)
102 { 135 {
103 player->state = STATE_PAUSED; 136 player->state = STATE_PAUSED;
104 player->playback_time = 0; 137 player->playback_time = 0;
105 player->current_offset = player->vgm->data_offset + offsetof(vgm_header, data_offset); 138 player->current_offset = player->vgm->data_offset + offsetof(vgm_header, data_offset);
139 player->loop_count = 2;
106 } 140 }
107 141
108 chip_info *find_chip(media_player *player, uint8_t cmd) 142 chip_info *find_chip(media_player *player, uint8_t cmd)
109 { 143 {
110 for (uint32_t i = 0; i < player->num_chips; i++) 144 for (uint32_t i = 0; i < player->num_chips; i++)
177 } 211 }
178 vgm_wait(player, to_wait); 212 vgm_wait(player, to_wait);
179 player->wait_samples -= to_wait; 213 player->wait_samples -= to_wait;
180 remaining_samples -= to_wait; 214 remaining_samples -= to_wait;
181 if (player->wait_samples) { 215 if (player->wait_samples) {
182 return; 216 goto frame_end;
183 } 217 }
184 } 218 }
185 if (player->current_offset >= player->media->size) { 219 if (player->current_offset >= player->media->size) {
186 vgm_stop(player); 220 vgm_stop(player);
187 return; 221 goto frame_end;
188 } 222 }
189 uint8_t cmd = read_byte(player); 223 uint8_t cmd = read_byte(player);
190 psg_context *psg; 224 psg_context *psg;
191 ym2612_context *ym; 225 ym2612_context *ym;
192 rf5c164 *pcm; 226 rf5c164 *pcm;
194 { 228 {
195 case CMD_PSG_STEREO: 229 case CMD_PSG_STEREO:
196 psg = find_chip_context(player, CMD_PSG); 230 psg = find_chip_context(player, CMD_PSG);
197 if (!psg || player->current_offset > player->media->size - 1) { 231 if (!psg || player->current_offset > player->media->size - 1) {
198 vgm_stop(player); 232 vgm_stop(player);
199 return; 233 goto frame_end;
200 } 234 }
201 psg->pan = read_byte(player); 235 psg->pan = read_byte(player);
202 break; 236 break;
203 case CMD_PSG: 237 case CMD_PSG:
204 psg = find_chip_context(player, CMD_PSG); 238 psg = find_chip_context(player, CMD_PSG);
205 if (!psg || player->current_offset > player->media->size - 1) { 239 if (!psg || player->current_offset > player->media->size - 1) {
206 vgm_stop(player); 240 vgm_stop(player);
207 return; 241 goto frame_end;
208 } 242 }
209 psg_write(psg, read_byte(player)); 243 psg_write(psg, read_byte(player));
210 break; 244 break;
211 case CMD_YM2612_0: 245 case CMD_YM2612_0:
212 ym = find_chip_context(player, CMD_YM2612_0); 246 ym = find_chip_context(player, CMD_YM2612_0);
213 if (!ym || player->current_offset > player->media->size - 2) { 247 if (!ym || player->current_offset > player->media->size - 2) {
214 vgm_stop(player); 248 vgm_stop(player);
215 return; 249 goto frame_end;
216 } 250 }
217 ym_address_write_part1(ym, read_byte(player)); 251 ym_address_write_part1(ym, read_byte(player));
218 ym_data_write(ym, read_byte(player)); 252 ym_data_write(ym, read_byte(player));
219 break; 253 break;
220 case CMD_YM2612_1: 254 case CMD_YM2612_1:
221 ym = find_chip_context(player, CMD_YM2612_0); 255 ym = find_chip_context(player, CMD_YM2612_0);
222 if (!ym || player->current_offset > player->media->size - 2) { 256 if (!ym || player->current_offset > player->media->size - 2) {
223 vgm_stop(player); 257 vgm_stop(player);
224 return; 258 goto frame_end;
225 } 259 }
226 ym_address_write_part2(ym, read_byte(player)); 260 ym_address_write_part2(ym, read_byte(player));
227 ym_data_write(ym, read_byte(player)); 261 ym_data_write(ym, read_byte(player));
228 break; 262 break;
229 case CMD_WAIT: { 263 case CMD_WAIT: {
230 if (player->current_offset > player->media->size - 2) { 264 if (player->current_offset > player->media->size - 2) {
231 vgm_stop(player); 265 vgm_stop(player);
232 return; 266 goto frame_end;
233 } 267 }
234 player->wait_samples += read_word_le(player); 268 player->wait_samples += read_word_le(player);
235 break; 269 break;
236 } 270 }
237 case CMD_WAIT_60: 271 case CMD_WAIT_60:
239 break; 273 break;
240 case CMD_WAIT_50: 274 case CMD_WAIT_50:
241 player->wait_samples += 882; 275 player->wait_samples += 882;
242 break; 276 break;
243 case CMD_END: 277 case CMD_END:
244 //TODO: loops 278 if (player->vgm->loop_offset && --player->loop_count) {
245 vgm_stop(player); 279 player->current_offset = player->vgm->loop_offset + offsetof(vgm_header, loop_offset);
280 if (player->current_offset < player->vgm->data_offset + offsetof(vgm_header, data_offset)) {
281 // invalid loop offset
282 vgm_stop(player);
283 goto frame_end;
284 }
285 } else {
286 //TODO: fade out?
287 vgm_stop(player);
288 goto frame_end;
289 }
246 return; 290 return;
247 case CMD_PCM_WRITE: { 291 case CMD_PCM_WRITE: {
248 if (player->current_offset > player->media->size - 11) { 292 if (player->current_offset > player->media->size - 11) {
249 vgm_stop(player); 293 vgm_stop(player);
250 return; 294 goto frame_end;
251 } 295 }
252 player->current_offset++; //skip compatibility command 296 player->current_offset++; //skip compatibility command
253 uint8_t data_type = read_byte(player); 297 uint8_t data_type = read_byte(player);
254 uint32_t read_offset = read_24_le(player); 298 uint32_t read_offset = read_24_le(player);
255 uint32_t write_offset = read_24_le(player); 299 uint32_t write_offset = read_24_le(player);
335 player->current_offset++; //skip compat command 379 player->current_offset++; //skip compat command
336 uint8_t data_type = read_byte(player); 380 uint8_t data_type = read_byte(player);
337 uint32_t data_size = read_long_le(player); 381 uint32_t data_size = read_long_le(player);
338 if (data_size > player->media->size || player->current_offset > player->media->size - data_size) { 382 if (data_size > player->media->size || player->current_offset > player->media->size - data_size) {
339 vgm_stop(player); 383 vgm_stop(player);
340 return; 384 goto frame_end;
341 } 385 }
342 chip_info *chip = find_chip_by_data(player, data_type); 386 chip_info *chip = find_chip_by_data(player, data_type);
343 if (chip) { 387 if (chip) {
344 data_block **cur = &(chip->blocks); 388 data_block **cur = &(chip->blocks);
345 while (*cur) 389 while (*cur)
400 } 444 }
401 player->wait_samples += cmd & 0xF; 445 player->wait_samples += cmd & 0xF;
402 } else { 446 } else {
403 warning("unimplemented command: %X at offset %X\n", cmd, player->current_offset); 447 warning("unimplemented command: %X at offset %X\n", cmd, player->current_offset);
404 vgm_stop(player); 448 vgm_stop(player);
405 return; 449 goto frame_end;
406 } 450 }
407 } 451 }
452 }
453 frame_end:
454 if (player->scope) {
455 scope_render(player->scope);
408 } 456 }
409 } 457 }
410 458
411 void wave_frame(media_player *player) 459 void wave_frame(media_player *player)
412 { 460 {
491 if (player->vgm_ext && player->vgm_ext->rf5c164_clk) { 539 if (player->vgm_ext && player->vgm_ext->rf5c164_clk) {
492 player->num_chips++; 540 player->num_chips++;
493 } 541 }
494 player->chips = calloc(player->num_chips, sizeof(chip_info)); 542 player->chips = calloc(player->num_chips, sizeof(chip_info));
495 uint32_t chip = 0; 543 uint32_t chip = 0;
496 if (player->vgm->sn76489_clk) {
497 psg_context *psg = calloc(1, sizeof(psg_context));
498 psg_init(psg, player->vgm->sn76489_clk, 1);
499 player->chips[chip++] = (chip_info) {
500 .context = psg,
501 .run = (chip_run_fun)psg_run,
502 .adjust = psg_adjust,
503 .clock = player->vgm->sn76489_clk,
504 .samples = 0,
505 .cmd = CMD_PSG,
506 .data_type = 0xFF
507 };
508 }
509 if (player->vgm->ym2612_clk) { 544 if (player->vgm->ym2612_clk) {
510 ym2612_context *ym = calloc(1, sizeof(ym2612_context)); 545 ym2612_context *ym = calloc(1, sizeof(ym2612_context));
511 ym_init(ym, player->vgm->ym2612_clk, 1, opts); 546 ym_init(ym, player->vgm->ym2612_clk, 1, opts);
512 player->chips[chip++] = (chip_info) { 547 player->chips[chip++] = (chip_info) {
513 .context = ym, 548 .context = ym,
514 .run = (chip_run_fun)ym_run, 549 .run = (chip_run_fun)ym_run,
515 .adjust = ym_adjust, 550 .adjust = ym_adjust,
551 .scope = ym_scope,
552 .no_scope = ym_no_scope,
516 .clock = player->vgm->ym2612_clk, 553 .clock = player->vgm->ym2612_clk,
517 .samples = 0, 554 .samples = 0,
518 .cmd = CMD_YM2612_0, 555 .cmd = CMD_YM2612_0,
519 .data_type = DATA_YM2612_PCM 556 .data_type = DATA_YM2612_PCM
557 };
558 }
559 if (player->vgm->sn76489_clk) {
560 psg_context *psg = calloc(1, sizeof(psg_context));
561 psg_init(psg, player->vgm->sn76489_clk, 16);
562 player->chips[chip++] = (chip_info) {
563 .context = psg,
564 .run = (chip_run_fun)psg_run,
565 .adjust = psg_adjust,
566 .scope = psg_scope,
567 .no_scope = ym_no_scope,
568 .clock = player->vgm->sn76489_clk,
569 .samples = 0,
570 .cmd = CMD_PSG,
571 .data_type = 0xFF
520 }; 572 };
521 } 573 }
522 if (player->vgm_ext && player->vgm_ext->rf5c68_clk) { 574 if (player->vgm_ext && player->vgm_ext->rf5c68_clk) {
523 rf5c164 *pcm = calloc(1, sizeof(rf5c164)); 575 rf5c164 *pcm = calloc(1, sizeof(rf5c164));
524 rf5c164_init(pcm, player->vgm_ext->rf5c68_clk, 1); 576 rf5c164_init(pcm, player->vgm_ext->rf5c68_clk, 1);
525 player->chips[chip++] = (chip_info) { 577 player->chips[chip++] = (chip_info) {
526 .context = pcm, 578 .context = pcm,
527 .run = (chip_run_fun)rf5c164_run, 579 .run = (chip_run_fun)rf5c164_run,
528 .adjust = pcm_adjust, 580 .adjust = pcm_adjust,
581 .scope = pcm_scope,
582 .no_scope = pcm_no_scope,
529 .clock = player->vgm_ext->rf5c68_clk, 583 .clock = player->vgm_ext->rf5c68_clk,
530 .samples = 0, 584 .samples = 0,
531 .cmd = CMD_PCM68_REG, 585 .cmd = CMD_PCM68_REG,
532 .data_type = DATA_RF5C68 586 .data_type = DATA_RF5C68
533 }; 587 };
537 rf5c164_init(pcm, player->vgm_ext->rf5c164_clk, 1); 591 rf5c164_init(pcm, player->vgm_ext->rf5c164_clk, 1);
538 player->chips[chip++] = (chip_info) { 592 player->chips[chip++] = (chip_info) {
539 .context = pcm, 593 .context = pcm,
540 .run = (chip_run_fun)rf5c164_run, 594 .run = (chip_run_fun)rf5c164_run,
541 .adjust = pcm_adjust, 595 .adjust = pcm_adjust,
596 .scope = pcm_scope,
597 .no_scope = pcm_no_scope,
542 .clock = player->vgm_ext->rf5c164_clk, 598 .clock = player->vgm_ext->rf5c164_clk,
543 .samples = 0, 599 .samples = 0,
544 .cmd = CMD_PCM164_REG, 600 .cmd = CMD_PCM164_REG,
545 .data_type = DATA_RF5C164 601 .data_type = DATA_RF5C164
546 }; 602 };
547 } 603 }
548 player->current_offset = player->vgm->data_offset + offsetof(vgm_header, data_offset); 604 player->current_offset = player->vgm->data_offset + offsetof(vgm_header, data_offset);
605 player->loop_count = 2;
549 } 606 }
550 607
551 static void wave_player_init(media_player *player) 608 static void wave_player_init(media_player *player)
552 { 609 {
553 player->wave = calloc(1, sizeof(wave_header)); 610 player->wave = calloc(1, sizeof(wave_header));
686 { 743 {
687 media_player *player = (media_player *)system; 744 media_player *player = (media_player *)system;
688 player->should_return = 1; 745 player->should_return = 1;
689 } 746 }
690 747
748 static void toggle_debug_view(system_header *system, uint8_t debug_view)
749 {
750 #ifndef IS_LIB
751 media_player *player = (media_player *)system;
752 if (debug_view == DEBUG_OSCILLOSCOPE && player->chips) {
753 if (player->scope) {
754 for (uint32_t i = 0; i < player->num_chips; i++)
755 {
756 player->chips[i].no_scope(player->chips[i].context);
757 }
758 scope_close(player->scope);
759 player->scope = NULL;
760 } else {
761 player->scope = create_oscilloscope();
762 for (uint32_t i = 0; i < player->num_chips; i++)
763 {
764 player->chips[i].scope(player->chips + i, player->scope);
765 }
766 }
767 }
768 #endif
769 }
770
691 media_player *alloc_media_player(system_media *media, uint32_t opts) 771 media_player *alloc_media_player(system_media *media, uint32_t opts)
692 { 772 {
693 media_player *player = calloc(1, sizeof(media_player)); 773 media_player *player = calloc(1, sizeof(media_player));
694 player->header.start_context = start_player; 774 player->header.start_context = start_player;
695 player->header.resume_context = resume_player; 775 player->header.resume_context = resume_player;
696 player->header.request_exit = request_exit; 776 player->header.request_exit = request_exit;
697 player->header.free_context = free_player; 777 player->header.free_context = free_player;
698 player->header.gamepad_down = gamepad_down; 778 player->header.gamepad_down = gamepad_down;
699 player->header.gamepad_up = gamepad_down; 779 player->header.gamepad_up = gamepad_down;
780 player->header.toggle_debug_view = toggle_debug_view;
700 player->header.type = SYSTEM_MEDIA_PLAYER; 781 player->header.type = SYSTEM_MEDIA_PLAYER;
701 player->header.info.name = strdup(media->name); 782 player->header.info.name = strdup(media->name);
702 783
703 player->media = media; 784 player->media = media;
704 player->media_type = detect_media_type(media); 785 player->media_type = detect_media_type(media);