CDROM: Add current file to debug window

This commit is contained in:
Stenzek 2023-11-29 22:01:45 +10:00
parent 5442242c64
commit 35799aba47
No known key found for this signature in database
2 changed files with 207 additions and 61 deletions

View file

@ -14,6 +14,7 @@
#include "util/cd_image.h" #include "util/cd_image.h"
#include "util/cd_xa.h" #include "util/cd_xa.h"
#include "util/imgui_manager.h" #include "util/imgui_manager.h"
#include "util/iso_reader.h"
#include "util/state_wrapper.h" #include "util/state_wrapper.h"
#include "common/align.h" #include "common/align.h"
@ -27,6 +28,7 @@
#include "imgui.h" #include "imgui.h"
#include <cmath> #include <cmath>
#include <map>
#include <vector> #include <vector>
Log_SetChannel(CDROM); Log_SetChannel(CDROM);
@ -293,6 +295,10 @@ static void ResampleXAADPCM(const s16* frames_in, u32 num_frames_in);
static TinyString LBAToMSFString(CDImage::LBA lba); static TinyString LBAToMSFString(CDImage::LBA lba);
static void CreateFileMap();
static void CreateFileMap(IsoReader& iso, const std::string_view& dir);
static const std::string* LookupFileMap(u32 lba, u32* start_lba, u32* end_lba);
static std::unique_ptr<TimingEvent> s_command_event; static std::unique_ptr<TimingEvent> s_command_event;
static std::unique_ptr<TimingEvent> s_command_second_response_event; static std::unique_ptr<TimingEvent> s_command_second_response_event;
static std::unique_ptr<TimingEvent> s_async_interrupt_event; static std::unique_ptr<TimingEvent> s_async_interrupt_event;
@ -365,11 +371,15 @@ static u32 s_current_read_sector_buffer = 0;
static u32 s_current_write_sector_buffer = 0; static u32 s_current_write_sector_buffer = 0;
static std::array<SectorBuffer, NUM_SECTOR_BUFFERS> s_sector_buffers; static std::array<SectorBuffer, NUM_SECTOR_BUFFERS> s_sector_buffers;
static CDROMAsyncReader m_reader; static CDROMAsyncReader s_reader;
// two 16-bit samples packed in 32-bits // two 16-bit samples packed in 32-bits
static HeapFIFOQueue<u32, AUDIO_FIFO_SIZE> s_audio_fifo; static HeapFIFOQueue<u32, AUDIO_FIFO_SIZE> s_audio_fifo;
static std::map<u32, std::pair<u32, std::string>> s_file_map;
static bool s_file_map_created = false;
static bool s_show_current_file = false;
static constexpr std::array<const char*, 15> s_drive_state_names = { static constexpr std::array<const char*, 15> s_drive_state_names = {
{"Idle", "Opening Shell", "Resetting", "Seeking (Physical)", "Seeking (Logical)", "Reading ID", "Reading TOC", {"Idle", "Opening Shell", "Resetting", "Seeking (Physical)", "Seeking (Logical)", "Reading ID", "Reading TOC",
"Reading", "Playing", "Pausing", "Stopping", "Changing Session", "Spinning Up", "Seeking (Implicit)", "Reading", "Playing", "Pausing", "Stopping", "Changing Session", "Spinning Up", "Seeking (Implicit)",
@ -434,19 +444,23 @@ void CDROM::Initialize()
s_drive_event = TimingEvents::CreateTimingEvent("CDROM Drive Event", 1, 1, &CDROM::ExecuteDrive, nullptr, false); s_drive_event = TimingEvents::CreateTimingEvent("CDROM Drive Event", 1, 1, &CDROM::ExecuteDrive, nullptr, false);
if (g_settings.cdrom_readahead_sectors > 0) if (g_settings.cdrom_readahead_sectors > 0)
m_reader.StartThread(g_settings.cdrom_readahead_sectors); s_reader.StartThread(g_settings.cdrom_readahead_sectors);
Reset(); Reset();
} }
void CDROM::Shutdown() void CDROM::Shutdown()
{ {
s_file_map.clear();
s_file_map_created = false;
s_show_current_file = false;
s_drive_event.reset(); s_drive_event.reset();
s_async_interrupt_event.reset(); s_async_interrupt_event.reset();
s_command_second_response_event.reset(); s_command_second_response_event.reset();
s_command_event.reset(); s_command_event.reset();
m_reader.StopThread(); s_reader.StopThread();
m_reader.RemoveMedia(); s_reader.RemoveMedia();
} }
void CDROM::Reset() void CDROM::Reset()
@ -558,7 +572,7 @@ void CDROM::SoftReset(TickCount ticks_late)
s_drive_state = DriveState::SeekingImplicit; s_drive_state = DriveState::SeekingImplicit;
s_drive_event->SetIntervalAndSchedule(total_ticks); s_drive_event->SetIntervalAndSchedule(total_ticks);
s_requested_lba = 0; s_requested_lba = 0;
m_reader.QueueReadSector(s_requested_lba); s_reader.QueueReadSector(s_requested_lba);
s_seek_start_lba = s_current_lba; s_seek_start_lba = s_current_lba;
s_seek_end_lba = 0; s_seek_end_lba = 0;
} }
@ -637,8 +651,8 @@ bool CDROM::DoState(StateWrapper& sw)
if (sw.IsReading()) if (sw.IsReading())
{ {
if (m_reader.HasMedia()) if (s_reader.HasMedia())
m_reader.QueueReadSector(s_requested_lba); s_reader.QueueReadSector(s_requested_lba);
UpdateCommandEvent(); UpdateCommandEvent();
s_drive_event->SetState(!IsDriveIdle()); s_drive_event->SetState(!IsDriveIdle());
@ -651,17 +665,17 @@ bool CDROM::DoState(StateWrapper& sw)
bool CDROM::HasMedia() bool CDROM::HasMedia()
{ {
return m_reader.HasMedia(); return s_reader.HasMedia();
} }
const std::string& CDROM::GetMediaFileName() const std::string& CDROM::GetMediaFileName()
{ {
return m_reader.GetMediaFileName(); return s_reader.GetMediaFileName();
} }
const CDImage* CDROM::GetMedia() const CDImage* CDROM::GetMedia()
{ {
return m_reader.GetMedia(); return s_reader.GetMedia();
} }
DiscRegion CDROM::GetDiscRegion() DiscRegion CDROM::GetDiscRegion()
@ -676,11 +690,11 @@ bool CDROM::IsMediaPS1Disc()
bool CDROM::IsMediaAudioCD() bool CDROM::IsMediaAudioCD()
{ {
if (!m_reader.HasMedia()) if (!s_reader.HasMedia())
return false; return false;
// Check for an audio track as the first track. // Check for an audio track as the first track.
return (m_reader.GetMedia()->GetTrackMode(1) == CDImage::TrackMode::Audio); return (s_reader.GetMedia()->GetTrackMode(1) == CDImage::TrackMode::Audio);
} }
bool CDROM::DoesMediaRegionMatchConsole() bool CDROM::DoesMediaRegionMatchConsole()
@ -717,7 +731,7 @@ bool CDROM::IsReadingOrPlaying()
bool CDROM::CanReadMedia() bool CDROM::CanReadMedia()
{ {
return (s_drive_state != DriveState::ShellOpening && m_reader.HasMedia()); return (s_drive_state != DriveState::ShellOpening && s_reader.HasMedia());
} }
void CDROM::InsertMedia(std::unique_ptr<CDImage> media, DiscRegion region) void CDROM::InsertMedia(std::unique_ptr<CDImage> media, DiscRegion region)
@ -729,12 +743,15 @@ void CDROM::InsertMedia(std::unique_ptr<CDImage> media, DiscRegion region)
Settings::GetConsoleRegionName(System::GetRegion())); Settings::GetConsoleRegionName(System::GetRegion()));
s_disc_region = region; s_disc_region = region;
m_reader.SetMedia(std::move(media)); s_reader.SetMedia(std::move(media));
SetHoldPosition(0, true); SetHoldPosition(0, true);
// motor automatically spins up // motor automatically spins up
if (s_drive_state != DriveState::ShellOpening) if (s_drive_state != DriveState::ShellOpening)
StartMotor(); StartMotor();
if (s_show_current_file)
CreateFileMap();
} }
std::unique_ptr<CDImage> CDROM::RemoveMedia(bool for_disc_swap) std::unique_ptr<CDImage> CDROM::RemoveMedia(bool for_disc_swap)
@ -748,7 +765,10 @@ std::unique_ptr<CDImage> CDROM::RemoveMedia(bool for_disc_swap)
stop_ticks += System::ScaleTicksToOverclock(System::MASTER_CLOCK * 2); stop_ticks += System::ScaleTicksToOverclock(System::MASTER_CLOCK * 2);
Log_InfoPrintf("Removing CD..."); Log_InfoPrintf("Removing CD...");
std::unique_ptr<CDImage> image = m_reader.RemoveMedia(); std::unique_ptr<CDImage> image = s_reader.RemoveMedia();
if (s_show_current_file)
CreateFileMap();
s_last_sector_header_valid = false; s_last_sector_header_valid = false;
@ -780,19 +800,19 @@ std::unique_ptr<CDImage> CDROM::RemoveMedia(bool for_disc_swap)
bool CDROM::PrecacheMedia() bool CDROM::PrecacheMedia()
{ {
if (!m_reader.HasMedia()) if (!s_reader.HasMedia())
return false; return false;
if (m_reader.GetMedia()->HasSubImages() && m_reader.GetMedia()->GetSubImageCount() > 1) if (s_reader.GetMedia()->HasSubImages() && s_reader.GetMedia()->GetSubImageCount() > 1)
{ {
Host::AddFormattedOSDMessage(15.0f, Host::AddFormattedOSDMessage(15.0f,
TRANSLATE("OSDMessage", "CD image preloading not available for multi-disc image '%s'"), TRANSLATE("OSDMessage", "CD image preloading not available for multi-disc image '%s'"),
FileSystem::GetDisplayNameFromPath(m_reader.GetMedia()->GetFileName()).c_str()); FileSystem::GetDisplayNameFromPath(s_reader.GetMedia()->GetFileName()).c_str());
return false; return false;
} }
HostInterfaceProgressCallback callback; HostInterfaceProgressCallback callback;
if (!m_reader.Precache(&callback)) if (!s_reader.Precache(&callback))
{ {
Host::AddOSDMessage(TRANSLATE_STR("OSDMessage", "Precaching CD image failed, it may be unreliable."), 15.0f); Host::AddOSDMessage(TRANSLATE_STR("OSDMessage", "Precaching CD image failed, it may be unreliable."), 15.0f);
return false; return false;
@ -810,16 +830,16 @@ TinyString CDROM::LBAToMSFString(CDImage::LBA lba)
void CDROM::SetReadaheadSectors(u32 readahead_sectors) void CDROM::SetReadaheadSectors(u32 readahead_sectors)
{ {
const bool want_thread = (readahead_sectors > 0); const bool want_thread = (readahead_sectors > 0);
if (want_thread == m_reader.IsUsingThread() && m_reader.GetReadaheadCount() == readahead_sectors) if (want_thread == s_reader.IsUsingThread() && s_reader.GetReadaheadCount() == readahead_sectors)
return; return;
if (want_thread) if (want_thread)
m_reader.StartThread(readahead_sectors); s_reader.StartThread(readahead_sectors);
else else
m_reader.StopThread(); s_reader.StopThread();
if (HasMedia()) if (HasMedia())
m_reader.QueueReadSector(s_requested_lba); s_reader.QueueReadSector(s_requested_lba);
} }
void CDROM::CPUClockChanged() void CDROM::CPUClockChanged()
@ -1342,8 +1362,8 @@ CDImage::LBA CDROM::GetNextSectorToBeRead()
if (!IsReadingOrPlaying()) if (!IsReadingOrPlaying())
return s_current_lba; return s_current_lba;
m_reader.WaitForReadToComplete(); s_reader.WaitForReadToComplete();
return m_reader.GetLastReadSector(); return s_reader.GetLastReadSector();
} }
void CDROM::BeginCommand(Command command) void CDROM::BeginCommand(Command command)
@ -1914,12 +1934,12 @@ void CDROM::ExecuteCommand(void*, TickCount ticks, TickCount ticks_late)
Log_DebugPrintf("CDROM GetTN command"); Log_DebugPrintf("CDROM GetTN command");
if (CanReadMedia()) if (CanReadMedia())
{ {
Log_DevPrintf("GetTN -> %u %u", m_reader.GetMedia()->GetFirstTrackNumber(), Log_DevPrintf("GetTN -> %u %u", s_reader.GetMedia()->GetFirstTrackNumber(),
m_reader.GetMedia()->GetLastTrackNumber()); s_reader.GetMedia()->GetLastTrackNumber());
s_response_fifo.Push(s_secondary_status.bits); s_response_fifo.Push(s_secondary_status.bits);
s_response_fifo.Push(BinaryToBCD(Truncate8(m_reader.GetMedia()->GetFirstTrackNumber()))); s_response_fifo.Push(BinaryToBCD(Truncate8(s_reader.GetMedia()->GetFirstTrackNumber())));
s_response_fifo.Push(BinaryToBCD(Truncate8(m_reader.GetMedia()->GetLastTrackNumber()))); s_response_fifo.Push(BinaryToBCD(Truncate8(s_reader.GetMedia()->GetLastTrackNumber())));
SetInterrupt(Interrupt::ACK); SetInterrupt(Interrupt::ACK);
} }
else else
@ -1941,7 +1961,7 @@ void CDROM::ExecuteCommand(void*, TickCount ticks, TickCount ticks_late)
{ {
SendErrorResponse(STAT_ERROR, ERROR_REASON_NOT_READY); SendErrorResponse(STAT_ERROR, ERROR_REASON_NOT_READY);
} }
else if (track > m_reader.GetMedia()->GetTrackCount()) else if (track > s_reader.GetMedia()->GetTrackCount())
{ {
SendErrorResponse(STAT_ERROR, ERROR_REASON_INVALID_ARGUMENT); SendErrorResponse(STAT_ERROR, ERROR_REASON_INVALID_ARGUMENT);
} }
@ -1949,9 +1969,9 @@ void CDROM::ExecuteCommand(void*, TickCount ticks, TickCount ticks_late)
{ {
CDImage::Position pos; CDImage::Position pos;
if (track == 0) if (track == 0)
pos = CDImage::Position::FromLBA(m_reader.GetMedia()->GetLBACount()); pos = CDImage::Position::FromLBA(s_reader.GetMedia()->GetLBACount());
else else
pos = m_reader.GetMedia()->GetTrackStartMSFPosition(track); pos = s_reader.GetMedia()->GetTrackStartMSFPosition(track);
s_response_fifo.Push(s_secondary_status.bits); s_response_fifo.Push(s_secondary_status.bits);
s_response_fifo.Push(BinaryToBCD(Truncate8(pos.minute))); s_response_fifo.Push(BinaryToBCD(Truncate8(pos.minute)));
@ -2284,7 +2304,7 @@ void CDROM::BeginReading(TickCount ticks_late /* = 0 */, bool after_seek /* = fa
s_current_write_sector_buffer = 0; s_current_write_sector_buffer = 0;
s_requested_lba = s_current_lba; s_requested_lba = s_current_lba;
m_reader.QueueReadSector(s_requested_lba); s_reader.QueueReadSector(s_requested_lba);
} }
void CDROM::BeginPlaying(u8 track, TickCount ticks_late /* = 0 */, bool after_seek /* = false */) void CDROM::BeginPlaying(u8 track, TickCount ticks_late /* = 0 */, bool after_seek /* = false */)
@ -2298,13 +2318,13 @@ void CDROM::BeginPlaying(u8 track, TickCount ticks_late /* = 0 */, bool after_se
if (track != 0) if (track != 0)
{ {
// play specific track? // play specific track?
if (track > m_reader.GetMedia()->GetTrackCount()) if (track > s_reader.GetMedia()->GetTrackCount())
{ {
// restart current track // restart current track
track = Truncate8(m_reader.GetMedia()->GetTrackNumber()); track = Truncate8(s_reader.GetMedia()->GetTrackNumber());
} }
s_setloc_position = m_reader.GetMedia()->GetTrackStartMSFPosition(track); s_setloc_position = s_reader.GetMedia()->GetTrackStartMSFPosition(track);
s_setloc_pending = true; s_setloc_pending = true;
} }
@ -2328,7 +2348,7 @@ void CDROM::BeginPlaying(u8 track, TickCount ticks_late /* = 0 */, bool after_se
s_current_write_sector_buffer = 0; s_current_write_sector_buffer = 0;
s_requested_lba = s_current_lba; s_requested_lba = s_current_lba;
m_reader.QueueReadSector(s_requested_lba); s_reader.QueueReadSector(s_requested_lba);
} }
void CDROM::BeginSeeking(bool logical, bool read_after_seek, bool play_after_seek) void CDROM::BeginSeeking(bool logical, bool read_after_seek, bool play_after_seek)
@ -2360,7 +2380,7 @@ void CDROM::BeginSeeking(bool logical, bool read_after_seek, bool play_after_see
s_seek_start_lba = s_current_lba; s_seek_start_lba = s_current_lba;
s_seek_end_lba = seek_lba; s_seek_end_lba = seek_lba;
s_requested_lba = seek_lba; s_requested_lba = seek_lba;
m_reader.QueueReadSector(s_requested_lba); s_reader.QueueReadSector(s_requested_lba);
} }
void CDROM::UpdatePositionWhileSeeking() void CDROM::UpdatePositionWhileSeeking()
@ -2396,7 +2416,7 @@ void CDROM::UpdatePositionWhileSeeking()
// access the image directly since we want to preserve the cached data for the seek complete // access the image directly since we want to preserve the cached data for the seek complete
CDImage::SubChannelQ subq; CDImage::SubChannelQ subq;
if (!m_reader.ReadSectorUncached(current_lba, &subq, nullptr)) if (!s_reader.ReadSectorUncached(current_lba, &subq, nullptr))
Log_ErrorPrintf("Failed to read subq for sector %u for physical position", current_lba); Log_ErrorPrintf("Failed to read subq for sector %u for physical position", current_lba);
else if (subq.IsCRCValid()) else if (subq.IsCRCValid())
s_last_subq = subq; s_last_subq = subq;
@ -2468,7 +2488,7 @@ void CDROM::UpdatePhysicalPosition(bool update_logical)
CDImage::SubChannelQ subq; CDImage::SubChannelQ subq;
CDROMAsyncReader::SectorBuffer raw_sector; CDROMAsyncReader::SectorBuffer raw_sector;
if (!m_reader.ReadSectorUncached(new_physical_lba, &subq, update_logical ? &raw_sector : nullptr)) if (!s_reader.ReadSectorUncached(new_physical_lba, &subq, update_logical ? &raw_sector : nullptr))
{ {
Log_ErrorPrintf("Failed to read subq for sector %u for physical position", new_physical_lba); Log_ErrorPrintf("Failed to read subq for sector %u for physical position", new_physical_lba);
} }
@ -2492,7 +2512,7 @@ void CDROM::SetHoldPosition(CDImage::LBA lba, bool update_subq)
if (update_subq && s_physical_lba != lba && CanReadMedia()) if (update_subq && s_physical_lba != lba && CanReadMedia())
{ {
CDImage::SubChannelQ subq; CDImage::SubChannelQ subq;
if (!m_reader.ReadSectorUncached(lba, &subq, nullptr)) if (!s_reader.ReadSectorUncached(lba, &subq, nullptr))
Log_ErrorPrintf("Failed to read subq for sector %u for physical position", lba); Log_ErrorPrintf("Failed to read subq for sector %u for physical position", lba);
else if (subq.IsCRCValid()) else if (subq.IsCRCValid())
s_last_subq = subq; s_last_subq = subq;
@ -2518,15 +2538,15 @@ bool CDROM::CompleteSeek()
const bool logical = (s_drive_state == DriveState::SeekingLogical); const bool logical = (s_drive_state == DriveState::SeekingLogical);
ClearDriveState(); ClearDriveState();
bool seek_okay = m_reader.WaitForReadToComplete(); bool seek_okay = s_reader.WaitForReadToComplete();
if (seek_okay) if (seek_okay)
{ {
const CDImage::SubChannelQ& subq = m_reader.GetSectorSubQ(); const CDImage::SubChannelQ& subq = s_reader.GetSectorSubQ();
if (subq.IsCRCValid()) if (subq.IsCRCValid())
{ {
// seek and update sub-q for ReadP command // seek and update sub-q for ReadP command
s_last_subq = subq; s_last_subq = subq;
const auto [seek_mm, seek_ss, seek_ff] = CDImage::Position::FromLBA(m_reader.GetLastReadSector()).ToBCD(); const auto [seek_mm, seek_ss, seek_ff] = CDImage::Position::FromLBA(s_reader.GetLastReadSector()).ToBCD();
seek_okay = (subq.IsCRCValid() && subq.absolute_minute_bcd == seek_mm && subq.absolute_second_bcd == seek_ss && seek_okay = (subq.IsCRCValid() && subq.absolute_minute_bcd == seek_mm && subq.absolute_second_bcd == seek_ss &&
subq.absolute_frame_bcd == seek_ff); subq.absolute_frame_bcd == seek_ff);
if (seek_okay) if (seek_okay)
@ -2535,7 +2555,7 @@ bool CDROM::CompleteSeek()
{ {
if (logical) if (logical)
{ {
ProcessDataSectorHeader(m_reader.GetSectorBuffer().data()); ProcessDataSectorHeader(s_reader.GetSectorBuffer().data());
seek_okay = (s_last_sector_header.minute == seek_mm && s_last_sector_header.second == seek_ss && seek_okay = (s_last_sector_header.minute == seek_mm && s_last_sector_header.second == seek_ss &&
s_last_sector_header.frame == seek_ff); s_last_sector_header.frame == seek_ff);
} }
@ -2558,13 +2578,13 @@ bool CDROM::CompleteSeek()
if (subq.track_number_bcd == CDImage::LEAD_OUT_TRACK_NUMBER) if (subq.track_number_bcd == CDImage::LEAD_OUT_TRACK_NUMBER)
{ {
Log_WarningPrintf("Invalid seek to lead-out area (LBA %u)", m_reader.GetLastReadSector()); Log_WarningPrintf("Invalid seek to lead-out area (LBA %u)", s_reader.GetLastReadSector());
seek_okay = false; seek_okay = false;
} }
} }
} }
s_current_lba = m_reader.GetLastReadSector(); s_current_lba = s_reader.GetLastReadSector();
} }
s_physical_lba = s_current_lba; s_physical_lba = s_current_lba;
@ -2599,7 +2619,7 @@ void CDROM::DoSeekComplete(TickCount ticks_late)
else else
{ {
Log_WarningPrintf("%s seek to [%s] failed", logical ? "Logical" : "Physical", Log_WarningPrintf("%s seek to [%s] failed", logical ? "Logical" : "Physical",
LBAToMSFString(m_reader.GetLastReadSector()).c_str()); LBAToMSFString(s_reader.GetLastReadSector()).c_str());
s_secondary_status.ClearActiveBits(); s_secondary_status.ClearActiveBits();
SendAsyncErrorResponse(STAT_SEEK_ERROR, 0x04); SendAsyncErrorResponse(STAT_SEEK_ERROR, 0x04);
s_last_sector_header_valid = false; s_last_sector_header_valid = false;
@ -2739,17 +2759,17 @@ void CDROM::DoSectorRead()
{ {
// TODO: Queue the next read here and swap the buffer. // TODO: Queue the next read here and swap the buffer.
// TODO: Error handling // TODO: Error handling
if (!m_reader.WaitForReadToComplete()) if (!s_reader.WaitForReadToComplete())
Panic("Sector read failed"); Panic("Sector read failed");
s_current_lba = m_reader.GetLastReadSector(); s_current_lba = s_reader.GetLastReadSector();
s_physical_lba = s_current_lba; s_physical_lba = s_current_lba;
s_physical_lba_update_tick = TimingEvents::GetGlobalTickCounter(); s_physical_lba_update_tick = TimingEvents::GetGlobalTickCounter();
s_physical_lba_update_carry = 0; s_physical_lba_update_carry = 0;
s_secondary_status.SetReadingBits(s_drive_state == DriveState::Playing); s_secondary_status.SetReadingBits(s_drive_state == DriveState::Playing);
const CDImage::SubChannelQ& subq = m_reader.GetSectorSubQ(); const CDImage::SubChannelQ& subq = s_reader.GetSectorSubQ();
const bool subq_valid = subq.IsCRCValid(); const bool subq_valid = subq.IsCRCValid();
if (subq_valid) if (subq_valid)
{ {
@ -2762,7 +2782,7 @@ void CDROM::DoSectorRead()
if (subq.track_number_bcd == CDImage::LEAD_OUT_TRACK_NUMBER) if (subq.track_number_bcd == CDImage::LEAD_OUT_TRACK_NUMBER)
{ {
Log_DevPrintf("Read reached lead-out area of disc at LBA %u, stopping", m_reader.GetLastReadSector()); Log_DevPrintf("Read reached lead-out area of disc at LBA %u, stopping", s_reader.GetLastReadSector());
StopReadingWithDataEnd(); StopReadingWithDataEnd();
StopMotor(); StopMotor();
return; return;
@ -2787,18 +2807,18 @@ void CDROM::DoSectorRead()
} }
else else
{ {
ProcessDataSectorHeader(m_reader.GetSectorBuffer().data()); ProcessDataSectorHeader(s_reader.GetSectorBuffer().data());
} }
u32 next_sector = s_current_lba + 1u; u32 next_sector = s_current_lba + 1u;
if (is_data_sector && s_drive_state == DriveState::Reading) if (is_data_sector && s_drive_state == DriveState::Reading)
{ {
ProcessDataSector(m_reader.GetSectorBuffer().data(), subq); ProcessDataSector(s_reader.GetSectorBuffer().data(), subq);
} }
else if (!is_data_sector && else if (!is_data_sector &&
(s_drive_state == DriveState::Playing || (s_drive_state == DriveState::Reading && s_mode.cdda))) (s_drive_state == DriveState::Playing || (s_drive_state == DriveState::Reading && s_mode.cdda)))
{ {
ProcessCDDASector(m_reader.GetSectorBuffer().data(), subq); ProcessCDDASector(s_reader.GetSectorBuffer().data(), subq);
if (s_fast_forward_rate != 0) if (s_fast_forward_rate != 0)
next_sector = s_current_lba + SignExtend32(s_fast_forward_rate); next_sector = s_current_lba + SignExtend32(s_fast_forward_rate);
@ -2814,7 +2834,7 @@ void CDROM::DoSectorRead()
} }
s_requested_lba = next_sector; s_requested_lba = next_sector;
m_reader.QueueReadSector(s_requested_lba); s_reader.QueueReadSector(s_requested_lba);
} }
void CDROM::ProcessDataSectorHeader(const u8* raw_sector) void CDROM::ProcessDataSectorHeader(const u8* raw_sector)
@ -3254,13 +3274,75 @@ void CDROM::ClearSectorBuffers()
s_sector_buffers[i].size = 0; s_sector_buffers[i].size = 0;
} }
void CDROM::CreateFileMap()
{
s_file_map.clear();
s_file_map_created = true;
if (!s_reader.HasMedia())
return;
s_reader.WaitForIdle();
CDImage* media = s_reader.GetMedia();
IsoReader iso;
if (!iso.Open(media, 1))
{
Log_ErrorFmt("Failed to open ISO filesystem.");
return;
}
Log_DevFmt("Creating file map for {}...", media->GetFileName());
CreateFileMap(iso, std::string_view());
Log_DevFmt("Found {} files", s_file_map.size());
}
void CDROM::CreateFileMap(IsoReader& iso, const std::string_view& dir)
{
for (auto& [path, entry] : iso.GetEntriesInDirectory(dir))
{
if (entry.IsDirectory())
{
CreateFileMap(iso, path);
continue;
}
Log_DevFmt("{}-{} = {}", entry.location_le, entry.location_le + entry.GetSizeInSectors() - 1, path);
s_file_map.emplace(entry.location_le,
std::make_pair(entry.location_le + entry.GetSizeInSectors() - 1, std::move(path)));
}
}
const std::string* CDROM::LookupFileMap(u32 lba, u32* start_lba, u32* end_lba)
{
if (s_file_map.empty())
return nullptr;
auto iter = s_file_map.lower_bound(lba);
if (iter == s_file_map.end())
iter = (++s_file_map.rbegin()).base();
if (lba < iter->first)
{
// before first file
if (iter == s_file_map.begin())
return nullptr;
--iter;
}
if (lba > iter->second.first)
return nullptr;
*start_lba = iter->first;
*end_lba = iter->second.first;
return &iter->second.second;
}
void CDROM::DrawDebugWindow() void CDROM::DrawDebugWindow()
{ {
static const ImVec4 active_color{1.0f, 1.0f, 1.0f, 1.0f}; static const ImVec4 active_color{1.0f, 1.0f, 1.0f, 1.0f};
static const ImVec4 inactive_color{0.4f, 0.4f, 0.4f, 1.0f}; static const ImVec4 inactive_color{0.4f, 0.4f, 0.4f, 1.0f};
const float framebuffer_scale = Host::GetOSDScale(); const float framebuffer_scale = Host::GetOSDScale();
ImGui::SetNextWindowSize(ImVec2(800.0f * framebuffer_scale, 560.0f * framebuffer_scale), ImGuiCond_FirstUseEver); ImGui::SetNextWindowSize(ImVec2(800.0f * framebuffer_scale, 580.0f * framebuffer_scale), ImGuiCond_FirstUseEver);
if (!ImGui::Begin("CDROM State", nullptr)) if (!ImGui::Begin("CDROM State", nullptr))
{ {
ImGui::End(); ImGui::End();
@ -3270,20 +3352,21 @@ void CDROM::DrawDebugWindow()
// draw voice states // draw voice states
if (ImGui::CollapsingHeader("Media", ImGuiTreeNodeFlags_DefaultOpen)) if (ImGui::CollapsingHeader("Media", ImGuiTreeNodeFlags_DefaultOpen))
{ {
if (m_reader.HasMedia()) if (s_reader.HasMedia())
{ {
const CDImage* media = m_reader.GetMedia(); const CDImage* media = s_reader.GetMedia();
const CDImage::Position disc_position = CDImage::Position::FromLBA(s_current_lba); const CDImage::Position disc_position = CDImage::Position::FromLBA(s_current_lba);
const float start_y = ImGui::GetCursorPosY();
if (media->HasSubImages()) if (media->HasSubImages())
{ {
ImGui::Text("Filename: %s [Subimage %u of %u] [%u buffered sectors]", media->GetFileName().c_str(), ImGui::Text("Filename: %s [Subimage %u of %u] [%u buffered sectors]", media->GetFileName().c_str(),
media->GetCurrentSubImage() + 1u, media->GetSubImageCount(), m_reader.GetBufferedSectorCount()); media->GetCurrentSubImage() + 1u, media->GetSubImageCount(), s_reader.GetBufferedSectorCount());
} }
else else
{ {
ImGui::Text("Filename: %s [%u buffered sectors]", media->GetFileName().c_str(), ImGui::Text("Filename: %s [%u buffered sectors]", media->GetFileName().c_str(),
m_reader.GetBufferedSectorCount()); s_reader.GetBufferedSectorCount());
} }
ImGui::Text("Disc Position: MSF[%02u:%02u:%02u] LBA[%u]", disc_position.minute, disc_position.second, ImGui::Text("Disc Position: MSF[%02u:%02u:%02u] LBA[%u]", disc_position.minute, disc_position.second,
@ -3303,6 +3386,68 @@ void CDROM::DrawDebugWindow()
ImGui::Text("Last Sector: %02X:%02X:%02X (Mode %u)", s_last_sector_header.minute, s_last_sector_header.second, ImGui::Text("Last Sector: %02X:%02X:%02X (Mode %u)", s_last_sector_header.minute, s_last_sector_header.second,
s_last_sector_header.frame, s_last_sector_header.sector_mode); s_last_sector_header.frame, s_last_sector_header.sector_mode);
if (s_show_current_file)
{
if (media->GetTrackNumber() == 1)
{
if (!s_file_map_created)
CreateFileMap();
u32 current_file_start_lba, current_file_end_lba;
const u32 track_lba = s_current_lba - media->GetTrackStartPosition(static_cast<u8>(media->GetTrackNumber()));
const std::string* current_file = LookupFileMap(track_lba, &current_file_start_lba, &current_file_end_lba);
if (current_file)
{
static constexpr auto readable_size = [](u32 val) {
// based on
// https://stackoverflow.com/questions/1449805/how-to-format-a-number-using-comma-as-thousands-separator-in-c
// don't want to use locale...
TinyString ret;
TinyString temp;
temp.append_fmt("{}", val);
u32 commas = 2u - (temp.length() % 3u);
for (const char* p = temp.c_str(); *p != 0u; p++)
{
ret.append(*p);
if (commas == 1)
ret.append(',');
commas = (commas + 1) % 3;
}
DebugAssert(!ret.empty());
ret.erase(-1);
return ret;
};
ImGui::Text(
"Current File: %s (%s of %s bytes)", current_file->c_str(),
readable_size((track_lba - current_file_start_lba) * CDImage::DATA_SECTOR_SIZE).c_str(),
readable_size((current_file_end_lba - current_file_start_lba + 1) * CDImage::DATA_SECTOR_SIZE).c_str());
}
else
{
ImGui::Text("Current File: <Unknown>");
}
}
else
{
ImGui::Text("Current File: <Non-Data Track>");
}
ImGui::SameLine();
ImGui::Text("[%u files on disc]", static_cast<u32>(s_file_map.size()));
}
else
{
const float end_y = ImGui::GetCursorPosY();
ImGui::SetCursorPosX(ImGui::GetWindowWidth() - 120.0f * framebuffer_scale);
ImGui::SetCursorPosY(start_y);
if (ImGui::Button("Show Current File"))
s_show_current_file = true;
ImGui::SetCursorPosY(end_y);
}
} }
else else
{ {

View file

@ -36,6 +36,7 @@ public:
bool HasMedia() const { return static_cast<bool>(m_media); } bool HasMedia() const { return static_cast<bool>(m_media); }
const CDImage* GetMedia() const { return m_media.get(); } const CDImage* GetMedia() const { return m_media.get(); }
CDImage* GetMedia() { return m_media.get(); }
const std::string& GetMediaFileName() const { return m_media->GetFileName(); } const std::string& GetMediaFileName() const { return m_media->GetFileName(); }
bool IsUsingThread() const { return m_read_thread.joinable(); } bool IsUsingThread() const { return m_read_thread.joinable(); }