mirror of
https://github.com/JaCzekanski/Avocado.git
synced 2024-06-02 19:27:41 -04:00
fab6bd3881
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.
152 lines
4.6 KiB
C++
152 lines
4.6 KiB
C++
#include "chd_format.h"
|
|
#include <fmt/core.h>
|
|
#include <cstring>
|
|
#include "disc/track.h"
|
|
#include "utils/file.h"
|
|
|
|
namespace disc {
|
|
namespace format {
|
|
|
|
std::unique_ptr<Chd> Chd::open(const std::string& path) {
|
|
chd_file* chdFile;
|
|
auto err = chd_open(path.c_str(), CHD_OPEN_READ, nullptr, &chdFile);
|
|
if (err != CHDERR_NONE) {
|
|
fmt::print("[CHD] Unable to load file {} (error: {})\n", path, err);
|
|
return {};
|
|
}
|
|
|
|
// I'm not using make_unique - I want the constructor to be private
|
|
auto chd = std::unique_ptr<Chd>(new Chd(path, chdFile));
|
|
|
|
const chd_header* header = chd_get_header(chdFile);
|
|
chd->hunkSize = header->hunkbytes;
|
|
chd->lastHunk = std::vector<uint8_t>(chd->hunkSize);
|
|
chd->lastHunkId = 0xfffffff;
|
|
|
|
if ((chd->hunkSize % chd->sectorSize) != 0) {
|
|
fmt::print("[CHD] Image uses invalid hunkSize: {}\n", chd->hunkSize);
|
|
return {};
|
|
}
|
|
|
|
char metadata[512];
|
|
|
|
for (;;) {
|
|
int trackNum;
|
|
char type[64];
|
|
char subtype[64];
|
|
int frames;
|
|
int pregap = 0;
|
|
char pgtype[32];
|
|
char pgsub[32];
|
|
int postgap = 0;
|
|
|
|
if (chd_get_metadata(chdFile, CDROM_TRACK_METADATA2_TAG, chd->tracks.size(), metadata, sizeof(metadata), NULL, NULL, NULL)
|
|
== CHDERR_NONE) {
|
|
sscanf(metadata, CDROM_TRACK_METADATA2_FORMAT, &trackNum, type, subtype, &frames, &pregap, pgtype, pgsub, &postgap);
|
|
} else if (chd_get_metadata(chdFile, CDROM_TRACK_METADATA_TAG, chd->tracks.size(), metadata, sizeof(metadata), NULL, NULL, NULL)
|
|
== CHDERR_NONE) {
|
|
sscanf(metadata, CDROM_TRACK_METADATA_FORMAT, &trackNum, type, subtype, &frames);
|
|
} else {
|
|
if (chd->tracks.size() != 0) {
|
|
break;
|
|
}
|
|
|
|
fmt::print("[CHD] No valid metadata found, are you using correct .chd file?\n");
|
|
return {};
|
|
}
|
|
|
|
Track track;
|
|
if (strcmp(type, "MODE2_RAW") == 0 || strcmp(type, "MODE2") == 0) {
|
|
track.type = disc::TrackType::DATA;
|
|
} else if (strcmp(type, "AUDIO") == 0) {
|
|
track.type = disc::TrackType::AUDIO;
|
|
} else {
|
|
track.type = disc::TrackType::INVALID;
|
|
fmt::print("[CHD] Unsupported track type {}\n", type);
|
|
return {};
|
|
}
|
|
|
|
track.number = trackNum;
|
|
track.frames = frames;
|
|
track.pregap = Position::fromLba(pregap);
|
|
track.index0 = Position::fromLba(0);
|
|
track.index1 = Position::fromLba(pregap);
|
|
track.postgap = Position::fromLba(postgap);
|
|
|
|
chd->tracks.push_back(track);
|
|
}
|
|
|
|
chd->loadSubchannel(path);
|
|
|
|
return chd;
|
|
}
|
|
|
|
Chd::Chd(const std::string& path, chd_file* chdFile) : path(path), chdFile(chdFile) {}
|
|
|
|
Chd::~Chd() { chd_close(chdFile); }
|
|
|
|
Sector Chd::read(Position pos) {
|
|
int lba = (pos - Position{0, 2, 0}).toLba();
|
|
size_t hunk = (lba * sectorSize) / hunkSize;
|
|
size_t offset = (lba * sectorSize) % hunkSize;
|
|
|
|
if (hunk != lastHunkId || lastHunk.empty()) {
|
|
chd_read(chdFile, hunk, lastHunk.data());
|
|
lastHunkId = hunk;
|
|
}
|
|
|
|
std::vector<uint8_t> data(Track::SECTOR_SIZE);
|
|
std::copy(lastHunk.begin() + offset, lastHunk.begin() + offset + Track::SECTOR_SIZE, data.begin());
|
|
|
|
disc::TrackType type = disc::TrackType::DATA;
|
|
|
|
int trackN = getTrackByPosition(pos);
|
|
if (trackN != -1) {
|
|
type = tracks[trackN].type;
|
|
}
|
|
|
|
return std::make_pair(data, type);
|
|
}
|
|
|
|
std::string Chd::getFile() const { return path; }
|
|
|
|
size_t Chd::getTrackCount() const { return tracks.size(); }
|
|
|
|
int Chd::getTrackByPosition(Position pos) const {
|
|
size_t posFrames = (pos - Position(0, 2, 0)).toLba();
|
|
|
|
size_t frames = 0;
|
|
for (size_t i = 0; i < tracks.size(); i++) {
|
|
if (posFrames > frames && posFrames < frames + tracks[i].frames) {
|
|
return i;
|
|
}
|
|
|
|
frames += tracks[i].frames;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
Position Chd::getTrackBegin(int track) const {
|
|
size_t frames = 75 * 2;
|
|
if ((unsigned)track < tracks.size()) {
|
|
for (int i = 0; i < track; i++) {
|
|
frames += tracks[i].frames;
|
|
}
|
|
}
|
|
|
|
return Position::fromLba(frames);
|
|
}
|
|
Position Chd::getTrackStart(int track) const { return getTrackBegin(track) + tracks[track].start(); }
|
|
|
|
Position Chd::getTrackLength(int track) const { return Position::fromLba(tracks[track].pregap.toLba() + tracks[track].frames); }
|
|
|
|
Position Chd::getDiskSize() const {
|
|
size_t frames = 75 * 2;
|
|
for (auto t : tracks) {
|
|
frames += t.pregap.toLba() + t.frames;
|
|
}
|
|
return Position::fromLba(frames);
|
|
}
|
|
} // namespace format
|
|
} // namespace disc
|