CDROM: Simulate real pause timing

This commit is contained in:
Stenzek 2024-11-11 01:31:38 +10:00
parent a2af51b856
commit 5219e4f987
No known key found for this signature in database

View File

@ -286,6 +286,7 @@ static bool CanReadMedia();
static bool IsDriveIdle();
static bool IsMotorOn();
static bool IsSeeking();
static bool IsReading();
static bool IsReadingOrPlaying();
static bool HasPendingCommand();
static bool HasPendingInterrupt();
@ -312,6 +313,7 @@ static TickCount GetTicksForSpinUp();
static TickCount GetTicksForIDRead();
static TickCount GetTicksForRead();
static TickCount GetTicksForSeek(CDImage::LBA new_lba, bool ignore_speed_change = false);
static TickCount GetTicksForPause();
static TickCount GetTicksForStop(bool motor_was_on);
static TickCount GetTicksForSpeedChange();
static TickCount GetTicksForTOCRead();
@ -889,6 +891,11 @@ bool CDROM::IsSeeking()
s_state.drive_state == DriveState::SeekingImplicit);
}
bool CDROM::IsReading()
{
return (s_state.drive_state == DriveState::Reading);
}
bool CDROM::IsReadingOrPlaying()
{
return (s_state.drive_state == DriveState::Reading || s_state.drive_state == DriveState::Playing);
@ -1581,10 +1588,10 @@ TickCount CDROM::GetTicksForSeek(CDImage::LBA new_lba, bool ignore_speed_change)
// If we're behind the current sector, and within a small distance, the mech just waits for the sector to come up
// by reading normally. This timing is actually needed for Transformers - Beast Wars Transmetals, it gets very
// unstable during loading if seeks are too fast.
ticks += ticks_per_sector * std::max(lba_diff, 1u);
ticks += ticks_per_sector * std::max(lba_diff, 2u);
seek_type = "forward";
}
else if (current_lba > new_lba && tjump_position <= new_lba)
else if (current_lba >= new_lba && tjump_position <= new_lba)
{
// Track jump back. We cap this at 8 sectors (~53ms), so it doesn't take longer than the medium seek below.
ticks += ticks_per_sector * std::max(new_lba - tjump_position, 1u);
@ -1642,6 +1649,25 @@ TickCount CDROM::GetTicksForSeek(CDImage::LBA new_lba, bool ignore_speed_change)
return System::ScaleTicksToOverclock(static_cast<TickCount>(ticks));
}
TickCount CDROM::GetTicksForPause()
{
if (!IsReadingOrPlaying())
return 7000;
const u32 sectors_per_track = GetSectorsPerTrack(s_state.current_lba);
const TickCount ticks_per_read = GetTicksForRead();
// Jump backwards one track, then the time to reach the target again.
// Subtract another 2 in data mode, because holding is based on subq, not data.
const TickCount ticks_to_reach_target =
(static_cast<TickCount>(sectors_per_track - (IsReading() ? 2 : 0)) * ticks_per_read) -
s_state.drive_event.GetTicksSinceLastExecution();
// Clamp to a minimum time of 4 sectors or so, because otherwise read speedup is going to break things...
const TickCount min_ticks = (s_state.mode.double_speed ? 1000000 : 2000000);
return std::max(ticks_to_reach_target, min_ticks);
}
TickCount CDROM::GetTicksForStop(bool motor_was_on)
{
return System::ScaleTicksToOverclock(motor_was_on ? (s_state.mode.double_speed ? 25000000 : 13000000) : 7000);
@ -2077,8 +2103,8 @@ void CDROM::ExecuteCommand(void*, TickCount ticks, TickCount ticks_late)
else
DEV_COLOR_LOG(StrongRed, "Pause Not Reading");
const TickCount pause_time = IsReadingOrPlaying() ? (s_state.mode.double_speed ? 2000000 : 1000000) : 7000;
if (s_state.drive_state == DriveState::Reading && s_state.last_subq.IsData())
const TickCount pause_time = GetTicksForPause();
if (IsReading() && s_state.last_subq.IsData())
{
// Hit target, immediately jump back in data mode.
const u32 spt = GetSectorsPerTrack(s_state.current_lba);