Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CDVD: CHD cue support for audio CDs #12037

Draft
wants to merge 3 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions pcsx2/CDVD/CDVDcommon.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,14 @@ struct cdvdTN
u8 etrack; //number of the last track
};

struct toc_entry
{
u32 lba;
u8 track;
u8 adr : 4;
u8 control : 4;
};

// SpindleCtrl Masks
#define CDVD_SPINDLE_SPEED 0x7 // Speed ranges from 0-3 (1, 2, 3, 4x for DVD) and 0-5 (1, 2, 4, 12, 24x for CD)
#define CDVD_SPINDLE_NOMINAL 0x40 // Changes the speed to be constant (CLV) based on current speed
Expand Down
8 changes: 0 additions & 8 deletions pcsx2/CDVD/CDVDdiscReader.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,6 @@ class Error;
extern int curDiskType;
extern int curTrayStatus;

struct toc_entry
{
u32 lba;
u8 track;
u8 adr : 4;
u8 control : 4;
};

class IOCtlSrc
{
IOCtlSrc(const IOCtlSrc&) = delete;
Expand Down
119 changes: 92 additions & 27 deletions pcsx2/CDVD/CDVDisoReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,44 @@ static int pmode, cdtype;
static s32 layer1start = -1;
static bool layer1searched = false;

static void ISOParseTOC()
{
tracks.fill(cdvdTrack{});
if (iso.GetType() != ISOTYPE_AUDIO)
{
strack = 1;
etrack = 1;
return;
}

strack = 0xFF;
etrack = 0;
// Audio CD
for (const auto& entry : iso.ReadTOC())
{
const u8 track = entry.track;
if (track < 1 || track >= tracks.size())
{
Console.Warning("CDVD: Invalid track index %u, ignoring\n", track);
continue;
}
strack = std::min(strack, track);
etrack = std::max(etrack, track);
tracks[track].start_lba = entry.lba;

if ((entry.control & 0x0C) == 0x04)
{
Console.Warning("CDVD: Unsupported data track reading. Assuming MODE1?\n");
tracks[track].type = CDVD_MODE1_TRACK;
}
else
{
tracks[track].type = CDVD_AUDIO_TRACK;
}
}

}

static void ISOclose()
{
iso.Close();
Expand Down Expand Up @@ -49,6 +87,8 @@ static bool ISOopen(std::string filename, Error* error)
break;
}

ISOParseTOC();

layer1start = -1;
layer1searched = false;

Expand All @@ -60,34 +100,56 @@ static bool ISOprecache(ProgressCallback* progress, Error* error)
return iso.Precache(progress, error);
}

static void lsn_to_msf(u8* minute, u8* second, u8* frame, u32 lsn)
{
*frame = itob(lsn % 75);
lsn /= 75;
*second = itob(lsn % 60);
lsn /= 60;
*minute = itob(lsn % 100);
}

static s32 ISOreadSubQ(u32 lsn, cdvdSubQ* subq)
{
// fake it
u8 min, sec, frm;
subq->ctrl = 4;
subq->adr = 1;
subq->trackNum = itob(1);
subq->trackIndex = itob(1);


lba_to_msf(lsn, &min, &sec, &frm);
subq->trackM = itob(min);
subq->trackS = itob(sec);
subq->trackF = itob(frm);
memset(subq, 0, sizeof(cdvdSubQ));

subq->pad = 0;
lsn_to_msf(&subq->discM, &subq->discS, &subq->discF, lsn + 150);

lba_to_msf(lsn + (2 * 75), &min, &sec, &frm);
subq->discM = itob(min);
subq->discS = itob(sec);
subq->discF = itob(frm);
// FIXME: Verify this is correct for ISOTYPE_CD :S
if (iso.GetType() != ISOTYPE_AUDIO && iso.GetType() != ISOTYPE_CD)
{
subq->ctrl = 4;
subq->adr = 1;
subq->trackNum = itob(1);
subq->trackIndex = itob(1);
}
else
{
u8 i = strack;
while (i < etrack && lsn >= tracks[i + 1].start_lba)
++i;

lsn -= tracks[i].start_lba;

subq->ctrl = 1;
subq->adr = 1;
subq->trackNum = i;
subq->trackIndex = 1; // FIXME ???
}

lsn_to_msf(&subq->trackM, &subq->trackS, &subq->trackF, lsn);

Console.Warning("CDVD: SubQ M %02x S %02x F %02x\n", subq->trackM, subq->trackS, subq->trackF);
return 0;
}

