avoid bogus warning
[pcsx_rearmed.git] / libpcsxcore / cdrom.c
index 142c1e2..60f03e7 100644 (file)
@@ -26,6 +26,7 @@
 #include "psxdma.h"
 
 cdrStruct cdr;
+static unsigned char *pTransfer;
 
 /* CD-ROM magic numbers */
 #define CdlSync        0
@@ -119,13 +120,20 @@ unsigned char Test23[] = { 0x43, 0x58, 0x44, 0x32, 0x39 ,0x34, 0x30, 0x51 };
 // so (PSXCLK / 75) = cdr read time (linuzappz)
 #define cdReadTime (PSXCLK / 75)
 
+// for cdr.Seeked
+enum seeked_state {
+       SEEK_PENDING = 0,
+       SEEK_DONE = 1,
+       SEEK_DOING_CMD = 2,
+};
+
 static struct CdrStat stat;
 
-static unsigned int msf2sec(char *msf) {
+static unsigned int msf2sec(u8 *msf) {
        return ((msf[0] * 60 + msf[1]) * 75) + msf[2];
 }
 
-static void sec2msf(unsigned int s, char *msf) {
+static void sec2msf(unsigned int s, u8 *msf) {
        msf[0] = s / 75 / 60;
        s = s - msf[0] * 75 * 60;
        msf[1] = s / 75;
@@ -133,7 +141,7 @@ static void sec2msf(unsigned int s, char *msf) {
        msf[2] = s;
 }
 
-
+// cdrInterrupt
 #define CDR_INT(eCycle) { \
        psxRegs.interrupt |= (1 << PSXINT_CDR); \
        psxRegs.intCycle[PSXINT_CDR].cycle = eCycle; \
@@ -141,6 +149,7 @@ static void sec2msf(unsigned int s, char *msf) {
        new_dyna_set_event(PSXINT_CDR, eCycle); \
 }
 
+// cdrReadInterrupt
 #define CDREAD_INT(eCycle) { \
        psxRegs.interrupt |= (1 << PSXINT_CDREAD); \
        psxRegs.intCycle[PSXINT_CDREAD].cycle = eCycle; \
@@ -148,6 +157,7 @@ static void sec2msf(unsigned int s, char *msf) {
        new_dyna_set_event(PSXINT_CDREAD, eCycle); \
 }
 
+// cdrLidSeekInterrupt
 #define CDRLID_INT(eCycle) { \
        psxRegs.interrupt |= (1 << PSXINT_CDRLID); \
        psxRegs.intCycle[PSXINT_CDRLID].cycle = eCycle; \
@@ -155,7 +165,8 @@ static void sec2msf(unsigned int s, char *msf) {
        new_dyna_set_event(PSXINT_CDRLID, eCycle); \
 }
 
-#define CDRPLAY_INT(eCycle) { \
+// cdrPlayInterrupt
+#define CDRMISC_INT(eCycle) { \
        psxRegs.interrupt |= (1 << PSXINT_CDRPLAY); \
        psxRegs.intCycle[PSXINT_CDRPLAY].cycle = eCycle; \
        psxRegs.intCycle[PSXINT_CDRPLAY].sCycle = psxRegs.cycle; \
@@ -251,7 +262,6 @@ void cdrLidSeekInterrupt()
        }
 }
 
-
 static void Check_Shell( int Irq )
 {
        // check case open/close
@@ -410,12 +420,13 @@ static void ReadTrack( u8 *time ) {
 }
 
 
-void AddIrqQueue(unsigned char irq, unsigned long ecycle) {
+static void AddIrqQueue(unsigned char irq, unsigned long ecycle) {
+       //if (cdr.Irq != 0 && cdr.Irq != 0xff)
+       //      printf("cdr: override cmd %02x -> %02x\n", cdr.Irq, irq);
+
        cdr.Irq = irq;
        cdr.eCycle = ecycle;
 
-       // Doom: Force rescheduling
-       // - Fixes boot
        CDR_INT(ecycle);
 }
 
@@ -539,7 +550,11 @@ static void Create_Fake_Subq()
 static void cdrPlayInterrupt_Autopause()
 {
        struct SubQ *subq = (struct SubQ *)CDR_getBufferSub();
+       int track_changed = 0;
        if (subq != NULL ) {
+               // update subq
+               ReadTrack( cdr.SetSectorPlay );
+
 #ifdef CDR_LOG
                CDR_LOG( "CDDA SUB - %X:%X:%X\n",
                        subq->AbsoluteAddress[0], subq->AbsoluteAddress[1], subq->AbsoluteAddress[2] );
@@ -552,8 +567,10 @@ static void cdrPlayInterrupt_Autopause()
                Tomb Raider 1 ($7)
                */
 
-               if( cdr.CurTrack >= btoi( subq->TrackNumber ) )
-                       return;
+               // .. + 1 is probably wrong, but deals with corrupted subq + good checksum
+               // (how does real thing handle those?)
+               if( cdr.CurTrack + 1 == btoi( subq->TrackNumber ) )
+                       track_changed = 1;
        } else {
                Create_Fake_Subq();
 #ifdef CDR_LOG___0
@@ -561,13 +578,11 @@ static void cdrPlayInterrupt_Autopause()
                        fake_subq_real[0], fake_subq_real[1], fake_subq_real[2] );
 #endif
 
-               if( !fake_subq_change )
-                       return;
-
+               track_changed = fake_subq_change;
                fake_subq_change = 0;
        }
 
-       if (cdr.Mode & MODE_AUTOPAUSE) {
+       if ((cdr.Mode & MODE_AUTOPAUSE) && track_changed) {
 #ifdef CDR_LOG
                CDR_LOG( "CDDA STOP\n" );
 #endif
@@ -583,19 +598,19 @@ static void cdrPlayInterrupt_Autopause()
 
                StopCdda();
        }
-       if (cdr.Mode & MODE_REPORT) {
-               // rearmed note: PCSX-Reloaded does this for every sector,
-               // but we try to get away with only track change here.
-               memset( cdr.Result, 0, 8 );
-               cdr.Result[0] |= 0x10;
-
+       else if (cdr.Mode & MODE_REPORT) {
                if (subq != NULL) {
 #ifdef CDR_LOG
                        CDR_LOG( "REPPLAY SUB - %X:%X:%X\n",
                                subq->AbsoluteAddress[0], subq->AbsoluteAddress[1], subq->AbsoluteAddress[2] );
 #endif
-                       cdr.CurTrack = btoi( subq->TrackNumber );
+                       // breaks when .sub doesn't have index 0 for some reason (bad rip?)
+                       //cdr.CurTrack = btoi( subq->TrackNumber );
+
+                       if (subq->AbsoluteAddress[2] & 0xf)
+                               return;
 
+                       cdr.Result[0] = cdr.StatP;
                        // BIOS CD Player: data already BCD format
                        cdr.Result[1] = subq->TrackNumber;
                        cdr.Result[2] = subq->IndexNumber;
@@ -609,6 +624,10 @@ static void cdrPlayInterrupt_Autopause()
                                fake_subq_real[0], fake_subq_real[1], fake_subq_real[2] );
 #endif
 
+                       if (fake_subq_real[2] & 0xf)
+                               return;
+
+                       cdr.Result[0] = cdr.StatP;
                        // track # / index #
                        cdr.Result[1] = itob(cdr.CurTrack);
                        cdr.Result[2] = itob(fake_subq_index);
@@ -627,15 +646,40 @@ static void cdrPlayInterrupt_Autopause()
        }
 }
 
+// also handles seek
 void cdrPlayInterrupt()
 {
-       if( !cdr.Play ) return;
+       if (cdr.Seeked == SEEK_DOING_CMD) {
+               SetResultSize(1);
+               cdr.StatP |= STATUS_ROTATING;
+               cdr.StatP &= ~STATUS_SEEK;
+               cdr.Result[0] = cdr.StatP;
+               if (cdr.Irq == 0 || cdr.Irq == 0xff) {
+                       cdr.Stat = Complete;
+                       if (cdr.Stat != NoIntr)
+                               psxHu32ref(0x1070) |= SWAP32(0x4);
+               }
+
+               cdr.Seeked = SEEK_PENDING;
+               CDRMISC_INT(cdReadTime * 20); // ???
+               return;
+       }
+       else if (cdr.Seeked == SEEK_PENDING) {
+               cdr.Seeked = SEEK_DONE;
+               if (!cdr.Play && !cdr.Reading) {
+                       memcpy(cdr.SetSectorPlay, cdr.SetSector, 4);
+                       Find_CurTrack();
+                       ReadTrack(cdr.SetSector);
+               }
+       }
+
+       if (!cdr.Play) return;
 
 #ifdef CDR_LOG
        CDR_LOG( "CDDA - %d:%d:%d\n",
                cdr.SetSectorPlay[0], cdr.SetSectorPlay[1], cdr.SetSectorPlay[2] );
 #endif
-       CDRPLAY_INT( cdReadTime );
+       CDRMISC_INT( cdReadTime );
 
        if (!cdr.Irq && !cdr.Stat && (cdr.Mode & MODE_CDDA) && (cdr.Mode & (MODE_AUTOPAUSE|MODE_REPORT)))
                cdrPlayInterrupt_Autopause();
@@ -694,9 +738,10 @@ void cdrInterrupt() {
                case CdlPlay:
                        fake_subq_change = 0;
 
-                       if( cdr.Seeked == FALSE ) {
+                       if (cdr.Seeked == SEEK_PENDING) {
+                               // XXX: wrong, should seek instead..
                                memcpy( cdr.SetSectorPlay, cdr.SetSector, 4 );
-                               cdr.Seeked = TRUE;
+                               cdr.Seeked = SEEK_DONE;
                        }
 
                        /*
@@ -709,11 +754,12 @@ void cdrInterrupt() {
                        Wild 9: skip PREGAP + starting accurate SubQ
                        - plays tracks without retry play
                        */
+                       /* unneeded with correct cdriso?
                        Set_Track();
+                       */
                        Find_CurTrack();
                        ReadTrack( cdr.SetSectorPlay );
 
-
                        // GameShark CD Player: Calls 2x + Play 2x
                        if( cdr.FastBackward || cdr.FastForward ) {
                                if( cdr.FastForward ) cdr.FastForward--;
@@ -776,7 +822,7 @@ void cdrInterrupt() {
                                                                cdr.SetSectorPlay[2] = cdr.ResultTD[0];
 
                                                                // reset data
-                                                               Set_Track();
+                                                               //Set_Track();
                                                                Find_CurTrack();
                                                                ReadTrack( cdr.SetSectorPlay );
 
@@ -804,7 +850,7 @@ void cdrInterrupt() {
                        // BIOS player - set flag again
                        cdr.Play = TRUE;
 
-                       CDRPLAY_INT( cdReadTime );
+                       CDRMISC_INT( cdReadTime );
                        break;
 
                case CdlForward:
@@ -955,6 +1001,10 @@ void cdrInterrupt() {
                        subq = (struct SubQ *)CDR_getBufferSub();
 
                        if (subq != NULL) {
+                               if( cdr.Play && (cdr.Mode & MODE_CDDA) && !(cdr.Mode & (MODE_AUTOPAUSE|MODE_REPORT)) )
+                                       // update subq
+                                       ReadTrack( cdr.SetSectorPlay );
+
                                cdr.Result[0] = subq->TrackNumber;
                                cdr.Result[1] = subq->IndexNumber;
                                memcpy(cdr.Result + 2, subq->TrackRelativeAddress, 3);
@@ -1033,6 +1083,7 @@ void cdrInterrupt() {
                        break;
 
                case CdlSeekL:
+               case CdlSeekP:
                        SetResultSize(1);
                        cdr.StatP |= STATUS_ROTATING;
                        cdr.Result[0] = cdr.StatP;
@@ -1052,45 +1103,8 @@ void cdrInterrupt() {
                        Rockman X5 = 0.5-4x
                        - fix capcom logo
                        */
-                       AddIrqQueue(CdlSeekL + 0x20, cdReadTime * 4);
-                       break;
-
-               case CdlSeekL + 0x20:
-                       SetResultSize(1);
-                       cdr.StatP |= STATUS_ROTATING;
-                       cdr.StatP &= ~STATUS_SEEK;
-                       cdr.Result[0] = cdr.StatP;
-                       cdr.Seeked = TRUE;
-                       cdr.Stat = Complete;
-
-
-                       // Mega Man Legends 2: must update read cursor for getlocp
-                       ReadTrack( cdr.SetSector );
-                       break;
-
-               case CdlSeekP:
-                       SetResultSize(1);
-                       cdr.StatP |= STATUS_ROTATING;
-                       cdr.Result[0] = cdr.StatP;
-                       cdr.StatP |= STATUS_SEEK;
-                       cdr.Stat = Acknowledge;
-                       AddIrqQueue(CdlSeekP + 0x20, cdReadTime * 1);
-                       break;
-
-               case CdlSeekP + 0x20:
-                       SetResultSize(1);
-                       cdr.StatP |= STATUS_ROTATING;
-                       cdr.StatP &= ~STATUS_SEEK;
-                       cdr.Result[0] = cdr.StatP;
-                       cdr.Stat = Complete;
-                       cdr.Seeked = TRUE;
-
-                       // GameShark Music Player
-                       memcpy( cdr.SetSectorPlay, cdr.SetSector, 4 );
-
-                       // Tomb Raider 2: must update read cursor for getlocp
-                       Find_CurTrack();
-                       ReadTrack( cdr.SetSectorPlay );
+                       CDRMISC_INT(cdr.Seeked == SEEK_DONE ? 0x800 : cdReadTime * 4);
+                       cdr.Seeked = SEEK_DOING_CMD;
                        break;
 
                case CdlTest:
@@ -1216,18 +1230,17 @@ void cdrInterrupt() {
                        // - fixes cutscene speech
                        {
                                u8 *buf = CDR_getBuffer();
-                               memcpy(cdr.Transfer, buf, 8);
+                               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
                        */
 
-                       if (!cdr.Seeked) {
-                               cdr.Seeked = TRUE;
-
+                       if (cdr.Seeked != SEEK_DONE) {
                                cdr.StatP |= STATUS_SEEK;
                                cdr.StatP &= ~STATUS_READ;
 
@@ -1259,12 +1272,18 @@ void cdrInterrupt() {
 
        Check_Shell( Irq );
 
+       cdr.ParamP = 0;
+       cdr.ParamC = 0;
+
        if (cdr.Stat != NoIntr && cdr.Reg2 != 0x18) {
                psxHu32ref(0x1070) |= SWAP32((u32)0x4);
        }
 
 #ifdef CDR_LOG
-       CDR_LOG("cdrInterrupt() Log: CDR Interrupt IRQ %x\n", Irq);
+       printf("cdrInterrupt() Log: CDR Interrupt IRQ %x: ", Irq);
+       for (i = 0; i < cdr.ResultC; i++)
+               printf("%02x ", cdr.Result[i]);
+       printf("\n");
 #endif
 }
 
@@ -1288,6 +1307,7 @@ void cdrReadInterrupt() {
        cdr.StatP |= STATUS_READ|STATUS_ROTATING;
        cdr.StatP &= ~STATUS_SEEK;
        cdr.Result[0] = cdr.StatP;
+       cdr.Seeked = SEEK_DONE;
 
        ReadTrack( cdr.SetSector );
 
@@ -1327,6 +1347,23 @@ void cdrReadInterrupt() {
                        int ret = xa_decode_sector(&cdr.Xa, cdr.Transfer+4, cdr.FirstSector);
 
                        if (!ret) {
+                               // only handle attenuator basic channel switch for now
+                               if (cdr.Xa.stereo) {
+                                       int i;
+                                       if ((cdr.AttenuatorLeft[0] | cdr.AttenuatorLeft[1])
+                                           && !(cdr.AttenuatorRight[0] | cdr.AttenuatorRight[1]))
+                                       {
+                                               for (i = 0; i < cdr.Xa.nsamples; i++)
+                                                       cdr.Xa.pcm[i*2 + 1] = cdr.Xa.pcm[i*2];
+                                       }
+                                       else if (!(cdr.AttenuatorLeft[0] | cdr.AttenuatorLeft[1])
+                                           && (cdr.AttenuatorRight[0] | cdr.AttenuatorRight[1]))
+                                       {
+                                               for (i = 0; i < cdr.Xa.nsamples; i++)
+                                                       cdr.Xa.pcm[i*2] = cdr.Xa.pcm[i*2 + 1];
+                                       }
+                               }
+
                                SPU_playADPCMchannel(&cdr.Xa);
                                cdr.FirstSector = 0;
 
@@ -1428,13 +1465,7 @@ void cdrWrite0(unsigned char rt) {
 #ifdef CDR_LOG
        CDR_LOG("cdrWrite0() Log: CD0 write: %x\n", rt);
 #endif
-       cdr.Ctrl = rt | (cdr.Ctrl & ~0x3);
-
-       if (rt == 0) {
-               cdr.ParamP = 0;
-               cdr.ParamC = 0;
-               cdr.ResultReady = 0;
-       }
+       cdr.Ctrl = (rt & 3) | (cdr.Ctrl & ~3);
 }
 
 unsigned char cdrRead1(void) {
@@ -1454,6 +1485,7 @@ unsigned char cdrRead1(void) {
 }
 
 void cdrWrite1(unsigned char rt) {
+       u8 set_loc[3];
        int i;
 
 #ifdef CDR_LOG
@@ -1463,7 +1495,7 @@ void cdrWrite1(unsigned char rt) {
 
        // Tekken: CDXA fade-out
        if( (cdr.Ctrl & 3) == 3 ) {
-               //cdr.AttenuatorRight[0] = rt;
+               cdr.AttenuatorRight[0] = rt;
        }
 
 
@@ -1483,7 +1515,9 @@ void cdrWrite1(unsigned char rt) {
        }
 #endif
 
-       if (cdr.Ctrl & 0x1) return;
+       if (cdr.Ctrl & 0x3) return;
+
+       cdr.ResultReady = 0;
 
        switch (cdr.Cmd) {
        case CdlSync:
@@ -1502,15 +1536,15 @@ void cdrWrite1(unsigned char rt) {
 
        case CdlSetloc:
                StopReading();
-               cdr.Seeked = FALSE;
                for (i = 0; i < 3; i++)
-                       cdr.SetSector[i] = btoi(cdr.Param[i]);
-               cdr.SetSector[3] = 0;
+                       set_loc[i] = btoi(cdr.Param[i]);
 
-               /*
-                  if ((cdr.SetSector[0] | cdr.SetSector[1] | cdr.SetSector[2]) == 0) {
-                *(u32 *)cdr.SetSector = *(u32 *)cdr.SetSectorSeek;
-                }*/
+               i = abs(msf2sec(cdr.SetSector) - msf2sec(set_loc));
+               if (i > 16)
+                      cdr.Seeked = SEEK_PENDING;
+
+               memcpy(cdr.SetSector, set_loc, 3);
+               cdr.SetSector[3] = 0;
 
                cdr.Ctrl |= 0x80;
                cdr.Stat = NoIntr;
@@ -1627,6 +1661,7 @@ void cdrWrite1(unsigned char rt) {
 
        case CdlReset:
        case CdlInit:
+               cdr.Seeked = SEEK_DONE;
                StopCdda();
                StopReading();
                cdr.Ctrl |= 0x80;
@@ -1783,6 +1818,8 @@ void cdrWrite1(unsigned char rt) {
                break;
 
        default:
+               cdr.ParamP = 0;
+               cdr.ParamC = 0;
 #ifdef CDR_LOG
                CDR_LOG("cdrWrite1() Log: Unknown command: %x\n", cdr.Cmd);
 #endif
@@ -1799,7 +1836,7 @@ unsigned char cdrRead2(void) {
        if (cdr.Readed == 0) {
                ret = 0;
        } else {
-               ret = *cdr.pTransfer++;
+               ret = *pTransfer++;
        }
 
 #ifdef CDR_LOG
@@ -1815,10 +1852,10 @@ void cdrWrite2(unsigned char rt) {
 
        // Tekken: CDXA fade-out
        if( (cdr.Ctrl & 3) == 2 ) {
-               //cdr.AttenuatorLeft[0] = rt;
+               cdr.AttenuatorLeft[0] = rt;
        }
        else if( (cdr.Ctrl & 3) == 3 ) {
-               //cdr.AttenuatorRight[1] = rt;
+               cdr.AttenuatorRight[1] = rt;
        }
 
 
@@ -1835,7 +1872,7 @@ void cdrWrite2(unsigned char rt) {
                                cdr.Reg2 = rt;
                                break;
                }
-       } else if (!(cdr.Ctrl & 0x1) && cdr.ParamP < 8) {
+       } else if (!(cdr.Ctrl & 0x3) && cdr.ParamP < 8) {
                cdr.Param[cdr.ParamP++] = rt;
                cdr.ParamC++;
        }
@@ -1860,7 +1897,7 @@ void cdrWrite3(unsigned char rt) {
 #ifdef CDR_LOG
        CDR_LOG("cdrWrite3() Log: CD3 write: %x\n", rt);
 #endif
-/*
+
        // Tekken: CDXA fade-out
        if( (cdr.Ctrl & 3) == 2 ) {
                cdr.AttenuatorLeft[1] = rt;
@@ -1872,7 +1909,7 @@ void cdrWrite3(unsigned char rt) {
                        cdr.AttenuatorRight[0], cdr.AttenuatorRight[1] );
 #endif
        }
-*/
+
 
        // GameShark CDX CD Player: Irq timing mania
        if( rt == 0 &&
@@ -1888,7 +1925,7 @@ void cdrWrite3(unsigned char rt) {
        }
 
 
-       if (rt == 0x07 && cdr.Ctrl & 0x1) {
+       if (rt == 0x07 && (cdr.Ctrl & 3) == 1) {
                cdr.Stat = 0;
 
                if (cdr.Irq == 0xff) {
@@ -1900,26 +1937,31 @@ void cdrWrite3(unsigned char rt) {
                // - Final Fantasy Tactics
                // - various other games
 
-               if (cdr.Irq) // rearmed guesswork hack
                if (cdr.Reading && !cdr.ResultReady) {
-                       CDREAD_INT((cdr.Mode & MODE_SPEED) ? (cdReadTime / 2) : cdReadTime);
+                       int left = psxRegs.intCycle[PSXINT_CDREAD].sCycle + psxRegs.intCycle[PSXINT_CDREAD].cycle - psxRegs.cycle;
+                       int time = (cdr.Mode & MODE_SPEED) ? (cdReadTime / 2) : cdReadTime;
+                       if (Config.CdrReschedule != 2)
+                       if (left < time / 2 || Config.CdrReschedule) { // rearmed guesswork hack
+                               //printf("-- resched %d -> %d\n", left, time);
+                               CDREAD_INT(time);
+                       }
                }
 
                return;
        }
 
-       if (rt == 0x80 && !(cdr.Ctrl & 0x1) && cdr.Readed == 0) {
+       if (rt == 0x80 && !(cdr.Ctrl & 0x3) && cdr.Readed == 0) {
                cdr.Readed = 1;
-               cdr.pTransfer = cdr.Transfer;
+               pTransfer = cdr.Transfer;
 
                switch (cdr.Mode & 0x30) {
                        case MODE_SIZE_2328:
                        case 0x00:
-                               cdr.pTransfer += 12;
+                               pTransfer += 12;
                                break;
 
                        case MODE_SIZE_2340:
-                               cdr.pTransfer += 0;
+                               pTransfer += 0;
                                break;
 
                        default:
@@ -1930,6 +1972,7 @@ void cdrWrite3(unsigned char rt) {
 
 void psxDma3(u32 madr, u32 bcr, u32 chcr) {
        u32 cdsize;
+       int size;
        u8 *ptr;
 
 #ifdef CDR_LOG
@@ -1974,19 +2017,16 @@ void psxDma3(u32 madr, u32 bcr, u32 chcr) {
                        - CdlPlay
                        - Spams DMA3 and gets buffer overrun
                        */
-
-                       if( (cdr.pTransfer-cdr.Transfer) + cdsize > 2352 )
-                       {
-                               // avoid crash - probably should wrap here
-                               //memcpy(ptr, cdr.pTransfer, cdsize);
-                       }
-                       else
+                       size = CD_FRAMESIZE_RAW - (pTransfer - cdr.Transfer);
+                       if (size > cdsize)
+                               size = cdsize;
+                       if (size > 0)
                        {
-                               memcpy(ptr, cdr.pTransfer, cdsize);
+                               memcpy(ptr, pTransfer, size);
                        }
 
                        psxCpu->Clear(madr, cdsize / 4);
-                       cdr.pTransfer += cdsize;
+                       pTransfer += cdsize;
 
 
                        // burst vs normal
@@ -2011,8 +2051,11 @@ void psxDma3(u32 madr, u32 bcr, u32 chcr) {
 
 void cdrDmaInterrupt()
 {
-       HW_DMA3_CHCR &= SWAP32(~0x01000000);
-       DMA_INTERRUPT(3);
+       if (HW_DMA3_CHCR & SWAP32(0x01000000))
+       {
+               HW_DMA3_CHCR &= SWAP32(~0x01000000);
+               DMA_INTERRUPT(3);
+       }
 }
 
 void cdrReset() {
@@ -2020,11 +2063,17 @@ void cdrReset() {
        cdr.CurTrack = 1;
        cdr.File = 1;
        cdr.Channel = 1;
+       pTransfer = cdr.Transfer;
+
+       // BIOS player - default values
+       cdr.AttenuatorLeft[0] = 0x80;
+       cdr.AttenuatorLeft[1] = 0x00;
+       cdr.AttenuatorRight[0] = 0x80;
+       cdr.AttenuatorRight[1] = 0x00;
 }
 
 int cdrFreeze(gzFile f, int Mode) {
-       uintptr_t tmp;
-
+       u32 tmp;
 
        if( Mode == 0 ) {
                StopCdda();
@@ -2033,12 +2082,16 @@ int cdrFreeze(gzFile f, int Mode) {
        gzfreeze(&cdr, sizeof(cdr));
        
        if (Mode == 1)
-               tmp = cdr.pTransfer - cdr.Transfer;
+               tmp = pTransfer - cdr.Transfer;
 
        gzfreeze(&tmp, sizeof(tmp));
 
-       if (Mode == 0)
-               cdr.pTransfer = cdr.Transfer + tmp;
+       if (Mode == 0) {
+               pTransfer = cdr.Transfer + tmp;
+
+               if (cdr.Play && !Config.Cdda)
+                       CDR_play(cdr.SetSectorPlay);
+       }
 
        return 0;
 }