enum seeked_state {
SEEK_PENDING = 0,
SEEK_DONE = 1,
- SEEK_DOING_CMD = 2,
};
static struct CdrStat stat;
-static unsigned int msf2sec(u8 *msf) {
+static unsigned int msf2sec(const u8 *msf) {
return ((msf[0] * 60 + msf[1]) * 75) + msf[2];
}
+// for that weird psemu API..
+static unsigned int fsm2sec(const u8 *msf) {
+ return ((msf[2] * 60 + msf[1]) * 75) + msf[0];
+}
+
static void sec2msf(unsigned int s, u8 *msf) {
msf[0] = s / 75 / 60;
s = s - msf[0] * 75 * 60;
}
}
-void Find_CurTrack() {
- cdr.CurTrack = 0;
-
- if (CDR_getTN(cdr.ResultTN) != -1) {
- int lcv;
-
- for( lcv = 1; lcv <= cdr.ResultTN[1]; lcv++ ) {
- if (CDR_getTD((u8)(lcv), cdr.ResultTD) != -1) {
- u32 sect1, sect2;
-
- CDR_LOG( "curtrack %d %d %d | %d %d %d | %d\n",
- cdr.SetSectorPlay[0], cdr.SetSectorPlay[1], cdr.SetSectorPlay[2],
- cdr.ResultTD[2], cdr.ResultTD[1], cdr.ResultTD[0],
- cdr.CurTrack );
-
- // find next track boundary - only need m:s accuracy
- sect1 = cdr.SetSectorPlay[0] * 60 * 75 + cdr.SetSectorPlay[1] * 75;
- sect2 = cdr.ResultTD[2] * 60 * 75 + cdr.ResultTD[1] * 75;
-
- // Twisted Metal 4 - psx cdda pregap (2-sec)
- // - fix in-game music
- sect2 -= 75 * 2;
+static void Find_CurTrack(const u8 *time)
+{
+ int current, sect;
- if( sect1 >= sect2 ) {
- cdr.CurTrack++;
- continue;
- }
- }
+ current = msf2sec(time);
+ for (cdr.CurTrack = 1; cdr.CurTrack < cdr.ResultTN[1]; cdr.CurTrack++) {
+ CDR_getTD(cdr.CurTrack + 1, cdr.ResultTD);
+ sect = fsm2sec(cdr.ResultTD);
+ if (sect - current >= 150)
break;
- }
}
}
-static void ReadTrack( u8 *time ) {
- cdr.Prev[0] = itob( time[0] );
- cdr.Prev[1] = itob( time[1] );
- cdr.Prev[2] = itob( time[2] );
-
- CDR_LOG("ReadTrack() Log: KEY *** %x:%x:%x\n", cdr.Prev[0], cdr.Prev[1], cdr.Prev[2]);
- cdr.RErr = CDR_readTrack(cdr.Prev);
-}
-
-
-static void AddIrqQueue(unsigned char irq, unsigned long ecycle) {
- if (cdr.Irq != 0)
- CDR_LOG_I("cdr: override cmd %02x -> %02x\n", cdr.Irq, irq);
-
- cdr.Irq = irq;
- cdr.eCycle = ecycle;
-
- CDR_INT(ecycle);
-}
-
-
-void Set_Track()
-{
- if (CDR_getTN(cdr.ResultTN) != -1) {
- int lcv;
-
- for( lcv = 1; lcv < cdr.ResultTN[1]; lcv++ ) {
- if (CDR_getTD((u8)(lcv), cdr.ResultTD) != -1) {
- CDR_LOG( "settrack %d %d %d | %d %d %d | %d\n",
- cdr.SetSectorPlay[0], cdr.SetSectorPlay[1], cdr.SetSectorPlay[2],
- cdr.ResultTD[2], cdr.ResultTD[1], cdr.ResultTD[0],
- cdr.CurTrack );
-
- // check if time matches track start (only need min, sec accuracy)
- // - m:s:f vs f:s:m
- if( cdr.SetSectorPlay[0] == cdr.ResultTD[2] &&
- cdr.SetSectorPlay[1] == cdr.ResultTD[1] ) {
- // skip pregap frames
- if( cdr.SetSectorPlay[2] < cdr.ResultTD[0] )
- cdr.SetSectorPlay[2] = cdr.ResultTD[0];
-
- break;
- }
- else if( cdr.SetSectorPlay[0] < cdr.ResultTD[2] )
- break;
- }
- }
- }
-}
-
-
-static u8 fake_subq_local[3], fake_subq_real[3], fake_subq_index, fake_subq_change;
-static void Create_Fake_Subq()
+static void generate_subq(const u8 *time)
{
- u8 temp_cur[3], temp_next[3], temp_start[3], pregap;
- int diff;
+ unsigned char start[3], next[3];
+ unsigned int this_s, start_s, next_s, pregap;
+ int relative_s;
- if (CDR_getTN(cdr.ResultTN) == -1) return;
- if( cdr.CurTrack+1 <= cdr.ResultTN[1] ) {
+ CDR_getTD(cdr.CurTrack, start);
+ if (cdr.CurTrack + 1 <= cdr.ResultTN[1]) {
pregap = 150;
- if( CDR_getTD(cdr.CurTrack+1, cdr.ResultTD) == -1 ) return;
- } else {
+ CDR_getTD(cdr.CurTrack + 1, next);
+ }
+ else {
// last track - cd size
pregap = 0;
- if( CDR_getTD(0, cdr.ResultTD) == -1 ) return;
- }
-
- if( cdr.Play == TRUE ) {
- temp_cur[0] = cdr.SetSectorPlay[0];
- temp_cur[1] = cdr.SetSectorPlay[1];
- temp_cur[2] = cdr.SetSectorPlay[2];
- } else {
- temp_cur[0] = btoi( cdr.Prev[0] );
- temp_cur[1] = btoi( cdr.Prev[1] );
- temp_cur[2] = btoi( cdr.Prev[2] );
+ next[0] = cdr.SetSectorEnd[2];
+ next[1] = cdr.SetSectorEnd[1];
+ next[2] = cdr.SetSectorEnd[0];
}
- fake_subq_real[0] = temp_cur[0];
- fake_subq_real[1] = temp_cur[1];
- fake_subq_real[2] = temp_cur[2];
-
- temp_next[0] = cdr.ResultTD[2];
- temp_next[1] = cdr.ResultTD[1];
- temp_next[2] = cdr.ResultTD[0];
+ this_s = msf2sec(time);
+ start_s = fsm2sec(start);
+ next_s = fsm2sec(next);
+ cdr.TrackChanged = FALSE;
- // flag- next track
- if( msf2sec(temp_cur) >= msf2sec( temp_next )-pregap ) {
- fake_subq_change = 1;
-
+ if (next_s - this_s < pregap) {
+ cdr.TrackChanged = TRUE;
cdr.CurTrack++;
-
- // end cd
- if( pregap == 0 ) StopCdda();
+ start_s = next_s;
}
- //////////////////////////////////////////////////
- //////////////////////////////////////////////////
+ cdr.subq.Index = 1;
- // repair
- if( cdr.CurTrack <= cdr.ResultTN[1] ) {
- if( CDR_getTD(cdr.CurTrack, cdr.ResultTD) == -1 ) return;
- } else {
- // last track - cd size
- if( CDR_getTD(0, cdr.ResultTD) == -1 ) return;
+ relative_s = this_s - start_s;
+ if (relative_s < 0) {
+ cdr.subq.Index = 0;
+ relative_s = -relative_s;
}
-
- temp_start[0] = cdr.ResultTD[2];
- temp_start[1] = cdr.ResultTD[1];
- temp_start[2] = cdr.ResultTD[0];
+ sec2msf(relative_s, cdr.subq.Relative);
+
+ cdr.subq.Track = itob(cdr.CurTrack);
+ cdr.subq.Relative[0] = itob(cdr.subq.Relative[0]);
+ cdr.subq.Relative[1] = itob(cdr.subq.Relative[1]);
+ cdr.subq.Relative[2] = itob(cdr.subq.Relative[2]);
+ cdr.subq.Absolute[0] = itob(time[0]);
+ cdr.subq.Absolute[1] = itob(time[1]);
+ cdr.subq.Absolute[2] = itob(time[2]);
+}
+static void ReadTrack(const u8 *time) {
+ unsigned char tmp[3];
+ struct SubQ *subq;
+ u16 crc;
- CDR_LOG( "CDDA FAKE SUB - %d:%d:%d / %d:%d:%d / %d:%d:%d\n",
- temp_cur[0], temp_cur[1], temp_cur[2],
- temp_start[0], temp_start[1], temp_start[2],
- temp_next[0], temp_next[1], temp_next[2]);
+ tmp[0] = itob(time[0]);
+ tmp[1] = itob(time[1]);
+ tmp[2] = itob(time[2]);
+ if (memcmp(cdr.Prev, tmp, 3) == 0)
+ return;
+ CDR_LOG("ReadTrack *** %02x:%02x:%02x\n", tmp[0], tmp[1], tmp[2]);
- // local time - pregap / real
- diff = msf2sec(temp_cur) - msf2sec( temp_start );
- if( diff < 0 ) {
- fake_subq_index = 0;
+ cdr.RErr = CDR_readTrack(tmp);
+ memcpy(cdr.Prev, tmp, 3);
- sec2msf( -diff, fake_subq_local );
- } else {
- fake_subq_index = 1;
+ if (CheckSBI(time))
+ return;
- sec2msf( diff, fake_subq_local );
+ subq = (struct SubQ *)CDR_getBufferSub();
+ if (subq != NULL && cdr.CurTrack == 1) {
+ crc = calcCrc((u8 *)subq + 12, 10);
+ if (crc == (((u16)subq->CRC[0] << 8) | subq->CRC[1])) {
+ cdr.subq.Track = subq->TrackNumber;
+ cdr.subq.Index = subq->IndexNumber;
+ memcpy(cdr.subq.Relative, subq->TrackRelativeAddress, 3);
+ memcpy(cdr.subq.Absolute, subq->AbsoluteAddress, 3);
+ }
+ else {
+ CDR_LOG_I("subq bad crc @%02x:%02x:%02x\n",
+ tmp[0], tmp[1], tmp[2]);
+ }
+ }
+ else {
+ generate_subq(time);
}
-}
-
-
-static void cdrPlayInterrupt_Autopause()
-{
- struct SubQ *subq = (struct SubQ *)CDR_getBufferSub();
- int track_changed = 0;
- if (subq != NULL ) {
- // update subq
- ReadTrack( cdr.SetSectorPlay );
-
- CDR_LOG( "CDDA SUB - %X:%X:%X\n",
- subq->AbsoluteAddress[0], subq->AbsoluteAddress[1], subq->AbsoluteAddress[2] );
- /*
- CDDA Autopause
+ CDR_LOG(" -> %02x,%02x %02x:%02x:%02x %02x:%02x:%02x\n",
+ 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]);
+}
- Silhouette Mirage ($3)
- Tomb Raider 1 ($7)
- */
+static void AddIrqQueue(unsigned char irq, unsigned long ecycle) {
+ if (cdr.Irq != 0)
+ CDR_LOG_I("cdr: override cmd %02x -> %02x\n", cdr.Irq, irq);
- // .. + 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();
- CDR_LOG( "CDDA FAKE SUB - %d:%d:%d\n",
- fake_subq_real[0], fake_subq_real[1], fake_subq_real[2] );
+ cdr.Irq = irq;
+ cdr.eCycle = ecycle;
- track_changed = fake_subq_change;
- fake_subq_change = 0;
- }
+ CDR_INT(ecycle);
+}
- if ((cdr.Mode & MODE_AUTOPAUSE) && track_changed) {
+static void cdrPlayInterrupt_Autopause()
+{
+ if ((cdr.Mode & MODE_AUTOPAUSE) && cdr.TrackChanged) {
CDR_LOG( "CDDA STOP\n" );
// Magic the Gathering
StopCdda();
}
else if (cdr.Mode & MODE_REPORT) {
- if (subq != NULL) {
- CDR_LOG( "REPPLAY SUB - %X:%X:%X\n",
- subq->AbsoluteAddress[0], subq->AbsoluteAddress[1], subq->AbsoluteAddress[2] );
-
- // 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;
- cdr.Result[3] = subq->AbsoluteAddress[0];
- cdr.Result[4] = subq->AbsoluteAddress[1];
- cdr.Result[5] = subq->AbsoluteAddress[2];
- } else {
- CDR_LOG( "REPPLAY FAKE - %d:%d:%d\n",
- fake_subq_real[0], fake_subq_real[1], fake_subq_real[2] );
-
- if (fake_subq_real[2] & 0xf)
- return;
+ cdr.Result[0] = cdr.StatP;
+ cdr.Result[1] = cdr.subq.Track;
+ cdr.Result[2] = cdr.subq.Index;
- cdr.Result[0] = cdr.StatP;
- // track # / index #
- cdr.Result[1] = itob(cdr.CurTrack);
- cdr.Result[2] = itob(fake_subq_index);
- // absolute
- cdr.Result[3] = itob( fake_subq_real[0] );
- cdr.Result[4] = itob( fake_subq_real[1] );
- cdr.Result[5] = itob( fake_subq_real[2] );
+ if (cdr.subq.Absolute[2] & 0x10) {
+ cdr.Result[3] = cdr.subq.Relative[0];
+ cdr.Result[4] = cdr.subq.Relative[1] | 0x80;
+ cdr.Result[5] = cdr.subq.Relative[2];
}
+ else {
+ cdr.Result[3] = cdr.subq.Absolute[0];
+ cdr.Result[4] = cdr.subq.Absolute[1];
+ cdr.Result[5] = cdr.subq.Absolute[2];
+ }
+
+ cdr.Result[6] = 0;
+ cdr.Result[7] = 0;
// Rayman: Logo freeze (resultready + dataready)
cdr.ResultReady = 1;
// also handles seek
void cdrPlayInterrupt()
{
- if (cdr.Seeked == SEEK_DOING_CMD) {
+ if (cdr.Seeked == SEEK_PENDING) {
if (cdr.Stat) {
CDR_LOG_I("cdrom: seek stat hack\n");
CDRMISC_INT(0x1000);
cdr.StatP |= STATUS_ROTATING;
cdr.StatP &= ~STATUS_SEEK;
cdr.Result[0] = cdr.StatP;
+ cdr.Seeked = SEEK_DONE;
if (cdr.Irq == 0) {
cdr.Stat = Complete;
setIrq();
}
- 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);
- }
+ memcpy(cdr.SetSectorPlay, cdr.SetSector, 4);
+ Find_CurTrack(cdr.SetSectorPlay);
+ ReadTrack(cdr.SetSectorPlay);
+ cdr.TrackChanged = FALSE;
}
if (!cdr.Play) return;
CDR_LOG( "CDDA - %d:%d:%d\n",
cdr.SetSectorPlay[0], cdr.SetSectorPlay[1], cdr.SetSectorPlay[2] );
- CDRMISC_INT( cdReadTime );
+ if (memcmp(cdr.SetSectorPlay, cdr.SetSectorEnd, 3) == 0) {
+ StopCdda();
+ cdr.TrackChanged = TRUE;
+ }
- if (!cdr.Irq && !cdr.Stat && (cdr.Mode & MODE_CDDA) && (cdr.Mode & (MODE_AUTOPAUSE|MODE_REPORT)))
+ if (!cdr.Irq && !cdr.Stat && (cdr.Mode & (MODE_AUTOPAUSE|MODE_REPORT)))
cdrPlayInterrupt_Autopause();
+ if (!cdr.Play) return;
+
cdr.SetSectorPlay[2]++;
if (cdr.SetSectorPlay[2] == 75) {
cdr.SetSectorPlay[2] = 0;
}
}
- //Check_Shell(0);
+ CDRMISC_INT(cdReadTime);
+
+ // update for CdlGetlocP/autopause
+ generate_subq(cdr.SetSectorPlay);
}
void cdrInterrupt() {
int i;
unsigned char Irq = cdr.Irq;
- struct SubQ *subq;
// Reschedule IRQ
if (cdr.Stat) {
break;
case CdlPlay:
- fake_subq_change = 0;
-
if (cdr.Seeked == SEEK_PENDING) {
// XXX: wrong, should seek instead..
memcpy( cdr.SetSectorPlay, cdr.SetSector, 4 );
cdr.Seeked = SEEK_DONE;
}
+ // 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
+ {
+ int track = btoi( cdr.Param[0] );
+
+ if (track <= cdr.ResultTN[1])
+ cdr.CurTrack = track;
+
+ 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];
+ }
+ }
+
/*
Rayman: detect track changes
- fixes logo freeze
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--;
- if( cdr.FastBackward ) cdr.FastBackward--;
-
- if( cdr.FastBackward == 0 && cdr.FastForward == 0 ) {
- if( cdr.Play && CDR_getStatus(&stat) != -1 ) {
- cdr.SetSectorPlay[0] = stat.Time[0];
- cdr.SetSectorPlay[1] = stat.Time[1];
- cdr.SetSectorPlay[2] = stat.Time[2];
- }
- }
- }
-
-
- if (!Config.Cdda) {
- // BIOS CD Player
- // - Pause player, hit Track 01/02/../xx (Setloc issued!!)
-
- // GameShark CD Player: Resume play
- if( cdr.ParamC == 0 ) {
- CDR_LOG( "PLAY Resume @ %d:%d:%d\n",
- cdr.SetSectorPlay[0], cdr.SetSectorPlay[1], cdr.SetSectorPlay[2] );
-
- //CDR_play( cdr.SetSectorPlay );
- }
- else
- {
- // BIOS CD Player: Resume play
- if( cdr.Param[0] == 0 ) {
- CDR_LOG( "PLAY Resume T0 @ %d:%d:%d\n",
- cdr.SetSectorPlay[0], cdr.SetSectorPlay[1], cdr.SetSectorPlay[2] );
-
- //CDR_play( cdr.SetSectorPlay );
- }
- else {
- CDR_LOG( "PLAY Resume Td @ %d:%d:%d\n",
- cdr.SetSectorPlay[0], cdr.SetSectorPlay[1], cdr.SetSectorPlay[2] );
-
- // BIOS CD Player: Allow track replaying
- StopCdda();
-
-
- cdr.CurTrack = btoi( cdr.Param[0] );
-
- if (CDR_getTN(cdr.ResultTN) != -1) {
- // check last track
- if (cdr.CurTrack > cdr.ResultTN[1])
- cdr.CurTrack = cdr.ResultTN[1];
-
- 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];
-
- // reset data
- //Set_Track();
- Find_CurTrack();
- ReadTrack( cdr.SetSectorPlay );
-
- //CDR_play(cdr.SetSectorPlay);
- }
- }
- }
- }
- }
+ Find_CurTrack(cdr.SetSectorPlay);
+ ReadTrack(cdr.SetSectorPlay);
+ cdr.TrackChanged = FALSE;
+ if (!Config.Cdda)
+ CDR_play(cdr.SetSectorPlay);
// Vib Ribbon: gameplay checks flag
cdr.StatP &= ~STATUS_SEEK;
-
cdr.CmdProcess = 0;
SetResultSize(1);
cdr.StatP |= STATUS_ROTATING;
break;
case CdlGetlocP:
- // GameShark CDX CD Player: uses 17 bytes output (wraps around)
- SetResultSize(17);
- memset( cdr.Result, 0, 16 );
-
- 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);
- memcpy(cdr.Result + 5, subq->AbsoluteAddress, 3);
-
-
- // subQ integrity check - data only (skip audio)
- if( subq->TrackNumber == 1 && stat.Type == 0x01 ) {
- if (calcCrc((u8 *)subq + 12, 10) != (((u16)subq->CRC[0] << 8) | subq->CRC[1])) {
- memset(cdr.Result + 2, 0, 3 + 3); // CRC wrong, wipe out time data
- }
- }
- } else {
- if( cdr.Play == FALSE || !(cdr.Mode & MODE_CDDA) || !(cdr.Mode & (MODE_AUTOPAUSE|MODE_REPORT)) )
- Create_Fake_Subq();
-
-
- // track # / index #
- cdr.Result[0] = itob(cdr.CurTrack);
- cdr.Result[1] = itob(fake_subq_index);
-
- // local
- cdr.Result[2] = itob( fake_subq_local[0] );
- cdr.Result[3] = itob( fake_subq_local[1] );
- cdr.Result[4] = itob( fake_subq_local[2] );
-
- // absolute
- cdr.Result[5] = itob( fake_subq_real[0] );
- cdr.Result[6] = itob( fake_subq_real[1] );
- cdr.Result[7] = itob( fake_subq_real[2] );
- }
+ SetResultSize(8);
+ memcpy(&cdr.Result, &cdr.subq, 8);
- // redump.org - wipe time
- if( !cdr.Play && CheckSBI(cdr.Result+5) ) {
- memset( cdr.Result+2, 0, 6 );
- }
+ if (!cdr.Play && !cdr.Reading)
+ cdr.Result[1] = 0; // HACK?
cdr.Stat = Acknowledge;
break;
- fix capcom logo
*/
CDRMISC_INT(cdr.Seeked == SEEK_DONE ? 0x800 : cdReadTime * 4);
- cdr.Seeked = SEEK_DOING_CMD;
+ cdr.Seeked = SEEK_PENDING;
break;
case CdlTest:
case CdlReadS:
if (!cdr.Reading) return;
-
// Fighting Force 2 - update subq time immediately
// - fixes new game
- ReadTrack( cdr.SetSector );
+ Find_CurTrack(cdr.SetSector);
+ ReadTrack(cdr.SetSector);
// Crusaders of Might and Magic - update getlocl now
cdr.Stat = Acknowledge;
break;
- case 0xff:
- return;
-
default:
cdr.Stat = Complete;
break;
#endif
}
+#ifdef __ARM_ARCH_7A__
+ #define ssat32_to_16(v) \
+ asm("ssat %0,#16,%1" : "=r" (v) : "r" (v))
+#else
+ #define ssat32_to_16(v) do { \
+ if (v < -32768) v = -32768; \
+ else if (v > 32767) v = 32767; \
+ } while (0)
+#endif
+
+void cdrAttenuate(s16 *buf, int samples, int stereo)
+{
+ int i, l, r;
+ int ll = cdr.AttenuatorLeftToLeft;
+ int lr = cdr.AttenuatorLeftToRight;
+ int rl = cdr.AttenuatorRightToLeft;
+ int rr = cdr.AttenuatorRightToRight;
+
+ if (lr == 0 && rl == 0 && 0x78 <= ll && ll <= 0x88 && 0x78 <= rr && rr <= 0x88)
+ return;
+
+ if (!stereo && ll == 0x40 && lr == 0x40 && rl == 0x40 && rr == 0x40)
+ return;
+
+ if (stereo) {
+ for (i = 0; i < samples; i++) {
+ l = buf[i * 2];
+ r = buf[i * 2 + 1];
+ l = (l * ll + r * rl) >> 7;
+ r = (r * rr + l * lr) >> 7;
+ ssat32_to_16(l);
+ ssat32_to_16(r);
+ buf[i * 2] = l;
+ buf[i * 2 + 1] = r;
+ }
+ }
+ else {
+ for (i = 0; i < samples; i++) {
+ l = buf[i];
+ l = l * (ll + rl) >> 7;
+ //r = r * (rr + lr) >> 7;
+ ssat32_to_16(l);
+ //ssat32_to_16(r);
+ buf[i] = l;
+ }
+ }
+}
+
void cdrReadInterrupt() {
u8 *buf;
cdr.Result[0] = cdr.StatP;
cdr.Seeked = SEEK_DONE;
- ReadTrack( cdr.SetSector );
+ ReadTrack(cdr.SetSector);
buf = CDR_getBuffer();
if (buf == NULL)
(cdr.Transfer[4 + 1] == cdr.Channel) &&
(cdr.Transfer[4 + 0] == cdr.File)) {
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];
- }
- }
+ cdrAttenuate(cdr.Xa.pcm, cdr.Xa.nsamples, cdr.Xa.stereo);
SPU_playADPCMchannel(&cdr.Xa);
cdr.FirstSector = 0;
setIrq();
}
+ // update for CdlGetlocP
+ ReadTrack(cdr.SetSector);
+
Check_Shell(0);
}
case 0:
break;
case 3:
- cdr.AttenuatorRight[1] = rt;
+ cdr.AttenuatorRightToRightT = rt;
return;
default:
return;
for (i = 0; i < 3; i++)
set_loc[i] = btoi(cdr.Param[i]);
- i = abs(msf2sec(cdr.SetSector) - msf2sec(set_loc));
+ // FIXME: clean up this SetSector/SetSectorPlay mess,
+ // there should be single var tracking current sector pos
+ if (cdr.Play)
+ i = msf2sec(cdr.SetSectorPlay);
+ else
+ i = msf2sec(cdr.SetSector);
+ i = abs(i - msf2sec(set_loc));
if (i > 16)
cdr.Seeked = SEEK_PENDING;
// Vib Ribbon: try same track again
StopCdda();
+#if 0
if (!cdr.SetSector[0] & !cdr.SetSector[1] & !cdr.SetSector[2]) {
if (CDR_getTN(cdr.ResultTN) != -1) {
if (cdr.CurTrack > cdr.ResultTN[1])
if (!Config.Cdda) CDR_play(cdr.ResultTD);
}
}
- } else if (!Config.Cdda) {
- CDR_play(cdr.SetSector);
}
-
+#endif
// Vib Ribbon - decoded buffer IRQ for CDDA reading
// - fixes ribbon timing + music CD mode
//TODO?
case CdlStop:
// GameShark CD Player: Reset CDDA to track start
- if( cdr.Play && CDR_getStatus(&stat) != -1 ) {
- cdr.SetSectorPlay[0] = stat.Time[0];
- cdr.SetSectorPlay[1] = stat.Time[1];
- cdr.SetSectorPlay[2] = stat.Time[2];
-
- Find_CurTrack();
-
+ if (cdr.Play) {
// grab time for current track
CDR_getTD((u8)(cdr.CurTrack), cdr.ResultTD);
setIrq();
return;
case 2:
- cdr.AttenuatorLeft[0] = rt;
+ cdr.AttenuatorLeftToLeftT = rt;
return;
case 3:
- cdr.AttenuatorRight[0] = rt;
+ cdr.AttenuatorRightToLeftT = rt;
return;
}
}
cdr.ParamC = 0;
return;
case 2:
- cdr.AttenuatorLeft[1] = rt;
+ cdr.AttenuatorLeftToRightT = rt;
return;
case 3:
- if (rt == 0x20)
- CDR_LOG( "CD-XA Volume: %X %X | %X %X\n",
- cdr.AttenuatorLeft[0], cdr.AttenuatorLeft[1],
- cdr.AttenuatorRight[0], cdr.AttenuatorRight[1] );
+ if (rt & 0x20) {
+ memcpy(&cdr.AttenuatorLeftToLeft, &cdr.AttenuatorLeftToLeftT, 4);
+ CDR_LOG_I("CD-XA Volume: %02x %02x | %02x %02x\n",
+ cdr.AttenuatorLeftToLeft, cdr.AttenuatorLeftToRight,
+ cdr.AttenuatorRightToLeft, cdr.AttenuatorRightToRight);
+ }
return;
}
}
}
+static void getCdInfo(void)
+{
+ u8 tmp;
+
+ CDR_getTN(cdr.ResultTN);
+ CDR_getTD(0, cdr.SetSectorEnd);
+ tmp = cdr.SetSectorEnd[0];
+ cdr.SetSectorEnd[0] = cdr.SetSectorEnd[2];
+ cdr.SetSectorEnd[2] = tmp;
+}
+
void cdrReset() {
memset(&cdr, 0, sizeof(cdr));
cdr.CurTrack = 1;
pTransfer = cdr.Transfer;
// BIOS player - default values
- cdr.AttenuatorLeft[0] = 0x80;
- cdr.AttenuatorLeft[1] = 0x00;
- cdr.AttenuatorRight[0] = 0x00;
- cdr.AttenuatorRight[1] = 0x80;
+ cdr.AttenuatorLeftToLeft = 0x80;
+ cdr.AttenuatorLeftToRight = 0x00;
+ cdr.AttenuatorRightToLeft = 0x00;
+ cdr.AttenuatorRightToRight = 0x80;
+
+ getCdInfo();
}
int cdrFreeze(void *f, int Mode) {
u32 tmp;
+ u8 tmpp[3];
- if( Mode == 0 ) {
- StopCdda();
- }
+ if (Mode == 0 && !Config.Cdda)
+ CDR_stop();
+ cdr.freeze_ver = 0x63647201;
gzfreeze(&cdr, sizeof(cdr));
if (Mode == 1) {
gzfreeze(&tmp, sizeof(tmp));
if (Mode == 0) {
+ getCdInfo();
+
pTransfer = cdr.Transfer + tmp;
- if (cdr.Play && !Config.Cdda)
- CDR_play(cdr.SetSectorPlay);
+ // read right sub data
+ memcpy(tmpp, cdr.Prev, 3);
+ cdr.Prev[0]++;
+ ReadTrack(tmpp);
+
+ if (cdr.Play) {
+ Find_CurTrack(cdr.SetSectorPlay);
+ if (!Config.Cdda)
+ CDR_play(cdr.SetSectorPlay);
+ }
+
+ if ((cdr.freeze_ver & 0xffffff00) != 0x63647200) {
+ // old versions did not latch Reg2, have to fixup..
+ if (cdr.Reg2 == 0) {
+ SysPrintf("cdrom: fixing up old savestate\n");
+ cdr.Reg2 = 7;
+ }
+ }
}
return 0;
void LidInterrupt() {
cdr.LidCheck = 0x20; // start checker
+ getCdInfo();
+
+ StopCdda();
CDRLID_INT( cdReadTime * 3 );
// generate interrupt if none active - open or close