comparison mediaplayer.c @ 2482:fb8f49b0aece

Impelement partial support for DAC stream commands in VGM player
author Michael Pavone <pavone@retrodev.com>
date Sat, 30 Mar 2024 21:10:20 -0700
parents 9da3de58410d
children 6c834c281fa2
comparison
equal deleted inserted replaced
2481:f0645adddf0d 2482:fb8f49b0aece
19 AUDIO_WAVE, 19 AUDIO_WAVE,
20 AUDIO_FLAC, 20 AUDIO_FLAC,
21 MEDIA_UNKNOWN 21 MEDIA_UNKNOWN
22 }; 22 };
23 23
24 #define STREAM_FLAG_REVERSE 0x01
25 #define STREAM_FLAG_LOOP 0x10
26 #define STREAM_FLAG_PLAY 0x80
27
24 uint32_t cycles_to_samples(uint32_t clock_rate, uint32_t cycles) 28 uint32_t cycles_to_samples(uint32_t clock_rate, uint32_t cycles)
25 { 29 {
26 return ((uint64_t)cycles) * ((uint64_t)44100) / ((uint64_t)clock_rate); 30 return ((uint64_t)cycles) * ((uint64_t)44100) / ((uint64_t)clock_rate);
27 } 31 }
28 32
48 52
49 void ym_no_scope(void *context) 53 void ym_no_scope(void *context)
50 { 54 {
51 ym2612_context *ym = context; 55 ym2612_context *ym = context;
52 ym->scope = NULL; 56 ym->scope = NULL;
57 }
58
59 void ym_stream(chip_info *chip, uint8_t port, uint8_t command, uint16_t sample)
60 {
61 ym2612_context *ym = chip->context;
62 if (port) {
63 ym_address_write_part2(ym, command);
64 } else {
65 ym_address_write_part1(ym, command);
66 }
67 ym_data_write(ym, sample);
53 } 68 }
54 69
55 void psg_adjust(chip_info *chip) 70 void psg_adjust(chip_info *chip)
56 { 71 {
57 psg_context *psg = chip->context; 72 psg_context *psg = chip->context;
123 while (samples > MAX_RUN_SAMPLES) 138 while (samples > MAX_RUN_SAMPLES)
124 { 139 {
125 vgm_wait(player, MAX_RUN_SAMPLES); 140 vgm_wait(player, MAX_RUN_SAMPLES);
126 samples -= MAX_RUN_SAMPLES; 141 samples -= MAX_RUN_SAMPLES;
127 } 142 }
143 uint8_t keep_going;
144 do {
145 keep_going = 0;
146 for (uint32_t i = 0; i < 0xFF; i++)
147 {
148 if (!player->streams[i] || !(player->streams[i]->flags & STREAM_FLAG_PLAY)) {
149 continue;
150 }
151 vgm_stream *stream = player->streams[i];
152 uint32_t cycle = samples_to_cycles(stream->chip->clock, stream->chip->samples + samples);
153 if (cycle >= stream->next_sample_cycle) {
154 stream->chip->run(stream->chip->context, stream->next_sample_cycle);
155 if (stream->block_offset >= stream->cur_block->size) {
156 stream->cur_block = stream->cur_block->next;
157 if (!stream->cur_block) {
158 //TODO: looping support
159 player->streams[i]->flags &= ~STREAM_FLAG_PLAY;
160 continue;
161 }
162 }
163 //TODO: support for chips where the stream data unit is not a byte
164 uint16_t sample = stream->cur_block->data[stream->block_offset];
165 stream->block_offset += stream->step;
166 if (stream->chip->stream) {
167 stream->chip->stream(stream->chip, stream->port, stream->command, sample);
168 }
169 stream->next_sample_cycle += stream->cycles_per_sample;
170 //TODO: deal with cycle adjustments
171 keep_going = 1;
172 }
173 }
174 } while (keep_going);
128 for (uint32_t i = 0; i < num_chips; i++) 175 for (uint32_t i = 0; i < num_chips; i++)
129 { 176 {
130 chips[i].samples += samples; 177 chips[i].samples += samples;
131 chips[i].run(chips[i].context, samples_to_cycles(chips[i].clock, chips[i].samples)); 178 chips[i].run(chips[i].context, samples_to_cycles(chips[i].clock, chips[i].samples));
132 chips[i].adjust(chips + i); 179 chips[i].adjust(chips + i);
161 chip_info *find_chip_by_data(media_player *player, uint8_t data_type) 208 chip_info *find_chip_by_data(media_player *player, uint8_t data_type)
162 { 209 {
163 for (uint32_t i = 0; i < player->num_chips; i++) 210 for (uint32_t i = 0; i < player->num_chips; i++)
164 { 211 {
165 if (player->chips[i].data_type == data_type) { 212 if (player->chips[i].data_type == data_type) {
213 return &player->chips[i];
214 }
215 }
216 return NULL;
217 }
218
219 chip_info *find_chip_by_stream(media_player *player, uint8_t stream_type)
220 {
221 for (uint32_t i = 0; i < player->num_chips; i++)
222 {
223 if (player->chips[i].stream_type == stream_type) {
166 return &player->chips[i]; 224 return &player->chips[i];
167 } 225 }
168 } 226 }
169 return NULL; 227 return NULL;
170 } 228 }
398 (*cur)->data = ((uint8_t *)player->media->buffer) + player->current_offset; 456 (*cur)->data = ((uint8_t *)player->media->buffer) + player->current_offset;
399 } else { 457 } else {
400 fprintf(stderr, "Skipping data block with unrecognized type %X\n", data_type); 458 fprintf(stderr, "Skipping data block with unrecognized type %X\n", data_type);
401 } 459 }
402 player->current_offset += data_size; 460 player->current_offset += data_size;
461 }
462 break;
463 case CMD_DAC_STREAM_SETUP:
464 if (player->current_offset > player->media->size - 4) {
465 vgm_stop(player);
466 goto frame_end;
467 } else {
468 uint8_t stream_id = read_byte(player);
469 if (!player->streams[stream_id]) {
470 player->streams[stream_id] = calloc(1, sizeof(vgm_stream));
471 }
472 vgm_stream *stream = player->streams[stream_id];
473 uint8_t chip_type = read_byte(player);
474 stream->chip = find_chip_by_stream(player, chip_type);
475 if (!stream->chip) {
476 fprintf(stderr, "Failed to find chip with stream type %d for stream %d\n", chip_type, stream_id);
477 }
478 stream->port = read_byte(player);
479 stream->command = read_byte(player);
480 }
481 break;
482 case CMD_DAC_STREAM_DATA:
483 if (player->current_offset > player->media->size - 4) {
484 vgm_stop(player);
485 goto frame_end;
486 } else {
487 uint8_t stream_id = read_byte(player);
488 if (!player->streams[stream_id]) {
489 player->streams[stream_id] = calloc(1, sizeof(vgm_stream));
490 }
491 vgm_stream *stream = player->streams[stream_id];
492 stream->data_type = read_byte(player);
493 stream->step = read_byte(player);
494 stream->start_offset = read_byte(player);
495 }
496 break;
497 case CMD_DAC_STREAM_FREQ:
498 if (player->current_offset > player->media->size - 4) {
499 vgm_stop(player);
500 goto frame_end;
501 } else {
502 uint8_t stream_id = read_byte(player);
503 if (!player->streams[stream_id]) {
504 player->streams[stream_id] = calloc(1, sizeof(vgm_stream));
505 }
506 vgm_stream *stream = player->streams[stream_id];
507 stream->sample_rate = read_long_le(player);
508 if (stream->chip) {
509 stream->cycles_per_sample = stream->chip->clock / stream->sample_rate;
510 }
511 }
512 break;
513 case CMD_DAC_STREAM_START:
514 if (player->current_offset > player->media->size - 10) {
515 vgm_stop(player);
516 goto frame_end;
517 } else {
518 uint8_t stream_id = read_byte(player);
519 if (!player->streams[stream_id]) {
520 player->streams[stream_id] = calloc(1, sizeof(vgm_stream));
521 }
522 vgm_stream *stream = player->streams[stream_id];
523 uint32_t data_start_offset = read_long_le(player);
524 uint8_t length_mode = read_byte(player);
525 uint32_t length = read_long_le(player);
526 stream->flags = length_mode & STREAM_FLAG_REVERSE;
527 if (length_mode & 0x80) {
528 stream->flags |= STREAM_FLAG_LOOP;
529 }
530 length_mode &= 0x3;
531 if (length_mode) {
532 stream->length_mode = length_mode;
533 if (length_mode == 2) {
534 //length is in msec
535 if (stream->chip) {
536 stream->remaining = (((uint64_t)length) * (uint64_t)stream->sample_rate) / 1000;
537 }
538 } else if (length_mode == 3) {
539 //play until end of data
540 stream->remaining = 0xFFFFFFFF;
541 } else {
542 //length is in commands?
543 stream->remaining = length;
544 }
545 }
546 if (stream->chip && data_start_offset != 0xFFFFFFFF) {
547 data_block * cur_block = stream->chip->blocks;
548 data_start_offset += stream->start_offset;
549 while (cur_block)
550 {
551 if (cur_block->type == stream->data_type) {
552 if (data_start_offset >= cur_block->size) {
553 data_start_offset -= cur_block->size;
554 cur_block = cur_block->next;
555 } else {
556 stream->block_offset = data_start_offset;
557 stream->cur_block = cur_block;
558 break;
559 }
560 } else {
561 cur_block = cur_block->next;
562 }
563 }
564 }
565 if (stream->chip && stream->cur_block) {
566 stream->flags |= STREAM_FLAG_PLAY;
567 }
568 }
569 break;
570 case CMD_DAC_STREAM_STOP:
571 if (player->current_offset < player->media->size) {
572 vgm_stop(player);
573 goto frame_end;
574 } else {
575 uint8_t stream_id = read_byte(player);
576 if (stream_id == 0xFF) {
577 for (uint32_t i = 0; i < 0xFF; i++) {
578 if (player->streams[i]) {
579 player->streams[i]->flags &= ~STREAM_FLAG_PLAY;
580 }
581 }
582 } else {
583 if (!player->streams[stream_id]) {
584 player->streams[stream_id] = calloc(1, sizeof(vgm_stream));
585 }
586 player->streams[stream_id]->flags &= ~STREAM_FLAG_PLAY;
587 }
588 }
589 break;
590 case CMD_DAC_STREAM_STARTFAST:
591 if (player->current_offset > player->media->size - 4) {
592 vgm_stop(player);
593 goto frame_end;
594 } else {
595 uint8_t stream_id = read_byte(player);
596 if (!player->streams[stream_id]) {
597 player->streams[stream_id] = calloc(1, sizeof(vgm_stream));
598 }
599 vgm_stream *stream = player->streams[stream_id];
600 uint16_t block_id = read_word_le(player);
601 stream->flags = read_byte(player) & (STREAM_FLAG_LOOP|STREAM_FLAG_REVERSE);
602 if (stream->chip) {
603 uint16_t cur_block_id = 0;
604 data_block *cur_block = stream->chip->blocks;
605 while (cur_block)
606 {
607 if (cur_block_id == block_id) {
608 stream->cur_block = cur_block;
609 stream->block_offset = stream->start_offset;
610 break;
611 }
612 if (cur_block->type == stream->data_type) {
613 cur_block_id++;
614 }
615 cur_block = cur_block->next;
616 }
617 if (stream->cur_block) {
618 stream->flags |= STREAM_FLAG_PLAY;
619 stream->next_sample_cycle = samples_to_cycles(stream->chip->clock, stream->chip->samples);
620 }
621 }
403 } 622 }
404 break; 623 break;
405 case CMD_DATA_SEEK: 624 case CMD_DATA_SEEK:
406 if (player->current_offset > player->media->size - 4) { 625 if (player->current_offset > player->media->size - 4) {
407 vgm_stop(player); 626 vgm_stop(player);
556 .run = (chip_run_fun)ym_run, 775 .run = (chip_run_fun)ym_run,
557 .adjust = ym_adjust, 776 .adjust = ym_adjust,
558 .scope = ym_scope, 777 .scope = ym_scope,
559 .no_scope = ym_no_scope, 778 .no_scope = ym_no_scope,
560 .free = (chip_noarg_fun)ym_free, 779 .free = (chip_noarg_fun)ym_free,
780 .stream = ym_stream,
561 .clock = player->vgm->ym2612_clk, 781 .clock = player->vgm->ym2612_clk,
562 .samples = 0, 782 .samples = 0,
563 .cmd = CMD_YM2612_0, 783 .cmd = CMD_YM2612_0,
564 .data_type = DATA_YM2612_PCM 784 .data_type = DATA_YM2612_PCM,
785 .stream_type = STREAM_CHIP_YM2612
565 }; 786 };
566 } 787 }
567 if (player->vgm->sn76489_clk) { 788 if (player->vgm->sn76489_clk) {
568 psg_context *psg = calloc(1, sizeof(psg_context)); 789 psg_context *psg = calloc(1, sizeof(psg_context));
569 psg_init(psg, player->vgm->sn76489_clk, 16); 790 psg_init(psg, player->vgm->sn76489_clk, 16);
575 .no_scope = ym_no_scope, 796 .no_scope = ym_no_scope,
576 .free = (chip_noarg_fun)psg_free, 797 .free = (chip_noarg_fun)psg_free,
577 .clock = player->vgm->sn76489_clk, 798 .clock = player->vgm->sn76489_clk,
578 .samples = 0, 799 .samples = 0,
579 .cmd = CMD_PSG, 800 .cmd = CMD_PSG,
580 .data_type = 0xFF 801 .data_type = 0xFF,
802 .stream_type = STREAM_CHIP_PSG
581 }; 803 };
582 } 804 }
583 if (player->vgm_ext && player->vgm_ext->rf5c68_clk) { 805 if (player->vgm_ext && player->vgm_ext->rf5c68_clk) {
584 rf5c164 *pcm = calloc(1, sizeof(rf5c164)); 806 rf5c164 *pcm = calloc(1, sizeof(rf5c164));
585 rf5c164_init(pcm, player->vgm_ext->rf5c68_clk, 1); 807 rf5c164_init(pcm, player->vgm_ext->rf5c68_clk, 1);
591 .no_scope = pcm_no_scope, 813 .no_scope = pcm_no_scope,
592 .free = pcm_free, 814 .free = pcm_free,
593 .clock = player->vgm_ext->rf5c68_clk, 815 .clock = player->vgm_ext->rf5c68_clk,
594 .samples = 0, 816 .samples = 0,
595 .cmd = CMD_PCM68_REG, 817 .cmd = CMD_PCM68_REG,
596 .data_type = DATA_RF5C68 818 .data_type = DATA_RF5C68,
819 .stream_type = STREAM_CHIP_RF5C68
597 }; 820 };
598 } 821 }
599 if (player->vgm_ext && player->vgm_ext->rf5c164_clk) { 822 if (player->vgm_ext && player->vgm_ext->rf5c164_clk) {
600 rf5c164 *pcm = calloc(1, sizeof(rf5c164)); 823 rf5c164 *pcm = calloc(1, sizeof(rf5c164));
601 rf5c164_init(pcm, player->vgm_ext->rf5c164_clk, 1); 824 rf5c164_init(pcm, player->vgm_ext->rf5c164_clk, 1);
607 .no_scope = pcm_no_scope, 830 .no_scope = pcm_no_scope,
608 .free = pcm_free, 831 .free = pcm_free,
609 .clock = player->vgm_ext->rf5c164_clk, 832 .clock = player->vgm_ext->rf5c164_clk,
610 .samples = 0, 833 .samples = 0,
611 .cmd = CMD_PCM164_REG, 834 .cmd = CMD_PCM164_REG,
612 .data_type = DATA_RF5C164 835 .data_type = DATA_RF5C164,
836 .stream_type = STREAM_CHIP_RF5C164
613 }; 837 };
614 } 838 }
615 player->current_offset = player->vgm->data_offset + offsetof(vgm_header, data_offset); 839 player->current_offset = player->vgm->data_offset + offsetof(vgm_header, data_offset);
616 player->loop_count = 2; 840 player->loop_count = 2;
617 } 841 }