Skip to content

Commit

Permalink
disc: reworked track handling
Browse files Browse the repository at this point in the history
getTrackBegin returns the first position of the track, whereas getTrackStart returns index1 of that track
That with other smaller bugfixes should play CDDA tracks from the beginning (it was 2 seconds into the track before).
Also, pregap wasn't handled properly.
  • Loading branch information
JaCzekanski committed Oct 19, 2021
1 parent 4307af0 commit fab6bd3
Show file tree
Hide file tree
Showing 17 changed files with 181 additions and 90 deletions.
19 changes: 16 additions & 3 deletions src/device/cdrom/cdrom.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,13 @@ void CDROM::handleSector() {
if (q.validCrc()) {
this->lastQ = q;
}
readSector++;
if (audioStatus == AudioStatus::Forward) {
readSector += 5;
} else if (audioStatus == AudioStatus::Backward) {
readSector -= 5;
} else {
readSector++;
}

if (trackType == disc::TrackType::AUDIO && stat.play) {
if (memcmp(rawSector.data(), sync.data(), sync.size()) == 0) {
Expand Down Expand Up @@ -82,12 +88,18 @@ void CDROM::handleSector() {
}
}

// Broken :( - gets triggered very soon after track starts playing
// in Ridge racer music preview.
if (mode.cddaAutoPause) {
if (track > previousTrack) {
postInterrupt(4);
writeResponse(stat._reg);

stat.play = false; // Pause

if (verbose) {
fmt::print("CDROM: CDDA end of track {}, auto pause\n", track);
}
}
}
previousTrack = track;
Expand Down Expand Up @@ -298,8 +310,8 @@ void CDROM::handleCommand(uint8_t cmd) {
case 0x01: cmdGetstat(); break;
case 0x02: cmdSetloc(); break;
case 0x03: cmdPlay(); break;
// Missing 0x04 cmdForward
// Missing 0x05 cmdBackward
case 0x04: cmdForward(); break;
case 0x05: cmdBackward(); break;
case 0x06: cmdReadN(); break;
case 0x07: cmdMotorOn(); break;
case 0x08: cmdStop(); break;
Expand Down Expand Up @@ -337,6 +349,7 @@ void CDROM::handleCommand(uint8_t cmd) {
postInterrupt(5);
writeResponse(0x11);
writeResponse(0x40);
if (verbose) fmt::print("CDROM: cmd{:02x} -> ({})\n", cmd, dumpFifo(interruptQueue.peek().response));
break;
}

Expand Down
5 changes: 5 additions & 0 deletions src/device/cdrom/cdrom.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ namespace device {
namespace cdrom {

class CDROM {
enum class AudioStatus { Stop, Play, Pause, Forward, Backward };
union StatusCode {
enum class Mode { None, Reading, Seeking, Playing };
struct {
Expand Down Expand Up @@ -129,12 +130,15 @@ class CDROM {
int seekSector = 0;

StatusCode stat;
AudioStatus audioStatus = AudioStatus::Stop;

int scexCounter = 0;

void cmdGetstat();
void cmdSetloc();
void cmdPlay();
void cmdForward();
void cmdBackward();
void cmdReadN();
void cmdMotorOn();
void cmdStop();
Expand Down Expand Up @@ -234,6 +238,7 @@ class CDROM {
ar(seekSector);
ar(scexCounter);
ar(stat._reg);
ar(audioStatus);
ar(volumeLeftToLeft, volumeLeftToRight, volumeRightToLeft, volumeRightToRight);
ar(audio);
ar(rawSector);
Expand Down
72 changes: 59 additions & 13 deletions src/device/cdrom/commands.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,30 +31,69 @@ void CDROM::cmdSetloc() {
}

void CDROM::cmdPlay() {
disc::Position pos;
if (CDROM_params.is_empty() || CDROM_params.peek() == 0) {
pos = disc::Position::fromLba(seekSector);
// Too many args
if (CDROM_params.size() > 1) {
postInterrupt(5);
writeResponse(0x01);
writeResponse(0x20);
return;
}

int trackNo = 0;
if (CDROM_params.size() == 1) {
trackNo = bcd::toBinary(readParam());
}

disc::Position pos = disc::Position::fromLba(readSector);

// Start playing track n
if (trackNo > 0) {
int track = std::min(trackNo - 1, (int)disc->getTrackCount() - 1);
pos = disc->getTrackStart(track);

if (verbose) fmt::print("CDROM: PLAY (track: {}, pos: {})\n", trackNo, pos.toString());
} else {
int track = bcd::toBinary(readParam()) - 1;
if (track >= (int)disc->getTrackCount()) {
pos = disc->getTrackStart(disc->getTrackCount() - 1);
} else {
pos = disc->getTrackStart(track);
if (seekSector != 0) {
pos = disc::Position::fromLba(seekSector);
seekSector = 0;
}
if (verbose) fmt::print("CDROM: PLAY (track: {})\n", track + 1);

if (audioStatus == AudioStatus::Pause || audioStatus == AudioStatus::Forward || audioStatus == AudioStatus::Backward) {
audioStatus = AudioStatus::Play;
} else if (audioStatus == AudioStatus::Play) {
} else if (audioStatus == AudioStatus::Stop) {
if (seekSector == 0) {
pos = disc->getTrackStart(0);
}
audioStatus = AudioStatus::Play;
}

if (verbose) fmt::print("CDROM: cmdPlay (pos: {})\n", pos.toString());
}
// Too many params - INT5 0x93 0x20

readSector = pos.toLba();

stat.setMode(StatusCode::Mode::Playing);

postInterrupt(3);
writeResponse(stat._reg);

previousTrack = disc->getTrackByPosition(pos);
}

void CDROM::cmdForward() {
audioStatus = AudioStatus::Forward;
postInterrupt(3);
writeResponse(stat._reg);

if (verbose) fmt::print("CDROM: cmdForward -> 0x{:02x}\n", interruptQueue.peek().response[0]);
}

void CDROM::cmdBackward() {
audioStatus = AudioStatus::Backward;
postInterrupt(3);
writeResponse(stat._reg);

if (verbose) fmt::print("CDROM: cmdPlay (pos: {})\n", pos.toString());
if (verbose) fmt::print("CDROM: cmdBackward -> 0x{:02x}\n", interruptQueue.peek().response[0]);
}

void CDROM::cmdReadN() {
Expand Down Expand Up @@ -88,6 +127,7 @@ void CDROM::cmdMotorOn() {

void CDROM::cmdStop() {
stat.setMode(StatusCode::Mode::None);
audioStatus = AudioStatus::Stop;
stat.motor = 0;

postInterrupt(3);
Expand All @@ -104,6 +144,7 @@ void CDROM::cmdPause() {
writeResponse(stat._reg);

stat.setMode(StatusCode::Mode::None);
audioStatus = AudioStatus::Pause;

postInterrupt(2);
writeResponse(stat._reg);
Expand Down Expand Up @@ -188,10 +229,15 @@ void CDROM::cmdSetSession() {

void CDROM::cmdSeekP() {
readSector = seekSector;
seekSector = 0;

auto prevStat = stat;

stat.setMode(StatusCode::Mode::None);
postInterrupt(3);
writeResponse(stat._reg);

stat = prevStat;
postInterrupt(2, 500000);
writeResponse(stat._reg);

Expand Down Expand Up @@ -357,7 +403,7 @@ void CDROM::cmdTest() {

if (verbose) {
auto CDROM_response = interruptQueue.peek().response;
fmt::print("//CDROM: cmdTest(0x{:02x}) -> ({})\n", opcode, dumpFifo(CDROM_response));
fmt::print("CDROM: cmdTest(0x{:02x}) -> ({})\n", opcode, dumpFifo(CDROM_response));
}
}

Expand Down
3 changes: 2 additions & 1 deletion src/disc/disc.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ struct Disc {
virtual std::string getFile() const = 0;
virtual size_t getTrackCount() const = 0;
virtual int getTrackByPosition(Position pos) const = 0;
virtual Position getTrackStart(int track) const = 0;
virtual Position getTrackBegin(int track) const = 0; // MMSSFF of track first sector
virtual Position getTrackStart(int track) const = 0; // MMSSFF of track index1
virtual Position getTrackLength(int track) const = 0;
virtual Position getDiskSize() const = 0;

Expand Down
5 changes: 5 additions & 0 deletions src/disc/empty.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@ struct Empty : public Disc {
return 0;
}

Position getTrackBegin(int track) const {
(void)track;
return Position{0, 0, 0};
}

Position getTrackStart(int track) const {
(void)track;
return Position{0, 0, 0};
Expand Down
25 changes: 10 additions & 15 deletions src/disc/format/chd_format.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -127,31 +127,26 @@ int Chd::getTrackByPosition(Position pos) const {
return 0;
}

Position Chd::getTrackStart(int track) const {
size_t frames = 0;
Position Chd::getTrackBegin(int track) const {
size_t frames = 75 * 2;
if ((unsigned)track < tracks.size()) {
for (int i = 0; i < track - 1; i++) {
for (int i = 0; i < track; i++) {
frames += tracks[i].frames;
}
}

return Position::fromLba(frames) + Position(0, 2, 0);
return Position::fromLba(frames);
}
Position Chd::getTrackStart(int track) const { return getTrackBegin(track) + tracks[track].start(); }

Position Chd::getTrackLength(int track) const {
if ((unsigned)track < tracks.size()) {
return Position::fromLba(tracks[track].frames);
} else {
return Position(0, 2, 0);
}
}
Position Chd::getTrackLength(int track) const { return Position::fromLba(tracks[track].pregap.toLba() + tracks[track].frames); }

Position Chd::getDiskSize() const {
size_t frames = 0;
for (size_t i = 0; i < tracks.size(); i++) {
frames += tracks[i].frames;
size_t frames = 75 * 2;
for (auto t : tracks) {
frames += t.pregap.toLba() + t.frames;
}
return Position::fromLba(frames) + Position(0, 2, 0);
return Position::fromLba(frames);
}
} // namespace format
} // namespace disc
1 change: 1 addition & 0 deletions src/disc/format/chd_format.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ struct Chd : public Disc {
std::string getFile() const override;
size_t getTrackCount() const override;
int getTrackByPosition(Position pos) const override;
Position getTrackBegin(int track) const override;
Position getTrackStart(int track) const override;
Position getTrackLength(int track) const override;
Position getDiskSize() const override;
Expand Down
69 changes: 34 additions & 35 deletions src/disc/format/cue.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,69 +6,68 @@ namespace format {
std::string Cue::getFile() const { return file; }

Position Cue::getDiskSize() const {
int frames = 0;
size_t frames = 75 * 2;
for (auto t : tracks) {
frames += t.frames;
frames += t.pregap.toLba() + t.frames;
}
return Position::fromLba(frames) + Position{0, 2, 0};
return Position::fromLba(frames);
}

size_t Cue::getTrackCount() const { return tracks.size(); }

Position Cue::getTrackStart(int track) const {
size_t total = 0;
if (tracks.at(0).type == disc::TrackType::DATA) {
total += 75 * 2;
}
Position Cue::getTrackBegin(int track) const {
size_t total = 75 * 2;
for (int i = 0; i < track; i++) {
total += tracks.at(i).frames;
total += tracks[i].pregap.toLba() + tracks[i].frames;
}
return Position::fromLba(total);
}

Position Cue::getTrackLength(int track) const { return Position::fromLba(tracks.at(track).frames); }
Position Cue::getTrackStart(int track) const { return getTrackBegin(track) + tracks[track].start(); }

Position Cue::getTrackLength(int track) const { return Position::fromLba(tracks[track].pregap.toLba() + tracks[track].frames); }

int Cue::getTrackByPosition(Position pos) const {
for (size_t i = 0; i < getTrackCount(); i++) {
auto start = getTrackStart(i);
auto size = tracks[i].frames;
auto begin = getTrackBegin(i);
auto length = getTrackLength(i);

if (pos >= start && pos < start + Position::fromLba(size)) {
if (pos >= begin && pos < begin + length) {
return i;
}
}
return -1;
}

disc::Sector Cue::read(Position pos) {
auto buffer = std::vector<uint8_t>(Track::SECTOR_SIZE);
auto type = disc::TrackType::INVALID;

auto buffer = std::vector<uint8_t>(Track::SECTOR_SIZE, 0);
auto trackNum = getTrackByPosition(pos);
if (trackNum != -1) {
auto track = tracks[trackNum];
if (files.find(track.filename) == files.end()) {
auto f = unique_ptr_file(fopen(track.filename.c_str(), "rb"));
if (!f) {
fmt::print("Unable to load file {}\n", track.filename);
return std::make_pair(buffer, type);
}

files.emplace(track.filename, std::move(f));
if (trackNum == -1) {
return std::make_pair(buffer, disc::TrackType::INVALID);
}

auto track = tracks[trackNum];
if (files.find(track.filename) == files.end()) {
auto f = unique_ptr_file(fopen(track.filename.c_str(), "rb"));
if (!f) {
fmt::print("Unable to load file {}\n", track.filename);
return std::make_pair(buffer, disc::TrackType::INVALID);
}

type = track.type;
auto file = files[track.filename].get();
files.emplace(track.filename, std::move(f));
}
auto file = files[track.filename].get();
auto seek = pos - (getTrackBegin(trackNum) + track.pregap);

if (trackNum == 0 && type == disc::TrackType::DATA) {
pos = pos - Position{0, 2, 0};
}
auto seek = pos - *track.index0;
fseek(file, (long)(track.offset + seek.toLba() * Track::SECTOR_SIZE), SEEK_SET);
fread(buffer.data(), Track::SECTOR_SIZE, 1, file);
long offset = track.offset + seek.toLba() * Track::SECTOR_SIZE;
if (offset < 0) { // Pregap
return std::make_pair(buffer, track.type);
}

return std::make_pair(buffer, type);
fseek(file, offset, SEEK_SET);
fread(buffer.data(), Track::SECTOR_SIZE, 1, file);

return std::make_pair(buffer, track.type);
}

std::unique_ptr<Cue> Cue::fromBin(const char* file) {
Expand Down
1 change: 1 addition & 0 deletions src/disc/format/cue.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ struct Cue : public Disc {
std::string getFile() const override;
Position getDiskSize() const override;
size_t getTrackCount() const override;
Position getTrackBegin(int track) const override;
Position getTrackStart(int track) const override;
Position getTrackLength(int track) const override;
int getTrackByPosition(Position pos) const override;
Expand Down
Loading

0 comments on commit fab6bd3

Please sign in to comment.