unsigned char Absolute[3];
} subq;
unsigned char TrackChanged;
- boolean m_locationChanged;
- unsigned char pad1[2];
+ unsigned char pad1[3];
unsigned int freeze_ver;
unsigned char Prev[4];
u8 IrqRepeated;
u32 eCycle;
- u8 Seeked;
+ u8 pad2;
u8 DriveState;
u8 FastForward;
#define cdReadTime (PSXCLK / 75)
enum drive_state {
- DRIVESTATE_STANDBY = 0,
+ DRIVESTATE_STANDBY = 0, // pause, play, read
DRIVESTATE_LID_OPEN,
DRIVESTATE_RESCAN_CD,
DRIVESTATE_PREPARE_CD,
DRIVESTATE_STOPPED,
};
-// for cdr.Seeked
-enum seeked_state {
- SEEK_PENDING = 0,
- SEEK_DONE = 1,
-};
-
static struct CdrStat stat;
static unsigned int msf2sec(const u8 *msf) {
}
// cdrPlayInterrupt
-#define CDRMISC_INT(eCycle) { \
+#define CDRSEEKPLAY_INT(eCycle) { \
psxRegs.interrupt |= (1 << PSXINT_CDRPLAY); \
psxRegs.intCycle[PSXINT_CDRPLAY].cycle = eCycle; \
psxRegs.intCycle[PSXINT_CDRPLAY].sCycle = psxRegs.cycle; \
}
#define StopReading() { \
- if (cdr.Reading) { \
- cdr.Reading = 0; \
- psxRegs.interrupt &= ~(1 << PSXINT_CDREAD); \
- } \
- cdr.StatP &= ~(STATUS_READ|STATUS_SEEK);\
+ cdr.Reading = 0; \
+ psxRegs.interrupt &= ~(1 << PSXINT_CDREAD); \
}
#define StopCdda() { \
- if (cdr.Play) { \
- if (!Config.Cdda) CDR_stop(); \
- cdr.StatP &= ~STATUS_PLAY; \
- cdr.Play = FALSE; \
- cdr.FastForward = 0; \
- cdr.FastBackward = 0; \
- /*SPU_registerCallback( SPUirq );*/ \
- } \
+ if (cdr.Play && !Config.Cdda) CDR_stop(); \
+ cdr.Play = FALSE; \
+ cdr.FastForward = 0; \
+ cdr.FastBackward = 0; \
+}
+
+#define SetPlaySeekRead(x, f) { \
+ x &= ~(STATUS_PLAY | STATUS_SEEK | STATUS_READ); \
+ x |= f; \
}
#define SetResultSize(size) { \
switch (cdr.DriveState) {
default:
case DRIVESTATE_STANDBY:
- cdr.StatP &= ~STATUS_SEEK;
+ StopCdda();
+ StopReading();
+ SetPlaySeekRead(cdr.StatP, 0);
if (CDR_getStatus(&stat) == -1)
return;
if (stat.Status & STATUS_SHELLOPEN)
{
- StopCdda();
cdr.DriveState = DRIVESTATE_LID_OPEN;
CDRLID_INT(0x800);
}
// 02, 12, 10
if (!(cdr.StatP & STATUS_SHELLOPEN)) {
- StopReading();
cdr.StatP |= STATUS_SHELLOPEN;
// could generate error irq here, but real hardware
setIrq(0x200);
StopCdda();
+ SetPlaySeekRead(cdr.StatP, 0);
}
else if (((cdr.Mode & MODE_REPORT) || cdr.FastForward || cdr.FastBackward)) {
cdr.Result[0] = cdr.StatP;
}
}
+static int cdrSeekTime(unsigned char *target)
+{
+ int seekTime = abs(msf2sec(cdr.SetSectorPlay) - msf2sec(target)) * (cdReadTime / 200);
+ /*
+ * Gameblabla :
+ * It was originally set to 1000000 for Driver, however it is not high enough for Worms Pinball
+ * and was unreliable for that game.
+ * I also tested it against Mednafen and Driver's titlescreen music starts 25 frames later, not immediatly.
+ *
+ * Obviously, this isn't perfect but right now, it should be a bit better.
+ * Games to test this against if you change that setting :
+ * - Driver (titlescreen music delay and retry mission)
+ * - Worms Pinball (Will either not boot or crash in the memory card screen)
+ * - Viewpoint (short pauses if the delay in the ingame music is too long)
+ *
+ * It seems that 3386880 * 5 is too much for Driver's titlescreen and it starts skipping.
+ * However, 1000000 is not enough for Worms Pinball to reliably boot.
+ */
+ if(seekTime > 3386880 * 2) seekTime = 3386880 * 2;
+ CDR_LOG("seek: %.2f %.2f\n", (float)seekTime / PSXCLK, (float)seekTime / cdReadTime);
+ return seekTime;
+}
+
// also handles seek
void cdrPlayInterrupt()
{
- if (cdr.Seeked == SEEK_PENDING) {
+ if (cdr.StatP & STATUS_SEEK) {
if (cdr.Stat) {
CDR_LOG_I("cdrom: seek stat hack\n");
- CDRMISC_INT(0x1000);
+ CDRSEEKPLAY_INT(0x1000);
return;
}
SetResultSize(1);
cdr.StatP |= STATUS_ROTATING;
- cdr.StatP &= ~STATUS_SEEK;
+ SetPlaySeekRead(cdr.StatP, cdr.Play ? STATUS_PLAY : 0);
cdr.Result[0] = cdr.StatP;
- cdr.Seeked = SEEK_DONE;
if (cdr.Irq == 0) {
cdr.Stat = Complete;
setIrq(0x202);
}
- if (cdr.SetlocPending) {
- memcpy(cdr.SetSectorPlay, cdr.SetSector, 4);
- cdr.SetlocPending = 0;
- cdr.m_locationChanged = TRUE;
- }
Find_CurTrack(cdr.SetSectorPlay);
ReadTrack(cdr.SetSectorPlay);
cdr.TrackChanged = FALSE;
if (memcmp(cdr.SetSectorPlay, cdr.SetSectorEnd, 3) == 0) {
StopCdda();
+ SetPlaySeekRead(cdr.StatP, 0);
cdr.TrackChanged = TRUE;
}
else {
}
}
- if (cdr.m_locationChanged)
- {
- CDRMISC_INT(cdReadTime * 30);
- cdr.m_locationChanged = FALSE;
- }
- else
- {
- CDRMISC_INT(cdReadTime);
- }
+ CDRSEEKPLAY_INT(cdReadTime);
// update for CdlGetlocP/autopause
generate_subq(cdr.SetSectorPlay);
else
{
for (i = 0; i < 3; i++)
- {
set_loc[i] = btoi(cdr.Param[i]);
- }
-
- i = msf2sec(cdr.SetSectorPlay);
- i = abs(i - msf2sec(set_loc));
- if (i > 16)
- cdr.Seeked = SEEK_PENDING;
-
memcpy(cdr.SetSector, set_loc, 3);
cdr.SetSector[3] = 0;
cdr.SetlocPending = 1;
do_CdlPlay:
case CdlPlay:
StopCdda();
- if (cdr.Seeked == SEEK_PENDING) {
- // XXX: wrong, should seek instead..
- cdr.Seeked = SEEK_DONE;
- }
-
+ StopReading();
+
cdr.FastBackward = 0;
cdr.FastForward = 0;
- if (cdr.SetlocPending) {
- memcpy(cdr.SetSectorPlay, cdr.SetSector, 4);
- cdr.SetlocPending = 0;
- cdr.m_locationChanged = TRUE;
- }
-
// BIOS CD Player
// - Pause player, hit Track 01/02/../xx (Setloc issued!!)
- if (cdr.ParamC == 0 || cdr.Param[0] == 0) {
- CDR_LOG("PLAY Resume @ %d:%d:%d\n",
- cdr.SetSectorPlay[0], cdr.SetSectorPlay[1], cdr.SetSectorPlay[2]);
- }
- else
- {
+ if (cdr.ParamC != 0 && cdr.Param[0] != 0) {
int track = btoi( cdr.Param[0] );
if (track <= cdr.ResultTN[1])
CDR_LOG("PLAY track %d\n", cdr.CurTrack);
if (CDR_getTD((u8)cdr.CurTrack, cdr.ResultTD) != -1) {
- cdr.SetSectorPlay[0] = cdr.ResultTD[2];
- cdr.SetSectorPlay[1] = cdr.ResultTD[1];
- cdr.SetSectorPlay[2] = cdr.ResultTD[0];
+ for (i = 0; i < 3; i++)
+ set_loc[i] = cdr.ResultTD[2 - i];
+ seekTime = cdrSeekTime(set_loc);
+ memcpy(cdr.SetSectorPlay, set_loc, 3);
}
}
+ else if (cdr.SetlocPending) {
+ seekTime = cdrSeekTime(cdr.SetSector);
+ memcpy(cdr.SetSectorPlay, cdr.SetSector, 4);
+ }
+ else {
+ CDR_LOG("PLAY Resume @ %d:%d:%d\n",
+ cdr.SetSectorPlay[0], cdr.SetSectorPlay[1], cdr.SetSectorPlay[2]);
+ }
+ cdr.SetlocPending = 0;
/*
Rayman: detect track changes
ReadTrack(cdr.SetSectorPlay);
cdr.TrackChanged = FALSE;
- StopReading();
if (!Config.Cdda)
CDR_play(cdr.SetSectorPlay);
- // Vib Ribbon: gameplay checks flag
- cdr.StatP &= ~STATUS_SEEK;
- cdr.Result[0] = cdr.StatP;
-
- cdr.StatP |= STATUS_PLAY;
+ SetPlaySeekRead(cdr.StatP, STATUS_SEEK | STATUS_ROTATING);
// BIOS player - set flag again
cdr.Play = TRUE;
- CDRMISC_INT( cdReadTime );
+ CDRSEEKPLAY_INT(cdReadTime + seekTime);
start_rotating = 1;
break;
StopCdda();
StopReading();
+ SetPlaySeekRead(cdr.StatP, 0);
+ cdr.StatP &= ~STATUS_ROTATING;
delay = 0x800;
if (cdr.DriveState == DRIVESTATE_STANDBY)
break;
case CdlStop + 0x100:
- cdr.StatP &= ~STATUS_ROTATING;
- cdr.Result[0] = cdr.StatP;
cdr.Stat = Complete;
break;
case CdlPause:
+ StopCdda();
+ StopReading();
/*
Gundam Battle Assault 2: much slower (*)
- Fixes boot, gameplay
* Mednafen's timing don't work for Gundam Battle Assault 2 in PAL/50hz mode,
* seems to be timing sensitive as it can depend on the CPU's clock speed.
* */
- if (cdr.DriveState == DRIVESTATE_STANDBY)
+ if (!(cdr.StatP & (STATUS_PLAY | STATUS_READ)))
{
delay = 7000;
}
else
{
delay = (((cdr.Mode & MODE_SPEED) ? 2 : 1) * (1000000));
- CDRMISC_INT((cdr.Mode & MODE_SPEED) ? cdReadTime / 2 : cdReadTime);
}
AddIrqQueue(CdlPause + 0x100, delay);
+ SetPlaySeekRead(cdr.StatP, 0);
cdr.Ctrl |= 0x80;
break;
case CdlPause + 0x100:
- cdr.StatP &= ~STATUS_READ;
- cdr.Result[0] = cdr.StatP;
cdr.Stat = Complete;
break;
case CdlReset:
+ StopCdda();
+ StopReading();
+ SetPlaySeekRead(cdr.StatP, 0);
cdr.Muted = FALSE;
cdr.Mode = 0x20; /* This fixes This is Football 2, Pooh's Party lockups */
AddIrqQueue(CdlReset + 0x100, 4100000);
case CdlSeekP:
StopCdda();
StopReading();
- cdr.StatP |= STATUS_SEEK;
+ SetPlaySeekRead(cdr.StatP, STATUS_SEEK);
+ seekTime = cdrSeekTime(cdr.SetSector);
+ memcpy(cdr.SetSectorPlay, cdr.SetSector, 4);
/*
Crusaders of Might and Magic = 0.5x-4x
- fix cutscene speech start
Rockman X5 = 0.5-4x
- fix capcom logo
*/
- CDRMISC_INT(cdr.Seeked == SEEK_DONE ? 0x800 : cdReadTime * 4);
- cdr.Seeked = SEEK_PENDING;
- memcpy(cdr.SetSectorPlay, cdr.SetSector, 4);
+ CDRSEEKPLAY_INT(cdReadTime + seekTime);
start_rotating = 1;
break;
break;
case CdlInit:
+ StopCdda();
+ StopReading();
+ SetPlaySeekRead(cdr.StatP, 0);
// yes, it really sets STATUS_SHELLOPEN
cdr.StatP |= STATUS_SHELLOPEN;
cdr.DriveState = DRIVESTATE_RESCAN_CD;
case CdlReadN:
case CdlReadS:
- if (cdr.SetlocPending) {
- seekTime = abs(msf2sec(cdr.SetSectorPlay) - msf2sec(cdr.SetSector)) * (cdReadTime / 200);
- /*
- * Gameblabla :
- * It was originally set to 1000000 for Driver, however it is not high enough for Worms Pinball
- * and was unreliable for that game.
- * I also tested it against Mednafen and Driver's titlescreen music starts 25 frames later, not immediatly.
- *
- * Obviously, this isn't perfect but right now, it should be a bit better.
- * Games to test this against if you change that setting :
- * - Driver (titlescreen music delay and retry mission)
- * - Worms Pinball (Will either not boot or crash in the memory card screen)
- * - Viewpoint (short pauses if the delay in the ingame music is too long)
- *
- * It seems that 3386880 * 5 is too much for Driver's titlescreen and it starts skipping.
- * However, 1000000 is not enough for Worms Pinball to reliably boot.
- */
- if(seekTime > 3386880 * 2) seekTime = 3386880 * 2;
- memcpy(cdr.SetSectorPlay, cdr.SetSector, 4);
- cdr.SetlocPending = 0;
- cdr.m_locationChanged = TRUE;
- }
- Find_CurTrack(cdr.SetSectorPlay);
+ Find_CurTrack(cdr.SetlocPending ? cdr.SetSector : cdr.SetSectorPlay);
if ((cdr.Mode & MODE_CDDA) && cdr.CurTrack > 1)
// Read* acts as play for cdda tracks in cdda mode
goto do_CdlPlay;
+ StopCdda();
+ if (cdr.SetlocPending) {
+ seekTime = cdrSeekTime(cdr.SetSector);
+ memcpy(cdr.SetSectorPlay, cdr.SetSector, 4);
+ cdr.SetlocPending = 0;
+ }
cdr.Reading = 1;
cdr.FirstSector = 1;
Gameblabla additional notes :
This still needs the "+ seekTime" that PCSX Redux doesn't have for the Driver "retry" mission error.
*/
- cdr.StatP |= STATUS_READ;
- cdr.StatP &= ~STATUS_SEEK;
-
CDREAD_INT(((cdr.Mode & 0x80) ? (cdReadTime) : cdReadTime * 2) + seekTime);
- cdr.Result[0] = cdr.StatP;
+ SetPlaySeekRead(cdr.StatP, STATUS_SEEK);
start_rotating = 1;
break;
case CdlSync:
if (cdr.Irq || cdr.Stat) {
CDR_LOG_I("cdrom: read stat hack %02x %x\n", cdr.Irq, cdr.Stat);
- CDREAD_INT(0x1000);
+ CDREAD_INT(2048);
return;
}
cdr.OCUP = 1;
SetResultSize(1);
- cdr.StatP |= STATUS_READ|STATUS_ROTATING;
- cdr.StatP &= ~STATUS_SEEK;
+ SetPlaySeekRead(cdr.StatP, STATUS_READ | STATUS_ROTATING);
cdr.Result[0] = cdr.StatP;
- cdr.Seeked = SEEK_DONE;
ReadTrack(cdr.SetSectorPlay);
int ret = xa_decode_sector(&cdr.Xa, cdr.Transfer+4, cdr.FirstSector);
if (!ret) {
cdrAttenuate(cdr.Xa.pcm, cdr.Xa.nsamples, cdr.Xa.stereo);
- /*
- * Gameblabla -
- * This is a hack for Megaman X4, Castlevania etc...
- * that regressed from the new m_locationChanged and CDROM timings changes.
- * It is mostly noticeable in Castevania however and the stuttering can be very jarring.
- *
- * According to PCSX redux authors, we shouldn't cause a location change if
- * the sector difference is too small.
- * I attempted to go with that approach but came empty handed.
- * So for now, let's just set cdr.m_locationChanged to false when playing back any ADPCM samples.
- * This does not regress Crash Team Racing's intro at least.
- */
- cdr.m_locationChanged = FALSE;
SPU_playADPCMchannel(&cdr.Xa);
cdr.FirstSector = 0;
}
cdr.Readed = 0;
- uint32_t delay = (cdr.Mode & MODE_SPEED) ? (cdReadTime / 2) : cdReadTime;
- if (cdr.m_locationChanged) {
- CDREAD_INT(delay * 30);
- cdr.m_locationChanged = FALSE;
- } else {
- CDREAD_INT(delay);
- }
+ CDREAD_INT((cdr.Mode & MODE_SPEED) ? (cdReadTime / 2) : cdReadTime);
/*
Croc 2: $40 - only FORM1 (*)
AddIrqQueue(cdr.Cmd, 0x800);
switch (cdr.Cmd) {
-
- case CdlReadN:
- case CdlReadS:
- case CdlPause:
- StopCdda();
- StopReading();
- break;
-
- case CdlInit:
- case CdlReset:
- cdr.Seeked = SEEK_DONE;
- StopCdda();
- StopReading();
- break;
-
case CdlSetmode:
CDR_LOG("cdrWrite1() Log: Setmode %x\n", cdr.Param[0]);
cdr.Mode = cdr.Param[0];
-
- // Squaresoft on PlayStation 1998 Collector's CD Vol. 1
- // - fixes choppy movie sound
- if( cdr.Play && (cdr.Mode & MODE_CDDA) == 0 )
- StopCdda();
break;
}
}
void LidInterrupt() {
getCdInfo();
- StopCdda();
cdrLidSeekInterrupt();
}