cdrom: change GetlocP handling
authornotaz <notasas@gmail.com>
Wed, 2 Nov 2022 20:24:20 +0000 (22:24 +0200)
committernotaz <notasas@gmail.com>
Wed, 2 Nov 2022 22:03:05 +0000 (00:03 +0200)
maybe better?
notaz/pcsx_rearmed#268

libpcsxcore/cdriso.c
libpcsxcore/cdrom.c
libpcsxcore/plugins.h

index 2a31950..a755a23 100644 (file)
@@ -54,7 +54,6 @@ static FILE *subHandle = NULL;
 
 static boolean subChanMixed = FALSE;
 static boolean subChanRaw = FALSE;
-static boolean subChanMissing = FALSE;
 
 static boolean multifile = FALSE;
 
@@ -93,7 +92,8 @@ static struct {
 } *chd_img;
 #endif
 
-int (*cdimg_read_func)(FILE *f, unsigned int base, void *dest, int sector);
+static int (*cdimg_read_func)(FILE *f, unsigned int base, void *dest, int sector);
+static int (*cdimg_read_sub_func)(FILE *f, int sector);
 
 char* CALLBACK CDR__getDriveLetter(void);
 long CALLBACK CDR__configure(void);
@@ -1070,29 +1070,48 @@ static int opensbifile(const char *isoname) {
 
 static int cdread_normal(FILE *f, unsigned int base, void *dest, int sector)
 {
-       fseek(f, base + sector * CD_FRAMESIZE_RAW, SEEK_SET);
-       return fread(dest, 1, CD_FRAMESIZE_RAW, f);
+       int ret;
+       if (fseek(f, base + sector * CD_FRAMESIZE_RAW, SEEK_SET))
+               goto fail_io;
+       ret = fread(dest, 1, CD_FRAMESIZE_RAW, f);
+       if (ret <= 0)
+               goto fail_io;
+       return ret;
+
+fail_io:
+       // often happens in cdda gaps of a split cue/bin, so not logged
+       //SysPrintf("File IO error %d, base %u, sector %u\n", errno, base, sector);
+       return -1;
 }
 
 static int cdread_sub_mixed(FILE *f, unsigned int base, void *dest, int sector)
 {
        int ret;
 
-       fseek(f, base + sector * (CD_FRAMESIZE_RAW + SUB_FRAMESIZE), SEEK_SET);
+       if (fseek(f, base + sector * (CD_FRAMESIZE_RAW + SUB_FRAMESIZE), SEEK_SET))
+               goto fail_io;
        ret = fread(dest, 1, CD_FRAMESIZE_RAW, f);
+       if (ret <= 0)
+               goto fail_io;
+       return ret;
+
+fail_io:
+       //SysPrintf("File IO error %d, base %u, sector %u\n", errno, base, sector);
+       return -1;
+}
+
+static int cdread_sub_sub_mixed(FILE *f, int sector)
+{
+       if (fseek(f, sector * (CD_FRAMESIZE_RAW + SUB_FRAMESIZE) + CD_FRAMESIZE_RAW, SEEK_SET))
+               goto fail_io;
        if (fread(subbuffer, 1, SUB_FRAMESIZE, f) != SUB_FRAMESIZE)
                goto fail_io;
 
-       if (subChanRaw) DecodeRawSubData();
-       goto done;
+       return SUB_FRAMESIZE;
 
 fail_io:
-#ifndef NDEBUG
-       SysPrintf(_("File IO error in <%s:%s>.\n"), __FILE__, __func__);
-#endif
-
-done:
-       return ret;
+       SysPrintf("subchannel: file IO error %d, sector %u\n", errno, sector);
+       return -1;
 }
 
 static int uncompress2_pcsx(void *out, unsigned long *out_size, void *in, unsigned long in_size)
@@ -1201,8 +1220,7 @@ static int cdread_chd(FILE *f, unsigned int base, void *dest, int sector)
 {
        int hunk;
 
-       if (base)
-               sector += base;
+       sector += base;
 
        hunk = sector / chd_img->sectors_per_hunk;
        chd_img->sector_in_hunk = sector % chd_img->sectors_per_hunk;
@@ -1216,14 +1234,28 @@ static int cdread_chd(FILE *f, unsigned int base, void *dest, int sector)
        if (dest != cdbuffer) // copy avoid HACK
                memcpy(dest, chd_img->buffer[chd_img->sector_in_hunk],
                        CD_FRAMESIZE_RAW);
-       if (subChanMixed) {
-               memcpy(subbuffer, chd_img->buffer[chd_img->sector_in_hunk] + CD_FRAMESIZE_RAW,
-                       SUB_FRAMESIZE);
-               if (subChanRaw)
-                       DecodeRawSubData();
-       }
        return CD_FRAMESIZE_RAW;
 }
+
+static int cdread_sub_chd(FILE *f, int sector)
+{
+       int hunk;
+
+       if (!subChanMixed)
+               return -1;
+
+       hunk = sector / chd_img->sectors_per_hunk;
+       chd_img->sector_in_hunk = sector % chd_img->sectors_per_hunk;
+
+       if (hunk != chd_img->current_hunk)
+       {
+               chd_read(chd_img->chd, hunk, chd_img->buffer);
+               chd_img->current_hunk = hunk;
+       }
+
+       memcpy(subbuffer, chd_img->buffer[chd_img->sector_in_hunk] + CD_FRAMESIZE_RAW, SUB_FRAMESIZE);
+       return SUB_FRAMESIZE;
+}
 #endif
 
 static int cdread_2048(FILE *f, unsigned int base, void *dest, int sector)
@@ -1298,6 +1330,7 @@ static long CALLBACK ISOopen(void) {
 
        CDR_getBuffer = ISOgetBuffer;
        cdimg_read_func = cdread_normal;
+       cdimg_read_sub_func = NULL;
 
        if (parsetoc(GetIsoFile()) == 0) {
                strcat(image_str, "[+toc]");
@@ -1326,6 +1359,7 @@ static long CALLBACK ISOopen(void) {
                strcat(image_str, "[+chd]");
                CDR_getBuffer = ISOgetBuffer_chd;
                cdimg_read_func = cdread_chd;
+               cdimg_read_sub_func = cdread_sub_chd;
                is_chd = 1;
        }
 #endif
@@ -1387,10 +1421,14 @@ static long CALLBACK ISOopen(void) {
 
        PrintTracks();
 
-       if (subChanMixed && !is_chd)
+       if (subChanMixed && !is_chd) {
                cdimg_read_func = cdread_sub_mixed;
-       else if (isMode1ISO)
+               cdimg_read_sub_func = cdread_sub_sub_mixed;
+       }
+       else if (isMode1ISO) {
                cdimg_read_func = cdread_2048;
+               cdimg_read_sub_func = NULL;
+       }
 
        // make sure we have another handle open for cdda
        if (numtracks > 1 && ti[1].handle == NULL) {
@@ -1530,28 +1568,13 @@ static boolean CALLBACK ISOreadTrack(unsigned char *time) {
                return 0;
        }
 
-       if (pregapOffset) {
-               subChanMissing = FALSE;
-               if (sector >= pregapOffset) {
-                       sector -= 2 * 75;
-                       if (sector < pregapOffset)
-                               subChanMissing = TRUE;
-               }
-       }
+       if (pregapOffset && sector >= pregapOffset)
+               sector -= 2 * 75;
 
        ret = cdimg_read_func(cdHandle, 0, cdbuffer, sector);
        if (ret < 12*2 + 2048)
                return 0;
 
-       if (subHandle != NULL) {
-               fseek(subHandle, sector * SUB_FRAMESIZE, SEEK_SET);
-               if (fread(subbuffer, 1, SUB_FRAMESIZE, subHandle) != SUB_FRAMESIZE)
-                       /* Faulty subchannel data shouldn't cause a read failure */
-                       return 1;
-
-               if (subChanRaw) DecodeRawSubData();
-       }
-
        return 1;
 }
 
@@ -1570,12 +1593,29 @@ static long CALLBACK ISOstop(void) {
 }
 
 // gets subchannel data
-static unsigned char* CALLBACK ISOgetBufferSub(void) {
-       if ((subHandle != NULL || subChanMixed) && !subChanMissing) {
-               return subbuffer;
+static unsigned char* CALLBACK ISOgetBufferSub(int sector) {
+       if (pregapOffset && sector >= pregapOffset) {
+               sector -= 2 * 75;
+               if (sector < pregapOffset) // ?
+                       return NULL;
        }
 
-       return NULL;
+       if (cdimg_read_sub_func != NULL) {
+               if (cdimg_read_sub_func(cdHandle, sector) != SUB_FRAMESIZE)
+                       return NULL;
+       }
+       else if (subHandle != NULL) {
+               if (fseek(subHandle, sector * SUB_FRAMESIZE, SEEK_SET))
+                       return NULL;
+               if (fread(subbuffer, 1, SUB_FRAMESIZE, subHandle) != SUB_FRAMESIZE)
+                       return NULL;
+       }
+       else {
+               return NULL;
+       }
+
+       if (subChanRaw) DecodeRawSubData();
+       return subbuffer;
 }
 
 static long CALLBACK ISOgetStatus(struct CdrStat *stat) {
index e106573..145ca32 100644 (file)
@@ -21,6 +21,7 @@
 * Handles all CD-ROM registers and functions.
 */
 
+#include <assert.h>
 #include "cdrom.h"
 #include "ppf.h"
 #include "psxdma.h"
@@ -76,7 +77,7 @@ static struct {
        unsigned char ResultP;
        unsigned char ResultReady;
        unsigned char Cmd;
-       unsigned char unused4;
+       unsigned char SubqForwardSectors;
        unsigned char SetlocPending;
        u32 Reading;
 
@@ -208,6 +209,7 @@ unsigned char Test23[] = { 0x43, 0x58, 0x44, 0x32, 0x39 ,0x34, 0x30, 0x51 };
 #define cdReadTime (PSXCLK / 75)
 
 #define LOCL_INVALID 0xff
+#define SUBQ_FORWARD_SECTORS 2u
 
 enum drive_state {
        DRIVESTATE_STANDBY = 0, // pause, play, read
@@ -447,11 +449,10 @@ static void generate_subq(const u8 *time)
        cdr.subq.Absolute[2] = itob(time[2]);
 }
 
-static int ReadTrack(const u8 *time) {
+static int ReadTrack(const u8 *time)
+{
        unsigned char tmp[3];
-       struct SubQ *subq;
        int read_ok;
-       u16 crc;
 
        tmp[0] = itob(time[0]);
        tmp[1] = itob(time[1]);
@@ -465,11 +466,18 @@ static int ReadTrack(const u8 *time) {
        read_ok = CDR_readTrack(tmp);
        if (read_ok)
                memcpy(cdr.Prev, tmp, 3);
+       return read_ok;
+}
+
+static void UpdateSubq(const u8 *time)
+{
+       const struct SubQ *subq;
+       u16 crc;
 
        if (CheckSBI(time))
-               return read_ok;
+               return;
 
-       subq = (struct SubQ *)CDR_getBufferSub();
+       subq = (struct SubQ *)CDR_getBufferSub(MSF2SECT(time[0], time[1], time[2]));
        if (subq != NULL && cdr.CurTrack == 1) {
                crc = calcCrc((u8 *)subq + 12, 10);
                if (crc == (((u16)subq->CRC[0] << 8) | subq->CRC[1])) {
@@ -479,8 +487,8 @@ static int ReadTrack(const u8 *time) {
                        memcpy(cdr.subq.Absolute, subq->AbsoluteAddress, 3);
                }
                else {
-                       CDR_LOG_I("subq bad crc @%02x:%02x:%02x\n",
-                               tmp[0], tmp[1], tmp[2]);
+                       CDR_LOG_I("subq bad crc @%02d:%02d:%02d\n",
+                               time[0], time[1], time[2]);
                }
        }
        else {
@@ -491,8 +499,6 @@ static int ReadTrack(const u8 *time) {
                cdr.subq.Track, cdr.subq.Index,
                cdr.subq.Relative[0], cdr.subq.Relative[1], cdr.subq.Relative[2],
                cdr.subq.Absolute[0], cdr.subq.Absolute[1], cdr.subq.Absolute[2]);
-
-       return read_ok;
 }
 
 static void cdrPlayInterrupt_Autopause()
@@ -604,6 +610,20 @@ static void cdrReadInterrupt(void);
 static void cdrPrepCdda(s16 *buf, int samples);
 static void cdrAttenuate(s16 *buf, int samples, int stereo);
 
+static void msfiAdd(u8 *msfi, u32 count)
+{
+       assert(count < 75);
+       msfi[2] += count;
+       if (msfi[2] >= 75) {
+               msfi[2] -= 75;
+               msfi[1]++;
+               if (msfi[1] == 60) {
+                       msfi[1] = 0;
+                       msfi[0]++;
+               }
+       }
+}
+
 void cdrPlayReadInterrupt(void)
 {
        if (cdr.Reading) {
@@ -636,15 +656,7 @@ void cdrPlayReadInterrupt(void)
                cdr.FirstSector = 0;
        }
 
-       cdr.SetSectorPlay[2]++;
-       if (cdr.SetSectorPlay[2] == 75) {
-               cdr.SetSectorPlay[2] = 0;
-               cdr.SetSectorPlay[1]++;
-               if (cdr.SetSectorPlay[1] == 60) {
-                       cdr.SetSectorPlay[1] = 0;
-                       cdr.SetSectorPlay[0]++;
-               }
-       }
+       msfiAdd(cdr.SetSectorPlay, 1);
 
        // update for CdlGetlocP/autopause
        generate_subq(cdr.SetSectorPlay);
@@ -794,8 +806,9 @@ void cdrInterrupt(void) {
                        - plays tracks without retry play
                        */
                        Find_CurTrack(cdr.SetSectorPlay);
-                       ReadTrack(cdr.SetSectorPlay);
+                       generate_subq(cdr.SetSectorPlay);
                        cdr.LocL[0] = LOCL_INVALID;
+                       cdr.SubqForwardSectors = 1;
                        cdr.TrackChanged = FALSE;
                        cdr.FirstSector = 1;
 
@@ -1035,6 +1048,7 @@ void cdrInterrupt(void) {
                        read_ok = ReadTrack(cdr.SetSectorPlay);
                        if (read_ok && (buf = CDR_getBuffer()))
                                memcpy(cdr.LocL, buf, 8);
+                       UpdateSubq(cdr.SetSectorPlay);
                        cdr.TrackChanged = FALSE;
                        break;
 
@@ -1134,8 +1148,9 @@ void cdrInterrupt(void) {
 
                        // Fighting Force 2 - update subq time immediately
                        // - fixes new game
-                       ReadTrack(cdr.SetSectorPlay);
+                       UpdateSubq(cdr.SetSectorPlay);
                        cdr.LocL[0] = LOCL_INVALID;
+                       cdr.SubqForwardSectors = 1;
 
                        cycles = (cdr.Mode & 0x80) ? cdReadTime : cdReadTime * 2;
                        cycles += seekTime;
@@ -1266,10 +1281,20 @@ static void cdrUpdateTransferBuf(const u8 *buf)
 static void cdrReadInterrupt(void)
 {
        u8 *buf = NULL, *hdr;
+       u8 subqPos[3];
        int read_ok;
 
        SetPlaySeekRead(cdr.StatP, STATUS_READ | STATUS_ROTATING);
 
+       memcpy(subqPos, cdr.SetSectorPlay, sizeof(subqPos));
+       msfiAdd(subqPos, cdr.SubqForwardSectors);
+       UpdateSubq(subqPos);
+       if (cdr.SubqForwardSectors < SUBQ_FORWARD_SECTORS) {
+               cdr.SubqForwardSectors++;
+               CDRPLAYREAD_INT((cdr.Mode & MODE_SPEED) ? (cdReadTime / 2) : cdReadTime, 0);
+               return;
+       }
+
        read_ok = ReadTrack(cdr.SetSectorPlay);
        if (read_ok)
                buf = CDR_getBuffer();
@@ -1319,20 +1344,7 @@ static void cdrReadInterrupt(void)
        if (!(cdr.Mode & MODE_STRSND) || !(buf[4+2] & 0x4))
                cdrReadInterruptSetResult(cdr.StatP);
 
-       cdr.SetSectorPlay[2]++;
-       if (cdr.SetSectorPlay[2] == 75) {
-               cdr.SetSectorPlay[2] = 0;
-               cdr.SetSectorPlay[1]++;
-               if (cdr.SetSectorPlay[1] == 60) {
-                       cdr.SetSectorPlay[1] = 0;
-                       cdr.SetSectorPlay[0]++;
-               }
-       }
-
-       if (!cdr.Irq1Pending) {
-               // update for CdlGetlocP
-               ReadTrack(cdr.SetSectorPlay);
-       }
+       msfiAdd(cdr.SetSectorPlay, 1);
 
        CDRPLAYREAD_INT((cdr.Mode & MODE_SPEED) ? (cdReadTime / 2) : cdReadTime, 0);
 }
@@ -1659,6 +1671,8 @@ int cdrFreeze(void *f, int Mode) {
 
                cdr.FifoOffset = tmp < DATA_SIZE ? tmp : DATA_SIZE;
                cdr.FifoSize = (cdr.Mode & 0x20) ? 2340 : 2048 + 12;
+               if (cdr.SubqForwardSectors > SUBQ_FORWARD_SECTORS)
+                       cdr.SubqForwardSectors = SUBQ_FORWARD_SECTORS;
 
                // read right sub data
                tmpp[0] = btoi(cdr.Prev[0]);
index 38c41ca..178f83a 100644 (file)
@@ -112,7 +112,7 @@ typedef long (CALLBACK* CDRgetTN)(unsigned char *);
 typedef long (CALLBACK* CDRgetTD)(unsigned char, unsigned char *);\r
 typedef boolean (CALLBACK* CDRreadTrack)(unsigned char *);\r
 typedef unsigned char* (CALLBACK* CDRgetBuffer)(void);\r
-typedef unsigned char* (CALLBACK* CDRgetBufferSub)(void);\r
+typedef unsigned char* (CALLBACK* CDRgetBufferSub)(int sector);\r
 typedef long (CALLBACK* CDRconfigure)(void);\r
 typedef long (CALLBACK* CDRtest)(void);\r
 typedef void (CALLBACK* CDRabout)(void);\r