cdrom: try to eliminate playback timing drifting
[pcsx_rearmed.git] / libpcsxcore / cdrom.c
index 2b30e89..184d07a 100644 (file)
@@ -242,11 +242,15 @@ static void sec2msf(unsigned int s, u8 *msf) {
 }
 
 // cdrPlaySeekReadInterrupt
-#define CDRPLAYSEEKREAD_INT(eCycle) { \
+#define CDRPLAYSEEKREAD_INT(eCycle, isFirst) { \
+       u32 e_ = eCycle; \
        psxRegs.interrupt |= (1 << PSXINT_CDREAD); \
-       psxRegs.intCycle[PSXINT_CDREAD].cycle = eCycle; \
-       psxRegs.intCycle[PSXINT_CDREAD].sCycle = psxRegs.cycle; \
-       new_dyna_set_event(PSXINT_CDREAD, eCycle); \
+       if (isFirst) \
+               psxRegs.intCycle[PSXINT_CDREAD].sCycle = psxRegs.cycle; \
+       else \
+               psxRegs.intCycle[PSXINT_CDREAD].sCycle += psxRegs.intCycle[PSXINT_CDREAD].cycle; \
+       psxRegs.intCycle[PSXINT_CDREAD].cycle = e_; \
+       new_dyna_set_event_abs(PSXINT_CDREAD, psxRegs.intCycle[PSXINT_CDREAD].sCycle + e_); \
 }
 
 // cdrLidSeekInterrupt
@@ -588,7 +592,7 @@ void cdrPlaySeekReadInterrupt(void)
        if (!cdr.Play && (cdr.StatP & STATUS_SEEK)) {
                if (cdr.Stat) {
                        CDR_LOG_I("cdrom: seek stat hack\n");
-                       CDRPLAYSEEKREAD_INT(0x1000);
+                       CDRPLAYSEEKREAD_INT(0x1000, 1);
                        return;
                }
                SetResultSize(1);
@@ -624,10 +628,10 @@ void cdrPlaySeekReadInterrupt(void)
        if (!cdr.Irq && !cdr.Stat && (cdr.Mode & (MODE_AUTOPAUSE|MODE_REPORT)))
                cdrPlayInterrupt_Autopause();
 
-       if (CDR_readCDDA && !cdr.Muted && !Config.Cdda) {
+       if (!cdr.Muted && !Config.Cdda) {
                cdrAttenuate(read_buf, CD_FRAMESIZE_RAW / 4, 1);
-               if (SPU_playCDDAchannel)
-                       SPU_playCDDAchannel(read_buf, CD_FRAMESIZE_RAW);
+               SPU_playCDDAchannel(read_buf, CD_FRAMESIZE_RAW, psxRegs.cycle, cdr.FirstSector);
+               cdr.FirstSector = 0;
        }
 
        cdr.SetSectorPlay[2]++;
@@ -640,7 +644,7 @@ void cdrPlaySeekReadInterrupt(void)
                }
        }
 
-       CDRPLAYSEEKREAD_INT(cdReadTime);
+       CDRPLAYSEEKREAD_INT(cdReadTime, 0);
 
        // update for CdlGetlocP/autopause
        generate_subq(cdr.SetSectorPlay);
