CDROM: Synthesize lead-out area and stop reading when reached

This commit is contained in:
Connor McLaughlin 2020-05-08 10:50:22 +10:00
parent c67e877d82
commit 5b389ae13d
7 changed files with 54 additions and 10 deletions

View file

@ -168,8 +168,16 @@ bool CDImage::ReadRawSector(void* buffer)
} }
else else
{ {
// This in an implicit pregap. Return silence. if (m_current_index->track_number == LEAD_OUT_TRACK_NUMBER)
std::fill(static_cast<u8*>(buffer), static_cast<u8*>(buffer) + RAW_SECTOR_SIZE, u8(0)); {
// Lead-out area.
std::fill(static_cast<u8*>(buffer), static_cast<u8*>(buffer) + RAW_SECTOR_SIZE, u8(0xAA));
}
else
{
// This in an implicit pregap. Return silence.
std::fill(static_cast<u8*>(buffer), static_cast<u8*>(buffer) + RAW_SECTOR_SIZE, u8(0));
}
} }
m_position_on_disc++; m_position_on_disc++;
@ -246,6 +254,16 @@ void CDImage::GenerateSubChannelQ(SubChannelQ* subq, const Index* index, u32 ind
subq->crc = SubChannelQ::ComputeCRC(subq->data); 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) u16 CDImage::SubChannelQ::ComputeCRC(const u8* data)
{ {
static constexpr std::array<u16, 256> crc16_table = { static constexpr std::array<u16, 256> crc16_table = {

View file

@ -23,7 +23,13 @@ public:
FRAMES_PER_SECOND = 75, // "sectors", or "timecode frames" (not "channel frames") FRAMES_PER_SECOND = 75, // "sectors", or "timecode frames" (not "channel frames")
SECONDS_PER_MINUTE = 60, SECONDS_PER_MINUTE = 60,
FRAMES_PER_MINUTE = FRAMES_PER_SECOND * SECONDS_PER_MINUTE, 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 enum class ReadMode : u32
@ -235,6 +241,9 @@ protected:
/// Generates sub-channel Q from the given index and index-offset. /// Generates sub-channel Q from the given index and index-offset.
void GenerateSubChannelQ(SubChannelQ* subq, const Index* index, u32 index_offset); void GenerateSubChannelQ(SubChannelQ* subq, const Index* index, u32 index_offset);
/// Synthesis of lead-out data.
void AddLeadOutIndex();
std::string m_filename; std::string m_filename;
u32 m_lba_count = 0; u32 m_lba_count = 0;

View file

@ -99,6 +99,8 @@ bool CDImageBin::Open(const char* filename)
m_tracks.push_back( m_tracks.push_back(
Track{static_cast<u32>(1), data_index.start_lba_on_disc, static_cast<u32>(0), m_lba_count, mode, control}); Track{static_cast<u32>(1), data_index.start_lba_on_disc, static_cast<u32>(0), m_lba_count, mode, control});
AddLeadOutIndex();
m_sbi.LoadSBI(ReplaceExtension(filename, "sbi").c_str()); m_sbi.LoadSBI(ReplaceExtension(filename, "sbi").c_str());
return Seek(1, Position{0, 0, 0}); return Seek(1, Position{0, 0, 0});

View file

@ -222,6 +222,7 @@ bool CDImageCHD::Open(const char* filename)
} }
m_lba_count = disc_lba; m_lba_count = disc_lba;
AddLeadOutIndex();
m_sbi.LoadSBI(FileSystem::ReplaceExtension(filename, "sbi").c_str()); m_sbi.LoadSBI(FileSystem::ReplaceExtension(filename, "sbi").c_str());

View file

@ -210,6 +210,7 @@ bool CDImageCueSheet::OpenAndParse(const char* filename)
} }
m_lba_count = disc_lba; m_lba_count = disc_lba;
AddLeadOutIndex();
m_sbi.LoadSBI(FileSystem::ReplaceExtension(filename, "sbi").c_str()); m_sbi.LoadSBI(FileSystem::ReplaceExtension(filename, "sbi").c_str());

View file

@ -1448,6 +1448,17 @@ void CDROM::DoTOCRead()
SetAsyncInterrupt(Interrupt::Complete); 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() void CDROM::DoSectorRead()
{ {
if (!m_reader.WaitForReadToComplete()) if (!m_reader.WaitForReadToComplete())
@ -1456,6 +1467,13 @@ void CDROM::DoSectorRead()
// TODO: Error handling // TODO: Error handling
// TODO: Check SubQ checksum. // TODO: Check SubQ checksum.
const CDImage::SubChannelQ& subq = m_reader.GetSectorSubQ(); 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; const bool is_data_sector = subq.control.data;
if (!is_data_sector) 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, Log_DevPrintf("Auto pause at the end of track %u (LBA %u)", m_play_track_number_bcd,
m_reader.GetLastReadSector()); m_reader.GetLastReadSector());
ClearAsyncInterrupt(); StopReadingWithDataEnd();
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();
return; return;
} }
} }

View file

@ -234,6 +234,7 @@ private:
void ProcessDataSector(const u8* raw_sector, const CDImage::SubChannelQ& subq); void ProcessDataSector(const u8* raw_sector, const CDImage::SubChannelQ& subq);
void ProcessXAADPCMSector(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 ProcessCDDASector(const u8* raw_sector, const CDImage::SubChannelQ& subq);
void StopReadingWithDataEnd();
void BeginSeeking(bool logical, bool read_after_seek, bool play_after_seek); void BeginSeeking(bool logical, bool read_after_seek, bool play_after_seek);
void ResetCurrentXAFile(); void ResetCurrentXAFile();
void LoadDataFIFO(); void LoadDataFIFO();