Skip to content

Commit

Permalink
Parse Commodore .tap header only once.
Browse files Browse the repository at this point in the history
  • Loading branch information
TomHarte committed Jan 17, 2025
1 parent 062b581 commit 3f59a03
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 60 deletions.
66 changes: 35 additions & 31 deletions Storage/Tape/Formats/CommodoreTAP.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,50 +13,58 @@
using namespace Storage::Tape;

CommodoreTAP::CommodoreTAP(const std::string &file_name) : file_name_(file_name) {
Serialiser test(file_name);
target_platforms_ = test.target_platforms();
}

std::unique_ptr<FormatSerialiser> CommodoreTAP::format_serialiser() const {
return std::make_unique<Serialiser>(file_name_);
}
Storage::FileHolder file(file_name);

CommodoreTAP::Serialiser::Serialiser(const std::string &file_name) :
file_(file_name, FileHolder::FileMode::Read)
{
const bool is_c64 = file_.check_signature("C64-TAPE-RAW");
file_.seek(0, SEEK_SET);
const bool is_c16 = file_.check_signature("C16-TAPE-RAW");
const bool is_c64 = file.check_signature("C64-TAPE-RAW");
file.seek(0, SEEK_SET);
const bool is_c16 = file.check_signature("C16-TAPE-RAW");
if(!is_c64 && !is_c16) {
throw ErrorNotCommodoreTAP;
}
type_ = is_c16 ? FileType::C16 : FileType::C64;
const FileType type = is_c16 ? FileType::C16 : FileType::C64;

// Get and check the file version.
version_ = file_.get8();
if(version_ > 2) {
const uint8_t version = file.get8();
if(version > 2) {
throw ErrorNotCommodoreTAP;
}
updated_layout_ = version >= 1;
half_waves_ = version >= 2;

// Read clock rate-implying bytes.
platform_ = Platform(file_.get8());
video_ = VideoStandard(file_.get8());
file_.seek(1, SEEK_CUR);
platform_ = Platform(file.get8());
const VideoStandard video = VideoStandard(file.get8());
file.seek(1, SEEK_CUR);

// Read file size.
file_size_ = file_.get32le();
const bool double_clock = platform_ != Platform::C16 || !half_waves_; // TODO: is the platform check correct?

// Pick clock rate.
current_pulse_.length.clock_rate = static_cast<unsigned int>(
initial_pulse_.length.clock_rate = static_cast<unsigned int>(
[&] {
switch(platform_) {
default:
case Platform::Vic20: // It empirically seems like Vic-20 waves are counted with C64 timings?
case Platform::C64: return video_ == VideoStandard::PAL ? 985'248 : 1'022'727;
case Platform::C16: return video_ == VideoStandard::PAL ? 886'722 : 894'886;
case Platform::C64: return video == VideoStandard::PAL ? 985'248 : 1'022'727;
case Platform::C16: return video == VideoStandard::PAL ? 886'722 : 894'886;
}
}() * (double_clock() ? 2 : 1)
}() * (double_clock ? 2 : 1)
);
}

std::unique_ptr<FormatSerialiser> CommodoreTAP::format_serialiser() const {
return std::make_unique<Serialiser>(file_name_, initial_pulse_, half_waves_, updated_layout_);
}

CommodoreTAP::Serialiser::Serialiser(
const std::string &file_name,
Pulse initial,
bool half_waves,
bool updated_layout) :
file_(file_name, FileHolder::FileMode::Read),
current_pulse_(initial),
half_waves_(half_waves),
updated_layout_(updated_layout)
{
reset();
}

Expand All @@ -78,7 +86,7 @@ Storage::Tape::Pulse CommodoreTAP::Serialiser::next_pulse() {
const auto read_next_length = [&]() -> bool {
uint32_t next_length;
const uint8_t next_byte = file_.get8();
if(!updated_layout() || next_byte > 0) {
if(updated_layout_ || next_byte > 0) {
next_length = uint32_t(next_byte) << 3;
} else {
next_length = file_.get24le();
Expand All @@ -95,7 +103,7 @@ Storage::Tape::Pulse CommodoreTAP::Serialiser::next_pulse() {
}
};

if(half_waves()) {
if(half_waves_) {
if(read_next_length()) {
current_pulse_.type = current_pulse_.type == Pulse::High ? Pulse::Low : Pulse::High;
}
Expand All @@ -113,10 +121,6 @@ Storage::Tape::Pulse CommodoreTAP::Serialiser::next_pulse() {
// MARK: - TargetPlatform::Distinguisher

TargetPlatform::Type CommodoreTAP::target_platforms() {
return target_platforms_;
}

TargetPlatform::Type CommodoreTAP::Serialiser::target_platforms() {
switch(platform_) {
default: return TargetPlatform::Type::Commodore;
case Platform::C64: return TargetPlatform::Type::C64;
Expand Down
50 changes: 21 additions & 29 deletions Storage/Tape/Formats/CommodoreTAP.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,47 +38,39 @@ class CommodoreTAP: public Tape, public TargetPlatform::Distinguisher {
TargetPlatform::Type target_platforms() override;
std::unique_ptr<FormatSerialiser> format_serialiser() const override;

struct Serialiser: public FormatSerialiser {
Serialiser(const std::string &file_name);
enum class FileType {
C16, C64,
};
enum class Platform: uint8_t {
C64 = 0,
Vic20 = 1,
C16 = 2,
};
enum class VideoStandard: uint8_t {
PAL = 0,
NTSC1 = 1,
NTSC2 = 2,
};

TargetPlatform::Type target_platforms();
struct Serialiser: public FormatSerialiser {
Serialiser(const std::string &file_name, Pulse initial, bool half_waves, bool updated_layout);

private:
bool is_at_end() const override;
void reset() override;
Pulse next_pulse() override;

Storage::FileHolder file_;

uint32_t file_size_;
enum class FileType {
C16, C64,
} type_;
uint8_t version_;
enum class Platform: uint8_t {
C64 = 0,
Vic20 = 1,
C16 = 2,
} platform_;
enum class VideoStandard: uint8_t {
PAL = 0,
NTSC1 = 1,
NTSC2 = 2,
} video_;
bool updated_layout() const {
return version_ >= 1;
}
bool half_waves() const {
return version_ >= 2;
}
bool double_clock() const {
return platform_ != Platform::C16 || !half_waves();
}

Pulse current_pulse_;
bool half_waves_;
bool updated_layout_;
bool is_at_end_ = false;
};
std::string file_name_;
Pulse initial_pulse_;
bool half_waves_;
bool updated_layout_;
Platform platform_;
TargetPlatform::Type target_platforms_;
};

Expand Down

0 comments on commit 3f59a03

Please sign in to comment.