Mercurial > repos > blastem
changeset 2516:69c28808b49a
Fix some TOC/CUE parser bugs and simplify how "fake" pregap is handled
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Sat, 05 Oct 2024 01:03:57 -0700 |
parents | 0775f5e0c468 |
children | 9fb04d29049e |
files | cdd_mcu.c cdimage.c |
diffstat | 2 files changed, 131 insertions(+), 127 deletions(-) [+] |
line wrap: on
line diff
--- a/cdd_mcu.c Thu Sep 05 23:44:01 2024 -0700 +++ b/cdd_mcu.c Sat Oct 05 01:03:57 2024 -0700 @@ -221,7 +221,7 @@ if (context->head_pba > 3*(context->media->num_tracks + 2)) { context->toc_valid = 1; context->seeking = 1; - context->seek_pba = LEADIN_SECTORS + context->media->tracks[0].start_lba + context->media->tracks[0].fake_pregap; + context->seek_pba = LEADIN_SECTORS + context->media->tracks[0].start_lba; context->status = DS_PAUSE; } @@ -267,15 +267,6 @@ for (uint32_t i = 0; i < context->media->num_tracks; i++) { if (lba < context->media->tracks[i].end_lba) { - if (context->media->tracks[i].fake_pregap) { - if (lba > context->media->tracks[i].fake_pregap) { - lba -= context->media->tracks[i].fake_pregap; - } else { - //relative time counts down to 0 in pregap - lba = context->media->tracks[i].fake_pregap - lba; - break; - } - } if (lba < context->media->tracks[i].start_lba) { //relative time counts down to 0 in pregap lba = context->media->tracks[i].start_lba - lba; @@ -283,8 +274,6 @@ lba -= context->media->tracks[i].start_lba; } break; - } else if (context->media->tracks[i].fake_pregap) { - lba -= context->media->tracks[i].fake_pregap; } } lba_to_status(context, lba); @@ -300,24 +289,7 @@ for (i = 0; i < context->media->num_tracks; i++) { if (lba < context->media->tracks[i].end_lba) { - if (context->media->tracks[i].fake_pregap) { - if (lba > context->media->tracks[i].fake_pregap) { - lba -= context->media->tracks[i].fake_pregap; - } else { - //relative time counts down to 0 in pregap - lba = context->media->tracks[i].fake_pregap - lba; - break; - } - } - if (lba < context->media->tracks[i].start_lba) { - //relative time counts down to 0 in pregap - lba = context->media->tracks[i].start_lba - lba; - } else { - lba -= context->media->tracks[i].start_lba; - } break; - } else if (context->media->tracks[i].fake_pregap) { - lba -= context->media->tracks[i].fake_pregap; } } context->status_buffer.b.track.track_high = (i + 1) / 10; @@ -337,12 +309,7 @@ break; case SF_TOCO: if (context->toc_valid) { - uint32_t total_fake_pregap = 0; - for (uint32_t i = 0; i < context->media->num_tracks; i++) - { - total_fake_pregap += context->media->tracks[i].fake_pregap; - } - lba_to_status(context, context->media->tracks[context->media->num_tracks - 1].end_lba + total_fake_pregap); + lba_to_status(context, context->media->tracks[context->media->num_tracks - 1].end_lba); context->status_buffer.format = SF_TOCO; } else { context->status_buffer.format = SF_NOTREADY; @@ -367,9 +334,6 @@ exit(0); } uint32_t lba = context->media->tracks[context->requested_track - 1].start_lba; - for (uint32_t i = 0; i < context->requested_track; i++) { - lba += context->media->tracks[i].fake_pregap; - } lba_to_status(context, lba); if (context->media->tracks[context->requested_track - 1].type == TRACK_DATA) { context->status_buffer.b.tocn.frame_high |= 0x8; @@ -462,7 +426,7 @@ context->cmd_buffer.b.time.sec_high, context->cmd_buffer.b.time.sec_low, context->cmd_buffer.b.time.frame_high, context->cmd_buffer.b.time.frame_low ); - if (lba >= context->media->tracks[0].fake_pregap + context->media->tracks[context->media->num_tracks - 1].end_lba) { + if (lba >= context->media->tracks[context->media->num_tracks - 1].end_lba) { context->error_status = DS_CMD_ERROR; break; } @@ -534,7 +498,7 @@ } if (context->status == DS_STOP) { context->seeking = 1; - context->seek_pba = LEADIN_SECTORS + context->media->tracks[0].fake_pregap + context->media->tracks[0].start_lba; + context->seek_pba = LEADIN_SECTORS + context->media->tracks[0].start_lba; printf("CDD CMD: PAUSE, seeking to %u\n", context->seek_pba); } else { uint32_t lba = context->head_pba - LEADIN_SECTORS; @@ -572,7 +536,7 @@ } if (context->status == DS_STOP || context->status == DS_TOC_READ) { context->seeking = 1; - context->seek_pba = LEADIN_SECTORS + context->media->tracks[0].fake_pregap + context->media->tracks[0].start_lba - 4; + context->seek_pba = LEADIN_SECTORS + context->media->tracks[0].start_lba - 4; printf("CDD CMD: PLAY, seeking to %u\n", context->seek_pba); } else { puts("CDD CMD: PLAY");
--- a/cdimage.c Thu Sep 05 23:44:01 2024 -0700 +++ b/cdimage.c Sat Oct 05 01:03:57 2024 -0700 @@ -98,46 +98,37 @@ media->cur_sector = sector; uint32_t lba = sector; uint32_t track; + uint32_t rel; for (track = 0; track < media->num_tracks; track++) { - if (lba < media->tracks[track].fake_pregap) { + rel = lba - media->tracks[track].pregap_lba; + if (rel < media->tracks[track].fake_pregap) { media->in_fake_pregap = media->tracks[track].type == TRACK_DATA ? FAKE_DATA : FAKE_AUDIO; break; } - lba -= media->tracks[track].fake_pregap; - if (lba < media->tracks[track].start_lba) { - if (media->tracks[track].fake_pregap) { - media->in_fake_pregap = media->tracks[track].type == TRACK_DATA ? FAKE_DATA : FAKE_AUDIO; - } else { - media->in_fake_pregap = 0; - } - break; - } if (lba < media->tracks[track].end_lba) { media->in_fake_pregap = 0; + rel -= media->tracks[track].fake_pregap; break; } } if (track < media->num_tracks) { media->cur_track = track; if (!media->in_fake_pregap) { - if (track) { - lba -= media->tracks[track - 1].end_lba; - } if (media->tracks[track].flac) { - flac_seek(media->tracks[track].flac, (media->tracks[track].file_offset + lba * media->tracks[track].sector_bytes) / 4); + flac_seek(media->tracks[track].flac, (media->tracks[track].file_offset + rel * media->tracks[track].sector_bytes) / 4); } else { if (media->tracks[track].has_subcodes) { if (!media->tmp_buffer) { media->tmp_buffer = calloc(1, 96); } - fseek(media->tracks[track].f, media->tracks[track].file_offset + (lba + 1) * media->tracks[track].sector_bytes - 96, SEEK_SET); + fseek(media->tracks[track].f, media->tracks[track].file_offset + (rel + 1) * media->tracks[track].sector_bytes - 96, SEEK_SET); int bytes = fread(media->tmp_buffer, 1, 96, media->tracks[track].f); if (bytes != 96) { fprintf(stderr, "Only read %d subcode bytes\n", bytes); } } - fseek(media->tracks[track].f, media->tracks[track].file_offset + lba * media->tracks[track].sector_bytes, SEEK_SET); + fseek(media->tracks[track].f, media->tracks[track].file_offset + rel * media->tracks[track].sector_bytes, SEEK_SET); } } if (media->tracks[track].type == TRACK_DATA) { @@ -214,6 +205,25 @@ return media->tmp_buffer[offset]; } +static void print_toc(system_media *media) +{ + track_info * tracks = media->tracks; + for (uint32_t i = 0; i < media->num_tracks; i++) + { + uint32_t m,s,f; + f = tracks[i].pregap_lba % 75; + s = tracks[i].pregap_lba / 75; + m = s / 60; + s = s % 60; + printf("Track %02u - Index 0 %02u:%02u:%02u, Index 1 ", i + 1, m, s, f); + f = tracks[i].start_lba % 75; + s = tracks[i].start_lba / 75; + m = s / 60; + s = s % 60; + printf("%02u:%02u:%02u, Fake Pregap: %u\n", m, s, f, tracks[i].fake_pregap); + } +} + uint8_t parse_cue(system_media *media) { char *line = media->buffer; @@ -255,7 +265,6 @@ tracks[track].f = f; tracks[track].flac = flac; - cmd = cmd_start(end); if (*cmd) { if (startswith(cmd, "AUDIO")) { @@ -298,6 +307,17 @@ memcpy(fname + dirlen + 1, cmd, end-cmd); fname[dirlen + 1 + (end-cmd)] = 0; } + + if (track_of_file >= 0) { + long track_size = 0; + if (flac) { + track_size = flac->total_samples * 4; + } else if (f) { + track_size = file_size(f); + } + track_size -= tracks[track].file_offset; + tracks[track].end_lba = tracks[track].pregap_lba + tracks[track].fake_pregap + track_size / tracks[track].sector_bytes; + } flac = NULL; f = fopen(fname, "rb"); if (!f) { @@ -348,32 +368,63 @@ char *after; int index = strtol(cmd + 6, &after, 10); uint8_t has_start_lba = 0; - uint32_t start_lba; + uint32_t start_lba = timecode_to_lba(after); if (!index) { - tracks[track].pregap_lba = start_lba = timecode_to_lba(after); + tracks[track].file_offset = start_lba * tracks[track].sector_bytes + extra_offset; + if (track > 0) { + if (track_of_file > 0) { + //Previous track end is implicit based on this index position + uint32_t last_track_size = tracks[track].file_offset - tracks[track-1].file_offset; + last_track_size /= tracks[track-1].sector_bytes; + tracks[track-1].end_lba = tracks[track-1].pregap_lba + tracks[track-1].fake_pregap + last_track_size; + } + tracks[track].pregap_lba = tracks[track-1].end_lba; + } else { + tracks[track].pregap_lba = 0; + } has_index_0 = 1; has_start_lba = 1; } else if (index == 1) { - tracks[track].start_lba = timecode_to_lba(after); - if (!has_index_0) { - start_lba = tracks[track].start_lba; - if (!tracks[track].fake_pregap) { - tracks[track].pregap_lba = start_lba; + if (has_index_0) { + uint32_t real_pregap_size = start_lba * tracks[track].sector_bytes + extra_offset - tracks[track].file_offset; + real_pregap_size /= tracks[track].sector_bytes; + tracks[track].start_lba = tracks[track].pregap_lba + tracks[track].fake_pregap + real_pregap_size; + } else { + tracks[track].file_offset = start_lba * tracks[track].sector_bytes + extra_offset; + if (track > 0) { + if (track_of_file > 0) { + //Previous track end is implicit based on this index position + uint32_t last_track_size = tracks[track].file_offset - tracks[track-1].file_offset; + last_track_size /= tracks[track-1].sector_bytes; + tracks[track-1].end_lba = tracks[track-1].pregap_lba + tracks[track-1].fake_pregap + last_track_size; + } + tracks[track].pregap_lba = tracks[track-1].end_lba; + tracks[track].start_lba = tracks[track].pregap_lba + tracks[track].fake_pregap; + } else { + tracks[track].pregap_lba = 0; + if (!tracks[track].fake_pregap) { + if (tracks[track].type == TRACK_DATA && tracks[track].sector_bytes == 2352) { + //Infer pregap from position in sector header + fseek(f, start_lba + 12, SEEK_SET); + uint8_t timecode[3]; + if (sizeof(timecode) == fread(timecode, 1, sizeof(timecode), f)) { + tracks[track].fake_pregap = (timecode[0] >> 4) * 600; + tracks[track].fake_pregap += (timecode[0] & 0xF) * 60; + tracks[track].fake_pregap += (timecode[1] >> 4) * 10; + tracks[track].fake_pregap += timecode[1] & 0xF; + tracks[track].fake_pregap *= 75; + tracks[track].fake_pregap += (timecode[2] >> 4) * 10; + tracks[track].fake_pregap += timecode[2] & 0xF; + } else { + fatal_error("Failed to read from CD image"); + } + } else { + //Just assume a 2-second pre-gap for first track + tracks[track].fake_pregap = 2 * 75; + } + } + tracks[track].start_lba = tracks[track].fake_pregap; } - has_start_lba = 1; - } - } - if (has_start_lba) { - if (track > 0) { - tracks[track-1].end_lba = start_lba; - } - if (track_of_file > 0) { - tracks[track].file_offset = tracks[track-1].file_offset + tracks[track-1].end_lba * tracks[track-1].sector_bytes; - if (track_of_file > 1) { - tracks[track].file_offset -= tracks[track-2].end_lba * tracks[track-1].sector_bytes; - } - } else { - tracks[track].file_offset = extra_offset; } } } @@ -388,56 +439,28 @@ } } while (line); if (media->num_tracks > 0 && media->tracks[0].f) { - //end of last track in a file is implictly based on the size - f = tracks[0].f; - uint32_t offset = 0; - for (int track = 0; track < media->num_tracks; track++) { - if (track == media->num_tracks - 1 && tracks[track].f) { - uint32_t start_lba =tracks[track].fake_pregap ? tracks[track].start_lba : tracks[track].pregap_lba; - uint32_t fsize; - if (tracks[track].flac) { - fsize = tracks[track].flac->total_samples * 4; - } else { - fsize = file_size(tracks[track].f); - } - tracks[track].end_lba = start_lba + (fsize - tracks[track].file_offset)/ tracks[track].sector_bytes; - } else if (tracks[track].f != f) { - uint32_t start_lba =tracks[track-1].fake_pregap ? tracks[track-1].start_lba : tracks[track-1].pregap_lba; - uint32_t fsize; - if (tracks[track-1].flac) { - fsize = tracks[track-1].flac->total_samples * 4; - } else { - fsize = file_size(tracks[track-1].f); - } - tracks[track-1].end_lba = start_lba + (fsize - tracks[track-1].file_offset)/ tracks[track-1].sector_bytes; - offset = tracks[track-1].end_lba; - } - if (!tracks[track].fake_pregap) { - tracks[track].pregap_lba += offset; - } - tracks[track].start_lba += offset; - tracks[track].end_lba += offset; + //end of last track in a file is implictly based on file size + long track_size = 0; + if (flac) { + track_size = flac->total_samples * 4; + } else if (f) { + track_size = file_size(f); } - //replace cue sheet with first sector - free(media->buffer); - media->buffer = calloc(2048, 1); - if (tracks[0].type == TRACK_DATA && tracks[0].sector_bytes == 2352 && !tracks[0].flac) { - // if the first track is a data track, don't trust the CUE sheet and look at the MM:SS:FF from first sector - uint8_t msf[3]; - fseek(tracks[0].f, 12, SEEK_SET); - if (sizeof(msf) == fread(msf, 1, sizeof(msf), tracks[0].f)) { - tracks[0].fake_pregap = msf[2] + (msf[0] * 60 + msf[1]) * 75; - } - } else if (!tracks[0].start_lba && !tracks[0].fake_pregap) { - tracks[0].fake_pregap = 2 * 75; + track_size -= tracks[track].file_offset; + tracks[track].end_lba = tracks[track].pregap_lba + tracks[track].fake_pregap + track_size / tracks[track].sector_bytes; + + if (tracks[0].type == TRACK_DATA) { + //replace cue sheet with first sector + free(media->buffer); + media->buffer = calloc(2048, 1); + fseek(tracks[0].f, tracks[0].sector_bytes >= 2352 ? 16 : 0, SEEK_SET); + media->size = fread(media->buffer, 1, 2048, tracks[0].f); } - - fseek(tracks[0].f, tracks[0].sector_bytes >= 2352 ? 16 : 0, SEEK_SET); - media->size = fread(media->buffer, 1, 2048, tracks[0].f); media->seek = bin_seek; media->read = bin_read; media->read_subcodes = bin_subcode_read; } + print_toc(media); uint8_t valid = media->num_tracks > 0 && media->tracks[0].f != NULL; media->type = valid ? MEDIA_CDROM : MEDIA_CART; return valid; @@ -553,7 +576,7 @@ if (isdigit(*cmd)) { uint32_t start = timecode_to_lba(cmd); tracks[track].file_offset += start * tracks[track].sector_bytes; - cmd = cmd_start_sameline(cmd); + cmd = cmd_start_sameline(word_end(cmd)); } } if (isdigit(*cmd)) { @@ -561,14 +584,16 @@ tracks[track].end_lba += length; } else { long fsize = file_size(f); - tracks[track].end_lba += fsize - tracks[track].file_offset; + tracks[track].end_lba += (fsize - tracks[track].file_offset) / tracks[track].sector_bytes; } } } } } else if (startswith(cmd, "SILENCE")) { cmd = cmd_start_sameline(cmd + 7); - tracks[track].fake_pregap += timecode_to_lba(cmd); + uint32_t length = timecode_to_lba(cmd); + tracks[track].fake_pregap += length; + tracks[track].end_lba += length; } else if (startswith(cmd, "START")) { cmd = cmd_start_sameline(cmd + 5); tracks[track].start_lba = tracks[track].pregap_lba + timecode_to_lba(cmd); @@ -587,6 +612,7 @@ //replace cue sheet with first sector free(media->buffer); media->buffer = calloc(2048, 1); + uint32_t old_fake_pregap = tracks[0].fake_pregap; if (tracks[0].type == TRACK_DATA && tracks[0].sector_bytes == 2352) { // if the first track is a data track, don't trust the TOC file and look at the MM:SS:FF from first sector uint8_t msf[3]; @@ -594,9 +620,22 @@ if (sizeof(msf) == fread(msf, 1, sizeof(msf), tracks[0].f)) { tracks[0].fake_pregap = msf[2] + (msf[0] * 60 + msf[1]) * 75; } - } else if (!tracks[0].start_lba && !tracks[0].fake_pregap) { + } else if (!tracks[0].fake_pregap) { tracks[0].fake_pregap = 2 * 75; } + if (tracks[0].fake_pregap != old_fake_pregap) { + if (!tracks[0].start_lba) { + tracks[0].start_lba = tracks[0].fake_pregap; + } + uint32_t diff = tracks[0].fake_pregap - old_fake_pregap; + tracks[0].end_lba += diff; + for (uint32_t i = 1; i < media->num_tracks; i++) + { + tracks[i].pregap_lba += diff; + tracks[i].start_lba += diff; + tracks[i].end_lba += diff; + } + } fseek(tracks[0].f, tracks[0].sector_bytes == 2352 ? 16 : 0, SEEK_SET); media->size = fread(media->buffer, 1, 2048, tracks[0].f); @@ -604,6 +643,7 @@ media->read = bin_read; media->read_subcodes = bin_subcode_read; } + print_toc(media); uint8_t valid = media->num_tracks > 0 && media->tracks[0].f != NULL; media->type = valid ? MEDIA_CDROM : MEDIA_CART; return valid;