Mercurial > repos > blastem
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); |