static s32 ISOgetTN(cdvdTN* Buffer)
{
Buffer->strack = 1;
Buffer->etrack = 1;
Buffer->strack = strack;
Buffer->etrack = etrack;

return 0;
}
Expand All @@ -97,13 +159,15 @@ static s32 ISOgetTD(u8 Track, cdvdTD* Buffer)
if (Track == 0)
{
Buffer->lsn = iso.GetBlockCount();
Buffer->type = 0;
return 0;
}
else
{
Buffer->type = CDVD_MODE1_TRACK;
Buffer->lsn = 0;
}


if (Track < strack || Track > etrack)
return -1;

Buffer->lsn = tracks[Track].start_lba;
Buffer->type = tracks[Track].type;
return 0;
}

Expand Down Expand Up @@ -299,11 +363,12 @@ static s32 ISOgetTOC(void* toc)
{
err = ISOgetTD(i, &trackInfo);
lba_to_msf(trackInfo.lsn, &min, &sec, &frm);
tocBuff[i * 10 + 30] = trackInfo.type;
tocBuff[i * 10 + 32] = err == -1 ? 0 : itob(i); //number
tocBuff[i * 10 + 37] = itob(min);
tocBuff[i * 10 + 38] = itob(sec);
tocBuff[i * 10 + 39] = itob(frm);
const u8 tocIndex = i - diskInfo.strack;
tocBuff[tocIndex * 10 + 30] = trackInfo.type;
tocBuff[tocIndex * 10 + 32] = err == -1 ? 0 : itob(i); //number
tocBuff[tocIndex * 10 + 37] = itob(min);
tocBuff[tocIndex * 10 + 38] = itob(sec);
tocBuff[tocIndex * 10 + 39] = itob(frm);
}
}
else
Expand Down
45 changes: 36 additions & 9 deletions pcsx2/CDVD/ChdFileReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -176,8 +176,9 @@ bool ChdFileReader::Open2(std::string filename, Error* error)

// The file size in the header is incorrect, each track gets padded to a multiple of 4 frames.
// (see chdman.cpp from MAME). Instead, we pull the real frame count from the TOC.
std::vector<toc_entry> entries;
u64 total_frames;
if (ParseTOC(&total_frames))
if (ParseTOC(&total_frames, entries))
{
file_size = total_frames * static_cast<u64>(chd_header->unitbytes);
}
Expand Down Expand Up @@ -216,6 +217,21 @@ bool ChdFileReader::Precache2(ProgressCallback* progress, Error* error)
return true;
}

std::vector<toc_entry> ChdFileReader::ReadTOC()
{
u64 total_frames;
std::vector<toc_entry> entries;
if (ParseTOC(&total_frames, entries))
{
return entries;
}
else
{
Console.Warning("Failed to parse CHD TOC, file size may be incorrect.");
return {};
}
}

ThreadedFileReader::Chunk ChdFileReader::ChunkForOffset(u64 offset)
{
Chunk chunk = {0};
Expand Down Expand Up @@ -261,11 +277,11 @@ u32 ChdFileReader::GetBlockCount() const
return (file_size - m_dataoffset) / m_internalBlockSize;
}

bool ChdFileReader::ParseTOC(u64* out_frame_count)
bool ChdFileReader::ParseTOC(u64* out_frame_count, std::vector<toc_entry>& entries)
{
u64 total_frames = 0;
int max_found_track = -1;

u64 total_gap_frames = 0;
for (int search_index = 0;; search_index++)
{
char metadata_str[256];
Expand Down Expand Up @@ -305,17 +321,28 @@ bool ChdFileReader::ParseTOC(u64* out_frame_count)
}
}

