diff --git a/src/device/cdrom/cdrom.cpp b/src/device/cdrom/cdrom.cpp index c5d1f65..c4bbb5d 100644 --- a/src/device/cdrom/cdrom.cpp +++ b/src/device/cdrom/cdrom.cpp @@ -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) { @@ -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; @@ -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; @@ -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; } diff --git a/src/device/cdrom/cdrom.h b/src/device/cdrom/cdrom.h index add83b7..b774066 100644 --- a/src/device/cdrom/cdrom.h +++ b/src/device/cdrom/cdrom.h @@ -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 { @@ -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(); @@ -234,6 +238,7 @@ class CDROM { ar(seekSector); ar(scexCounter); ar(stat._reg); + ar(audioStatus); ar(volumeLeftToLeft, volumeLeftToRight, volumeRightToLeft, volumeRightToRight); ar(audio); ar(rawSector); diff --git a/src/device/cdrom/commands.cpp b/src/device/cdrom/commands.cpp index 7e7c52d..45a3b64 100644 --- a/src/device/cdrom/commands.cpp +++ b/src/device/cdrom/commands.cpp @@ -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() { @@ -88,6 +127,7 @@ void CDROM::cmdMotorOn() { void CDROM::cmdStop() { stat.setMode(StatusCode::Mode::None); + audioStatus = AudioStatus::Stop; stat.motor = 0; postInterrupt(3); @@ -104,6 +144,7 @@ void CDROM::cmdPause() { writeResponse(stat._reg); stat.setMode(StatusCode::Mode::None); + audioStatus = AudioStatus::Pause; postInterrupt(2); writeResponse(stat._reg); @@ -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); @@ -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)); } } diff --git a/src/disc/disc.h b/src/disc/disc.h index 194ca8a..8d88bd7 100644 --- a/src/disc/disc.h +++ b/src/disc/disc.h @@ -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; diff --git a/src/disc/empty.h b/src/disc/empty.h index f1120a7..b877f17 100644 --- a/src/disc/empty.h +++ b/src/disc/empty.h @@ -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}; diff --git a/src/disc/format/chd_format.cpp b/src/disc/format/chd_format.cpp index dfe4c81..2874b72 100644 --- a/src/disc/format/chd_format.cpp +++ b/src/disc/format/chd_format.cpp @@ -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 \ No newline at end of file diff --git a/src/disc/format/chd_format.h b/src/disc/format/chd_format.h index b82e7a4..95937f6 100644 --- a/src/disc/format/chd_format.h +++ b/src/disc/format/chd_format.h @@ -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; diff --git a/src/disc/format/cue.cpp b/src/disc/format/cue.cpp index 18a9faa..138274c 100644 --- a/src/disc/format/cue.cpp +++ b/src/disc/format/cue.cpp @@ -6,34 +6,33 @@ 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; } } @@ -41,34 +40,34 @@ int Cue::getTrackByPosition(Position pos) const { } disc::Sector Cue::read(Position pos) { - auto buffer = std::vector(Track::SECTOR_SIZE); - auto type = disc::TrackType::INVALID; - + auto buffer = std::vector(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::fromBin(const char* file) { diff --git a/src/disc/format/cue.h b/src/disc/format/cue.h index 73c1caf..eecb19e 100644 --- a/src/disc/format/cue.h +++ b/src/disc/format/cue.h @@ -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; diff --git a/src/disc/format/cue_parser.cpp b/src/disc/format/cue_parser.cpp index 233e853..bd1d16c 100644 --- a/src/disc/format/cue_parser.cpp +++ b/src/disc/format/cue_parser.cpp @@ -82,18 +82,8 @@ void CueParser::addTrackToCue() { // ignore if track is not completed if (track.number == 0) return; - // if (track.number == 1 && track.type == Track::Type::DATA) { - // track.pregap = track.pregap + Position{0,2,0}; - // } - - if (track.pregap == Position{0, 0, 0} && track.index0) { - track.pregap = track.index1 - *track.index0; - } else { - track.index0 = track.index1; - } - if (!track.index0) { - track.index0 = track.index1 - track.pregap; + track.index0 = track.index1; } cue.tracks.push_back(track); diff --git a/src/disc/format/ecm.cpp b/src/disc/format/ecm.cpp index ba6d694..a054955 100644 --- a/src/disc/format/ecm.cpp +++ b/src/disc/format/ecm.cpp @@ -11,6 +11,8 @@ disc::Position Ecm::getDiskSize() const { return disc::Position::fromLba(data.si size_t Ecm::getTrackCount() const { return 1; } +disc::Position Ecm::getTrackBegin(int track) const { return disc::Position(0, 2, 0); } + disc::Position Ecm::getTrackStart(int track) const { return disc::Position(0, 2, 0); } disc::Position Ecm::getTrackLength(int track) const { return disc::Position::fromLba(data.size() / Track::SECTOR_SIZE); } diff --git a/src/disc/format/ecm.h b/src/disc/format/ecm.h index 20e045c..a6bb427 100644 --- a/src/disc/format/ecm.h +++ b/src/disc/format/ecm.h @@ -21,6 +21,7 @@ struct Ecm : 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; diff --git a/src/disc/position.cpp b/src/disc/position.cpp index 340a37d..e06b282 100644 --- a/src/disc/position.cpp +++ b/src/disc/position.cpp @@ -13,7 +13,10 @@ Position Position::fromLba(size_t lba) { return Position(mm, ss, ff); } -std::string Position::toString() const { return fmt::format("{:02d}:{:02d}:{:02d}", mm, ss, ff); } +std::string Position::toString() const { + bool isNegative = mm < 0 || ss < 0 || ff < 0; + return fmt::format("{:02d}:{:02d}:{:02d}", std::abs(mm) * (isNegative ? -1 : 1), std::abs(ss), std::abs(ff)); +} int Position::toLba() const { return (mm * 60 * 75) + (ss * 75) + ff; } @@ -21,6 +24,22 @@ Position Position::operator+(const Position& p) const { return fromLba(toLba() + Position Position::operator-(const Position& p) const { return fromLba(toLba() - p.toLba()); } +Position& Position::operator+=(const Position& p) { + auto val = fromLba(toLba() + p.toLba()); + mm = val.mm; + ss = val.ss; + ff = val.ff; + return *this; +} + +Position& Position::operator-=(const Position& p) { + auto val = fromLba(toLba() - p.toLba()); + mm = val.mm; + ss = val.ss; + ff = val.ff; + return *this; +} + bool Position::operator==(const Position& p) const { return toLba() == p.toLba(); } bool Position::operator>=(const Position& p) const { return toLba() >= p.toLba(); } diff --git a/src/disc/position.h b/src/disc/position.h index 94ccfdc..54a10f3 100644 --- a/src/disc/position.h +++ b/src/disc/position.h @@ -16,6 +16,8 @@ struct Position { int toLba() const; Position operator+(const Position& p) const; Position operator-(const Position& p) const; + Position& operator+=(const Position& p); + Position& operator-=(const Position& p); bool operator==(const Position& p) const; bool operator>=(const Position& p) const; bool operator<(const Position& p) const; diff --git a/src/disc/track.h b/src/disc/track.h index 6a34c24..30a01f4 100644 --- a/src/disc/track.h +++ b/src/disc/track.h @@ -26,5 +26,14 @@ struct Track { frames = 0; } + + Position pause() const { + if (index0) { + return (index1 - *index0); + } + return Position(0, 0, 0); + } + + Position start() const { return pregap + pause(); } }; } // namespace disc diff --git a/src/platform/windows/gui/debug/cdrom.cpp b/src/platform/windows/gui/debug/cdrom.cpp index 2890537..ab583a2 100644 --- a/src/platform/windows/gui/debug/cdrom.cpp +++ b/src/platform/windows/gui/debug/cdrom.cpp @@ -21,21 +21,23 @@ void Cdrom::cdromWindow(System* sys) { ImGui::Text("%s", cue->file.c_str()); ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0)); - ImGui::Text("Track Pregap Start End Offset Type File"); + ImGui::Text("Track Pregap Pause Start End Length Offset Type File"); ImGuiListClipper clipper((int)cue->getTrackCount()); while (clipper.Step()) { for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) { auto track = cue->tracks[i]; - auto line = fmt::format("{:>5} {:<8} {:<8} {:<8} {:<9} {:<5} {}", - i + 1, // - POSITION(track.pregap), // - POSITION(track.index1), // - POSITION(track.index1 + Position::fromLba(track.frames)), // - track.offset, // - track.type == TrackType::DATA ? "DATA" : "AUDIO", // - getFilenameExt(track.filename) // + auto line = fmt::format("{:>5} {:<8} {:<8} {:<8} {:<8} {:<8} {:<9} {:<5} {}", + i + 1, // + POSITION(track.pregap), // + POSITION(track.pause()), // + POSITION(cue->getTrackStart(i)), // + POSITION(cue->getTrackStart(i) + cue->getTrackLength(i) - disc::Position(0, 0, 1)), // + POSITION(cue->getTrackLength(i)), // + track.offset, // + track.type == TrackType::DATA ? "DATA" : "AUDIO", // + getFilenameExt(track.filename) // ); ImGui::Selectable(line.c_str()); @@ -51,4 +53,4 @@ void Cdrom::cdromWindow(System* sys) { void Cdrom::displayWindows(System* sys) { if (cdromWindowOpen) cdromWindow(sys); } -} // namespace gui::debug::cdrom \ No newline at end of file +} // namespace gui::debug \ No newline at end of file diff --git a/src/state/state.cpp b/src/state/state.cpp index 7ac38d9..e04fdf1 100644 --- a/src/state/state.cpp +++ b/src/state/state.cpp @@ -20,7 +20,7 @@ namespace state { const char* lastSaveName = "last.state"; struct StateMetadata { - inline static const uint32_t SAVESTATE_VERSION = 6; + inline static const uint32_t SAVESTATE_VERSION = 7; uint32_t version = SAVESTATE_VERSION; std::string biosPath;