| 
						
						
							
								
							
						
						
					 | 
				
			
			 | 
			 | 
			
				@ -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);
 | 
			
		
		
	
	
		
			
				
					| 
						
							
								
							
						
						
						
					 | 
				
			
			 | 
			 | 
			
				
 
 |