-
-
Notifications
You must be signed in to change notification settings - Fork 30
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
disc: added Subchannel Q support - LibCrypt games are playable
- Loading branch information
1 parent
a18e8dd
commit 4dfa1bd
Showing
11 changed files
with
244 additions
and
40 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
#include "disc.h" | ||
#include "utils/file.h" | ||
|
||
namespace disc { | ||
SubchannelQ Disc::getSubQ(Position pos) { | ||
if (modifiedQ.find(pos) != modifiedQ.end()) { | ||
return modifiedQ[pos]; | ||
} | ||
|
||
TrackType type = read(pos).second; | ||
int track = getTrackByPosition(pos); | ||
auto posInTrack = pos - getTrackStart(track); | ||
|
||
return SubchannelQ::generateForPosition(track, pos, posInTrack, type == TrackType::AUDIO); | ||
} | ||
|
||
bool Disc::loadSubchannel(const std::string& path) { | ||
std::string basePath = getPath(path) + getFilename(path); | ||
|
||
if (auto f = getFileContents(basePath + ".lsd"); !f.empty()) { | ||
return loadLsd(f); | ||
} | ||
if (auto f = getFileContents(basePath + ".sbi"); !f.empty()) { | ||
return loadSbi(f); | ||
} | ||
|
||
return false; | ||
} | ||
|
||
bool Disc::loadLsd(const std::vector<uint8_t>& lsd) { | ||
if (lsd.empty()) { | ||
printf("[DISC] LSD file is empty\n"); | ||
return false; | ||
} | ||
|
||
const int bytesPerEntry = 15; | ||
const int count = lsd.size() / bytesPerEntry; | ||
|
||
for (int i = 0; i < count; i++) { | ||
int p = bytesPerEntry * i; | ||
|
||
int mm = bcd::toBinary(lsd[p + 0]); | ||
int ss = bcd::toBinary(lsd[p + 1]); | ||
int ff = bcd::toBinary(lsd[p + 2]); | ||
|
||
Position pos(mm, ss, ff); | ||
|
||
SubchannelQ q; | ||
q.control._ = lsd[p + 3]; | ||
for (int j = 0; j < 9; j++) { | ||
q.data[j] = lsd[p + 4 + j]; | ||
} | ||
q.crc16 = (lsd[p + 12] << 8) | lsd[p + 13]; | ||
|
||
modifiedQ[pos] = q; | ||
} | ||
|
||
printf("[DISC] Loaded LSD file\n"); | ||
return true; | ||
} | ||
|
||
bool Disc::loadSbi(const std::vector<uint8_t>& sbi) { | ||
if (sbi.empty()) { | ||
printf("[DISC] SBI file is empty\n"); | ||
return false; | ||
} | ||
|
||
if (sbi[0] != 'S' || sbi[1] != 'B' || sbi[2] != 'I' || sbi[3] != '\0') { | ||
printf("[DISC] Invalid sbi header\n"); | ||
return false; | ||
} | ||
|
||
const int headerSize = 4; | ||
const int bytesPerEntry = 14; | ||
const int count = (sbi.size() - headerSize) / bytesPerEntry; | ||
|
||
for (int i = 0; i < count; i++) { | ||
int p = headerSize + bytesPerEntry * i; | ||
|
||
int mm = bcd::toBinary(sbi[p + 0]); | ||
int ss = bcd::toBinary(sbi[p + 1]); | ||
int ff = bcd::toBinary(sbi[p + 2]); | ||
int dummy = sbi[p + 3]; | ||
if (dummy != 1) { | ||
printf("[DISC] Unsupported .sbi file, please create an issue on Github and attach this .sbi\n"); | ||
return false; | ||
} | ||
|
||
Position pos(mm, ss, ff); | ||
|
||
SubchannelQ q; | ||
q.control._ = sbi[p + 4]; | ||
for (int j = 0; j < 9; j++) { | ||
q.data[j] = sbi[p + 5 + j]; | ||
} | ||
// Sbi does not include CRC-16, LibCrypt checks only if crc is broken | ||
q.crc16 = ~q.calculateCrc(); | ||
|
||
modifiedQ[pos] = q; | ||
} | ||
|
||
printf("[DISC] Loaded SBI file\n"); | ||
return true; | ||
} | ||
} // namespace disc |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
#include "subchannel_q.h" | ||
|
||
namespace disc { | ||
|
||
SubchannelQ SubchannelQ::generateForPosition(int track, disc::Position pos, disc::Position posInTrack, bool isAudio) { | ||
SubchannelQ q; | ||
q.control.adr = 1; | ||
q.control.data = !isAudio; | ||
|
||
q.data[0] = bcd::toBcd(track + 1); // Track | ||
q.data[1] = bcd::toBcd(1); // Index | ||
q.data[2] = bcd::toBcd(posInTrack.mm); // M - Track | ||
q.data[3] = bcd::toBcd(posInTrack.ss); // S - Track | ||
q.data[4] = bcd::toBcd(posInTrack.ff); // F - Track | ||
q.data[5] = 0; // Reserved | ||
q.data[6] = bcd::toBcd(pos.mm); // M - Disc | ||
q.data[7] = bcd::toBcd(pos.ss); // S - Disc | ||
q.data[8] = bcd::toBcd(pos.ff); // F - Disc | ||
q.crc16 = q.calculateCrc(); | ||
|
||
return q; | ||
} | ||
|
||
uint16_t SubchannelQ::calculateCrc() { | ||
uint8_t lsb = 0; | ||
uint8_t msb = 0; | ||
for (int i = 0; i < 0x0a; i++) { | ||
uint8_t x; | ||
if (i == 0) { | ||
x = control._; | ||
} else { | ||
x = data[i - 1]; | ||
} | ||
x ^= msb; | ||
x = x ^ (x >> 4); | ||
msb = lsb ^ (x >> 3) ^ (x << 4); | ||
lsb = x ^ (x << 5); | ||
} | ||
return msb << 8 | lsb; | ||
} | ||
|
||
bool SubchannelQ::validCrc() { return crc16 == calculateCrc(); } | ||
}; // namespace disc |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
#pragma once | ||
#include <cstdint> | ||
#include "position.h" | ||
#include "utils/bcd.h" | ||
|
||
namespace disc { | ||
struct SubchannelQ { | ||
union Control { | ||
struct { | ||
uint8_t adr : 4; | ||
uint8_t audioPreemphasis : 1; | ||
uint8_t digitalCopy : 1; | ||
uint8_t data : 1; // 0 - audio, 1 - data; | ||
uint8_t quadAudio : 1; // 0 - stereo, 1 - quad | ||
}; | ||
|
||
uint8_t _; | ||
|
||
Control() : _(0) {} | ||
}; | ||
// Sync skipped | ||
Control control{}; | ||
uint8_t data[9]{}; | ||
uint16_t crc16{}; | ||
|
||
static SubchannelQ generateForPosition(int track, disc::Position pos, disc::Position posInTrack, bool isAudio); | ||
uint16_t calculateCrc(); | ||
bool validCrc(); | ||
}; | ||
}; // namespace disc |