diff --git a/src/common/cd_image.cpp b/src/common/cd_image.cpp index dcf723784..e033d6bbc 100644 --- a/src/common/cd_image.cpp +++ b/src/common/cd_image.cpp @@ -168,8 +168,16 @@ bool CDImage::ReadRawSector(void* buffer) } else { - // This in an implicit pregap. Return silence. - std::fill(static_cast(buffer), static_cast(buffer) + RAW_SECTOR_SIZE, u8(0)); + if (m_current_index->track_number == LEAD_OUT_TRACK_NUMBER) + { + // Lead-out area. + std::fill(static_cast(buffer), static_cast(buffer) + RAW_SECTOR_SIZE, u8(0xAA)); + } + else + { + // This in an implicit pregap. Return silence. + std::fill(static_cast(buffer), static_cast(buffer) + RAW_SECTOR_SIZE, u8(0)); + } } m_position_on_disc++; @@ -246,6 +254,16 @@ void CDImage::GenerateSubChannelQ(SubChannelQ* subq, const Index* index, u32 ind subq->crc = SubChannelQ::ComputeCRC(subq->data); } +void CDImage::AddLeadOutIndex() +{ + Index index = {}; + index.start_lba_on_disc = m_lba_count; + index.length = LEAD_OUT_SECTOR_COUNT; + index.track_number = 0xAA; + index.index_number = 0; + m_indices.push_back(index); +} + u16 CDImage::SubChannelQ::ComputeCRC(const u8* data) { static constexpr std::array crc16_table = { diff --git a/src/common/cd_image.h b/src/common/cd_image.h index 13e384937..5463b5f11 100644 --- a/src/common/cd_image.h +++ b/src/common/cd_image.h @@ -23,7 +23,13 @@ public: FRAMES_PER_SECOND = 75, // "sectors", or "timecode frames" (not "channel frames") SECONDS_PER_MINUTE = 60, FRAMES_PER_MINUTE = FRAMES_PER_SECOND * SECONDS_PER_MINUTE, - SUBCHANNEL_BYTES_PER_FRAME = 12 + SUBCHANNEL_BYTES_PER_FRAME = 12, + LEAD_OUT_SECTOR_COUNT = 6750 + }; + + enum : u8 + { + LEAD_OUT_TRACK_NUMBER = 0xAA }; enum class ReadMode : u32 @@ -235,6 +241,9 @@ protected: /// Generates sub-channel Q from the given index and index-offset. void GenerateSubChannelQ(SubChannelQ* subq, const Index* index, u32 index_offset); + /// Synthesis of lead-out data. + void AddLeadOutIndex(); + std::string m_filename; u32 m_lba_count = 0; diff --git a/src/common/cd_image_bin.cpp b/src/common/cd_image_bin.cpp index e7a5bb0c3..0ca461636 100644 --- a/src/common/cd_image_bin.cpp +++ b/src/common/cd_image_bin.cpp @@ -99,6 +99,8 @@ bool CDImageBin::Open(const char* filename) m_tracks.push_back( Track{static_cast(1), data_index.start_lba_on_disc, static_cast(0), m_lba_count, mode, control}); + AddLeadOutIndex(); + m_sbi.LoadSBI(ReplaceExtension(filename, "sbi").c_str()); return Seek(1, Position{0, 0, 0}); diff --git a/src/common/cd_image_chd.cpp b/src/common/cd_image_chd.cpp index e4e8126bb..15d8800cf 100644 --- a/src/common/cd_image_chd.cpp +++ b/src/common/cd_image_chd.cpp @@ -222,6 +222,7 @@ bool CDImageCHD::Open(const char* filename) } m_lba_count = disc_lba; + AddLeadOutIndex(); m_sbi.LoadSBI(FileSystem::ReplaceExtension(filename, "sbi").c_str()); diff --git a/src/common/cd_image_cue.cpp b/src/common/cd_image_cue.cpp index 3ac8f6a24..f8dd04a08 100644 --- a/src/common/cd_image_cue.cpp +++ b/src/common/cd_image_cue.cpp @@ -210,6 +210,7 @@ bool CDImageCueSheet::OpenAndParse(const char* filename) } m_lba_count = disc_lba; + AddLeadOutIndex(); m_sbi.LoadSBI(FileSystem::ReplaceExtension(filename, "sbi").c_str()); diff --git a/src/core/cdrom.cpp b/src/core/cdrom.cpp index b515db3f5..f028508df 100644 --- a/src/core/cdrom.cpp +++ b/src/core/cdrom.cpp @@ -1448,6 +1448,17 @@ void CDROM::DoTOCRead() SetAsyncInterrupt(Interrupt::Complete); } +void CDROM::StopReadingWithDataEnd() +{ + ClearAsyncInterrupt(); + m_async_response_fifo.Push(m_secondary_status.bits); + SetAsyncInterrupt(Interrupt::DataEnd); + + m_secondary_status.ClearActiveBits(); + m_drive_state = DriveState::Idle; + m_drive_event->Deactivate(); +} + void CDROM::DoSectorRead() { if (!m_reader.WaitForReadToComplete()) @@ -1456,6 +1467,13 @@ void CDROM::DoSectorRead() // TODO: Error handling // TODO: Check SubQ checksum. const CDImage::SubChannelQ& subq = m_reader.GetSectorSubQ(); + if (subq.track_number_bcd == CDImage::LEAD_OUT_TRACK_NUMBER) + { + Log_DevPrintf("Read reached lead-out area of disc at LBA %u, pausing", m_reader.GetLastReadSector()); + StopReadingWithDataEnd(); + return; + } + const bool is_data_sector = subq.control.data; if (!is_data_sector) { @@ -1471,13 +1489,7 @@ void CDROM::DoSectorRead() Log_DevPrintf("Auto pause at the end of track %u (LBA %u)", m_play_track_number_bcd, m_reader.GetLastReadSector()); - ClearAsyncInterrupt(); - m_async_response_fifo.Push(m_secondary_status.bits); - SetAsyncInterrupt(Interrupt::DataEnd); - - m_secondary_status.ClearActiveBits(); - m_drive_state = DriveState::Idle; - m_drive_event->Deactivate(); + StopReadingWithDataEnd(); return; } } diff --git a/src/core/cdrom.h b/src/core/cdrom.h index 4bf3d70b2..1edb23484 100644 --- a/src/core/cdrom.h +++ b/src/core/cdrom.h @@ -234,6 +234,7 @@ private: void ProcessDataSector(const u8* raw_sector, const CDImage::SubChannelQ& subq); void ProcessXAADPCMSector(const u8* raw_sector, const CDImage::SubChannelQ& subq); void ProcessCDDASector(const u8* raw_sector, const CDImage::SubChannelQ& subq); + void StopReadingWithDataEnd(); void BeginSeeking(bool logical, bool read_after_seek, bool play_after_seek); void ResetCurrentXAFile(); void LoadDataFIFO();