From a6947fbc7086dccd4d70e1a2b6ad54df19b2235f Mon Sep 17 00:00:00 2001 From: Connor McLaughlin Date: Thu, 29 Oct 2020 20:57:10 +1000 Subject: [PATCH] CDROM: Implement fast forward/rewind --- src/core/cdrom.cpp | 55 +++++++++++++++++++++++++++++++++++++++++++++- src/core/cdrom.h | 4 ++++ 2 files changed, 58 insertions(+), 1 deletion(-) diff --git a/src/core/cdrom.cpp b/src/core/cdrom.cpp index c88d89db7..1e2d765c6 100644 --- a/src/core/cdrom.cpp +++ b/src/core/cdrom.cpp @@ -198,6 +198,10 @@ bool CDROM::DoState(StateWrapper& sw) sw.Do(&m_last_cdda_report_frame_nibble); sw.Do(&m_play_track_number_bcd); sw.Do(&m_async_command_parameter); + + // TODO: Uncomment on the next save state version bump. + //sw.Do(&m_fast_forward_rate); + sw.Do(&m_cd_audio_volume_matrix); sw.Do(&m_next_cd_audio_volume_matrix); sw.Do(&m_xa_last_samples); @@ -228,6 +232,7 @@ bool CDROM::DoState(StateWrapper& sw) m_reader.QueueReadSector(requested_sector); UpdateCommandEvent(); m_drive_event->SetState(!IsDriveIdle()); + m_fast_forward_rate = 0; } return !sw.HasError(); @@ -946,6 +951,7 @@ void CDROM::ExecuteCommand() (m_drive_state == DriveState::Playing || (IsSeeking() && m_play_after_seek))) { Log_DevPrintf("Ignoring play command with no/same setloc, already playing/playing after seek"); + m_fast_forward_rate = 0; } else { @@ -960,6 +966,48 @@ void CDROM::ExecuteCommand() return; } + case Command::Forward: + { + if (m_drive_state != DriveState::Playing || !CanReadMedia()) + { + SendErrorResponse(STAT_ERROR, ERROR_REASON_NOT_READY); + } + else + { + SendACKAndStat(); + + if (m_fast_forward_rate < 0) + m_fast_forward_rate = 0; + + m_fast_forward_rate += static_cast(FAST_FORWARD_RATE_STEP); + m_fast_forward_rate = std::min(m_fast_forward_rate, static_cast(MAX_FAST_FORWARD_RATE)); + } + + EndCommand(); + return; + } + + case Command::Backward: + { + if (m_drive_state != DriveState::Playing || !CanReadMedia()) + { + SendErrorResponse(STAT_ERROR, ERROR_REASON_NOT_READY); + } + else + { + SendACKAndStat(); + + if (m_fast_forward_rate > 0) + m_fast_forward_rate = 0; + + m_fast_forward_rate -= static_cast(FAST_FORWARD_RATE_STEP); + m_fast_forward_rate = std::max(m_fast_forward_rate, -static_cast(MAX_FAST_FORWARD_RATE)); + } + + EndCommand(); + return; + } + case Command::Pause: { if (m_secondary_status.seeking) @@ -1392,6 +1440,7 @@ void CDROM::BeginPlaying(u8 track_bcd, TickCount ticks_late /* = 0 */, bool afte Log_DebugPrintf("Starting playing CDDA track %x", track_bcd); m_last_cdda_report_frame_nibble = 0xFF; m_play_track_number_bcd = track_bcd; + m_fast_forward_rate = 0; // if track zero, start from current position if (track_bcd != 0) @@ -1779,6 +1828,7 @@ void CDROM::DoSectorRead() ProcessDataSectorHeader(m_reader.GetSectorBuffer().data()); } + u32 next_sector = m_current_lba + 1u; if (is_data_sector && m_drive_state == DriveState::Reading) { ProcessDataSector(m_reader.GetSectorBuffer().data(), subq); @@ -1787,6 +1837,9 @@ void CDROM::DoSectorRead() (m_drive_state == DriveState::Playing || (m_drive_state == DriveState::Reading && m_mode.cdda))) { ProcessCDDASector(m_reader.GetSectorBuffer().data(), subq); + + if (m_fast_forward_rate != 0) + next_sector = m_current_lba + SignExtend32(m_fast_forward_rate); } else if (m_drive_state != DriveState::Reading && m_drive_state != DriveState::Playing) { @@ -1798,7 +1851,7 @@ void CDROM::DoSectorRead() is_data_sector ? "data" : "audio", is_data_sector ? "reading" : "playing"); } - m_reader.QueueReadSector(m_current_lba + 1u); + m_reader.QueueReadSector(next_sector); } void CDROM::ProcessDataSectorHeader(const u8* raw_sector) diff --git a/src/core/cdrom.h b/src/core/cdrom.h index 9c088c643..427ce0ced 100644 --- a/src/core/cdrom.h +++ b/src/core/cdrom.h @@ -69,6 +69,9 @@ private: AUDIO_FIFO_LOW_WATERMARK = 5, BASE_RESET_TICKS = 400000, + + MAX_FAST_FORWARD_RATE = 12, + FAST_FORWARD_RATE_STEP = 4 }; static constexpr u8 INTERRUPT_REGISTER_MASK = 0x1F; @@ -314,6 +317,7 @@ private: u8 m_last_cdda_report_frame_nibble = 0xFF; u8 m_play_track_number_bcd = 0xFF; u8 m_async_command_parameter = 0x00; + s8 m_fast_forward_rate = 0; std::array, 2> m_cd_audio_volume_matrix{}; std::array, 2> m_next_cd_audio_volume_matrix{};