DevCon.WriteLn(fmt::format("CHD Track {}: frames:{} pregap:{} postgap:{} type:{} sub:{} pgtype:{} pgsub:{}",
Console.WriteLn(fmt::format("CHD Track {}: frames:{} pregap:{} postgap:{} type:{} sub:{} pgtype:{} pgsub:{}",
track_num, frames, pregap_frames, postgap_frames, type_str, subtype_str, pgtype_str, pgsub_str));

// PCSX2 doesn't currently support multiple tracks for CDs.
if (track_num != 1)
if (track_num != 0)
{
Console.Warning(fmt::format(" Ignoring track {} in CHD.", track_num, frames));
continue;
toc_entry entry{};
entry.lba = static_cast<u32>(total_frames) - total_gap_frames;
entry.track = static_cast<u8>(track_num);
entry.adr = 1;
entry.control = 0;

//FIXME: DATA track?
if (strncmp(type_str, "AUDIO", 5) != 0)
entry.control |= 0x04;

entries.push_back(entry);
}

total_frames += static_cast<u64>(pregap_frames) + static_cast<u64>(frames) + static_cast<u64>(postgap_frames);
// I have not found a CHD with an audio track with a postgap, consider that untested
total_gap_frames += static_cast<u64>(pregap_frames) + static_cast<u64>(postgap_frames);
total_frames += total_gap_frames + static_cast<u64>(frames);

max_found_track = std::max(max_found_track, track_num);
}

Expand Down
4 changes: 3 additions & 1 deletion pcsx2/CDVD/ChdFileReader.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,16 @@ class ChdFileReader final : public ThreadedFileReader

bool Precache2(ProgressCallback* progress, Error* error) override;

std::vector<toc_entry> ReadTOC() override;

Chunk ChunkForOffset(u64 offset) override;
int ReadChunk(void* dst, s64 blockID) override;

void Close2(void) override;
uint GetBlockCount(void) const override;

private:
bool ParseTOC(u64* out_frame_count);
bool ParseTOC(u64* out_frame_count, std::vector<toc_entry>& entries);

chd_file* ChdFile = nullptr;
u64 file_size = 0;
Expand Down
24 changes: 23 additions & 1 deletion pcsx2/CDVD/InputIsoFile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -160,9 +160,31 @@ int InputIsoFile::FinishRead3(u8* dst, uint mode)
dst[diff - 9] = 2;
}

// Seems like CHD data ends up being the wrong endianess for audio
// Confidence is about 50% on this one, but it seems to work
// (CHD is the only file with a TOC anyways, so who cares about the other formats)
if (m_type == ISOTYPE_AUDIO && mode == CDVD_MODE_2352)
{
for (int i = 0; i < 2352; i += 2)
{
std::swap(dst[diff + i], dst[diff + i + 1]);
}
}

return 0;
}

std::vector<toc_entry> InputIsoFile::ReadTOC() const
{
std::vector<toc_entry> toc;

if (m_type == ISOTYPE_ILLEGAL)
return toc;

toc = m_reader->ReadTOC();
return toc;
}

InputIsoFile::InputIsoFile()
{
_init();
Expand Down Expand Up @@ -271,7 +293,7 @@ bool InputIsoFile::tryIsoType(u32 size, u32 offset, u32 blockofs)
// Returns true if the image is valid/known/supported, or false if not (type == ISOTYPE_ILLEGAL).
bool InputIsoFile::Detect(bool readType)
{
m_type = ISOTYPE_ILLEGAL;
m_type = ISOTYPE_ILLEGAL;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Forgot the space here.


// First sanity check: no sane CD image has less than 16 sectors, since that's what
// we need simply to contain a TOC. So if the file size is not large enough to
Expand Down
3 changes: 3 additions & 0 deletions pcsx2/CDVD/IsoFileFormats.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#pragma once

#include "CDVDcommon.h"
#include "CDVD/CDVD.h"
#include "CDVD/ThreadedFileReader.h"
#include <memory>
Expand Down Expand Up @@ -75,6 +76,8 @@ class InputIsoFile final
void BeginRead2(uint lsn);
int FinishRead3(u8* dest, uint mode);

std::vector<toc_entry> ReadTOC() const;

protected:
void _init();

Expand Down
6 changes: 6 additions & 0 deletions pcsx2/CDVD/ThreadedFileReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,12 @@ bool ThreadedFileReader::Precache2(ProgressCallback* progress, Error* error)
return false;
}

std::vector<toc_entry> ThreadedFileReader::ReadTOC()
{
return {};
}


Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Extra line.

bool ThreadedFileReader::CheckAvailableMemoryForPrecaching(u64 required_size, Error* error)
{
// Don't allow precaching to use more than 50% of system memory.
Expand Down
2 changes: 2 additions & 0 deletions pcsx2/CDVD/ThreadedFileReader.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#pragma once

#include "common/Pcsx2Defs.h"
#include "CDVDcommon.h"

#include <thread>
#include <mutex>
Expand Down Expand Up @@ -117,6 +118,7 @@ class ThreadedFileReader

bool Open(std::string filename, Error* error);
bool Precache(ProgressCallback* progress, Error* error);
virtual std::vector<toc_entry> ReadTOC();
int ReadSync(void* pBuffer, u32 sector, u32 count);
void BeginRead(void* pBuffer, u32 sector, u32 count);
int FinishRead();
Expand Down