@@ -756,6 +760,7 @@ void cdrInterrupt(void) {
                        Find_CurTrack(cdr.SetSectorPlay);
                        ReadTrack(cdr.SetSectorPlay);
                        cdr.TrackChanged = FALSE;
+                       cdr.FirstSector = 1;
 
                        if (!Config.Cdda)
                                CDR_play(cdr.SetSectorPlay);
@@ -765,7 +770,7 @@ void cdrInterrupt(void) {
                        // BIOS player - set flag again
                        cdr.Play = TRUE;
 
-                       CDRPLAYSEEKREAD_INT(cdReadTime + seekTime);
+                       CDRPLAYSEEKREAD_INT(cdReadTime + seekTime, 1);
                        start_rotating = 1;
                        break;
 
@@ -973,7 +978,7 @@ void cdrInterrupt(void) {
                        Rockman X5 = 0.5-4x
                        - fix capcom logo
                        */
-                       CDRPLAYSEEKREAD_INT(cdReadTime + seekTime);
+                       CDRPLAYSEEKREAD_INT(cdReadTime + seekTime, 1);
                        start_rotating = 1;
                        break;
 
@@ -1018,7 +1023,8 @@ void cdrInterrupt(void) {
                        }
                        cdr.Result[0] |= (cdr.Result[1] >> 4) & 0x08;
 
-                       strncpy((char *)&cdr.Result[4], "PCSX", 4);
+                       /* This adds the string "PCSX" in Playstation bios boot screen */
+                       memcpy((char *)&cdr.Result[4], "PCSX", 4);
                        cdr.Stat = Complete;
                        break;
 
@@ -1070,40 +1076,7 @@ void cdrInterrupt(void) {
                        // - fixes new game
                        ReadTrack(cdr.SetSectorPlay);
 
-
-                       // Crusaders of Might and Magic - update getlocl now
-                       // - fixes cutscene speech
-                       {
-                               u8 *buf = CDR_getBuffer();
-                               if (buf != NULL)
-                                       memcpy(cdr.Transfer, buf, 8);
-                       }
-
-                       /*
-                       Duke Nukem: Land of the Babes - seek then delay read for one frame
-                       - fixes cutscenes
-                       C-12 - Final Resistance - doesn't like seek
-                       */
-                       
-                       /*      
-                               By nicolasnoble from PCSX Redux :
-                               "It LOOKS like this logic is wrong, therefore disabling it with `&& false` for now.
-                               For "PoPoLoCrois Monogatari II", the game logic will soft lock and will never issue GetLocP to detect
-                               the end of its XA streams, as it seems to assume ReadS will not return a status byte with the SEEK
-                               flag set. I think the reasonning is that since it's invalid to call GetLocP while seeking, the game
-                               tries to protect itself against errors by preventing from issuing a GetLocP while it knows the
-                               last status was "seek". But this makes the logic just softlock as it'll never get a notification
-                               about the fact the drive is done seeking and the read actually started.
-
-                               In other words, this state machine here is probably wrong in assuming the response to ReadS/ReadN is
-                               done right away. It's rather when it's done seeking, and the read has actually started. This probably
-                               requires a bit more work to make sure seek delays are processed properly.
-                               Checked with a few games, this seems to work fine."
-                               
-                               Gameblabla additional notes :
-                               This still needs the "+ seekTime" that PCSX Redux doesn't have for the Driver "retry" mission error.
-                       */
-                       CDRPLAYSEEKREAD_INT(((cdr.Mode & 0x80) ? (cdReadTime) : cdReadTime * 2) + seekTime);
+                       CDRPLAYSEEKREAD_INT(((cdr.Mode & 0x80) ? (cdReadTime) : cdReadTime * 2) + seekTime, 1);
 
                        SetPlaySeekRead(cdr.StatP, STATUS_SEEK);
                        start_rotating = 1;
@@ -1199,7 +1172,7 @@ static void cdrReadInterrupt(void)
 
        if (cdr.Irq || cdr.Stat) {
                CDR_LOG_I("cdrom: read stat hack %02x %x\n", cdr.Irq, cdr.Stat);
-               CDRPLAYSEEKREAD_INT(2048);
+               CDRPLAYSEEKREAD_INT(2048, 1);
                return;
        }
 
@@ -1247,7 +1220,7 @@ static void cdrReadInterrupt(void)
                        int ret = xa_decode_sector(&cdr.Xa, cdr.Transfer+4, cdr.FirstSector);
                        if (!ret) {
                                cdrAttenuate(cdr.Xa.pcm, cdr.Xa.nsamples, cdr.Xa.stereo);
-                               SPU_playADPCMchannel(&cdr.Xa);
+                               SPU_playADPCMchannel(&cdr.Xa, psxRegs.cycle, cdr.FirstSector);
                                cdr.FirstSector = 0;
                        }
                        else cdr.FirstSector = -1;
@@ -1266,7 +1239,7 @@ static void cdrReadInterrupt(void)
 
        cdr.Readed = 0;
 
-       CDRPLAYSEEKREAD_INT((cdr.Mode & MODE_SPEED) ? (cdReadTime / 2) : cdReadTime);
+       CDRPLAYSEEKREAD_INT((cdr.Mode & MODE_SPEED) ? (cdReadTime / 2) : cdReadTime, 0);
 
        /*
        Croc 2: $40 - only FORM1 (*)
@@ -1619,7 +1592,7 @@ int cdrFreeze(void *f, int Mode) {
                        if (!Config.Cdda)
                                CDR_play(cdr.SetSectorPlay);
                        if (psxRegs.interrupt & (1 << PSXINT_CDRPLAY_OLD))
-                               CDRPLAYSEEKREAD_INT((cdr.Mode & 0x80) ? (cdReadTime / 2) : cdReadTime);
+                               CDRPLAYSEEKREAD_INT((cdr.Mode & 0x80) ? (cdReadTime / 2) : cdReadTime, 1);
                }
 
                if ((cdr.freeze_ver & 0xffffff00) != 0x63647200) {