CDImage: Support generating Q Sub-Channel

This commit is contained in:
Connor McLaughlin
2019-11-10 22:44:53 +10:00
parent 2cc5084dd1
commit 6bb4f8e728
4 changed files with 178 additions and 9 deletions

View File

@ -21,9 +21,10 @@ public:
DATA_SECTOR_SIZE = 2048,
SECTOR_SYNC_SIZE = 12,
SECTOR_HEADER_SIZE = 4,
FRAMES_PER_SECOND = 75, // "sectors"
FRAMES_PER_SECOND = 75, // "sectors", or "timecode frames" (not "channel frames")
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
};
enum class ReadMode : u32
@ -33,6 +34,18 @@ public:
RawNoSync, // 2340 bytes per sector.
};
enum class TrackMode : u32
{
Audio, // 2352 bytes per sector
Mode1, // 2048 bytes per sector
Mode1Raw, // 2352 bytes per sector
Mode2, // 2336 bytes per sector
Mode2Form1, // 2048 bytes per sector
Mode2Form2, // 2324 bytes per sector
Mode2FormMix, // 2332 bytes per sector
Mode2Raw // 2352 bytes per sector
};
struct SectorHeader
{
u8 minute;
@ -70,6 +83,11 @@ public:
return ZeroExtend32(minute) * FRAMES_PER_MINUTE + ZeroExtend32(second) * FRAMES_PER_SECOND + ZeroExtend32(frame);
}
constexpr std::tuple<u8, u8, u8> ToBCD() const
{
return std::make_tuple<u8, u8, u8>(DecimalToBCD(minute), DecimalToBCD(second), DecimalToBCD(frame));
}
Position operator+(const Position& rhs) { return FromLBA(ToLBA() + rhs.ToLBA()); }
Position& operator+=(const Position& pos)
{
@ -78,7 +96,7 @@ public:
}
#define RELATIONAL_OPERATOR(op) \
bool operator op (const Position& rhs) const \
bool operator op(const Position& rhs) const \
{ \
return std::tie(minute, second, frame) op std::tie(rhs.minute, rhs.second, rhs.frame); \
}
@ -93,6 +111,43 @@ public:
#undef RELATIONAL_OPERATOR
};
union SubChannelQ
{
union Control
{
u8 bits;
BitField<u8, u8, 0, 4> adr;
BitField<u8, bool, 4, 1> audio_preemphasis;
BitField<u8, bool, 5, 1> digital_copy_permitted;
BitField<u8, bool, 6, 1> data;
BitField<u8, bool, 7, 1> four_channel_audio;
};
struct
{
Control control;
u8 track_number_bcd;
u8 index_number_bcd;
u8 relative_minute_bcd;
u8 relative_second_bcd;
u8 relative_frame_bcd;
u8 reserved;
u8 absolute_minute_bcd;
u8 absolute_second_bcd;
u8 absolute_frame_bcd;
u16 crc;
};
u8 data[SUBCHANNEL_BYTES_PER_FRAME];
u16 ComputeCRC() const;
};
static_assert(sizeof(SubChannelQ) == SUBCHANNEL_BYTES_PER_FRAME, "SubChannelQ is correct size");
// Helper functions.
static u32 GetBytesPerSector(TrackMode mode);
// Opening disc image.
static std::unique_ptr<CDImage> Open(const char* filename);
static std::unique_ptr<CDImage> OpenBinImage(const char* filename);
@ -126,6 +181,9 @@ public:
// Read a single raw sector from the current LBA.
bool ReadRawSector(void* buffer);
// Reads sub-channel Q for the current LBA.
virtual bool ReadSubChannelQ(SubChannelQ* subq);
protected:
struct Track
{
@ -133,6 +191,8 @@ protected:
LBA start_lba;
u32 first_index;
u32 length;
TrackMode mode;
SubChannelQ::Control control;
};
struct Index
@ -145,12 +205,20 @@ protected:
u32 index_number;
LBA start_lba_in_track;
u32 length;
TrackMode mode;
SubChannelQ::Control control;
bool is_pregap;
};
const Index* GetIndexForDiscPosition(LBA pos);
const Index* GetIndexForTrackPosition(u32 track_number, LBA track_pos);
/// Generates sub-channel Q given the specified position.
bool GenerateSubChannelQ(SubChannelQ* subq, LBA lba);
/// Generates sub-channel Q from the given index and index-offset.
void GenerateSubChannelQ(SubChannelQ* subq, const Index* index, u32 index_offset);
std::string m_filename;
u32 m_lba_count = 0;