From 09e2ef334b74dec6885cac3b903040156f85cd96 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Mon, 2 Dec 2024 15:27:03 -0500 Subject: [PATCH 01/11] Fix sign of bounds check. --- Analyser/Static/Commodore/File.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Analyser/Static/Commodore/File.cpp b/Analyser/Static/Commodore/File.cpp index cfc41e577..6e05e8bc4 100644 --- a/Analyser/Static/Commodore/File.cpp +++ b/Analyser/Static/Commodore/File.cpp @@ -23,7 +23,7 @@ bool Analyser::Static::Commodore::File::is_basic() { // ... null-terminated code ... // (with a next line address of 0000 indicating end of program) while(1) { - if(size_t(line_address - starting_address) >= data.size() + 2) break; + if(size_t(line_address - starting_address) >= data.size() - 2) break; uint16_t next_line_address = data[line_address - starting_address]; next_line_address |= data[line_address - starting_address + 1] << 8; @@ -33,7 +33,7 @@ bool Analyser::Static::Commodore::File::is_basic() { } if(next_line_address < line_address + 5) break; - if(size_t(line_address - starting_address) >= data.size() + 5) break; + if(size_t(line_address - starting_address) >= data.size() - 5) break; uint16_t next_line_number = data[line_address - starting_address + 2]; next_line_number |= data[line_address - starting_address + 3] << 8; From 32beafc12d244a3e8eee3656f50cc25b4ccc0b69 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Mon, 2 Dec 2024 15:27:23 -0500 Subject: [PATCH 02/11] Test Plus 4 detectionl; add shout for additional start address. --- Analyser/Machines.hpp | 1 + Analyser/Static/Commodore/StaticAnalyser.cpp | 4 ++++ InstructionSets/M68k/Executor.hpp | 3 ++- OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj | 4 ++++ .../xcshareddata/xcschemes/Clock Signal.xcscheme | 2 ++ 5 files changed, 13 insertions(+), 1 deletion(-) diff --git a/Analyser/Machines.hpp b/Analyser/Machines.hpp index 9a0c41fe7..0a90310e9 100644 --- a/Analyser/Machines.hpp +++ b/Analyser/Machines.hpp @@ -25,6 +25,7 @@ enum class Machine { MasterSystem, MSX, Oric, + Plus4, PCCompatible, Vic20, ZX8081, diff --git a/Analyser/Static/Commodore/StaticAnalyser.cpp b/Analyser/Static/Commodore/StaticAnalyser.cpp index 34a4bb30b..dbe78bbc5 100644 --- a/Analyser/Static/Commodore/StaticAnalyser.cpp +++ b/Analyser/Static/Commodore/StaticAnalyser.cpp @@ -109,6 +109,10 @@ Analyser::Static::TargetList Analyser::Static::Commodore::GetTargets( case 0x0401: memory_model = Target::MemoryModel::EightKB; break; + + case 0x1c01: + Log::Logger().info().append("Unimplemented: C128"); + break; } target->set_memory_model(memory_model); diff --git a/InstructionSets/M68k/Executor.hpp b/InstructionSets/M68k/Executor.hpp index b41aff812..21877bcf9 100644 --- a/InstructionSets/M68k/Executor.hpp +++ b/InstructionSets/M68k/Executor.hpp @@ -158,7 +158,8 @@ private: }; EffectiveAddress calculate_effective_address(Preinstruction instruction, uint16_t opcode, int index); uint32_t index_8bitdisplacement(uint32_t); - } state_; + }; + mutable State state_; }; } diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj index 84bbbdf6d..aae7c1a32 100644 --- a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj +++ b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj @@ -405,6 +405,7 @@ 4B670AB12401CB8400D4E002 /* z80docflags.tap in Resources */ = {isa = PBXBuildFile; fileRef = 4B670A9A2401CB8400D4E002 /* z80docflags.tap */; }; 4B680CE223A5553100451D43 /* 68000ComparativeTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4B680CE123A5553100451D43 /* 68000ComparativeTests.mm */; }; 4B680CE423A555CA00451D43 /* 68000 Comparative Tests in Resources */ = {isa = PBXBuildFile; fileRef = 4B680CE323A555CA00451D43 /* 68000 Comparative Tests */; }; + 4B6823A42CFE45B800276DA6 /* CommodoreStaticAnalyserTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4B6823A32CFE45B800276DA6 /* CommodoreStaticAnalyserTests.mm */; }; 4B683B012727BE700043E541 /* Amiga Blitter Tests in Resources */ = {isa = PBXBuildFile; fileRef = 4B683B002727BE6F0043E541 /* Amiga Blitter Tests */; }; 4B69DEB62AB79E4F0055B217 /* Instruction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B69DEB52AB79E4F0055B217 /* Instruction.cpp */; }; 4B69DEB72AB79E4F0055B217 /* Instruction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B69DEB52AB79E4F0055B217 /* Instruction.cpp */; }; @@ -1626,6 +1627,7 @@ 4B670A9A2401CB8400D4E002 /* z80docflags.tap */ = {isa = PBXFileReference; lastKnownFileType = file; path = z80docflags.tap; sourceTree = ""; }; 4B680CE123A5553100451D43 /* 68000ComparativeTests.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = 68000ComparativeTests.mm; sourceTree = ""; }; 4B680CE323A555CA00451D43 /* 68000 Comparative Tests */ = {isa = PBXFileReference; lastKnownFileType = folder; path = "68000 Comparative Tests"; sourceTree = ""; }; + 4B6823A32CFE45B800276DA6 /* CommodoreStaticAnalyserTests.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = CommodoreStaticAnalyserTests.mm; sourceTree = ""; }; 4B683B002727BE6F0043E541 /* Amiga Blitter Tests */ = {isa = PBXFileReference; lastKnownFileType = folder; path = "Amiga Blitter Tests"; sourceTree = ""; }; 4B698D1A1FE768A100696C91 /* BufferSource.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = BufferSource.hpp; sourceTree = ""; }; 4B69DEB52AB79E4F0055B217 /* Instruction.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Instruction.cpp; sourceTree = ""; }; @@ -4653,6 +4655,7 @@ 4B2005422B804D6400420C5C /* ARMDecoderTests.mm */, 4B924E981E74D22700B76AF1 /* AtariStaticAnalyserTests.mm */, 4BE34437238389E10058E78F /* AtariSTVideoTests.mm */, + 4B6823A32CFE45B800276DA6 /* CommodoreStaticAnalyserTests.mm */, 4B882F582C2F9C6900D84031 /* CPCShakerTests.mm */, 4BB2A9AE1E13367E001A5C23 /* CRCTests.mm */, 4BB0CAA627E51B6300672A88 /* DingusdevPowerPCTests.mm */, @@ -6465,6 +6468,7 @@ 4B778F0A23A5EC150000D260 /* TapePRG.cpp in Sources */, 4B778F0823A5EC150000D260 /* CSW.cpp in Sources */, 4BA6B6AE284EDAC100A3B7A8 /* 68000OldVsNew.mm in Sources */, + 4B6823A42CFE45B800276DA6 /* CommodoreStaticAnalyserTests.mm in Sources */, 4B778F5323A5F23F0000D260 /* SerialBus.cpp in Sources */, 4B1E85811D176468001EF87D /* 6532Tests.swift in Sources */, 4B7752BA28217F160073E2C5 /* Bitplanes.cpp in Sources */, diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/xcshareddata/xcschemes/Clock Signal.xcscheme b/OSBindings/Mac/Clock Signal.xcodeproj/xcshareddata/xcschemes/Clock Signal.xcscheme index d8d798ff4..c71db3eb0 100644 --- a/OSBindings/Mac/Clock Signal.xcodeproj/xcshareddata/xcschemes/Clock Signal.xcscheme +++ b/OSBindings/Mac/Clock Signal.xcodeproj/xcshareddata/xcschemes/Clock Signal.xcscheme @@ -27,6 +27,7 @@ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" shouldUseLaunchSchemeArgsEnv = "YES" + enableAddressSanitizer = "YES" disableMainThreadChecker = "YES" codeCoverageEnabled = "YES"> @@ -67,6 +68,7 @@ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" enableASanStackUseAfterReturn = "YES" disableMainThreadChecker = "YES" + disablePerformanceAntipatternChecker = "YES" launchStyle = "0" useCustomWorkingDirectory = "NO" ignoresPersistentStateOnLaunch = "NO" From 9fa71231c4d6d3195b1981256d14adb3b5d92bb2 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Mon, 2 Dec 2024 17:23:50 -0500 Subject: [PATCH 03/11] Support zero-length files; further fix bounds checks. --- Analyser/Static/Commodore/Disk.cpp | 46 ++++++++++--------- Analyser/Static/Commodore/File.cpp | 4 +- .../xcschemes/Clock Signal.xcscheme | 1 - 3 files changed, 26 insertions(+), 25 deletions(-) diff --git a/Analyser/Static/Commodore/Disk.cpp b/Analyser/Static/Commodore/Disk.cpp index 2a72dcb54..0551fd997 100644 --- a/Analyser/Static/Commodore/Disk.cpp +++ b/Analyser/Static/Commodore/Disk.cpp @@ -216,34 +216,36 @@ std::vector Analyser::Static::Commodore::GetFiles(const std::shared_ptrdata[0]; - next_sector = sector->data[1]; + next_track = sector->data[0]; + next_sector = sector->data[1]; - if(is_first_sector) new_file.starting_address = uint16_t(sector->data[2]) | uint16_t(sector->data[3] << 8); - if(next_track) - new_file.data.insert( - new_file.data.end(), - sector->data.begin() + (is_first_sector ? 4 : 2), - sector->data.end() - ); - else - new_file.data.insert( - new_file.data.end(), - sector->data.begin() + 2, - sector->data.begin() + next_sector - ); + if(is_first_sector) new_file.starting_address = uint16_t(sector->data[2]) | uint16_t(sector->data[3] << 8); + if(next_track) + new_file.data.insert( + new_file.data.end(), + sector->data.begin() + (is_first_sector ? 4 : 2), + sector->data.end() + ); + else + new_file.data.insert( + new_file.data.end(), + sector->data.begin() + 2, + sector->data.begin() + next_sector + ); - is_first_sector = false; + is_first_sector = false; + } } if(!next_track) files.push_back(new_file); diff --git a/Analyser/Static/Commodore/File.cpp b/Analyser/Static/Commodore/File.cpp index 6e05e8bc4..6bcb9bfa6 100644 --- a/Analyser/Static/Commodore/File.cpp +++ b/Analyser/Static/Commodore/File.cpp @@ -23,7 +23,7 @@ bool Analyser::Static::Commodore::File::is_basic() { // ... null-terminated code ... // (with a next line address of 0000 indicating end of program) while(1) { - if(size_t(line_address - starting_address) >= data.size() - 2) break; + if(size_t(line_address - starting_address) + 1 >= data.size()) break; uint16_t next_line_address = data[line_address - starting_address]; next_line_address |= data[line_address - starting_address + 1] << 8; @@ -33,7 +33,7 @@ bool Analyser::Static::Commodore::File::is_basic() { } if(next_line_address < line_address + 5) break; - if(size_t(line_address - starting_address) >= data.size() - 5) break; + if(size_t(line_address - starting_address) + 3 >= data.size()) break; uint16_t next_line_number = data[line_address - starting_address + 2]; next_line_number |= data[line_address - starting_address + 3] << 8; diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/xcshareddata/xcschemes/Clock Signal.xcscheme b/OSBindings/Mac/Clock Signal.xcodeproj/xcshareddata/xcschemes/Clock Signal.xcscheme index c71db3eb0..bc950be25 100644 --- a/OSBindings/Mac/Clock Signal.xcodeproj/xcshareddata/xcschemes/Clock Signal.xcscheme +++ b/OSBindings/Mac/Clock Signal.xcodeproj/xcshareddata/xcschemes/Clock Signal.xcscheme @@ -27,7 +27,6 @@ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" shouldUseLaunchSchemeArgsEnv = "YES" - enableAddressSanitizer = "YES" disableMainThreadChecker = "YES" codeCoverageEnabled = "YES"> From 0371b0507ace8498ab30cc8b4acd4350e34e7709 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Tue, 3 Dec 2024 09:18:05 -0500 Subject: [PATCH 04/11] Avoid potential extending run-out-of-bounds. --- Storage/Tape/Formats/ZXSpectrumTAP.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Storage/Tape/Formats/ZXSpectrumTAP.cpp b/Storage/Tape/Formats/ZXSpectrumTAP.cpp index 5fa28c4de..41e742151 100644 --- a/Storage/Tape/Formats/ZXSpectrumTAP.cpp +++ b/Storage/Tape/Formats/ZXSpectrumTAP.cpp @@ -19,19 +19,20 @@ using namespace Storage::Tape; */ ZXSpectrumTAP::ZXSpectrumTAP(const std::string &file_name) : - file_(file_name) + file_(file_name, FileHolder::FileMode::Read) { // Check for a continuous series of blocks through to // exactly file end. // // To consider: could also check those blocks of type 0 // and type ff for valid checksums? - while(true) { + while(file_.tell() != file_.stats().st_size) { const uint16_t block_length = file_.get16le(); - if(file_.eof()) throw ErrorNotZXSpectrumTAP; + if(file_.eof() || file_.tell() + block_length >= file_.stats().st_size) { + throw ErrorNotZXSpectrumTAP; + } file_.seek(block_length, SEEK_CUR); - if(file_.tell() == file_.stats().st_size) break; } virtual_reset(); From 0b5cd4c66547075388841859c23abad18cf8be9a Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Tue, 3 Dec 2024 09:21:13 -0500 Subject: [PATCH 05/11] Lock all tape classes down to read-only. --- Storage/Tape/Formats/CAS.cpp | 2 +- Storage/Tape/Formats/CSW.cpp | 2 +- Storage/Tape/Formats/CommodoreTAP.cpp | 2 +- Storage/Tape/Formats/OricTAP.cpp | 2 +- Storage/Tape/Formats/TZX.cpp | 2 +- Storage/Tape/Formats/TapePRG.cpp | 2 +- Storage/Tape/Formats/ZX80O81P.cpp | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Storage/Tape/Formats/CAS.cpp b/Storage/Tape/Formats/CAS.cpp index 0d9dec328..2de796495 100644 --- a/Storage/Tape/Formats/CAS.cpp +++ b/Storage/Tape/Formats/CAS.cpp @@ -60,7 +60,7 @@ namespace { } CAS::CAS(const std::string &file_name) { - Storage::FileHolder file(file_name); + Storage::FileHolder file(file_name, FileHolder::FileMode::Read); enum class Mode { Seeking, diff --git a/Storage/Tape/Formats/CSW.cpp b/Storage/Tape/Formats/CSW.cpp index 4b6e04721..40f8ba700 100644 --- a/Storage/Tape/Formats/CSW.cpp +++ b/Storage/Tape/Formats/CSW.cpp @@ -16,7 +16,7 @@ using namespace Storage::Tape; CSW::CSW(const std::string &file_name) : source_data_pointer_(0) { - Storage::FileHolder file(file_name); + Storage::FileHolder file(file_name, FileHolder::FileMode::Read); if(file.stats().st_size < 0x20) throw ErrorNotCSW; // Check signature. diff --git a/Storage/Tape/Formats/CommodoreTAP.cpp b/Storage/Tape/Formats/CommodoreTAP.cpp index 40fd30658..c9049bb6c 100644 --- a/Storage/Tape/Formats/CommodoreTAP.cpp +++ b/Storage/Tape/Formats/CommodoreTAP.cpp @@ -13,7 +13,7 @@ using namespace Storage::Tape; CommodoreTAP::CommodoreTAP(const std::string &file_name) : - file_(file_name) + file_(file_name, FileHolder::FileMode::Read) { if(!file_.check_signature("C64-TAPE-RAW")) throw ErrorNotCommodoreTAP; diff --git a/Storage/Tape/Formats/OricTAP.cpp b/Storage/Tape/Formats/OricTAP.cpp index 9b13dc1b1..0a6441483 100644 --- a/Storage/Tape/Formats/OricTAP.cpp +++ b/Storage/Tape/Formats/OricTAP.cpp @@ -13,7 +13,7 @@ using namespace Storage::Tape; OricTAP::OricTAP(const std::string &file_name) : - file_(file_name) + file_(file_name, FileHolder::FileMode::Read) { // Check for a sequence of at least three 0x16s followed by a 0x24. while(true) { diff --git a/Storage/Tape/Formats/TZX.cpp b/Storage/Tape/Formats/TZX.cpp index 230194425..2a41bf362 100644 --- a/Storage/Tape/Formats/TZX.cpp +++ b/Storage/Tape/Formats/TZX.cpp @@ -22,7 +22,7 @@ Log::Logger logger; } TZX::TZX(const std::string &file_name) : - file_(file_name), + file_(file_name, FileHolder::FileMode::Read), current_level_(false) { // Check for signature followed by a 0x1a diff --git a/Storage/Tape/Formats/TapePRG.cpp b/Storage/Tape/Formats/TapePRG.cpp index f18162ba0..48f335acb 100644 --- a/Storage/Tape/Formats/TapePRG.cpp +++ b/Storage/Tape/Formats/TapePRG.cpp @@ -49,7 +49,7 @@ using namespace Storage::Tape; PRG::PRG(const std::string &file_name) : - file_(file_name) + file_(file_name, FileHolder::FileMode::Read) { // There's really no way to validate other than that if this file is larger than 64kb, // of if load address + length > 65536 then it's broken. diff --git a/Storage/Tape/Formats/ZX80O81P.cpp b/Storage/Tape/Formats/ZX80O81P.cpp index e10b1b74e..16145727f 100644 --- a/Storage/Tape/Formats/ZX80O81P.cpp +++ b/Storage/Tape/Formats/ZX80O81P.cpp @@ -12,7 +12,7 @@ using namespace Storage::Tape; ZX80O81P::ZX80O81P(const std::string &file_name) { - Storage::FileHolder file(file_name); + Storage::FileHolder file(file_name, FileHolder::FileMode::Read); // Grab the actual file contents data_.resize(size_t(file.stats().st_size)); From 3ffd986a1c98ec4d582e0602804d6b4bf5215635 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Tue, 3 Dec 2024 09:25:58 -0500 Subject: [PATCH 06/11] Start building Commodore analyser tests. --- .../xcschemes/Clock Signal.xcscheme | 3 +- .../CommodoreStaticAnalyserTests.mm | 81 +++++++++++++++++++ 2 files changed, 83 insertions(+), 1 deletion(-) create mode 100644 OSBindings/Mac/Clock SignalTests/CommodoreStaticAnalyserTests.mm diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/xcshareddata/xcschemes/Clock Signal.xcscheme b/OSBindings/Mac/Clock Signal.xcodeproj/xcshareddata/xcschemes/Clock Signal.xcscheme index bc950be25..1dec5b8a5 100644 --- a/OSBindings/Mac/Clock Signal.xcodeproj/xcshareddata/xcschemes/Clock Signal.xcscheme +++ b/OSBindings/Mac/Clock Signal.xcodeproj/xcshareddata/xcschemes/Clock Signal.xcscheme @@ -90,8 +90,9 @@ diff --git a/OSBindings/Mac/Clock SignalTests/CommodoreStaticAnalyserTests.mm b/OSBindings/Mac/Clock SignalTests/CommodoreStaticAnalyserTests.mm new file mode 100644 index 000000000..5fc87c3da --- /dev/null +++ b/OSBindings/Mac/Clock SignalTests/CommodoreStaticAnalyserTests.mm @@ -0,0 +1,81 @@ +// +// AtariStaticAnalyserTests.m +// Clock Signal +// +// Created by Thomas Harte on 11/03/2017. +// Copyright 2017 Thomas Harte. All rights reserved. +// + +#import + +#import +#include "../../../Analyser/Static/StaticAnalyser.hpp" +#include "../../../Analyser/Static/Commodore/Target.hpp" + +// This test runs through a whole bunch of files somewhere on disk. These files are not included in the repository +// because they are not suitably licensed. So this path is specific to my local system, at the time I happen to be +// writing these tests. Update in the future, as necessary. +static constexpr const char *const plus4Path = + "/Users/thomasharte/Library/Mobile Documents/com~apple~CloudDocs/Soft/C16+4"; +static constexpr const char *const vic20Path = + "/Users/thomasharte/Library/Mobile Documents/com~apple~CloudDocs/Soft/Vic-20"; + +@interface CommodoreStaticAnalyserTests : XCTestCase +@end + +struct HitRate { + int files = 0; + int matches = 0; + + HitRate &operator += (const HitRate &rhs) { + files += rhs.files; + matches += rhs.matches; + return *this; + } +}; + +@implementation CommodoreStaticAnalyserTests + +- (HitRate)hitRateBeneathPath:(NSString *)path forMachine:(Analyser::Machine)machine { + HitRate hits{}; + + NSDirectoryEnumerator *enumerator = [[NSFileManager defaultManager] enumeratorAtPath:path]; + while(NSString *diskItem = [enumerator nextObject]) { + const NSString *type = [[enumerator fileAttributes] objectForKey:NSFileType]; + if(![type isEqual:NSFileTypeRegular]) { + continue; + } + + NSLog(@"%@", diskItem); + const auto list = Analyser::Static::GetTargets([path stringByAppendingPathComponent:diskItem].UTF8String); + if(list.empty()) { + continue; + } + + ++hits.files; + if(list.size() != 1) { + continue; + } + + const auto &first = *list.begin(); + hits.matches += first->machine == machine; + } + + return hits; +} + +- (void)testPlus4 { + const auto hitRate = + [self hitRateBeneathPath:[NSString stringWithUTF8String:plus4Path] forMachine:Analyser::Machine::Plus4]; + NSLog(@"Got hit rate of %d in %d, i.e. %0.2f", + hitRate.matches, hitRate.files, float(hitRate.matches) / float(hitRate.files)); +} + +- (void)testVic20 { + const auto hitRate = + [self hitRateBeneathPath:[NSString stringWithUTF8String:vic20Path] forMachine:Analyser::Machine::Vic20]; + NSLog(@"Got hit rate of %d in %d, i.e. %0.2f", + hitRate.matches, hitRate.files, float(hitRate.matches) / float(hitRate.files)); +} + +@end From 6ef63790a9e589795452de45c95eaa296b553478 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Tue, 3 Dec 2024 17:33:09 -0500 Subject: [PATCH 07/11] Mark overrides, improve `const`iness. --- .../CommodoreStaticAnalyserTests.mm | 1 - Storage/FileHolder.cpp | 10 +++---- Storage/FileHolder.hpp | 10 +++---- Storage/Tape/Formats/CAS.cpp | 2 +- Storage/Tape/Formats/CAS.hpp | 6 ++--- Storage/Tape/Formats/CSW.cpp | 2 +- Storage/Tape/Formats/CSW.hpp | 6 ++--- Storage/Tape/Formats/CommodoreTAP.cpp | 2 +- Storage/Tape/Formats/CommodoreTAP.hpp | 6 ++--- Storage/Tape/Formats/OricTAP.cpp | 2 +- Storage/Tape/Formats/OricTAP.hpp | 6 ++--- Storage/Tape/Formats/TZX.cpp | 2 +- Storage/Tape/Formats/TapePRG.cpp | 2 +- Storage/Tape/Formats/TapePRG.hpp | 6 ++--- Storage/Tape/Formats/ZX80O81P.cpp | 4 +-- Storage/Tape/Formats/ZX80O81P.hpp | 10 +++---- Storage/Tape/Formats/ZXSpectrumTAP.cpp | 2 +- Storage/Tape/Formats/ZXSpectrumTAP.hpp | 2 +- Storage/Tape/PulseQueuedTape.cpp | 26 ++++++++----------- Storage/Tape/PulseQueuedTape.hpp | 9 +++---- Storage/Tape/Tape.cpp | 2 +- Storage/Tape/Tape.hpp | 4 +-- 22 files changed, 58 insertions(+), 64 deletions(-) diff --git a/OSBindings/Mac/Clock SignalTests/CommodoreStaticAnalyserTests.mm b/OSBindings/Mac/Clock SignalTests/CommodoreStaticAnalyserTests.mm index 5fc87c3da..f2dc2e2c0 100644 --- a/OSBindings/Mac/Clock SignalTests/CommodoreStaticAnalyserTests.mm +++ b/OSBindings/Mac/Clock SignalTests/CommodoreStaticAnalyserTests.mm @@ -46,7 +46,6 @@ struct HitRate { continue; } - NSLog(@"%@", diskItem); const auto list = Analyser::Static::GetTargets([path stringByAppendingPathComponent:diskItem].UTF8String); if(list.empty()) { continue; diff --git a/Storage/FileHolder.cpp b/Storage/FileHolder.cpp index 5a43b99c5..8dc772a64 100644 --- a/Storage/FileHolder.cpp +++ b/Storage/FileHolder.cpp @@ -133,7 +133,7 @@ void FileHolder::seek(long offset, int whence) { std::fseek(file_, offset, whence); } -long FileHolder::tell() { +long FileHolder::tell() const { return std::ftell(file_); } @@ -141,7 +141,7 @@ void FileHolder::flush() { std::fflush(file_); } -bool FileHolder::eof() { +bool FileHolder::eof() const { return std::feof(file_); } @@ -159,7 +159,7 @@ bool FileHolder::check_signature(const char *signature, std::size_t length) { return true; } -std::string FileHolder::extension() { +std::string FileHolder::extension() const { std::size_t pointer = name_.size() - 1; while(pointer > 0 && name_[pointer] != '.') pointer--; if(name_[pointer] == '.') pointer++; @@ -178,11 +178,11 @@ void FileHolder::ensure_is_at_least_length(long length) { } } -bool FileHolder::get_is_known_read_only() { +bool FileHolder::get_is_known_read_only() const { return is_read_only_; } -struct stat &FileHolder::stats() { +const struct stat &FileHolder::stats() const { return file_stats_; } diff --git a/Storage/FileHolder.hpp b/Storage/FileHolder.hpp index 2749a44e8..402f792dc 100644 --- a/Storage/FileHolder.hpp +++ b/Storage/FileHolder.hpp @@ -144,13 +144,13 @@ public: void seek(long offset, int whence); /*! @returns The current cursor position within this file. */ - long tell(); + long tell() const; /*! Flushes any queued content that has not yet been written to disk. */ void flush(); /*! @returns @c true if the end-of-file indicator is set, @c false otherwise. */ - bool eof(); + bool eof() const; class BitStream { public: @@ -214,7 +214,7 @@ public: Determines and returns the file extension: everything from the final character back to the first dot. The string is converted to lowercase before being returned. */ - std::string extension(); + std::string extension() const; /*! Ensures the file is at least @c length bytes long, appending 0s until it is @@ -225,12 +225,12 @@ public: /*! @returns @c true if an attempt was made to read this file in ReadWrite mode but it could be opened only for reading; @c false otherwise. */ - bool get_is_known_read_only(); + bool get_is_known_read_only() const; /*! @returns the stat struct describing this file. */ - struct stat &stats(); + const struct stat &stats() const; /*! @returns a mutex owned by the file that can be used to serialise file access. diff --git a/Storage/Tape/Formats/CAS.cpp b/Storage/Tape/Formats/CAS.cpp index 2de796495..b07db8216 100644 --- a/Storage/Tape/Formats/CAS.cpp +++ b/Storage/Tape/Formats/CAS.cpp @@ -168,7 +168,7 @@ CAS::CAS(const std::string &file_name) { } } -bool CAS::is_at_end() { +bool CAS::is_at_end() const { return phase_ == Phase::EndOfFile; } diff --git a/Storage/Tape/Formats/CAS.hpp b/Storage/Tape/Formats/CAS.hpp index 61fe55858..5ec222f53 100644 --- a/Storage/Tape/Formats/CAS.hpp +++ b/Storage/Tape/Formats/CAS.hpp @@ -34,11 +34,11 @@ public: }; // implemented to satisfy @c Tape - bool is_at_end(); + bool is_at_end() const override; private: - void virtual_reset(); - Pulse virtual_get_next_pulse(); + void virtual_reset() override; + Pulse virtual_get_next_pulse() override; // Storage for the array of data blobs to transcribe into audio; // each chunk is preceded by a header which may be long, and is optionally diff --git a/Storage/Tape/Formats/CSW.cpp b/Storage/Tape/Formats/CSW.cpp index 40f8ba700..251ad4fab 100644 --- a/Storage/Tape/Formats/CSW.cpp +++ b/Storage/Tape/Formats/CSW.cpp @@ -114,7 +114,7 @@ void CSW::invert_pulse() { pulse_.type = (pulse_.type == Pulse::High) ? Pulse::Low : Pulse::High; } -bool CSW::is_at_end() { +bool CSW::is_at_end() const { return source_data_pointer_ == source_data_.size(); } diff --git a/Storage/Tape/Formats/CSW.hpp b/Storage/Tape/Formats/CSW.hpp index e269a3084..318911c1a 100644 --- a/Storage/Tape/Formats/CSW.hpp +++ b/Storage/Tape/Formats/CSW.hpp @@ -43,11 +43,11 @@ public: }; // implemented to satisfy @c Tape - bool is_at_end(); + bool is_at_end() const override; private: - void virtual_reset(); - Pulse virtual_get_next_pulse(); + void virtual_reset() override; + Pulse virtual_get_next_pulse() override; Pulse pulse_; CompressionType compression_type_; diff --git a/Storage/Tape/Formats/CommodoreTAP.cpp b/Storage/Tape/Formats/CommodoreTAP.cpp index c9049bb6c..6a9044901 100644 --- a/Storage/Tape/Formats/CommodoreTAP.cpp +++ b/Storage/Tape/Formats/CommodoreTAP.cpp @@ -45,7 +45,7 @@ void CommodoreTAP::virtual_reset() { is_at_end_ = false; } -bool CommodoreTAP::is_at_end() { +bool CommodoreTAP::is_at_end() const { return is_at_end_; } diff --git a/Storage/Tape/Formats/CommodoreTAP.hpp b/Storage/Tape/Formats/CommodoreTAP.hpp index 25bfede2b..7a27ef0df 100644 --- a/Storage/Tape/Formats/CommodoreTAP.hpp +++ b/Storage/Tape/Formats/CommodoreTAP.hpp @@ -33,12 +33,12 @@ public: }; // implemented to satisfy @c Tape - bool is_at_end(); + bool is_at_end() const override; private: Storage::FileHolder file_; - void virtual_reset(); - Pulse virtual_get_next_pulse(); + void virtual_reset() override; + Pulse virtual_get_next_pulse() override; bool updated_layout_; uint32_t file_size_; diff --git a/Storage/Tape/Formats/OricTAP.cpp b/Storage/Tape/Formats/OricTAP.cpp index 0a6441483..efd41a057 100644 --- a/Storage/Tape/Formats/OricTAP.cpp +++ b/Storage/Tape/Formats/OricTAP.cpp @@ -158,6 +158,6 @@ Tape::Pulse OricTAP::virtual_get_next_pulse() { return pulse; } -bool OricTAP::is_at_end() { +bool OricTAP::is_at_end() const { return phase_ == End; } diff --git a/Storage/Tape/Formats/OricTAP.hpp b/Storage/Tape/Formats/OricTAP.hpp index 3a996a6e0..ff96d2ae3 100644 --- a/Storage/Tape/Formats/OricTAP.hpp +++ b/Storage/Tape/Formats/OricTAP.hpp @@ -33,12 +33,12 @@ public: }; // implemented to satisfy @c Tape - bool is_at_end(); + bool is_at_end() const override; private: Storage::FileHolder file_; - void virtual_reset(); - Pulse virtual_get_next_pulse(); + void virtual_reset() override; + Pulse virtual_get_next_pulse() override; // byte serialisation and output uint16_t current_value_; diff --git a/Storage/Tape/Formats/TZX.cpp b/Storage/Tape/Formats/TZX.cpp index 2a41bf362..1349e8add 100644 --- a/Storage/Tape/Formats/TZX.cpp +++ b/Storage/Tape/Formats/TZX.cpp @@ -115,7 +115,7 @@ void TZX::get_csw_recording_block() { while(!csw.is_at_end()) { Tape::Pulse next_pulse = csw.get_next_pulse(); current_level_ = (next_pulse.type == Tape::Pulse::High); - emplace_back(std::move(next_pulse)); + push_back(next_pulse); } (void)number_of_compressed_pulses; diff --git a/Storage/Tape/Formats/TapePRG.cpp b/Storage/Tape/Formats/TapePRG.cpp index 48f335acb..c5ddb6fa9 100644 --- a/Storage/Tape/Formats/TapePRG.cpp +++ b/Storage/Tape/Formats/TapePRG.cpp @@ -95,7 +95,7 @@ void PRG::virtual_reset() { copy_mask_ = 0x80; } -bool PRG::is_at_end() { +bool PRG::is_at_end() const { return file_phase_ == FilePhaseAtEnd; } diff --git a/Storage/Tape/Formats/TapePRG.hpp b/Storage/Tape/Formats/TapePRG.hpp index 0d0cd180e..c33143f8f 100644 --- a/Storage/Tape/Formats/TapePRG.hpp +++ b/Storage/Tape/Formats/TapePRG.hpp @@ -34,12 +34,12 @@ public: }; // implemented to satisfy @c Tape - bool is_at_end(); + bool is_at_end() const override; private: FileHolder file_; - Pulse virtual_get_next_pulse(); - void virtual_reset(); + Pulse virtual_get_next_pulse() override; + void virtual_reset() override; uint16_t load_address_; uint16_t length_; diff --git a/Storage/Tape/Formats/ZX80O81P.cpp b/Storage/Tape/Formats/ZX80O81P.cpp index 16145727f..b65e1e66b 100644 --- a/Storage/Tape/Formats/ZX80O81P.cpp +++ b/Storage/Tape/Formats/ZX80O81P.cpp @@ -42,11 +42,11 @@ void ZX80O81P::virtual_reset() { bit_pointer_ = wave_pointer_ = 0; } -bool ZX80O81P::has_finished_data() { +bool ZX80O81P::has_finished_data() const { return (data_pointer_ == data_.size()) && !wave_pointer_ && !bit_pointer_; } -bool ZX80O81P::is_at_end() { +bool ZX80O81P::is_at_end() const { return has_finished_data() && has_ended_final_byte_; } diff --git a/Storage/Tape/Formats/ZX80O81P.hpp b/Storage/Tape/Formats/ZX80O81P.hpp index 17c7d085f..132804d88 100644 --- a/Storage/Tape/Formats/ZX80O81P.hpp +++ b/Storage/Tape/Formats/ZX80O81P.hpp @@ -37,15 +37,15 @@ public: private: // implemented to satisfy @c Tape - bool is_at_end(); + bool is_at_end() const override; // implemented to satisfy TargetPlatform::TypeDistinguisher - TargetPlatform::Type target_platform_type(); + TargetPlatform::Type target_platform_type() override; TargetPlatform::Type platform_type_; - void virtual_reset(); - Pulse virtual_get_next_pulse(); - bool has_finished_data(); + void virtual_reset() override; + Pulse virtual_get_next_pulse() override; + bool has_finished_data() const; uint8_t byte_; int bit_pointer_; diff --git a/Storage/Tape/Formats/ZXSpectrumTAP.cpp b/Storage/Tape/Formats/ZXSpectrumTAP.cpp index 41e742151..e7103042c 100644 --- a/Storage/Tape/Formats/ZXSpectrumTAP.cpp +++ b/Storage/Tape/Formats/ZXSpectrumTAP.cpp @@ -38,7 +38,7 @@ ZXSpectrumTAP::ZXSpectrumTAP(const std::string &file_name) : virtual_reset(); } -bool ZXSpectrumTAP::is_at_end() { +bool ZXSpectrumTAP::is_at_end() const { return file_.tell() == file_.stats().st_size && phase_ == Phase::Gap; } diff --git a/Storage/Tape/Formats/ZXSpectrumTAP.hpp b/Storage/Tape/Formats/ZXSpectrumTAP.hpp index df7fb093a..74ee390d7 100644 --- a/Storage/Tape/Formats/ZXSpectrumTAP.hpp +++ b/Storage/Tape/Formats/ZXSpectrumTAP.hpp @@ -48,7 +48,7 @@ private: void read_next_block(); // Implemented to satisfy @c Tape. - bool is_at_end() override; + bool is_at_end() const override; void virtual_reset() override; Pulse virtual_get_next_pulse() override; }; diff --git a/Storage/Tape/PulseQueuedTape.cpp b/Storage/Tape/PulseQueuedTape.cpp index 42e16d45b..15f4fc5aa 100644 --- a/Storage/Tape/PulseQueuedTape.cpp +++ b/Storage/Tape/PulseQueuedTape.cpp @@ -12,11 +12,11 @@ using namespace Storage::Tape; PulseQueuedTape::PulseQueuedTape() : pulse_pointer_(0), is_at_end_(false) {} -bool PulseQueuedTape::is_at_end() { +bool PulseQueuedTape::is_at_end() const { return is_at_end_; } -void PulseQueuedTape::set_is_at_end(bool is_at_end) { +void PulseQueuedTape::set_is_at_end(const bool is_at_end) { is_at_end_ = is_at_end; } @@ -25,27 +25,23 @@ void PulseQueuedTape::clear() { pulse_pointer_ = 0; } -bool PulseQueuedTape::empty() { +bool PulseQueuedTape::empty() const { return queued_pulses_.empty(); } -void PulseQueuedTape::emplace_back(Tape::Pulse::Type type, Time length) { +void PulseQueuedTape::emplace_back(const Tape::Pulse::Type type, const Time length) { queued_pulses_.emplace_back(type, length); } -void PulseQueuedTape::emplace_back(const Tape::Pulse &&pulse) { - queued_pulses_.emplace_back(pulse); -} - -Tape::Pulse PulseQueuedTape::silence() { - Pulse silence; - silence.type = Pulse::Zero; - silence.length.length = 1; - silence.length.clock_rate = 1; - return silence; +void PulseQueuedTape::push_back(const Tape::Pulse pulse) { + queued_pulses_.push_back(pulse); } Tape::Pulse PulseQueuedTape::virtual_get_next_pulse() { + const auto silence = [] { + return Tape::Pulse(Tape::Pulse::Type::Zero, Storage::Time(1, 1)); + }; + if(is_at_end_) { return silence(); } @@ -59,7 +55,7 @@ Tape::Pulse PulseQueuedTape::virtual_get_next_pulse() { } } - std::size_t read_pointer = pulse_pointer_; + const std::size_t read_pointer = pulse_pointer_; pulse_pointer_++; return queued_pulses_[read_pointer]; } diff --git a/Storage/Tape/PulseQueuedTape.hpp b/Storage/Tape/PulseQueuedTape.hpp index 584814fb5..2fb2b5793 100644 --- a/Storage/Tape/PulseQueuedTape.hpp +++ b/Storage/Tape/PulseQueuedTape.hpp @@ -26,20 +26,19 @@ namespace Storage::Tape { class PulseQueuedTape: public Tape { public: PulseQueuedTape(); - bool is_at_end(); + bool is_at_end() const override; protected: void emplace_back(Tape::Pulse::Type type, Time length); - void emplace_back(const Tape::Pulse &&pulse); + void push_back(Tape::Pulse); void clear(); - bool empty(); + bool empty() const; void set_is_at_end(bool); virtual void get_next_pulses() = 0; private: - Pulse virtual_get_next_pulse(); - Pulse silence(); + Pulse virtual_get_next_pulse() override; std::vector queued_pulses_; std::size_t pulse_pointer_; diff --git a/Storage/Tape/Tape.cpp b/Storage/Tape/Tape.cpp index 9dcfa7165..910f2a1ea 100644 --- a/Storage/Tape/Tape.cpp +++ b/Storage/Tape/Tape.cpp @@ -49,7 +49,7 @@ Tape::Pulse Tape::get_next_pulse() { return pulse_; } -uint64_t Tape::get_offset() { +uint64_t Tape::get_offset() const { return offset_; } diff --git a/Storage/Tape/Tape.hpp b/Storage/Tape/Tape.hpp index d1a792d53..6011fffb9 100644 --- a/Storage/Tape/Tape.hpp +++ b/Storage/Tape/Tape.hpp @@ -54,14 +54,14 @@ public: void reset(); /// @returns @c true if the tape has progressed beyond all recorded content; @c false otherwise. - virtual bool is_at_end() = 0; + virtual bool is_at_end() const = 0; /*! Returns a numerical representation of progression into the tape. Precision is arbitrary but required to be at least to the whole pulse. Greater numbers are later than earlier numbers, but not necessarily continuous. */ - virtual uint64_t get_offset(); + virtual uint64_t get_offset() const; /*! Moves the tape to the first time at which the specified offset would be returned by get_offset. From 598003ea39380c190078744b3251f1727d5ff63d Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Tue, 3 Dec 2024 21:18:26 -0500 Subject: [PATCH 08/11] Continue marking override. --- Storage/Tape/Formats/TZX.hpp | 4 ++-- Storage/Tape/Formats/TapeUEF.hpp | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Storage/Tape/Formats/TZX.hpp b/Storage/Tape/Formats/TZX.hpp index a432d53c1..4d31e3ff3 100644 --- a/Storage/Tape/Formats/TZX.hpp +++ b/Storage/Tape/Formats/TZX.hpp @@ -34,8 +34,8 @@ public: private: Storage::FileHolder file_; - void virtual_reset(); - void get_next_pulses(); + void virtual_reset() override; + void get_next_pulses() override; bool current_level_; diff --git a/Storage/Tape/Formats/TapeUEF.hpp b/Storage/Tape/Formats/TapeUEF.hpp index 6122a688a..bb32ca0b1 100644 --- a/Storage/Tape/Formats/TapeUEF.hpp +++ b/Storage/Tape/Formats/TapeUEF.hpp @@ -36,10 +36,10 @@ public: }; private: - void virtual_reset(); + void virtual_reset() override; void set_platform_type(); - TargetPlatform::Type target_platform_type(); + TargetPlatform::Type target_platform_type() override; TargetPlatform::Type platform_type_ = TargetPlatform::Acorn; gzFile file_; @@ -53,7 +53,7 @@ private: }; bool get_next_chunk(Chunk &); - void get_next_pulses(); + void get_next_pulses() override; void queue_implicit_bit_pattern(uint32_t length); void queue_explicit_bit_pattern(uint32_t length); From 6d4ff0b89aa82b88bbcc52b41ded57da99b40253 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Tue, 3 Dec 2024 22:28:57 -0500 Subject: [PATCH 09/11] Finally eliminate all that `virtual_` nonsense. --- Machines/Acorn/Electron/Tape.cpp | 2 +- Machines/Acorn/Electron/Tape.hpp | 2 +- Storage/Tape/Formats/CAS.cpp | 10 ++- Storage/Tape/Formats/CAS.hpp | 55 ++++++------ Storage/Tape/Formats/CSW.cpp | 23 +++-- Storage/Tape/Formats/CSW.hpp | 41 +++++---- Storage/Tape/Formats/CommodoreTAP.cpp | 10 ++- Storage/Tape/Formats/CommodoreTAP.hpp | 24 +++--- Storage/Tape/Formats/OricTAP.cpp | 17 ++-- Storage/Tape/Formats/OricTAP.hpp | 34 ++++---- Storage/Tape/Formats/TZX.cpp | 91 +++++++++++--------- Storage/Tape/Formats/TZX.hpp | 114 ++++++++++++++----------- Storage/Tape/Formats/TapePRG.cpp | 22 ++--- Storage/Tape/Formats/TapePRG.hpp | 61 ++++++------- Storage/Tape/Formats/TapeUEF.cpp | 52 ++++++----- Storage/Tape/Formats/TapeUEF.hpp | 60 +++++++------ Storage/Tape/Formats/ZX80O81P.cpp | 20 +++-- Storage/Tape/Formats/ZX80O81P.hpp | 35 ++++---- Storage/Tape/Formats/ZXSpectrumTAP.cpp | 16 ++-- Storage/Tape/Formats/ZXSpectrumTAP.hpp | 34 ++++---- Storage/Tape/Parsers/Acorn.cpp | 6 +- Storage/Tape/Parsers/Acorn.hpp | 4 +- Storage/Tape/Parsers/Commodore.cpp | 4 +- Storage/Tape/Parsers/Commodore.hpp | 2 +- Storage/Tape/Parsers/Oric.cpp | 4 +- Storage/Tape/Parsers/Oric.hpp | 2 +- Storage/Tape/Parsers/Spectrum.cpp | 4 +- Storage/Tape/Parsers/Spectrum.hpp | 2 +- Storage/Tape/Parsers/TapeParser.hpp | 4 +- Storage/Tape/Parsers/ZX8081.cpp | 4 +- Storage/Tape/Parsers/ZX8081.hpp | 2 +- Storage/Tape/PulseQueuedTape.cpp | 18 ++-- Storage/Tape/PulseQueuedTape.hpp | 19 ++--- Storage/Tape/Tape.cpp | 25 ++++-- Storage/Tape/Tape.hpp | 59 +++++++------ 35 files changed, 488 insertions(+), 394 deletions(-) diff --git a/Machines/Acorn/Electron/Tape.cpp b/Machines/Acorn/Electron/Tape.cpp index ee6b94349..73d55a4a0 100644 --- a/Machines/Acorn/Electron/Tape.cpp +++ b/Machines/Acorn/Electron/Tape.cpp @@ -68,7 +68,7 @@ uint8_t Tape::get_data_register() { return uint8_t(data_register_ >> 2); } -void Tape::process_input_pulse(const Storage::Tape::Tape::Pulse &pulse) { +void Tape::process_input_pulse(const Storage::Tape::Pulse &pulse) { shifter_.process_pulse(pulse); } diff --git a/Machines/Acorn/Electron/Tape.hpp b/Machines/Acorn/Electron/Tape.hpp index 4ab9d94ee..1ecf532b2 100644 --- a/Machines/Acorn/Electron/Tape.hpp +++ b/Machines/Acorn/Electron/Tape.hpp @@ -46,7 +46,7 @@ public: void acorn_shifter_output_bit(int value); private: - void process_input_pulse(const Storage::Tape::Tape::Pulse &pulse); + void process_input_pulse(const Storage::Tape::Pulse &pulse); inline void push_tape_bit(uint16_t bit); inline void get_next_tape_pulse(); diff --git a/Storage/Tape/Formats/CAS.cpp b/Storage/Tape/Formats/CAS.cpp index b07db8216..cfca7aa43 100644 --- a/Storage/Tape/Formats/CAS.cpp +++ b/Storage/Tape/Formats/CAS.cpp @@ -59,7 +59,9 @@ namespace { const uint8_t ascii_signature[] = TenX(0xea); } -CAS::CAS(const std::string &file_name) { +CAS::CAS(const std::string &file_name) : Tape(serialiser_), serialiser_(file_name) {} + +CAS::Serialiser::Serialiser(const std::string &file_name) { Storage::FileHolder file(file_name, FileHolder::FileMode::Read); enum class Mode { @@ -168,18 +170,18 @@ CAS::CAS(const std::string &file_name) { } } -bool CAS::is_at_end() const { +bool CAS::Serialiser::is_at_end() const { return phase_ == Phase::EndOfFile; } -void CAS::virtual_reset() { +void CAS::Serialiser::reset() { phase_ = Phase::Header; chunk_pointer_ = 0; distance_into_phase_ = 0; distance_into_bit_ = 0; } -Tape::Pulse CAS::virtual_get_next_pulse() { +Pulse CAS::Serialiser::get_next_pulse() { Pulse pulse; pulse.length.clock_rate = 9600; // Clock rate is four times the baud rate (of 2400), because the quickest thing that might need diff --git a/Storage/Tape/Formats/CAS.hpp b/Storage/Tape/Formats/CAS.hpp index 5ec222f53..f21904fbc 100644 --- a/Storage/Tape/Formats/CAS.hpp +++ b/Storage/Tape/Formats/CAS.hpp @@ -33,36 +33,39 @@ public: ErrorNotCAS }; - // implemented to satisfy @c Tape - bool is_at_end() const override; - private: - void virtual_reset() override; - Pulse virtual_get_next_pulse() override; + struct Serialiser: public TapeSerialiser { + Serialiser(const std::string &file_name); - // Storage for the array of data blobs to transcribe into audio; - // each chunk is preceded by a header which may be long, and is optionally - // also preceded by a gap. - struct Chunk { - bool has_gap; - bool long_header; - std::vector data; + private: + bool is_at_end() const override; + void reset() override; + Pulse get_next_pulse() override; - Chunk(bool has_gap, bool long_header, const std::vector &data) : - has_gap(has_gap), long_header(long_header), data(std::move(data)) {} - }; - std::vector chunks_; + // Storage for the array of data blobs to transcribe into audio; + // each chunk is preceded by a header which may be long, and is optionally + // also preceded by a gap. + struct Chunk { + bool has_gap; + bool long_header; + std::vector data; - // Tracker for active state within the file list. - std::size_t chunk_pointer_ = 0; - enum class Phase { - Header, - Bytes, - Gap, - EndOfFile - } phase_ = Phase::Header; - std::size_t distance_into_phase_ = 0; - std::size_t distance_into_bit_ = 0; + Chunk(bool has_gap, bool long_header, const std::vector &data) : + has_gap(has_gap), long_header(long_header), data(std::move(data)) {} + }; + std::vector chunks_; + + // Tracker for active state within the file list. + std::size_t chunk_pointer_ = 0; + enum class Phase { + Header, + Bytes, + Gap, + EndOfFile + } phase_ = Phase::Header; + std::size_t distance_into_phase_ = 0; + std::size_t distance_into_bit_ = 0; + } serialiser_; }; } diff --git a/Storage/Tape/Formats/CSW.cpp b/Storage/Tape/Formats/CSW.cpp index 251ad4fab..7524bc2ca 100644 --- a/Storage/Tape/Formats/CSW.cpp +++ b/Storage/Tape/Formats/CSW.cpp @@ -14,7 +14,14 @@ using namespace Storage::Tape; -CSW::CSW(const std::string &file_name) : +CSW::CSW(const std::string &file_name) : Tape(serialiser_), serialiser_(file_name) {} + +CSW::CSW(const std::vector &&data, CompressionType type, bool initial_level, uint32_t sampling_rate) : + Tape(serialiser_), + serialiser_(std::move(data), type, initial_level, sampling_rate) {} + + +CSW::Serialiser::Serialiser(const std::string &file_name) : source_data_pointer_(0) { Storage::FileHolder file(file_name, FileHolder::FileMode::Read); if(file.stats().st_size < 0x20) throw ErrorNotCSW; @@ -86,20 +93,20 @@ CSW::CSW(const std::string &file_name) : invert_pulse(); } -CSW::CSW(const std::vector &&data, CompressionType compression_type, bool initial_level, uint32_t sampling_rate) : compression_type_(compression_type) { +CSW::Serialiser::Serialiser(const std::vector &&data, CompressionType compression_type, bool initial_level, uint32_t sampling_rate) : compression_type_(compression_type) { pulse_.length.clock_rate = sampling_rate; pulse_.type = initial_level ? Pulse::High : Pulse::Low; source_data_ = std::move(data); } -uint8_t CSW::get_next_byte() { +uint8_t CSW::Serialiser::get_next_byte() { if(source_data_pointer_ == source_data_.size()) return 0xff; uint8_t result = source_data_[source_data_pointer_]; source_data_pointer_++; return result; } -uint32_t CSW::get_next_int32le() { +uint32_t CSW::Serialiser::get_next_int32le() { if(source_data_pointer_ > source_data_.size() - 4) return 0xffff; uint32_t result = uint32_t( (source_data_[source_data_pointer_ + 0] << 0) | @@ -110,19 +117,19 @@ uint32_t CSW::get_next_int32le() { return result; } -void CSW::invert_pulse() { +void CSW::Serialiser::invert_pulse() { pulse_.type = (pulse_.type == Pulse::High) ? Pulse::Low : Pulse::High; } -bool CSW::is_at_end() const { +bool CSW::Serialiser::is_at_end() const { return source_data_pointer_ == source_data_.size(); } -void CSW::virtual_reset() { +void CSW::Serialiser::reset() { source_data_pointer_ = 0; } -Tape::Pulse CSW::virtual_get_next_pulse() { +Pulse CSW::Serialiser::get_next_pulse() { invert_pulse(); pulse_.length.length = get_next_byte(); if(!pulse_.length.length) pulse_.length.length = get_next_int32le(); diff --git a/Storage/Tape/Formats/CSW.hpp b/Storage/Tape/Formats/CSW.hpp index 318911c1a..19902113f 100644 --- a/Storage/Tape/Formats/CSW.hpp +++ b/Storage/Tape/Formats/CSW.hpp @@ -21,6 +21,11 @@ namespace Storage::Tape { */ class CSW: public Tape { public: + enum class CompressionType { + RLE, + ZRLE + }; + /*! Constructs a @c CSW containing content from the file with name @c file_name. @@ -28,36 +33,36 @@ public: */ CSW(const std::string &file_name); - enum class CompressionType { - RLE, - ZRLE - }; - /*! Constructs a @c CSW containing content as specified. Does not throw. */ - CSW(const std::vector &&data, CompressionType compression_type, bool initial_level, uint32_t sampling_rate); + CSW(const std::vector &&data, CompressionType, bool initial_level, uint32_t sampling_rate); enum { ErrorNotCSW }; - // implemented to satisfy @c Tape - bool is_at_end() const override; - private: - void virtual_reset() override; - Pulse virtual_get_next_pulse() override; + struct Serialiser: public TapeSerialiser { + Serialiser(const std::string &file_name); + Serialiser(const std::vector &&data, CompressionType, bool initial_level, uint32_t sampling_rate); - Pulse pulse_; - CompressionType compression_type_; + private: + // implemented to satisfy @c Tape + bool is_at_end() const override; + void reset() override; + Pulse get_next_pulse() override; - uint8_t get_next_byte(); - uint32_t get_next_int32le(); - void invert_pulse(); + Pulse pulse_; + CompressionType compression_type_; - std::vector source_data_; - std::size_t source_data_pointer_; + uint8_t get_next_byte(); + uint32_t get_next_int32le(); + void invert_pulse(); + + std::vector source_data_; + std::size_t source_data_pointer_; + } serialiser_; }; } diff --git a/Storage/Tape/Formats/CommodoreTAP.cpp b/Storage/Tape/Formats/CommodoreTAP.cpp index 6a9044901..95749fb29 100644 --- a/Storage/Tape/Formats/CommodoreTAP.cpp +++ b/Storage/Tape/Formats/CommodoreTAP.cpp @@ -12,7 +12,9 @@ using namespace Storage::Tape; -CommodoreTAP::CommodoreTAP(const std::string &file_name) : +CommodoreTAP::CommodoreTAP(const std::string &file_name) : Tape(serialiser_), serialiser_(file_name) {} + +CommodoreTAP::Serialiser::Serialiser(const std::string &file_name) : file_(file_name, FileHolder::FileMode::Read) { if(!file_.check_signature("C64-TAPE-RAW")) @@ -39,17 +41,17 @@ CommodoreTAP::CommodoreTAP(const std::string &file_name) : current_pulse_.type = Pulse::High; } -void CommodoreTAP::virtual_reset() { +void CommodoreTAP::Serialiser::reset() { file_.seek(0x14, SEEK_SET); current_pulse_.type = Pulse::High; is_at_end_ = false; } -bool CommodoreTAP::is_at_end() const { +bool CommodoreTAP::Serialiser::is_at_end() const { return is_at_end_; } -Storage::Tape::Tape::Pulse CommodoreTAP::virtual_get_next_pulse() { +Storage::Tape::Pulse CommodoreTAP::Serialiser::get_next_pulse() { if(is_at_end_) { return current_pulse_; } diff --git a/Storage/Tape/Formats/CommodoreTAP.hpp b/Storage/Tape/Formats/CommodoreTAP.hpp index 7a27ef0df..cc0e80134 100644 --- a/Storage/Tape/Formats/CommodoreTAP.hpp +++ b/Storage/Tape/Formats/CommodoreTAP.hpp @@ -32,19 +32,23 @@ public: ErrorNotCommodoreTAP }; - // implemented to satisfy @c Tape - bool is_at_end() const override; - private: - Storage::FileHolder file_; - void virtual_reset() override; - Pulse virtual_get_next_pulse() override; + struct Serialiser: public TapeSerialiser { + Serialiser(const std::string &file_name); - bool updated_layout_; - uint32_t file_size_; + private: + bool is_at_end() const override; + void reset() override; + Pulse get_next_pulse() override; - Pulse current_pulse_; - bool is_at_end_ = false; + Storage::FileHolder file_; + + bool updated_layout_; + uint32_t file_size_; + + Pulse current_pulse_; + bool is_at_end_ = false; + } serialiser_; }; } diff --git a/Storage/Tape/Formats/OricTAP.cpp b/Storage/Tape/Formats/OricTAP.cpp index efd41a057..69678d747 100644 --- a/Storage/Tape/Formats/OricTAP.cpp +++ b/Storage/Tape/Formats/OricTAP.cpp @@ -12,7 +12,10 @@ using namespace Storage::Tape; -OricTAP::OricTAP(const std::string &file_name) : +OricTAP::OricTAP(const std::string &file_name) : Tape(serialiser_), serialiser_(file_name) {} + + +OricTAP::Serialiser::Serialiser(const std::string &file_name) : file_(file_name, FileHolder::FileMode::Read) { // Check for a sequence of at least three 0x16s followed by a 0x24. @@ -29,11 +32,11 @@ OricTAP::OricTAP(const std::string &file_name) : } } - // then rewind and start again - virtual_reset(); + // Rewind and start again. + reset(); } -void OricTAP::virtual_reset() { +void OricTAP::Serialiser::reset() { file_.seek(0, SEEK_SET); bit_count_ = 13; phase_ = next_phase_ = LeadIn; @@ -41,7 +44,7 @@ void OricTAP::virtual_reset() { pulse_counter_ = 0; } -Tape::Pulse OricTAP::virtual_get_next_pulse() { +Pulse OricTAP::Serialiser::get_next_pulse() { // Each byte byte is written as 13 bits: 0, eight bits of data, parity, three 1s. if(bit_count_ == 13) { if(next_phase_ != phase_) { @@ -122,7 +125,7 @@ Tape::Pulse OricTAP::virtual_get_next_pulse() { // In slow mode, a 0 is 4 periods of 1200 Hz, a 1 is 8 periods at 2400 Hz. // In fast mode, a 1 is a single period of 2400 Hz, a 0 is a 2400 Hz pulse followed by a 1200 Hz pulse. // This code models fast mode. - Tape::Pulse pulse; + Pulse pulse; pulse.length.clock_rate = 4800; int next_bit; @@ -158,6 +161,6 @@ Tape::Pulse OricTAP::virtual_get_next_pulse() { return pulse; } -bool OricTAP::is_at_end() const { +bool OricTAP::Serialiser::is_at_end() const { return phase_ == End; } diff --git a/Storage/Tape/Formats/OricTAP.hpp b/Storage/Tape/Formats/OricTAP.hpp index ff96d2ae3..0faa58875 100644 --- a/Storage/Tape/Formats/OricTAP.hpp +++ b/Storage/Tape/Formats/OricTAP.hpp @@ -32,24 +32,28 @@ public: ErrorNotOricTAP }; - // implemented to satisfy @c Tape - bool is_at_end() const override; - private: - Storage::FileHolder file_; - void virtual_reset() override; - Pulse virtual_get_next_pulse() override; + struct Serialiser: public TapeSerialiser { + Serialiser(const std::string &file_name); - // byte serialisation and output - uint16_t current_value_; - int bit_count_; - int pulse_counter_; + private: + bool is_at_end() const override; + void reset() override; + Pulse get_next_pulse() override; - enum Phase { - LeadIn, Header, Data, Gap, End - } phase_, next_phase_; - int phase_counter_; - uint16_t data_end_address_, data_start_address_; + Storage::FileHolder file_; + + // byte serialisation and output + uint16_t current_value_; + int bit_count_; + int pulse_counter_; + + enum Phase { + LeadIn, Header, Data, Gap, End + } phase_, next_phase_; + int phase_counter_; + uint16_t data_end_address_, data_start_address_; + } serialiser_; }; } diff --git a/Storage/Tape/Formats/TZX.cpp b/Storage/Tape/Formats/TZX.cpp index 1349e8add..6b52c28cd 100644 --- a/Storage/Tape/Formats/TZX.cpp +++ b/Storage/Tape/Formats/TZX.cpp @@ -21,7 +21,9 @@ Log::Logger logger; } -TZX::TZX(const std::string &file_name) : +TZX::TZX(const std::string &file_name) : Tape(serialiser_), serialiser_(file_name) {} + +TZX::Serialiser::Serialiser(const std::string &file_name) : file_(file_name, FileHolder::FileMode::Read), current_level_(false) { @@ -36,10 +38,10 @@ TZX::TZX(const std::string &file_name) : // Reject if an incompatible version if(major_version != 1 || minor_version > 21) throw ErrorNotTZX; - virtual_reset(); + reset(); } -void TZX::virtual_reset() { +void TZX::Serialiser::reset() { clear(); set_is_at_end(false); file_.seek(0x0a, SEEK_SET); @@ -51,7 +53,7 @@ void TZX::virtual_reset() { post_gap(500); } -void TZX::get_next_pulses() { +void TZX::Serialiser::get_next_pulses() { while(empty()) { uint8_t chunk_id = file_.get8(); if(file_.eof()) { @@ -102,7 +104,7 @@ void TZX::get_next_pulses() { } } -void TZX::get_csw_recording_block() { +void TZX::Serialiser::get_csw_recording_block() { const uint32_t block_length = file_.get32le(); const uint16_t pause_after_block = file_.get16le(); const uint32_t sampling_rate = file_.get24le(); @@ -113,8 +115,8 @@ void TZX::get_csw_recording_block() { CSW csw(std::move(raw_block), (compression_type == 2) ? CSW::CompressionType::ZRLE : CSW::CompressionType::RLE, current_level_, sampling_rate); while(!csw.is_at_end()) { - Tape::Pulse next_pulse = csw.get_next_pulse(); - current_level_ = (next_pulse.type == Tape::Pulse::High); + Pulse next_pulse = csw.get_next_pulse(); + current_level_ = (next_pulse.type == Pulse::High); push_back(next_pulse); } @@ -122,7 +124,7 @@ void TZX::get_csw_recording_block() { post_gap(pause_after_block); } -void TZX::get_generalised_data_block() { +void TZX::Serialiser::get_generalised_data_block() { uint32_t block_length = file_.get32le(); long endpoint = file_.tell() + long(block_length); uint16_t pause_after_block = file_.get16le(); @@ -143,7 +145,12 @@ void TZX::get_generalised_data_block() { file_.seek(endpoint, SEEK_SET); } -void TZX::get_generalised_segment(uint32_t output_symbols, uint8_t max_pulses_per_symbol, uint8_t number_of_symbols, bool is_data) { +void TZX::Serialiser::get_generalised_segment( + uint32_t output_symbols, + uint8_t max_pulses_per_symbol, + uint8_t number_of_symbols, + bool is_data +) { if(!output_symbols) return; // Construct the symbol table. @@ -202,7 +209,7 @@ void TZX::get_generalised_segment(uint32_t output_symbols, uint8_t max_pulses_pe } } -void TZX::get_standard_speed_data_block() { +void TZX::Serialiser::get_standard_speed_data_block() { DataBlock data_block; data_block.length_of_pilot_pulse = 2168; data_block.length_of_sync_first_pulse = 667; @@ -222,7 +229,7 @@ void TZX::get_standard_speed_data_block() { get_data_block(data_block); } -void TZX::get_turbo_speed_data_block() { +void TZX::Serialiser::get_turbo_speed_data_block() { DataBlock data_block; data_block.length_of_pilot_pulse = file_.get16le(); data_block.length_of_sync_first_pulse = file_.get16le(); @@ -237,7 +244,7 @@ void TZX::get_turbo_speed_data_block() { get_data_block(data_block); } -void TZX::get_data_block(const DataBlock &data_block) { +void TZX::Serialiser::get_data_block(const DataBlock &data_block) { // Output pilot tone. post_pulses(data_block.length_of_pilot_tone, data_block.length_of_pilot_pulse); @@ -248,7 +255,7 @@ void TZX::get_data_block(const DataBlock &data_block) { get_data(data_block.data); } -void TZX::get_data(const Data &data) { +void TZX::Serialiser::get_data(const Data &data) { // Output data. for(decltype(data.data_length) c = 0; c < data.data_length; c++) { uint8_t next_byte = file_.get8(); @@ -267,14 +274,14 @@ void TZX::get_data(const Data &data) { post_gap(data.pause_after_block); } -void TZX::get_pure_tone_data_block() { +void TZX::Serialiser::get_pure_tone_data_block() { uint16_t length_of_pulse = file_.get16le(); uint16_t nunber_of_pulses = file_.get16le(); post_pulses(nunber_of_pulses, length_of_pulse); } -void TZX::get_pure_data_block() { +void TZX::Serialiser::get_pure_data_block() { Data data; data.length_of_zero_bit_pulse = file_.get16le(); data.length_of_one_bit_pulse = file_.get16le(); @@ -285,7 +292,7 @@ void TZX::get_pure_data_block() { get_data(data); } -void TZX::get_direct_recording_block() { +void TZX::Serialiser::get_direct_recording_block() { const Storage::Time length_per_sample(unsigned(file_.get16le()), StandardTZXClock); const uint16_t pause_after_block = file_.get16le(); uint8_t used_bits_in_final_byte = file_.get8(); @@ -302,7 +309,7 @@ void TZX::get_direct_recording_block() { if(!bit) level = byte&0x80; if((byte&0x80) != level) { - emplace_back(level ? Tape::Pulse::High : Tape::Pulse::Low, length_per_sample * bits_at_level); + emplace_back(level ? Pulse::High : Pulse::Low, length_per_sample * bits_at_level); bits_at_level = 0; level = byte&0x80; } @@ -310,19 +317,19 @@ void TZX::get_direct_recording_block() { } current_level_ = !!(level); - emplace_back(level ? Tape::Pulse::High : Tape::Pulse::Low, length_per_sample * bits_at_level); + emplace_back(level ? Pulse::High : Pulse::Low, length_per_sample * bits_at_level); post_gap(pause_after_block); } -void TZX::get_pulse_sequence() { +void TZX::Serialiser::get_pulse_sequence() { uint8_t number_of_pulses = file_.get8(); while(number_of_pulses--) { post_pulse(file_.get16le()); } } -void TZX::get_pause() { +void TZX::Serialiser::get_pause() { uint16_t duration = file_.get16le(); if(!duration) { // TODO (maybe): post a 'pause the tape' suggestion @@ -331,13 +338,13 @@ void TZX::get_pause() { } } -void TZX::get_set_signal_level() { +void TZX::Serialiser::get_set_signal_level() { file_.seek(4, SEEK_CUR); const uint8_t level = file_.get8(); current_level_ = !!level; } -void TZX::get_kansas_city_block() { +void TZX::Serialiser::get_kansas_city_block() { uint32_t block_length = file_.get32le(); const uint16_t pause_after_block = file_.get16le(); @@ -395,15 +402,15 @@ void TZX::get_kansas_city_block() { // MARK: - Output -void TZX::post_pulses(unsigned int count, unsigned int length) { +void TZX::Serialiser::post_pulses(unsigned int count, unsigned int length) { while(count--) post_pulse(length); } -void TZX::post_pulse(unsigned int length) { +void TZX::Serialiser::post_pulse(unsigned int length) { post_pulse(Storage::Time(length, StandardTZXClock)); } -void TZX::post_gap(unsigned int milliseconds) { +void TZX::Serialiser::post_gap(unsigned int milliseconds) { if(!milliseconds) return; if(milliseconds > 1 && !current_level_) { post_pulse(Storage::Time(TZXClockMSMultiplier, StandardTZXClock)); @@ -413,52 +420,52 @@ void TZX::post_gap(unsigned int milliseconds) { } } -void TZX::post_pulse(const Storage::Time &time) { - emplace_back(current_level_ ? Tape::Pulse::High : Tape::Pulse::Low, time); +void TZX::Serialiser::post_pulse(const Storage::Time &time) { + emplace_back(current_level_ ? Pulse::High : Pulse::Low, time); current_level_ ^= true; } // MARK: - Flow control; currently ignored -void TZX::ignore_group_start() { +void TZX::Serialiser::ignore_group_start() { uint8_t length = file_.get8(); file_.seek(length, SEEK_CUR); } -void TZX::ignore_group_end() { +void TZX::Serialiser::ignore_group_end() { } -void TZX::ignore_jump_to_block() { +void TZX::Serialiser::ignore_jump_to_block() { uint16_t target = file_.get16le(); (void)target; } -void TZX::ignore_loop_start() { +void TZX::Serialiser::ignore_loop_start() { uint16_t number_of_repetitions = file_.get16le(); (void)number_of_repetitions; } -void TZX::ignore_loop_end() { +void TZX::Serialiser::ignore_loop_end() { } -void TZX::ignore_call_sequence() { +void TZX::Serialiser::ignore_call_sequence() { uint16_t number_of_entries = file_.get16le(); file_.seek(number_of_entries * sizeof(uint16_t), SEEK_CUR); } -void TZX::ignore_return_from_sequence() { +void TZX::Serialiser::ignore_return_from_sequence() { } -void TZX::ignore_select_block() { +void TZX::Serialiser::ignore_select_block() { uint16_t length_of_block = file_.get16le(); file_.seek(length_of_block, SEEK_CUR); } -void TZX::ignore_stop_tape_if_in_48kb_mode() { +void TZX::Serialiser::ignore_stop_tape_if_in_48kb_mode() { file_.seek(4, SEEK_CUR); } -void TZX::ignore_custom_info_block() { +void TZX::Serialiser::ignore_custom_info_block() { file_.seek(0x10, SEEK_CUR); uint32_t length = file_.get32le(); file_.seek(length, SEEK_CUR); @@ -466,29 +473,29 @@ void TZX::ignore_custom_info_block() { // MARK: - Messaging -void TZX::ignore_text_description() { +void TZX::Serialiser::ignore_text_description() { uint8_t length = file_.get8(); file_.seek(length, SEEK_CUR); } -void TZX::ignore_message_block() { +void TZX::Serialiser::ignore_message_block() { uint8_t time_for_display = file_.get8(); uint8_t length = file_.get8(); file_.seek(length, SEEK_CUR); (void)time_for_display; } -void TZX::ignore_archive_info() { +void TZX::Serialiser::ignore_archive_info() { uint16_t length = file_.get16le(); file_.seek(length, SEEK_CUR); } -void TZX::get_hardware_type() { +void TZX::Serialiser::get_hardware_type() { // TODO: pick a way to retain and communicate this. uint8_t number_of_machines = file_.get8(); file_.seek(number_of_machines * 3, SEEK_CUR); } -void TZX::ignore_glue_block() { +void TZX::Serialiser::ignore_glue_block() { file_.seek(9, SEEK_CUR); } diff --git a/Storage/Tape/Formats/TZX.hpp b/Storage/Tape/Formats/TZX.hpp index 4d31e3ff3..c17e282b1 100644 --- a/Storage/Tape/Formats/TZX.hpp +++ b/Storage/Tape/Formats/TZX.hpp @@ -18,7 +18,7 @@ namespace Storage::Tape { /*! Provides a @c Tape containing a CSW tape image, which is a compressed 1-bit sampling. */ -class TZX: public PulseQueuedTape { +class TZX: public Tape { public: /*! Constructs a @c TZX containing content from the file with name @c file_name. @@ -32,69 +32,79 @@ public: }; private: - Storage::FileHolder file_; + struct Serialiser: public PulseQueuedSerialiser { + Serialiser(const std::string &file_name); - void virtual_reset() override; - void get_next_pulses() override; + private: + Storage::FileHolder file_; - bool current_level_; + void reset() override; + void get_next_pulses() override; - void get_standard_speed_data_block(); - void get_turbo_speed_data_block(); - void get_pure_tone_data_block(); - void get_pulse_sequence(); - void get_pure_data_block(); - void get_direct_recording_block(); - void get_csw_recording_block(); - void get_generalised_data_block(); - void get_pause(); + bool current_level_; - void ignore_group_start(); - void ignore_group_end(); - void ignore_jump_to_block(); - void ignore_loop_start(); - void ignore_loop_end(); - void ignore_call_sequence(); - void ignore_return_from_sequence(); - void ignore_select_block(); - void ignore_stop_tape_if_in_48kb_mode(); + void get_standard_speed_data_block(); + void get_turbo_speed_data_block(); + void get_pure_tone_data_block(); + void get_pulse_sequence(); + void get_pure_data_block(); + void get_direct_recording_block(); + void get_csw_recording_block(); + void get_generalised_data_block(); + void get_pause(); - void get_set_signal_level(); + void ignore_group_start(); + void ignore_group_end(); + void ignore_jump_to_block(); + void ignore_loop_start(); + void ignore_loop_end(); + void ignore_call_sequence(); + void ignore_return_from_sequence(); + void ignore_select_block(); + void ignore_stop_tape_if_in_48kb_mode(); - void ignore_text_description(); - void ignore_message_block(); - void ignore_archive_info(); - void get_hardware_type(); - void ignore_custom_info_block(); + void get_set_signal_level(); - void get_kansas_city_block(); - void ignore_glue_block(); + void ignore_text_description(); + void ignore_message_block(); + void ignore_archive_info(); + void get_hardware_type(); + void ignore_custom_info_block(); - struct Data { - unsigned int length_of_zero_bit_pulse; - unsigned int length_of_one_bit_pulse; - unsigned int number_of_bits_in_final_byte; - unsigned int pause_after_block; - uint32_t data_length; - }; + void get_kansas_city_block(); + void ignore_glue_block(); - struct DataBlock { - unsigned int length_of_pilot_pulse; - unsigned int length_of_sync_first_pulse; - unsigned int length_of_sync_second_pulse; - unsigned int length_of_pilot_tone; - Data data; - }; + struct Data { + unsigned int length_of_zero_bit_pulse; + unsigned int length_of_one_bit_pulse; + unsigned int number_of_bits_in_final_byte; + unsigned int pause_after_block; + uint32_t data_length; + }; - void get_generalised_segment(uint32_t output_symbols, uint8_t max_pulses_per_symbol, uint8_t number_of_symbols, bool is_data); - void get_data_block(const DataBlock &); - void get_data(const Data &); + struct DataBlock { + unsigned int length_of_pilot_pulse; + unsigned int length_of_sync_first_pulse; + unsigned int length_of_sync_second_pulse; + unsigned int length_of_pilot_tone; + Data data; + }; - void post_pulses(unsigned int count, unsigned int length); - void post_pulse(unsigned int length); - void post_gap(unsigned int milliseconds); + void get_generalised_segment( + uint32_t output_symbols, + uint8_t max_pulses_per_symbol, + uint8_t number_of_symbols, + bool is_data + ); + void get_data_block(const DataBlock &); + void get_data(const Data &); - void post_pulse(const Storage::Time &time); + void post_pulses(unsigned int count, unsigned int length); + void post_pulse(unsigned int length); + void post_gap(unsigned int milliseconds); + + void post_pulse(const Storage::Time &time); + } serialiser_; }; } diff --git a/Storage/Tape/Formats/TapePRG.cpp b/Storage/Tape/Formats/TapePRG.cpp index c5ddb6fa9..1a1ff9c9c 100644 --- a/Storage/Tape/Formats/TapePRG.cpp +++ b/Storage/Tape/Formats/TapePRG.cpp @@ -48,7 +48,9 @@ using namespace Storage::Tape; -PRG::PRG(const std::string &file_name) : +PRG::PRG(const std::string &file_name) : Tape(serialiser_), serialiser_(file_name) {} + +PRG::Serialiser::Serialiser(const std::string &file_name) : file_(file_name, FileHolder::FileMode::Read) { // There's really no way to validate other than that if this file is larger than 64kb, @@ -63,7 +65,7 @@ PRG::PRG(const std::string &file_name) : throw ErrorBadFormat; } -Storage::Tape::Tape::Pulse PRG::virtual_get_next_pulse() { +Storage::Tape::Pulse PRG::Serialiser::get_next_pulse() { // these are all microseconds per pole constexpr unsigned int leader_zero_length = 179; constexpr unsigned int zero_length = 169; @@ -73,21 +75,21 @@ Storage::Tape::Tape::Pulse PRG::virtual_get_next_pulse() { bit_phase_ = (bit_phase_+1)&3; if(!bit_phase_) get_next_output_token(); - Tape::Pulse pulse; + Pulse pulse; pulse.length.clock_rate = 1000000; - pulse.type = (bit_phase_&1) ? Tape::Pulse::High : Tape::Pulse::Low; + pulse.type = (bit_phase_&1) ? Pulse::High : Pulse::Low; switch(output_token_) { case Leader: pulse.length.length = leader_zero_length; break; - case Zero: pulse.length.length = (bit_phase_&2) ? one_length : zero_length; break; - case One: pulse.length.length = (bit_phase_&2) ? zero_length : one_length; break; + case Zero: pulse.length.length = (bit_phase_&2) ? one_length : zero_length; break; + case One: pulse.length.length = (bit_phase_&2) ? zero_length : one_length; break; case WordMarker: pulse.length.length = (bit_phase_&2) ? one_length : marker_length; break; case EndOfBlock: pulse.length.length = (bit_phase_&2) ? zero_length : marker_length; break; - case Silence: pulse.type = Tape::Pulse::Zero; pulse.length.length = 5000; break; + case Silence: pulse.type = Pulse::Zero; pulse.length.length = 5000; break; } return pulse; } -void PRG::virtual_reset() { +void PRG::Serialiser::reset() { bit_phase_ = 3; file_.seek(2, SEEK_SET); file_phase_ = FilePhaseLeadIn; @@ -95,11 +97,11 @@ void PRG::virtual_reset() { copy_mask_ = 0x80; } -bool PRG::is_at_end() const { +bool PRG::Serialiser::is_at_end() const { return file_phase_ == FilePhaseAtEnd; } -void PRG::get_next_output_token() { +void PRG::Serialiser::get_next_output_token() { constexpr int block_length = 192; // not counting the checksum constexpr int countdown_bytes = 9; constexpr int leadin_length = 20000; diff --git a/Storage/Tape/Formats/TapePRG.hpp b/Storage/Tape/Formats/TapePRG.hpp index c33143f8f..45a0bdb0d 100644 --- a/Storage/Tape/Formats/TapePRG.hpp +++ b/Storage/Tape/Formats/TapePRG.hpp @@ -33,39 +33,42 @@ public: ErrorBadFormat }; - // implemented to satisfy @c Tape - bool is_at_end() const override; - private: - FileHolder file_; - Pulse virtual_get_next_pulse() override; - void virtual_reset() override; + struct Serialiser: public TapeSerialiser { + Serialiser(const std::string &file_name); + private: + bool is_at_end() const override; + Pulse get_next_pulse() override; + void reset() override; - uint16_t load_address_; - uint16_t length_; + FileHolder file_; - enum FilePhase { - FilePhaseLeadIn, - FilePhaseHeader, - FilePhaseHeaderDataGap, - FilePhaseData, - FilePhaseAtEnd - } file_phase_ = FilePhaseLeadIn; - int phase_offset_ = 0; + uint16_t load_address_; + uint16_t length_; - int bit_phase_ = 3; - enum OutputToken { - Leader, - Zero, - One, - WordMarker, - EndOfBlock, - Silence - } output_token_; - void get_next_output_token(); - uint8_t output_byte_; - uint8_t check_digit_; - uint8_t copy_mask_ = 0x80; + enum FilePhase { + FilePhaseLeadIn, + FilePhaseHeader, + FilePhaseHeaderDataGap, + FilePhaseData, + FilePhaseAtEnd + } file_phase_ = FilePhaseLeadIn; + int phase_offset_ = 0; + + int bit_phase_ = 3; + enum OutputToken { + Leader, + Zero, + One, + WordMarker, + EndOfBlock, + Silence + } output_token_; + void get_next_output_token(); + uint8_t output_byte_; + uint8_t check_digit_; + uint8_t copy_mask_ = 0x80; + } serialiser_; }; } diff --git a/Storage/Tape/Formats/TapeUEF.cpp b/Storage/Tape/Formats/TapeUEF.cpp index dd0d5c3fd..455760388 100644 --- a/Storage/Tape/Formats/TapeUEF.cpp +++ b/Storage/Tape/Formats/TapeUEF.cpp @@ -18,11 +18,9 @@ namespace { Log::Logger logger; -} - // MARK: - ZLib extensions -static float gzgetfloat(gzFile file) { +float gzgetfloat(gzFile file) { uint8_t bytes[4]; gzread(file, bytes, 4); @@ -49,34 +47,38 @@ static float gzgetfloat(gzFile file) { return result; } -static uint8_t gzget8(gzFile file) { +uint8_t gzget8(gzFile file) { // This is a workaround for gzgetc, which seems to be broken in ZLib 1.2.8. uint8_t result; gzread(file, &result, 1); return result; } -static int gzget16(gzFile file) { +int gzget16(gzFile file) { uint8_t bytes[2]; gzread(file, bytes, 2); return bytes[0] | (bytes[1] << 8); } -static int gzget24(gzFile file) { +int gzget24(gzFile file) { uint8_t bytes[3]; gzread(file, bytes, 3); return bytes[0] | (bytes[1] << 8) | (bytes[2] << 16); } -static int gzget32(gzFile file) { +int gzget32(gzFile file) { uint8_t bytes[4]; gzread(file, bytes, 4); return bytes[0] | (bytes[1] << 8) | (bytes[2] << 16) | (bytes[3] << 24); } +} + using namespace Storage::Tape; -UEF::UEF(const std::string &file_name) { +UEF::UEF(const std::string &file_name) : Tape(serialiser_), serialiser_(file_name) {} + +UEF::Serialiser::Serialiser(const std::string &file_name) { file_ = gzopen(file_name.c_str(), "rb"); char identifier[10]; @@ -95,13 +97,13 @@ UEF::UEF(const std::string &file_name) { set_platform_type(); } -UEF::~UEF() { +UEF::Serialiser::~Serialiser() { gzclose(file_); } // MARK: - Public methods -void UEF::virtual_reset() { +void UEF::Serialiser::reset() { gzseek(file_, 12, SEEK_SET); set_is_at_end(false); clear(); @@ -109,7 +111,7 @@ void UEF::virtual_reset() { // MARK: - Chunk navigator -bool UEF::get_next_chunk(UEF::Chunk &result) { +bool UEF::Serialiser::get_next_chunk(Chunk &result) { const uint16_t chunk_id = uint16_t(gzget16(file_)); const uint32_t chunk_length = uint32_t(gzget32(file_)); const z_off_t start_of_next_chunk = gztell(file_) + chunk_length; @@ -125,7 +127,7 @@ bool UEF::get_next_chunk(UEF::Chunk &result) { return true; } -void UEF::get_next_pulses() { +void UEF::Serialiser::get_next_pulses() { while(empty()) { // read chunk details Chunk next_chunk; @@ -171,13 +173,13 @@ void UEF::get_next_pulses() { // MARK: - Chunk parsers -void UEF::queue_implicit_bit_pattern(uint32_t length) { +void UEF::Serialiser::queue_implicit_bit_pattern(uint32_t length) { while(length--) { queue_implicit_byte(gzget8(file_)); } } -void UEF::queue_explicit_bit_pattern(uint32_t length) { +void UEF::Serialiser::queue_explicit_bit_pattern(uint32_t length) { const std::size_t length_in_bits = (length << 3) - size_t(gzget8(file_)); uint8_t current_byte = 0; for(std::size_t bit = 0; bit < length_in_bits; bit++) { @@ -187,14 +189,14 @@ void UEF::queue_explicit_bit_pattern(uint32_t length) { } } -void UEF::queue_integer_gap() { +void UEF::Serialiser::queue_integer_gap() { Time duration; duration.length = unsigned(gzget16(file_)); duration.clock_rate = time_base_; emplace_back(Pulse::Zero, duration); } -void UEF::queue_floating_point_gap() { +void UEF::Serialiser::queue_floating_point_gap() { const float length = gzgetfloat(file_); Time duration; duration.length = unsigned(length * 4000000); @@ -202,12 +204,12 @@ void UEF::queue_floating_point_gap() { emplace_back(Pulse::Zero, duration); } -void UEF::queue_carrier_tone() { +void UEF::Serialiser::queue_carrier_tone() { unsigned int number_of_cycles = unsigned(gzget16(file_)); while(number_of_cycles--) queue_bit(1); } -void UEF::queue_carrier_tone_with_dummy() { +void UEF::Serialiser::queue_carrier_tone_with_dummy() { unsigned int pre_cycles = unsigned(gzget16(file_)); unsigned int post_cycles = unsigned(gzget16(file_)); while(pre_cycles--) queue_bit(1); @@ -215,7 +217,7 @@ void UEF::queue_carrier_tone_with_dummy() { while(post_cycles--) queue_bit(1); } -void UEF::queue_security_cycles() { +void UEF::Serialiser::queue_security_cycles() { int number_of_cycles = gzget24(file_); bool first_is_pulse = gzget8(file_) == 'P'; bool last_is_pulse = gzget8(file_) == 'P'; @@ -241,7 +243,7 @@ void UEF::queue_security_cycles() { } } -void UEF::queue_defined_data(uint32_t length) { +void UEF::Serialiser::queue_defined_data(uint32_t length) { if(length < 3) return; const int bits_per_packet = gzget8(file_); @@ -287,7 +289,7 @@ void UEF::queue_defined_data(uint32_t length) { // MARK: - Queuing helpers -void UEF::queue_implicit_byte(uint8_t byte) { +void UEF::Serialiser::queue_implicit_byte(uint8_t byte) { queue_bit(0); int c = 8; while(c--) { @@ -297,7 +299,7 @@ void UEF::queue_implicit_byte(uint8_t byte) { queue_bit(1); } -void UEF::queue_bit(int bit) { +void UEF::Serialiser::queue_bit(int bit) { int number_of_cycles; Time duration; duration.clock_rate = time_base_ * 4; @@ -323,10 +325,14 @@ void UEF::queue_bit(int bit) { // MARK: - TypeDistinguisher TargetPlatform::Type UEF::target_platform_type() { + return serialiser_.target_platform_type(); +} + +TargetPlatform::Type UEF::Serialiser::target_platform_type() { return platform_type_; } -void UEF::set_platform_type() { +void UEF::Serialiser::set_platform_type() { // If a chunk of type 0005 exists anywhere in the UEF then the UEF specifies its target machine. // So check and, if so, update the list of machines for which this file thinks it is suitable. Chunk next_chunk; diff --git a/Storage/Tape/Formats/TapeUEF.hpp b/Storage/Tape/Formats/TapeUEF.hpp index bb32ca0b1..0df5ca892 100644 --- a/Storage/Tape/Formats/TapeUEF.hpp +++ b/Storage/Tape/Formats/TapeUEF.hpp @@ -21,7 +21,7 @@ namespace Storage::Tape { /*! Provides a @c Tape containing a UEF tape image, a slightly-convoluted description of pulses. */ -class UEF : public PulseQueuedTape, public TargetPlatform::TypeDistinguisher { +class UEF : public Tape, public TargetPlatform::TypeDistinguisher { public: /*! Constructs a @c UEF containing content from the file with name @c file_name. @@ -29,46 +29,54 @@ public: @throws ErrorNotUEF if this file could not be opened and recognised as a valid UEF. */ UEF(const std::string &file_name); - ~UEF(); enum { ErrorNotUEF }; private: - void virtual_reset() override; - - void set_platform_type(); TargetPlatform::Type target_platform_type() override; - TargetPlatform::Type platform_type_ = TargetPlatform::Acorn; - gzFile file_; - unsigned int time_base_ = 1200; - bool is_300_baud_ = false; + struct Serialiser: public PulseQueuedSerialiser { + Serialiser(const std::string &file_name); + ~Serialiser(); - struct Chunk { - uint16_t id; - uint32_t length; - z_off_t start_of_next_chunk; - }; + TargetPlatform::Type target_platform_type(); - bool get_next_chunk(Chunk &); - void get_next_pulses() override; + private: + void reset() override; - void queue_implicit_bit_pattern(uint32_t length); - void queue_explicit_bit_pattern(uint32_t length); + void set_platform_type(); + TargetPlatform::Type platform_type_ = TargetPlatform::Acorn; - void queue_integer_gap(); - void queue_floating_point_gap(); + gzFile file_; + unsigned int time_base_ = 1200; + bool is_300_baud_ = false; - void queue_carrier_tone(); - void queue_carrier_tone_with_dummy(); + struct Chunk { + uint16_t id; + uint32_t length; + z_off_t start_of_next_chunk; + }; - void queue_security_cycles(); - void queue_defined_data(uint32_t length); + bool get_next_chunk(Chunk &); + void get_next_pulses() override; - void queue_bit(int bit); - void queue_implicit_byte(uint8_t byte); + void queue_implicit_bit_pattern(uint32_t length); + void queue_explicit_bit_pattern(uint32_t length); + + void queue_integer_gap(); + void queue_floating_point_gap(); + + void queue_carrier_tone(); + void queue_carrier_tone_with_dummy(); + + void queue_security_cycles(); + void queue_defined_data(uint32_t length); + + void queue_bit(int bit); + void queue_implicit_byte(uint8_t byte); + } serialiser_; }; } diff --git a/Storage/Tape/Formats/ZX80O81P.cpp b/Storage/Tape/Formats/ZX80O81P.cpp index b65e1e66b..d83c907f0 100644 --- a/Storage/Tape/Formats/ZX80O81P.cpp +++ b/Storage/Tape/Formats/ZX80O81P.cpp @@ -11,7 +11,9 @@ using namespace Storage::Tape; -ZX80O81P::ZX80O81P(const std::string &file_name) { +ZX80O81P::ZX80O81P(const std::string &file_name) : Tape(serialiser_), serialiser_(file_name) {} + +ZX80O81P::Serialiser::Serialiser(const std::string &file_name) { Storage::FileHolder file(file_name, FileHolder::FileMode::Read); // Grab the actual file contents @@ -31,10 +33,10 @@ ZX80O81P::ZX80O81P(const std::string &file_name) { if(!zx_file) throw ErrorNotZX80O81P; // then rewind and start again - virtual_reset(); + reset(); } -void ZX80O81P::virtual_reset() { +void ZX80O81P::Serialiser::reset() { data_pointer_ = 0; is_past_silence_ = false; has_ended_final_byte_ = false; @@ -42,16 +44,16 @@ void ZX80O81P::virtual_reset() { bit_pointer_ = wave_pointer_ = 0; } -bool ZX80O81P::has_finished_data() const { +bool ZX80O81P::Serialiser::has_finished_data() const { return (data_pointer_ == data_.size()) && !wave_pointer_ && !bit_pointer_; } -bool ZX80O81P::is_at_end() const { +bool ZX80O81P::Serialiser::is_at_end() const { return has_finished_data() && has_ended_final_byte_; } -Tape::Pulse ZX80O81P::virtual_get_next_pulse() { - Tape::Pulse pulse; +Pulse ZX80O81P::Serialiser::get_next_pulse() { + Pulse pulse; // Start with 1 second of silence. if(!is_past_silence_ || has_finished_data()) { @@ -104,5 +106,9 @@ Tape::Pulse ZX80O81P::virtual_get_next_pulse() { } TargetPlatform::Type ZX80O81P::target_platform_type() { + return serialiser_.target_platform_type(); +} + +TargetPlatform::Type ZX80O81P::Serialiser::target_platform_type() { return platform_type_; } diff --git a/Storage/Tape/Formats/ZX80O81P.hpp b/Storage/Tape/Formats/ZX80O81P.hpp index 132804d88..406005463 100644 --- a/Storage/Tape/Formats/ZX80O81P.hpp +++ b/Storage/Tape/Formats/ZX80O81P.hpp @@ -36,25 +36,30 @@ public: }; private: - // implemented to satisfy @c Tape - bool is_at_end() const override; - - // implemented to satisfy TargetPlatform::TypeDistinguisher + // TargetPlatform::TypeDistinguisher. TargetPlatform::Type target_platform_type() override; - TargetPlatform::Type platform_type_; - void virtual_reset() override; - Pulse virtual_get_next_pulse() override; - bool has_finished_data() const; + struct Serialiser: public TapeSerialiser { + Serialiser(const std::string &file_name); + TargetPlatform::Type target_platform_type(); - uint8_t byte_; - int bit_pointer_; - int wave_pointer_; - bool is_past_silence_, has_ended_final_byte_; - bool is_high_; + private: + bool is_at_end() const override; + void reset() override; + Pulse get_next_pulse() override; + bool has_finished_data() const; - std::vector data_; - std::size_t data_pointer_; + TargetPlatform::Type platform_type_; + + uint8_t byte_; + int bit_pointer_; + int wave_pointer_; + bool is_past_silence_, has_ended_final_byte_; + bool is_high_; + + std::vector data_; + std::size_t data_pointer_; + } serialiser_; }; } diff --git a/Storage/Tape/Formats/ZXSpectrumTAP.cpp b/Storage/Tape/Formats/ZXSpectrumTAP.cpp index e7103042c..c64f9b20f 100644 --- a/Storage/Tape/Formats/ZXSpectrumTAP.cpp +++ b/Storage/Tape/Formats/ZXSpectrumTAP.cpp @@ -18,7 +18,9 @@ using namespace Storage::Tape; https://sinclair.wiki.zxnet.co.uk/wiki/TAP_format */ -ZXSpectrumTAP::ZXSpectrumTAP(const std::string &file_name) : +ZXSpectrumTAP::ZXSpectrumTAP(const std::string &file_name) : Tape(serialiser_), serialiser_(file_name) {} + +ZXSpectrumTAP::Serialiser::Serialiser(const std::string &file_name) : file_(file_name, FileHolder::FileMode::Read) { // Check for a continuous series of blocks through to @@ -28,26 +30,26 @@ ZXSpectrumTAP::ZXSpectrumTAP(const std::string &file_name) : // and type ff for valid checksums? while(file_.tell() != file_.stats().st_size) { const uint16_t block_length = file_.get16le(); - if(file_.eof() || file_.tell() + block_length >= file_.stats().st_size) { + if(file_.eof() || file_.tell() + block_length > file_.stats().st_size) { throw ErrorNotZXSpectrumTAP; } file_.seek(block_length, SEEK_CUR); } - virtual_reset(); + reset(); } -bool ZXSpectrumTAP::is_at_end() const { +bool ZXSpectrumTAP::Serialiser::is_at_end() const { return file_.tell() == file_.stats().st_size && phase_ == Phase::Gap; } -void ZXSpectrumTAP::virtual_reset() { +void ZXSpectrumTAP::Serialiser::reset() { file_.seek(0, SEEK_SET); read_next_block(); } -Tape::Pulse ZXSpectrumTAP::virtual_get_next_pulse() { +Pulse ZXSpectrumTAP::Serialiser::get_next_pulse() { // Adopt a general pattern of high then low. Pulse pulse; pulse.type = (distance_into_phase_ & 1) ? Pulse::Type::High : Pulse::Type::Low; @@ -111,7 +113,7 @@ Tape::Pulse ZXSpectrumTAP::virtual_get_next_pulse() { return pulse; } -void ZXSpectrumTAP::read_next_block() { +void ZXSpectrumTAP::Serialiser::read_next_block() { if(file_.tell() == file_.stats().st_size) { phase_ = Phase::Gap; } else { diff --git a/Storage/Tape/Formats/ZXSpectrumTAP.hpp b/Storage/Tape/Formats/ZXSpectrumTAP.hpp index 74ee390d7..6b6fe3482 100644 --- a/Storage/Tape/Formats/ZXSpectrumTAP.hpp +++ b/Storage/Tape/Formats/ZXSpectrumTAP.hpp @@ -34,23 +34,27 @@ public: }; private: - Storage::FileHolder file_; + struct Serialiser: public TapeSerialiser { + Serialiser(const std::string &file_name); + private: + Storage::FileHolder file_; - uint16_t block_length_ = 0; - uint8_t block_type_ = 0; - uint8_t data_byte_ = 0; - enum Phase { - PilotTone, - Data, - Gap - } phase_ = Phase::PilotTone; - int distance_into_phase_ = 0; - void read_next_block(); + uint16_t block_length_ = 0; + uint8_t block_type_ = 0; + uint8_t data_byte_ = 0; + enum Phase { + PilotTone, + Data, + Gap + } phase_ = Phase::PilotTone; + int distance_into_phase_ = 0; + void read_next_block(); - // Implemented to satisfy @c Tape. - bool is_at_end() const override; - void virtual_reset() override; - Pulse virtual_get_next_pulse() override; + // Implemented to satisfy @c Tape. + bool is_at_end() const override; + void reset() override; + Pulse get_next_pulse() override; + } serialiser_; }; } diff --git a/Storage/Tape/Parsers/Acorn.cpp b/Storage/Tape/Parsers/Acorn.cpp index d23ade030..2bf95d9c3 100644 --- a/Storage/Tape/Parsers/Acorn.cpp +++ b/Storage/Tape/Parsers/Acorn.cpp @@ -61,7 +61,7 @@ void Parser::acorn_shifter_output_bit(int value) { push_symbol(value ? SymbolType::One : SymbolType::Zero); } -void Parser::process_pulse(const Storage::Tape::Tape::Pulse &pulse) { +void Parser::process_pulse(const Storage::Tape::Pulse &pulse) { shifter_.process_pulse(pulse); } @@ -72,10 +72,10 @@ Shifter::Shifter() : input_pattern_(0), delegate_(nullptr) {} -void Shifter::process_pulse(const Storage::Tape::Tape::Pulse &pulse) { +void Shifter::process_pulse(const Storage::Tape::Pulse &pulse) { pll_.run_for(Cycles(int(float(PLLClockRate) * pulse.length.get()))); - const bool is_high = pulse.type == Storage::Tape::Tape::Pulse::High; + const bool is_high = pulse.type == Storage::Tape::Pulse::High; if(is_high != was_high_) { pll_.add_pulse(); } diff --git a/Storage/Tape/Parsers/Acorn.hpp b/Storage/Tape/Parsers/Acorn.hpp index c8cdb4357..e6146307f 100644 --- a/Storage/Tape/Parsers/Acorn.hpp +++ b/Storage/Tape/Parsers/Acorn.hpp @@ -18,7 +18,7 @@ class Shifter { public: Shifter(); - void process_pulse(const Storage::Tape::Tape::Pulse &); + void process_pulse(const Storage::Tape::Pulse &); struct Delegate { virtual void acorn_shifter_output_bit(int value) = 0; @@ -55,7 +55,7 @@ public: private: void acorn_shifter_output_bit(int value) override; - void process_pulse(const Storage::Tape::Tape::Pulse &) override; + void process_pulse(const Storage::Tape::Pulse &) override; bool did_update_shifter(int new_value, int length); CRC::Generator crc_; diff --git a/Storage/Tape/Parsers/Commodore.cpp b/Storage/Tape/Parsers/Commodore.cpp index ea3bea801..cde725d41 100644 --- a/Storage/Tape/Parsers/Commodore.cpp +++ b/Storage/Tape/Parsers/Commodore.cpp @@ -230,12 +230,12 @@ uint16_t Parser::get_next_short(const std::shared_ptr &tape indicates a high to low transition, inspects the time since the last transition, to produce a long, medium, short or unrecognised wave period. */ -void Parser::process_pulse(const Storage::Tape::Tape::Pulse &pulse) { +void Parser::process_pulse(const Storage::Tape::Pulse &pulse) { // The Complete Commodore Inner Space Anthology, P 97, gives half-cycle lengths of: // short: 182us => 0.000364s cycle // medium: 262us => 0.000524s cycle // long: 342us => 0.000684s cycle - const bool is_high = pulse.type == Storage::Tape::Tape::Pulse::High; + const bool is_high = pulse.type == Storage::Tape::Pulse::High; if(!is_high && previous_was_high_) { if(wave_period_ >= 0.000764) push_wave(WaveType::Unrecognised); else if(wave_period_ >= 0.000604) push_wave(WaveType::Long); diff --git a/Storage/Tape/Parsers/Commodore.hpp b/Storage/Tape/Parsers/Commodore.hpp index 97748d70a..d65c16450 100644 --- a/Storage/Tape/Parsers/Commodore.hpp +++ b/Storage/Tape/Parsers/Commodore.hpp @@ -117,7 +117,7 @@ private: indicates a high to low transition, inspects the time since the last transition, to produce a long, medium, short or unrecognised wave period. */ - void process_pulse(const Storage::Tape::Tape::Pulse &pulse) override; + void process_pulse(const Storage::Tape::Pulse &pulse) override; bool previous_was_high_ = false; float wave_period_ = 0.0f; diff --git a/Storage/Tape/Parsers/Oric.cpp b/Storage/Tape/Parsers/Oric.cpp index c1ebdc007..ff4f49018 100644 --- a/Storage/Tape/Parsers/Oric.cpp +++ b/Storage/Tape/Parsers/Oric.cpp @@ -40,12 +40,12 @@ bool Parser::sync_and_get_encoding_speed(const std::shared_ptr &tape); private: - void process_pulse(const Storage::Tape::Tape::Pulse &pulse) override; + void process_pulse(const Storage::Tape::Pulse &pulse) override; void inspect_waves(const std::vector &waves) override; enum DetectionMode { diff --git a/Storage/Tape/Parsers/Spectrum.cpp b/Storage/Tape/Parsers/Spectrum.cpp index 4a884875a..b948ae98e 100644 --- a/Storage/Tape/Parsers/Spectrum.cpp +++ b/Storage/Tape/Parsers/Spectrum.cpp @@ -25,8 +25,8 @@ using namespace Storage::Tape::ZXSpectrum; Parser::Parser(MachineType machine_type) : machine_type_(machine_type) {} -void Parser::process_pulse(const Storage::Tape::Tape::Pulse &pulse) { - if(pulse.type == Storage::Tape::Tape::Pulse::Type::Zero) { +void Parser::process_pulse(const Storage::Tape::Pulse &pulse) { + if(pulse.type == Storage::Tape::Pulse::Type::Zero) { push_wave(WaveType::Gap); return; } diff --git a/Storage/Tape/Parsers/Spectrum.hpp b/Storage/Tape/Parsers/Spectrum.hpp index d6db5ea5b..1f41d838b 100644 --- a/Storage/Tape/Parsers/Spectrum.hpp +++ b/Storage/Tape/Parsers/Spectrum.hpp @@ -95,7 +95,7 @@ public: Push a pulse; primarily provided for Storage::Tape::PulseClassificationParser but also potentially useful for picking up fast loading from an ongoing tape. */ - void process_pulse(const Storage::Tape::Tape::Pulse &pulse) override; + void process_pulse(const Storage::Tape::Pulse &pulse) override; private: const MachineType machine_type_; diff --git a/Storage/Tape/Parsers/TapeParser.hpp b/Storage/Tape/Parsers/TapeParser.hpp index 6d62dee8d..6118906c3 100644 --- a/Storage/Tape/Parsers/TapeParser.hpp +++ b/Storage/Tape/Parsers/TapeParser.hpp @@ -69,7 +69,7 @@ protected: /*! Should be implemented by subclasses. Consumes @c pulse. */ - virtual void process_pulse(const Storage::Tape::Tape::Pulse &pulse) = 0; + virtual void process_pulse(const Storage::Tape::Pulse &pulse) = 0; /*! An optional implementation for subclasses; called to announce that the tape has ended: that @@ -104,7 +104,7 @@ protected: */ template class PulseClassificationParser: public Parser { public: - virtual void process_pulse(const Storage::Tape::Tape::Pulse &pulse) = 0; + virtual void process_pulse(const Storage::Tape::Pulse &pulse) = 0; /* process_pulse should either call @c push_wave or to take no action. diff --git a/Storage/Tape/Parsers/ZX8081.cpp b/Storage/Tape/Parsers/ZX8081.cpp index 487c6a398..c60f0d64f 100644 --- a/Storage/Tape/Parsers/ZX8081.cpp +++ b/Storage/Tape/Parsers/ZX8081.cpp @@ -12,10 +12,10 @@ using namespace Storage::Tape::ZX8081; Parser::Parser() : pulse_was_high_(false), pulse_time_(0) {} -void Parser::process_pulse(const Storage::Tape::Tape::Pulse &pulse) { +void Parser::process_pulse(const Storage::Tape::Pulse &pulse) { // If this is anything other than a transition from low to high, just add it to the // count of time. - const bool pulse_is_high = pulse.type == Storage::Tape::Tape::Pulse::High; + const bool pulse_is_high = pulse.type == Storage::Tape::Pulse::High; const bool pulse_did_change = pulse_is_high != pulse_was_high_; pulse_was_high_ = pulse_is_high; if(!pulse_did_change || !pulse_is_high) { diff --git a/Storage/Tape/Parsers/ZX8081.hpp b/Storage/Tape/Parsers/ZX8081.hpp index f235a6875..4804810b9 100644 --- a/Storage/Tape/Parsers/ZX8081.hpp +++ b/Storage/Tape/Parsers/ZX8081.hpp @@ -47,7 +47,7 @@ private: Time pulse_time_; void post_pulse(); - void process_pulse(const Storage::Tape::Tape::Pulse &pulse) override; + void process_pulse(const Storage::Tape::Pulse &pulse) override; void mark_end() override; void inspect_waves(const std::vector &waves) override; diff --git a/Storage/Tape/PulseQueuedTape.cpp b/Storage/Tape/PulseQueuedTape.cpp index 15f4fc5aa..383db3bb9 100644 --- a/Storage/Tape/PulseQueuedTape.cpp +++ b/Storage/Tape/PulseQueuedTape.cpp @@ -10,36 +10,34 @@ using namespace Storage::Tape; -PulseQueuedTape::PulseQueuedTape() : pulse_pointer_(0), is_at_end_(false) {} - -bool PulseQueuedTape::is_at_end() const { +bool PulseQueuedSerialiser::is_at_end() const { return is_at_end_; } -void PulseQueuedTape::set_is_at_end(const bool is_at_end) { +void PulseQueuedSerialiser::set_is_at_end(const bool is_at_end) { is_at_end_ = is_at_end; } -void PulseQueuedTape::clear() { +void PulseQueuedSerialiser::clear() { queued_pulses_.clear(); pulse_pointer_ = 0; } -bool PulseQueuedTape::empty() const { +bool PulseQueuedSerialiser::empty() const { return queued_pulses_.empty(); } -void PulseQueuedTape::emplace_back(const Tape::Pulse::Type type, const Time length) { +void PulseQueuedSerialiser::emplace_back(const Pulse::Type type, const Time length) { queued_pulses_.emplace_back(type, length); } -void PulseQueuedTape::push_back(const Tape::Pulse pulse) { +void PulseQueuedSerialiser::push_back(const Pulse pulse) { queued_pulses_.push_back(pulse); } -Tape::Pulse PulseQueuedTape::virtual_get_next_pulse() { +Pulse PulseQueuedSerialiser::get_next_pulse() { const auto silence = [] { - return Tape::Pulse(Tape::Pulse::Type::Zero, Storage::Time(1, 1)); + return Pulse(Pulse::Type::Zero, Storage::Time(1, 1)); }; if(is_at_end_) { diff --git a/Storage/Tape/PulseQueuedTape.hpp b/Storage/Tape/PulseQueuedTape.hpp index 2fb2b5793..96a98837f 100644 --- a/Storage/Tape/PulseQueuedTape.hpp +++ b/Storage/Tape/PulseQueuedTape.hpp @@ -23,26 +23,23 @@ namespace Storage::Tape { anything there, and otherwise calls get_next_pulses(). get_next_pulses() is virtual, giving subclasses a chance to provide the next batch of pulses. */ -class PulseQueuedTape: public Tape { +class PulseQueuedSerialiser: public TapeSerialiser { public: - PulseQueuedTape(); - bool is_at_end() const override; - -protected: - void emplace_back(Tape::Pulse::Type type, Time length); - void push_back(Tape::Pulse); + void emplace_back(Pulse::Type, Time); + void push_back(Pulse); void clear(); bool empty() const; void set_is_at_end(bool); + Pulse get_next_pulse() override; + bool is_at_end() const override; + virtual void get_next_pulses() = 0; private: - Pulse virtual_get_next_pulse() override; - std::vector queued_pulses_; - std::size_t pulse_pointer_; - bool is_at_end_; + std::size_t pulse_pointer_ = 0; + bool is_at_end_ = false; }; } diff --git a/Storage/Tape/Tape.cpp b/Storage/Tape/Tape.cpp index 910f2a1ea..6c1050749 100644 --- a/Storage/Tape/Tape.cpp +++ b/Storage/Tape/Tape.cpp @@ -16,9 +16,11 @@ TapePlayer::TapePlayer(int input_clock_rate) : TimedEventLoop(input_clock_rate) {} +Tape::Tape(TapeSerialiser &serialiser) : serialiser_(serialiser) {} + // MARK: - Seeking -void Storage::Tape::Tape::seek(Time &seek_time) { +void Storage::Tape::Tape::seek(const Time seek_time) { Time next_time(0); reset(); while(next_time <= seek_time) { @@ -40,11 +42,11 @@ Storage::Time Tape::get_current_time() { void Storage::Tape::Tape::reset() { offset_ = 0; - virtual_reset(); + serialiser_.reset(); } -Tape::Pulse Tape::get_next_pulse() { - pulse_ = virtual_get_next_pulse(); +Pulse Tape::get_next_pulse() { + pulse_ = serialiser_.get_next_pulse(); offset_++; return pulse_; } @@ -62,6 +64,11 @@ void Tape::set_offset(uint64_t offset) { while(offset--) get_next_pulse(); } +bool Tape::is_at_end() const { + return serialiser_.is_at_end(); +} + + // MARK: - Player ClockingHint::Preference TapePlayer::preferred_clocking() const { @@ -79,7 +86,7 @@ std::shared_ptr TapePlayer::get_tape() { return tape_; } -bool TapePlayer::has_tape() { +bool TapePlayer::has_tape() const { return bool(tape_); } @@ -91,13 +98,13 @@ void TapePlayer::get_next_pulse() { } else { current_pulse_.length.length = 1; current_pulse_.length.clock_rate = 1; - current_pulse_.type = Tape::Pulse::Zero; + current_pulse_.type = Pulse::Zero; } set_next_event_time_interval(current_pulse_.length); } -Tape::Pulse TapePlayer::get_current_pulse() { +Pulse TapePlayer::get_current_pulse() const { return current_pulse_; } @@ -170,8 +177,8 @@ void BinaryTapePlayer::set_delegate(Delegate *delegate) { delegate_ = delegate; } -void BinaryTapePlayer::process_input_pulse(const Storage::Tape::Tape::Pulse &pulse) { - bool new_input_level = pulse.type == Tape::Pulse::High; +void BinaryTapePlayer::process_input_pulse(const Storage::Tape::Pulse &pulse) { + bool new_input_level = pulse.type == Pulse::High; if(input_level_ != new_input_level) { input_level_ = new_input_level; if(delegate_) delegate_->tape_did_change_input(this); diff --git a/Storage/Tape/Tape.hpp b/Storage/Tape/Tape.hpp index 6011fffb9..6442a1a02 100644 --- a/Storage/Tape/Tape.hpp +++ b/Storage/Tape/Tape.hpp @@ -8,17 +8,36 @@ #pragma once -#include - #include "../../ClockReceiver/ClockReceiver.hpp" #include "../../ClockReceiver/ClockingHintSource.hpp" #include "../TimedEventLoop.hpp" #include "../../Activity/Source.hpp" +#include "../TargetPlatforms.hpp" + +#include +#include namespace Storage::Tape { +struct Pulse { + enum Type { + High, Low, Zero + } type; + Time length; + + Pulse(Type type, Time length) : type(type), length(length) {} + Pulse() = default; +}; + +class TapeSerialiser { +public: + virtual Pulse get_next_pulse() = 0; + virtual void reset() = 0; + virtual bool is_at_end() const = 0; +}; + /*! Models a tape as a sequence of pulses, each pulse being of arbitrary length and described by their relationship with zero: @@ -32,15 +51,6 @@ namespace Storage::Tape { */ class Tape { public: - struct Pulse { - enum Type { - High, Low, Zero - } type; - Time length; - - Pulse(Type type, Time length) : type(type), length(length) {} - Pulse() = default; - }; /*! If at the start of the tape returns the first stored pulse. Otherwise advances past @@ -54,38 +64,37 @@ public: void reset(); /// @returns @c true if the tape has progressed beyond all recorded content; @c false otherwise. - virtual bool is_at_end() const = 0; + bool is_at_end() const; /*! Returns a numerical representation of progression into the tape. Precision is arbitrary but required to be at least to the whole pulse. Greater numbers are later than earlier numbers, but not necessarily continuous. */ - virtual uint64_t get_offset() const; + uint64_t get_offset() const; /*! Moves the tape to the first time at which the specified offset would be returned by get_offset. */ - virtual void set_offset(uint64_t); + void set_offset(uint64_t); /*! Calculates and returns the amount of time that has elapsed since the time began. Potentially expensive. */ - virtual Time get_current_time(); + Time get_current_time(); /*! Seeks to @c time. Potentially expensive. */ - virtual void seek(Time &time); + void seek(Time); + Tape(TapeSerialiser &); virtual ~Tape() = default; private: uint64_t offset_; - Tape::Pulse pulse_; - - virtual Pulse virtual_get_next_pulse() = 0; - virtual void virtual_reset() = 0; + Pulse pulse_; + TapeSerialiser &serialiser_; }; /*! @@ -101,7 +110,7 @@ public: virtual ~TapePlayer() = default; void set_tape(std::shared_ptr tape); - bool has_tape(); + bool has_tape() const; std::shared_ptr get_tape(); void run_for(const Cycles cycles); @@ -110,18 +119,18 @@ public: ClockingHint::Preference preferred_clocking() const override; - Tape::Pulse get_current_pulse(); + Pulse get_current_pulse() const; void complete_pulse(); protected: virtual void process_next_event() override; - virtual void process_input_pulse(const Tape::Pulse &pulse) = 0; + virtual void process_input_pulse(const Pulse &pulse) = 0; private: inline void get_next_pulse(); std::shared_ptr tape_; - Tape::Pulse current_pulse_; + Pulse current_pulse_; }; /*! @@ -154,7 +163,7 @@ public: protected: Delegate *delegate_ = nullptr; - void process_input_pulse(const Storage::Tape::Tape::Pulse &pulse) final; + void process_input_pulse(const Storage::Tape::Pulse &pulse) final; bool input_level_ = false; bool motor_is_running_ = false; From b89ecadc3a0c54331ac9008d90f6ad449c727cb6 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Tue, 3 Dec 2024 22:54:29 -0500 Subject: [PATCH 10/11] Improve interface. --- Machines/Acorn/Electron/Electron.cpp | 2 +- Machines/Acorn/Electron/Tape.cpp | 2 +- Machines/Acorn/Electron/Tape.hpp | 4 +- Machines/AmstradCPC/AmstradCPC.cpp | 6 +-- Machines/Commodore/Vic-20/Vic20.cpp | 14 ++--- Machines/MSX/MSX.cpp | 4 +- Machines/Oric/Oric.cpp | 8 +-- Machines/Sinclair/ZX8081/ZX8081.cpp | 10 ++-- Machines/Sinclair/ZXSpectrum/ZXSpectrum.cpp | 10 ++-- Storage/Tape/Formats/CAS.cpp | 2 +- Storage/Tape/Formats/CAS.hpp | 2 +- Storage/Tape/Formats/CSW.cpp | 24 +++++---- Storage/Tape/Formats/CSW.hpp | 2 +- Storage/Tape/Formats/CommodoreTAP.cpp | 4 +- Storage/Tape/Formats/CommodoreTAP.hpp | 2 +- Storage/Tape/Formats/OricTAP.cpp | 2 +- Storage/Tape/Formats/OricTAP.hpp | 2 +- Storage/Tape/Formats/TZX.cpp | 58 ++++++++++----------- Storage/Tape/Formats/TZX.hpp | 2 +- Storage/Tape/Formats/TapePRG.cpp | 8 +-- Storage/Tape/Formats/TapePRG.hpp | 2 +- Storage/Tape/Formats/TapeUEF.cpp | 7 ++- Storage/Tape/Formats/TapeUEF.hpp | 2 +- Storage/Tape/Formats/ZX80O81P.cpp | 2 +- Storage/Tape/Formats/ZX80O81P.hpp | 2 +- Storage/Tape/Formats/ZXSpectrumTAP.cpp | 2 +- Storage/Tape/Formats/ZXSpectrumTAP.hpp | 2 +- Storage/Tape/Parsers/MSX.cpp | 48 ++++++++--------- Storage/Tape/Parsers/TapeParser.hpp | 2 +- Storage/Tape/PulseQueuedTape.cpp | 4 +- Storage/Tape/PulseQueuedTape.hpp | 12 ++--- Storage/Tape/Tape.cpp | 36 ++++++------- Storage/Tape/Tape.hpp | 44 ++++++++-------- 33 files changed, 168 insertions(+), 165 deletions(-) diff --git a/Machines/Acorn/Electron/Electron.cpp b/Machines/Acorn/Electron/Electron.cpp index 8bdba0b7b..fdf095255 100644 --- a/Machines/Acorn/Electron/Electron.cpp +++ b/Machines/Acorn/Electron/Electron.cpp @@ -454,7 +454,7 @@ public: int cycles_left_while_plausibly_in_data = 50; tape_.clear_interrupts(Interrupt::ReceiveDataFull); - while(!tape_.get_tape()->is_at_end()) { + while(!tape_.tape()->is_at_end()) { tape_.run_for_input_pulse(); --cycles_left_while_plausibly_in_data; if(!cycles_left_while_plausibly_in_data) fast_load_is_in_data_ = false; diff --git a/Machines/Acorn/Electron/Tape.cpp b/Machines/Acorn/Electron/Tape.cpp index 73d55a4a0..bb6580985 100644 --- a/Machines/Acorn/Electron/Tape.cpp +++ b/Machines/Acorn/Electron/Tape.cpp @@ -68,7 +68,7 @@ uint8_t Tape::get_data_register() { return uint8_t(data_register_ >> 2); } -void Tape::process_input_pulse(const Storage::Tape::Pulse &pulse) { +void Tape::process(const Storage::Tape::Pulse &pulse) { shifter_.process_pulse(pulse); } diff --git a/Machines/Acorn/Electron/Tape.hpp b/Machines/Acorn/Electron/Tape.hpp index 1ecf532b2..548dde30d 100644 --- a/Machines/Acorn/Electron/Tape.hpp +++ b/Machines/Acorn/Electron/Tape.hpp @@ -43,10 +43,10 @@ public: inline void set_is_enabled(bool is_enabled) { is_enabled_ = is_enabled; } void set_is_in_input_mode(bool is_in_input_mode); - void acorn_shifter_output_bit(int value); + void acorn_shifter_output_bit(int value) override; private: - void process_input_pulse(const Storage::Tape::Pulse &pulse); + void process(const Storage::Tape::Pulse &pulse) override; inline void push_tape_bit(uint16_t bit); inline void get_next_tape_pulse(); diff --git a/Machines/AmstradCPC/AmstradCPC.cpp b/Machines/AmstradCPC/AmstradCPC.cpp index 04ded757c..dfa0ebcdb 100644 --- a/Machines/AmstradCPC/AmstradCPC.cpp +++ b/Machines/AmstradCPC/AmstradCPC.cpp @@ -721,7 +721,7 @@ public: case 0: return ay_.ay().get_data_output(); // Port A is wired to the AY case 1: return (crtc_.get_bus_state().vsync ? 0x01 : 0x00) | // Bit 0 returns CRTC vsync. - (tape_player_.get_input() ? 0x80 : 0x00) | // Bit 7 returns cassette input. + (tape_player_.input() ? 0x80 : 0x00) | // Bit 7 returns cassette input. 0x7e; // Bits unimplemented: // // Bit 6: printer ready (1 = not) @@ -899,8 +899,8 @@ public: // Seed with the current pulse; the CPC will have finished the // preceding symbol and be a short way into the pulse that should determine the // first bit of this byte. - parser.process_pulse(tape_player_.get_current_pulse()); - const auto byte = parser.get_byte(tape_player_.get_tape()); + parser.process_pulse(tape_player_.current_pulse()); + const auto byte = parser.get_byte(tape_player_.tape()); auto flags = z80_.value_of(CPU::Z80::Register::Flags); if(byte) { diff --git a/Machines/Commodore/Vic-20/Vic20.cpp b/Machines/Commodore/Vic-20/Vic20.cpp index 54ea08660..dfc0462c4 100644 --- a/Machines/Commodore/Vic-20/Vic20.cpp +++ b/Machines/Commodore/Vic-20/Vic20.cpp @@ -526,9 +526,9 @@ class ConcreteMachine: // Address 0xf7b2 contains a JSR to 0xf8c0 that will fill the tape buffer with the next header. // So cancel that via a double NOP and fill in the next header programmatically. Storage::Tape::Commodore::Parser parser; - std::unique_ptr header = parser.get_next_header(tape_->get_tape()); + std::unique_ptr header = parser.get_next_header(tape_->tape()); - const uint64_t tape_position = tape_->get_tape()->get_offset(); + const auto tape_position = tape_->tape()->offset(); if(header) { // serialise to wherever b2:b3 points const uint16_t tape_buffer_pointer = uint16_t(ram_[0xb2]) | uint16_t(ram_[0xb3] << 8); @@ -537,7 +537,7 @@ class ConcreteMachine: logger.info().append("Found header"); } else { // no header found, so pretend this hack never interceded - tape_->get_tape()->set_offset(tape_position); + tape_->tape()->set_offset(tape_position); hold_tape_ = false; logger.info().append("Didn't find header"); } @@ -551,8 +551,8 @@ class ConcreteMachine: uint8_t x = uint8_t(m6502_.value_of(CPU::MOS6502::Register::X)); if(x == 0xe) { Storage::Tape::Commodore::Parser parser; - const uint64_t tape_position = tape_->get_tape()->get_offset(); - const std::unique_ptr data = parser.get_next_data(tape_->get_tape()); + const auto tape_position = tape_->tape()->offset(); + const std::unique_ptr data = parser.get_next_data(tape_->tape()); if(data) { uint16_t start_address, end_address; start_address = uint16_t(ram_[0xc1] | (ram_[0xc2] << 8)); @@ -582,7 +582,7 @@ class ConcreteMachine: hold_tape_ = true; logger.info().append("Found data"); } else { - tape_->get_tape()->set_offset(tape_position); + tape_->tape()->set_offset(tape_position); hold_tape_ = false; logger.info().append("Didn't find data"); } @@ -670,7 +670,7 @@ class ConcreteMachine: } void tape_did_change_input(Storage::Tape::BinaryTapePlayer *tape) final { - keyboard_via_.set_control_line_input(MOS::MOS6522::Port::A, MOS::MOS6522::Line::One, !tape->get_input()); + keyboard_via_.set_control_line_input(MOS::MOS6522::Port::A, MOS::MOS6522::Line::One, !tape->input()); } KeyboardMapper *get_keyboard_mapper() final { diff --git a/Machines/MSX/MSX.cpp b/Machines/MSX/MSX.cpp index 412627fdf..4d9950191 100644 --- a/Machines/MSX/MSX.cpp +++ b/Machines/MSX/MSX.cpp @@ -82,7 +82,7 @@ class AYPortHandler: public GI::AY38910::PortHandler { return (static_cast(joysticks_[selected_joystick_].get())->get_state() & 0x3f) | 0x40 | - (tape_player_.get_input() ? 0x00 : 0x80); + (tape_player_.input() ? 0x00 : 0x80); } return 0xff; } @@ -893,7 +893,7 @@ class ConcreteMachine: activity_observer_ = observer; if(activity_observer_) { activity_observer_->register_led("Tape motor"); - activity_observer_->set_led_status("Tape motor", tape_player_.get_motor_control()); + activity_observer_->set_led_status("Tape motor", tape_player_.motor_control()); } } diff --git a/Machines/Oric/Oric.cpp b/Machines/Oric/Oric.cpp index eab424a5d..1185e0c99 100644 --- a/Machines/Oric/Oric.cpp +++ b/Machines/Oric/Oric.cpp @@ -168,7 +168,7 @@ class TapePlayer: public Storage::Tape::BinaryTapePlayer { @returns The next byte from the tape. */ uint8_t get_next_byte(bool use_fast_encoding) { - return uint8_t(parser_.get_next_byte(get_tape(), use_fast_encoding)); + return uint8_t(parser_.get_next_byte(tape(), use_fast_encoding)); } private: @@ -469,7 +469,7 @@ template is_at_end()) { + !tape_player_.tape()->is_at_end()) { uint8_t next_byte = tape_player_.get_next_byte(!ram_[tape_speed_address_]); m6502_.set_value_of(CPU::MOS6502Esque::A, next_byte); @@ -632,8 +632,8 @@ template vsync() ); } diff --git a/Machines/Sinclair/ZX8081/ZX8081.cpp b/Machines/Sinclair/ZX8081/ZX8081.cpp index 95a6a2575..e2273717f 100644 --- a/Machines/Sinclair/ZX8081/ZX8081.cpp +++ b/Machines/Sinclair/ZX8081/ZX8081.cpp @@ -185,7 +185,7 @@ template class ConcreteMachine: if(!nmi_is_enabled_) set_vsync(true); value &= keyboard_.read(address); - value &= ~(tape_player_.get_input() ? 0x00 : 0x80); + value &= ~(tape_player_.input() ? 0x00 : 0x80); } // The below emulates the ZonX AY expansion device. @@ -232,8 +232,8 @@ template class ConcreteMachine: case CPU::Z80::PartialMachineCycle::ReadOpcode: // Check for use of the fast tape hack. if(use_fast_tape_hack_ && address == tape_trap_address_) { - const uint64_t prior_offset = tape_player_.get_tape()->get_offset(); - const int next_byte = parser_.get_next_byte(tape_player_.get_tape()); + const uint64_t prior_offset = tape_player_.tape()->offset(); + const int next_byte = parser_.get_next_byte(tape_player_.tape()); if(next_byte != -1) { const uint16_t hl = z80_.value_of(CPU::Z80::Register::HL); ram_[hl & ram_mask_] = uint8_t(next_byte); @@ -246,7 +246,7 @@ template class ConcreteMachine: tape_advance_delay_ = 1000; return 0; } else { - tape_player_.get_tape()->set_offset(prior_offset); + tape_player_.tape()->set_offset(prior_offset); } } @@ -365,7 +365,7 @@ template class ConcreteMachine: } bool get_tape_is_playing() final { - return tape_player_.get_motor_control(); + return tape_player_.motor_control(); } // MARK: - Typer timing diff --git a/Machines/Sinclair/ZXSpectrum/ZXSpectrum.cpp b/Machines/Sinclair/ZXSpectrum/ZXSpectrum.cpp index a94b715f0..34d5bbc7e 100644 --- a/Machines/Sinclair/ZXSpectrum/ZXSpectrum.cpp +++ b/Machines/Sinclair/ZXSpectrum/ZXSpectrum.cpp @@ -541,7 +541,7 @@ template class ConcreteMachine: // b6: tape input *cycle.value &= keyboard_.read(address); - *cycle.value &= tape_player_.get_input() ? 0xbf : 0xff; + *cycle.value &= tape_player_.input() ? 0xbf : 0xff; // Add Joystick input on top. if(!(address&0x1000)) *cycle.value &= static_cast(joysticks_[0].get())->get_sinclair(0); @@ -716,7 +716,7 @@ template class ConcreteMachine: } bool get_tape_is_playing() final { - return tape_player_.get_motor_control(); + return tape_player_.motor_control(); } // MARK: - Configuration options. @@ -921,7 +921,7 @@ template class ConcreteMachine: if(!(flags & 1)) return false; const uint8_t block_type = uint8_t(z80_.value_of(Register::ADash)); - const auto block = parser.find_block(tape_player_.get_tape()); + const auto block = parser.find_block(tape_player_.tape()); if(!block || block_type != (*block).type) return false; uint16_t length = z80_.value_of(Register::DE); @@ -930,7 +930,7 @@ template class ConcreteMachine: flags = 0x93; uint8_t parity = 0x00; while(length--) { - auto next = parser.get_byte(tape_player_.get_tape()); + auto next = parser.get_byte(tape_player_.tape()); if(!next) { flags &= ~1; break; @@ -941,7 +941,7 @@ template class ConcreteMachine: ++target; } - auto stored_parity = parser.get_byte(tape_player_.get_tape()); + auto stored_parity = parser.get_byte(tape_player_.tape()); if(!stored_parity) { flags &= ~1; } else { diff --git a/Storage/Tape/Formats/CAS.cpp b/Storage/Tape/Formats/CAS.cpp index cfca7aa43..43f1821a6 100644 --- a/Storage/Tape/Formats/CAS.cpp +++ b/Storage/Tape/Formats/CAS.cpp @@ -181,7 +181,7 @@ void CAS::Serialiser::reset() { distance_into_bit_ = 0; } -Pulse CAS::Serialiser::get_next_pulse() { +Pulse CAS::Serialiser::next_pulse() { Pulse pulse; pulse.length.clock_rate = 9600; // Clock rate is four times the baud rate (of 2400), because the quickest thing that might need diff --git a/Storage/Tape/Formats/CAS.hpp b/Storage/Tape/Formats/CAS.hpp index f21904fbc..afb9a4aa4 100644 --- a/Storage/Tape/Formats/CAS.hpp +++ b/Storage/Tape/Formats/CAS.hpp @@ -40,7 +40,7 @@ private: private: bool is_at_end() const override; void reset() override; - Pulse get_next_pulse() override; + Pulse next_pulse() override; // Storage for the array of data blobs to transcribe into audio; // each chunk is preceded by a header which may be long, and is optionally diff --git a/Storage/Tape/Formats/CSW.cpp b/Storage/Tape/Formats/CSW.cpp index 7524bc2ca..12b90e6dd 100644 --- a/Storage/Tape/Formats/CSW.cpp +++ b/Storage/Tape/Formats/CSW.cpp @@ -21,8 +21,7 @@ CSW::CSW(const std::vector &&data, CompressionType type, bool initial_l serialiser_(std::move(data), type, initial_level, sampling_rate) {} -CSW::Serialiser::Serialiser(const std::string &file_name) : - source_data_pointer_(0) { +CSW::Serialiser::Serialiser(const std::string &file_name) : source_data_pointer_(0) { Storage::FileHolder file(file_name, FileHolder::FileMode::Read); if(file.stats().st_size < 0x20) throw ErrorNotCSW; @@ -35,8 +34,8 @@ CSW::Serialiser::Serialiser(const std::string &file_name) : if(file.get8() != 0x1a) throw ErrorNotCSW; // Get version file number. - uint8_t major_version = file.get8(); - uint8_t minor_version = file.get8(); + const uint8_t major_version = file.get8(); + const uint8_t minor_version = file.get8(); // Reject if this is an unknown version. if(major_version > 2 || !major_version || minor_version > 1) throw ErrorNotCSW; @@ -70,7 +69,7 @@ CSW::Serialiser::Serialiser(const std::string &file_name) : // Grab all data remaining in the file. std::vector file_data; - std::size_t remaining_data = size_t(file.stats().st_size) - size_t(file.tell()); + const std::size_t remaining_data = size_t(file.stats().st_size) - size_t(file.tell()); file_data.resize(remaining_data); file.read(file_data.data(), remaining_data); @@ -93,7 +92,12 @@ CSW::Serialiser::Serialiser(const std::string &file_name) : invert_pulse(); } -CSW::Serialiser::Serialiser(const std::vector &&data, CompressionType compression_type, bool initial_level, uint32_t sampling_rate) : compression_type_(compression_type) { +CSW::Serialiser::Serialiser( + const std::vector &&data, + CompressionType compression_type, + bool initial_level, + uint32_t sampling_rate +) : compression_type_(compression_type) { pulse_.length.clock_rate = sampling_rate; pulse_.type = initial_level ? Pulse::High : Pulse::Low; source_data_ = std::move(data); @@ -101,14 +105,16 @@ CSW::Serialiser::Serialiser(const std::vector &&data, CompressionType c uint8_t CSW::Serialiser::get_next_byte() { if(source_data_pointer_ == source_data_.size()) return 0xff; - uint8_t result = source_data_[source_data_pointer_]; + + const uint8_t result = source_data_[source_data_pointer_]; source_data_pointer_++; return result; } uint32_t CSW::Serialiser::get_next_int32le() { if(source_data_pointer_ > source_data_.size() - 4) return 0xffff; - uint32_t result = uint32_t( + + const uint32_t result = uint32_t( (source_data_[source_data_pointer_ + 0] << 0) | (source_data_[source_data_pointer_ + 1] << 8) | (source_data_[source_data_pointer_ + 2] << 16) | @@ -129,7 +135,7 @@ void CSW::Serialiser::reset() { source_data_pointer_ = 0; } -Pulse CSW::Serialiser::get_next_pulse() { +Pulse CSW::Serialiser::next_pulse() { invert_pulse(); pulse_.length.length = get_next_byte(); if(!pulse_.length.length) pulse_.length.length = get_next_int32le(); diff --git a/Storage/Tape/Formats/CSW.hpp b/Storage/Tape/Formats/CSW.hpp index 19902113f..b61f98c56 100644 --- a/Storage/Tape/Formats/CSW.hpp +++ b/Storage/Tape/Formats/CSW.hpp @@ -51,7 +51,7 @@ private: // implemented to satisfy @c Tape bool is_at_end() const override; void reset() override; - Pulse get_next_pulse() override; + Pulse next_pulse() override; Pulse pulse_; CompressionType compression_type_; diff --git a/Storage/Tape/Formats/CommodoreTAP.cpp b/Storage/Tape/Formats/CommodoreTAP.cpp index 95749fb29..03509fb58 100644 --- a/Storage/Tape/Formats/CommodoreTAP.cpp +++ b/Storage/Tape/Formats/CommodoreTAP.cpp @@ -51,14 +51,14 @@ bool CommodoreTAP::Serialiser::is_at_end() const { return is_at_end_; } -Storage::Tape::Pulse CommodoreTAP::Serialiser::get_next_pulse() { +Storage::Tape::Pulse CommodoreTAP::Serialiser::next_pulse() { if(is_at_end_) { return current_pulse_; } if(current_pulse_.type == Pulse::High) { uint32_t next_length; - uint8_t next_byte = file_.get8(); + const uint8_t next_byte = file_.get8(); if(!updated_layout_ || next_byte > 0) { next_length = uint32_t(next_byte) << 3; } else { diff --git a/Storage/Tape/Formats/CommodoreTAP.hpp b/Storage/Tape/Formats/CommodoreTAP.hpp index cc0e80134..1e26d5616 100644 --- a/Storage/Tape/Formats/CommodoreTAP.hpp +++ b/Storage/Tape/Formats/CommodoreTAP.hpp @@ -39,7 +39,7 @@ private: private: bool is_at_end() const override; void reset() override; - Pulse get_next_pulse() override; + Pulse next_pulse() override; Storage::FileHolder file_; diff --git a/Storage/Tape/Formats/OricTAP.cpp b/Storage/Tape/Formats/OricTAP.cpp index 69678d747..9e349a09e 100644 --- a/Storage/Tape/Formats/OricTAP.cpp +++ b/Storage/Tape/Formats/OricTAP.cpp @@ -44,7 +44,7 @@ void OricTAP::Serialiser::reset() { pulse_counter_ = 0; } -Pulse OricTAP::Serialiser::get_next_pulse() { +Pulse OricTAP::Serialiser::next_pulse() { // Each byte byte is written as 13 bits: 0, eight bits of data, parity, three 1s. if(bit_count_ == 13) { if(next_phase_ != phase_) { diff --git a/Storage/Tape/Formats/OricTAP.hpp b/Storage/Tape/Formats/OricTAP.hpp index 0faa58875..c431ad4f5 100644 --- a/Storage/Tape/Formats/OricTAP.hpp +++ b/Storage/Tape/Formats/OricTAP.hpp @@ -39,7 +39,7 @@ private: private: bool is_at_end() const override; void reset() override; - Pulse get_next_pulse() override; + Pulse next_pulse() override; Storage::FileHolder file_; diff --git a/Storage/Tape/Formats/TZX.cpp b/Storage/Tape/Formats/TZX.cpp index 6b52c28cd..03ee816cb 100644 --- a/Storage/Tape/Formats/TZX.cpp +++ b/Storage/Tape/Formats/TZX.cpp @@ -32,8 +32,8 @@ TZX::Serialiser::Serialiser(const std::string &file_name) : if(file_.get8() != 0x1a) throw ErrorNotTZX; // Get version number - uint8_t major_version = file_.get8(); - uint8_t minor_version = file_.get8(); + const uint8_t major_version = file_.get8(); + const uint8_t minor_version = file_.get8(); // Reject if an incompatible version if(major_version != 1 || minor_version > 21) throw ErrorNotTZX; @@ -53,9 +53,9 @@ void TZX::Serialiser::reset() { post_gap(500); } -void TZX::Serialiser::get_next_pulses() { +void TZX::Serialiser::push_next_pulses() { while(empty()) { - uint8_t chunk_id = file_.get8(); + const uint8_t chunk_id = file_.get8(); if(file_.eof()) { set_is_at_end(true); return; @@ -115,7 +115,7 @@ void TZX::Serialiser::get_csw_recording_block() { CSW csw(std::move(raw_block), (compression_type == 2) ? CSW::CompressionType::ZRLE : CSW::CompressionType::RLE, current_level_, sampling_rate); while(!csw.is_at_end()) { - Pulse next_pulse = csw.get_next_pulse(); + Pulse next_pulse = csw.next_pulse(); current_level_ = (next_pulse.type == Pulse::High); push_back(next_pulse); } @@ -125,17 +125,17 @@ void TZX::Serialiser::get_csw_recording_block() { } void TZX::Serialiser::get_generalised_data_block() { - uint32_t block_length = file_.get32le(); - long endpoint = file_.tell() + long(block_length); - uint16_t pause_after_block = file_.get16le(); + const uint32_t block_length = file_.get32le(); + const long endpoint = file_.tell() + long(block_length); + const uint16_t pause_after_block = file_.get16le(); - uint32_t total_pilot_symbols = file_.get32le(); - uint8_t maximum_pulses_per_pilot_symbol = file_.get8(); - uint8_t symbols_in_pilot_table = file_.get8(); + const uint32_t total_pilot_symbols = file_.get32le(); + const uint8_t maximum_pulses_per_pilot_symbol = file_.get8(); + const uint8_t symbols_in_pilot_table = file_.get8(); - uint32_t total_data_symbols = file_.get32le(); - uint8_t maximum_pulses_per_data_symbol = file_.get8(); - uint8_t symbols_in_data_table = file_.get8(); + const uint32_t total_data_symbols = file_.get32le(); + const uint8_t maximum_pulses_per_data_symbol = file_.get8(); + const uint8_t symbols_in_data_table = file_.get8(); get_generalised_segment(total_pilot_symbols, maximum_pulses_per_pilot_symbol, symbols_in_pilot_table, false); get_generalised_segment(total_data_symbols, maximum_pulses_per_data_symbol, symbols_in_data_table, true); @@ -222,7 +222,7 @@ void TZX::Serialiser::get_standard_speed_data_block() { data_block.data.data_length = file_.get16le(); if(!data_block.data.data_length) return; - uint8_t first_byte = file_.get8(); + const uint8_t first_byte = file_.get8(); data_block.length_of_pilot_tone = (first_byte < 128) ? 8063 : 3223; file_.seek(-1, SEEK_CUR); @@ -275,8 +275,8 @@ void TZX::Serialiser::get_data(const Data &data) { } void TZX::Serialiser::get_pure_tone_data_block() { - uint16_t length_of_pulse = file_.get16le(); - uint16_t nunber_of_pulses = file_.get16le(); + const uint16_t length_of_pulse = file_.get16le(); + const uint16_t nunber_of_pulses = file_.get16le(); post_pulses(nunber_of_pulses, length_of_pulse); } @@ -330,7 +330,7 @@ void TZX::Serialiser::get_pulse_sequence() { } void TZX::Serialiser::get_pause() { - uint16_t duration = file_.get16le(); + const uint16_t duration = file_.get16le(); if(!duration) { // TODO (maybe): post a 'pause the tape' suggestion } else { @@ -428,7 +428,7 @@ void TZX::Serialiser::post_pulse(const Storage::Time &time) { // MARK: - Flow control; currently ignored void TZX::Serialiser::ignore_group_start() { - uint8_t length = file_.get8(); + const uint8_t length = file_.get8(); file_.seek(length, SEEK_CUR); } @@ -436,12 +436,12 @@ void TZX::Serialiser::ignore_group_end() { } void TZX::Serialiser::ignore_jump_to_block() { - uint16_t target = file_.get16le(); + const uint16_t target = file_.get16le(); (void)target; } void TZX::Serialiser::ignore_loop_start() { - uint16_t number_of_repetitions = file_.get16le(); + const uint16_t number_of_repetitions = file_.get16le(); (void)number_of_repetitions; } @@ -449,7 +449,7 @@ void TZX::Serialiser::ignore_loop_end() { } void TZX::Serialiser::ignore_call_sequence() { - uint16_t number_of_entries = file_.get16le(); + const uint16_t number_of_entries = file_.get16le(); file_.seek(number_of_entries * sizeof(uint16_t), SEEK_CUR); } @@ -457,7 +457,7 @@ void TZX::Serialiser::ignore_return_from_sequence() { } void TZX::Serialiser::ignore_select_block() { - uint16_t length_of_block = file_.get16le(); + const uint16_t length_of_block = file_.get16le(); file_.seek(length_of_block, SEEK_CUR); } @@ -467,32 +467,32 @@ void TZX::Serialiser::ignore_stop_tape_if_in_48kb_mode() { void TZX::Serialiser::ignore_custom_info_block() { file_.seek(0x10, SEEK_CUR); - uint32_t length = file_.get32le(); + const uint32_t length = file_.get32le(); file_.seek(length, SEEK_CUR); } // MARK: - Messaging void TZX::Serialiser::ignore_text_description() { - uint8_t length = file_.get8(); + const uint8_t length = file_.get8(); file_.seek(length, SEEK_CUR); } void TZX::Serialiser::ignore_message_block() { - uint8_t time_for_display = file_.get8(); - uint8_t length = file_.get8(); + const uint8_t time_for_display = file_.get8(); + const uint8_t length = file_.get8(); file_.seek(length, SEEK_CUR); (void)time_for_display; } void TZX::Serialiser::ignore_archive_info() { - uint16_t length = file_.get16le(); + const uint16_t length = file_.get16le(); file_.seek(length, SEEK_CUR); } void TZX::Serialiser::get_hardware_type() { // TODO: pick a way to retain and communicate this. - uint8_t number_of_machines = file_.get8(); + const uint8_t number_of_machines = file_.get8(); file_.seek(number_of_machines * 3, SEEK_CUR); } diff --git a/Storage/Tape/Formats/TZX.hpp b/Storage/Tape/Formats/TZX.hpp index c17e282b1..95bbc88c7 100644 --- a/Storage/Tape/Formats/TZX.hpp +++ b/Storage/Tape/Formats/TZX.hpp @@ -39,7 +39,7 @@ private: Storage::FileHolder file_; void reset() override; - void get_next_pulses() override; + void push_next_pulses() override; bool current_level_; diff --git a/Storage/Tape/Formats/TapePRG.cpp b/Storage/Tape/Formats/TapePRG.cpp index 1a1ff9c9c..58e5bce3c 100644 --- a/Storage/Tape/Formats/TapePRG.cpp +++ b/Storage/Tape/Formats/TapePRG.cpp @@ -65,7 +65,7 @@ PRG::Serialiser::Serialiser(const std::string &file_name) : throw ErrorBadFormat; } -Storage::Tape::Pulse PRG::Serialiser::get_next_pulse() { +Storage::Tape::Pulse PRG::Serialiser::next_pulse() { // these are all microseconds per pole constexpr unsigned int leader_zero_length = 179; constexpr unsigned int zero_length = 169; @@ -126,9 +126,9 @@ void PRG::Serialiser::get_next_output_token() { } // determine whether a new byte needs to be queued up - int block_offset = phase_offset_ - block_leadin_length; - int bit_offset = block_offset % 10; - int byte_offset = block_offset / 10; + const int block_offset = phase_offset_ - block_leadin_length; + const int bit_offset = block_offset % 10; + const int byte_offset = block_offset / 10; phase_offset_++; if(!bit_offset && diff --git a/Storage/Tape/Formats/TapePRG.hpp b/Storage/Tape/Formats/TapePRG.hpp index 45a0bdb0d..cdc1e64d7 100644 --- a/Storage/Tape/Formats/TapePRG.hpp +++ b/Storage/Tape/Formats/TapePRG.hpp @@ -38,7 +38,7 @@ private: Serialiser(const std::string &file_name); private: bool is_at_end() const override; - Pulse get_next_pulse() override; + Pulse next_pulse() override; void reset() override; FileHolder file_; diff --git a/Storage/Tape/Formats/TapeUEF.cpp b/Storage/Tape/Formats/TapeUEF.cpp index 455760388..97ce557a7 100644 --- a/Storage/Tape/Formats/TapeUEF.cpp +++ b/Storage/Tape/Formats/TapeUEF.cpp @@ -28,8 +28,7 @@ float gzgetfloat(gzFile file) { was the first byte read from the UEF, Float[1] the second, etc */ /* decode mantissa */ - int mantissa; - mantissa = bytes[0] | (bytes[1] << 8) | ((bytes[2]&0x7f)|0x80) << 16; + const int mantissa = bytes[0] | (bytes[1] << 8) | ((bytes[2]&0x7f)|0x80) << 16; float result = float(mantissa); result = float(ldexp(result, -23)); @@ -82,7 +81,7 @@ UEF::Serialiser::Serialiser(const std::string &file_name) { file_ = gzopen(file_name.c_str(), "rb"); char identifier[10]; - int bytes_read = gzread(file_, identifier, 10); + const int bytes_read = gzread(file_, identifier, 10); if(bytes_read < 10 || std::strcmp(identifier, "UEF File!")) { throw ErrorNotUEF; } @@ -127,7 +126,7 @@ bool UEF::Serialiser::get_next_chunk(Chunk &result) { return true; } -void UEF::Serialiser::get_next_pulses() { +void UEF::Serialiser::push_next_pulses() { while(empty()) { // read chunk details Chunk next_chunk; diff --git a/Storage/Tape/Formats/TapeUEF.hpp b/Storage/Tape/Formats/TapeUEF.hpp index 0df5ca892..4a4435226 100644 --- a/Storage/Tape/Formats/TapeUEF.hpp +++ b/Storage/Tape/Formats/TapeUEF.hpp @@ -60,7 +60,7 @@ private: }; bool get_next_chunk(Chunk &); - void get_next_pulses() override; + void push_next_pulses() override; void queue_implicit_bit_pattern(uint32_t length); void queue_explicit_bit_pattern(uint32_t length); diff --git a/Storage/Tape/Formats/ZX80O81P.cpp b/Storage/Tape/Formats/ZX80O81P.cpp index d83c907f0..9730f4d5e 100644 --- a/Storage/Tape/Formats/ZX80O81P.cpp +++ b/Storage/Tape/Formats/ZX80O81P.cpp @@ -52,7 +52,7 @@ bool ZX80O81P::Serialiser::is_at_end() const { return has_finished_data() && has_ended_final_byte_; } -Pulse ZX80O81P::Serialiser::get_next_pulse() { +Pulse ZX80O81P::Serialiser::next_pulse() { Pulse pulse; // Start with 1 second of silence. diff --git a/Storage/Tape/Formats/ZX80O81P.hpp b/Storage/Tape/Formats/ZX80O81P.hpp index 406005463..08972f888 100644 --- a/Storage/Tape/Formats/ZX80O81P.hpp +++ b/Storage/Tape/Formats/ZX80O81P.hpp @@ -46,7 +46,7 @@ private: private: bool is_at_end() const override; void reset() override; - Pulse get_next_pulse() override; + Pulse next_pulse() override; bool has_finished_data() const; TargetPlatform::Type platform_type_; diff --git a/Storage/Tape/Formats/ZXSpectrumTAP.cpp b/Storage/Tape/Formats/ZXSpectrumTAP.cpp index c64f9b20f..d3e790e57 100644 --- a/Storage/Tape/Formats/ZXSpectrumTAP.cpp +++ b/Storage/Tape/Formats/ZXSpectrumTAP.cpp @@ -49,7 +49,7 @@ void ZXSpectrumTAP::Serialiser::reset() { read_next_block(); } -Pulse ZXSpectrumTAP::Serialiser::get_next_pulse() { +Pulse ZXSpectrumTAP::Serialiser::next_pulse() { // Adopt a general pattern of high then low. Pulse pulse; pulse.type = (distance_into_phase_ & 1) ? Pulse::Type::High : Pulse::Type::Low; diff --git a/Storage/Tape/Formats/ZXSpectrumTAP.hpp b/Storage/Tape/Formats/ZXSpectrumTAP.hpp index 6b6fe3482..550b9ea0c 100644 --- a/Storage/Tape/Formats/ZXSpectrumTAP.hpp +++ b/Storage/Tape/Formats/ZXSpectrumTAP.hpp @@ -53,7 +53,7 @@ private: // Implemented to satisfy @c Tape. bool is_at_end() const override; void reset() override; - Pulse get_next_pulse() override; + Pulse next_pulse() override; } serialiser_; }; diff --git a/Storage/Tape/Parsers/MSX.cpp b/Storage/Tape/Parsers/MSX.cpp index fed2c6a6a..bff397414 100644 --- a/Storage/Tape/Parsers/MSX.cpp +++ b/Storage/Tape/Parsers/MSX.cpp @@ -13,7 +13,7 @@ using namespace Storage::Tape::MSX; std::unique_ptr Parser::find_header(Storage::Tape::BinaryTapePlayer &tape_player) { - if(!tape_player.get_motor_control()) { + if(!tape_player.motor_control()) { return nullptr; } @@ -21,17 +21,17 @@ std::unique_ptr Parser::find_header(Storage::Tape::BinaryTape "When 1,111 cycles have been found with less than 35 microseconds variation in their lengths a header has been located." */ - bool last_level = tape_player.get_input(); + bool last_level = tape_player.input(); float low = std::numeric_limits::max(); float high = std::numeric_limits::min(); int samples = 0; - while(!tape_player.get_tape()->is_at_end()) { + while(!tape_player.tape()->is_at_end()) { float next_length = 0.0f; do { next_length += float(tape_player.get_cycles_until_next_event()) / float(tape_player.get_input_clock_rate()); tape_player.run_for_input_pulse(); - } while(last_level == tape_player.get_input()); - last_level = tape_player.get_input(); + } while(last_level == tape_player.input()); + last_level = tape_player.input(); low = std::min(low, next_length); high = std::max(high, next_length); samples++; @@ -43,24 +43,24 @@ std::unique_ptr Parser::find_header(Storage::Tape::BinaryTape if(samples == 1111*2) break; // Cycles are read, not half-cycles. } - if(tape_player.get_tape()->is_at_end()) return nullptr; + if(tape_player.tape()->is_at_end()) return nullptr; /* "The next 256 cycles are then read (1B34H) and averaged to determine the cassette HI cycle length." */ float total_length = 0.0f; samples = 512; - while(!tape_player.get_tape()->is_at_end()) { + while(!tape_player.tape()->is_at_end()) { total_length += float(tape_player.get_cycles_until_next_event()) / float(tape_player.get_input_clock_rate()); - if(tape_player.get_input() != last_level) { + if(tape_player.input() != last_level) { samples--; if(!samples) break; - last_level = tape_player.get_input(); + last_level = tape_player.input(); } tape_player.run_for_input_pulse(); } - if(tape_player.get_tape()->is_at_end()) return nullptr; + if(tape_player.tape()->is_at_end()) return nullptr; /* This figure is multiplied by 1.5 and placed in LOWLIM where it defines the minimum acceptable length @@ -88,7 +88,7 @@ std::unique_ptr Parser::find_header(Storage::Tape::BinaryTape -1 otherwise. */ int Parser::get_byte(const FileSpeed &speed, Storage::Tape::BinaryTapePlayer &tape_player) { - if(!tape_player.get_motor_control()) { + if(!tape_player.motor_control()) { return -1; } @@ -103,11 +103,11 @@ int Parser::get_byte(const FileSpeed &speed, Storage::Tape::BinaryTapePlayer &ta */ const float minimum_start_bit_duration = float(speed.minimum_start_bit_duration) * 0.00001145f * 0.5f; int input = 0; - while(!tape_player.get_tape()->is_at_end()) { + while(!tape_player.tape()->is_at_end()) { // Find next transition. - bool level = tape_player.get_input(); + bool level = tape_player.input(); float duration = 0.0; - while(level == tape_player.get_input()) { + while(level == tape_player.input()) { duration += float(tape_player.get_cycles_until_next_event()) / float(tape_player.get_input_clock_rate()); tape_player.run_for_input_pulse(); } @@ -131,25 +131,25 @@ int Parser::get_byte(const FileSpeed &speed, Storage::Tape::BinaryTapePlayer &ta float(tape_player.get_input_clock_rate()) ); int bits_left = 8; - bool level = tape_player.get_input(); - while(!tape_player.get_tape()->is_at_end() && bits_left--) { + bool level = tape_player.input(); + while(!tape_player.tape()->is_at_end() && bits_left--) { // Count number of transitions within cycles_per_window. int transitions = 0; int cycles_remaining = cycles_per_window; - while(!tape_player.get_tape()->is_at_end() && cycles_remaining) { + while(!tape_player.tape()->is_at_end() && cycles_remaining) { const int cycles_until_next_event = int(tape_player.get_cycles_until_next_event()); const int cycles_to_run_for = std::min(cycles_until_next_event, cycles_remaining); cycles_remaining -= cycles_to_run_for; tape_player.run_for(Cycles(cycles_to_run_for)); - if(level != tape_player.get_input()) { - level = tape_player.get_input(); + if(level != tape_player.input()) { + level = tape_player.input(); transitions++; } } - if(tape_player.get_tape()->is_at_end()) return -1; + if(tape_player.tape()->is_at_end()) return -1; int next_bit = 0; switch(transitions) { @@ -170,16 +170,16 @@ int Parser::get_byte(const FileSpeed &speed, Storage::Tape::BinaryTapePlayer &ta transition count two more." */ int required_transitions = 2 - (transitions&1); - while(!tape_player.get_tape()->is_at_end()) { + while(!tape_player.tape()->is_at_end()) { tape_player.run_for_input_pulse(); - if(level != tape_player.get_input()) { - level = tape_player.get_input(); + if(level != tape_player.input()) { + level = tape_player.input(); required_transitions--; if(!required_transitions) break; } } - if(tape_player.get_tape()->is_at_end()) return -1; + if(tape_player.tape()->is_at_end()) return -1; } return result; } diff --git a/Storage/Tape/Parsers/TapeParser.hpp b/Storage/Tape/Parsers/TapeParser.hpp index 6118906c3..18ca29d79 100644 --- a/Storage/Tape/Parsers/TapeParser.hpp +++ b/Storage/Tape/Parsers/TapeParser.hpp @@ -29,7 +29,7 @@ public: */ SymbolType get_next_symbol(const std::shared_ptr &tape) { while(!has_next_symbol_ && !tape->is_at_end()) { - process_pulse(tape->get_next_pulse()); + process_pulse(tape->next_pulse()); } if(!has_next_symbol_ && tape->is_at_end()) mark_end(); has_next_symbol_ = false; diff --git a/Storage/Tape/PulseQueuedTape.cpp b/Storage/Tape/PulseQueuedTape.cpp index 383db3bb9..bc5a7d09d 100644 --- a/Storage/Tape/PulseQueuedTape.cpp +++ b/Storage/Tape/PulseQueuedTape.cpp @@ -35,7 +35,7 @@ void PulseQueuedSerialiser::push_back(const Pulse pulse) { queued_pulses_.push_back(pulse); } -Pulse PulseQueuedSerialiser::get_next_pulse() { +Pulse PulseQueuedSerialiser::next_pulse() { const auto silence = [] { return Pulse(Pulse::Type::Zero, Storage::Time(1, 1)); }; @@ -46,7 +46,7 @@ Pulse PulseQueuedSerialiser::get_next_pulse() { if(pulse_pointer_ == queued_pulses_.size()) { clear(); - get_next_pulses(); + push_next_pulses(); if(is_at_end_ || pulse_pointer_ == queued_pulses_.size()) { return silence(); diff --git a/Storage/Tape/PulseQueuedTape.hpp b/Storage/Tape/PulseQueuedTape.hpp index 96a98837f..420203903 100644 --- a/Storage/Tape/PulseQueuedTape.hpp +++ b/Storage/Tape/PulseQueuedTape.hpp @@ -16,11 +16,11 @@ namespace Storage::Tape { /*! Provides a @c Tape with a queue of upcoming pulses and an is-at-end flag. - If is-at-end is set then get_next_pulse() returns a second of silence and - is_at_end() returns true. + If is-at-end is set then @c next_pulse() returns a second of silence and + @c is_at_end() returns @c true. - Otherwise get_next_pulse() returns something from the pulse queue if there is - anything there, and otherwise calls get_next_pulses(). get_next_pulses() is + Otherwise @c next_pulse() returns something from the pulse queue if there is + anything there, and otherwise calls @c push_next_pulses() which is virtual, giving subclasses a chance to provide the next batch of pulses. */ class PulseQueuedSerialiser: public TapeSerialiser { @@ -31,10 +31,10 @@ public: bool empty() const; void set_is_at_end(bool); - Pulse get_next_pulse() override; + Pulse next_pulse() override; bool is_at_end() const override; - virtual void get_next_pulses() = 0; + virtual void push_next_pulses() = 0; private: std::vector queued_pulses_; diff --git a/Storage/Tape/Tape.cpp b/Storage/Tape/Tape.cpp index 6c1050749..e8f97b745 100644 --- a/Storage/Tape/Tape.cpp +++ b/Storage/Tape/Tape.cpp @@ -24,17 +24,17 @@ void Storage::Tape::Tape::seek(const Time seek_time) { Time next_time(0); reset(); while(next_time <= seek_time) { - get_next_pulse(); + next_pulse(); next_time += pulse_.length; } } -Storage::Time Tape::get_current_time() { +Storage::Time Tape::current_time() { Time time(0); - uint64_t steps = get_offset(); + uint64_t steps = offset(); reset(); while(steps--) { - get_next_pulse(); + next_pulse(); time += pulse_.length; } return time; @@ -45,13 +45,13 @@ void Storage::Tape::Tape::reset() { serialiser_.reset(); } -Pulse Tape::get_next_pulse() { - pulse_ = serialiser_.get_next_pulse(); +Pulse Tape::next_pulse() { + pulse_ = serialiser_.next_pulse(); offset_++; return pulse_; } -uint64_t Tape::get_offset() const { +uint64_t Tape::offset() const { return offset_; } @@ -61,7 +61,7 @@ void Tape::set_offset(uint64_t offset) { reset(); } offset -= offset_; - while(offset--) get_next_pulse(); + while(offset--) next_pulse(); } bool Tape::is_at_end() const { @@ -78,11 +78,11 @@ ClockingHint::Preference TapePlayer::preferred_clocking() const { void TapePlayer::set_tape(std::shared_ptr tape) { tape_ = tape; reset_timer(); - get_next_pulse(); + next_pulse(); update_clocking_observer(); } -std::shared_ptr TapePlayer::get_tape() { +std::shared_ptr TapePlayer::tape() { return tape_; } @@ -90,10 +90,10 @@ bool TapePlayer::has_tape() const { return bool(tape_); } -void TapePlayer::get_next_pulse() { +void TapePlayer::next_pulse() { // get the new pulse if(tape_) { - current_pulse_ = tape_->get_next_pulse(); + current_pulse_ = tape_->next_pulse(); if(tape_->is_at_end()) update_clocking_observer(); } else { current_pulse_.length.length = 1; @@ -104,7 +104,7 @@ void TapePlayer::get_next_pulse() { set_next_event_time_interval(current_pulse_.length); } -Pulse TapePlayer::get_current_pulse() const { +Pulse TapePlayer::current_pulse() const { return current_pulse_; } @@ -123,8 +123,8 @@ void TapePlayer::run_for_input_pulse() { } void TapePlayer::process_next_event() { - process_input_pulse(current_pulse_); - get_next_pulse(); + process(current_pulse_); + next_pulse(); } // MARK: - Binary Player @@ -157,7 +157,7 @@ void BinaryTapePlayer::set_activity_observer(Activity::Observer *observer) { } } -bool BinaryTapePlayer::get_motor_control() const { +bool BinaryTapePlayer::motor_control() const { return motor_is_running_; } @@ -165,7 +165,7 @@ void BinaryTapePlayer::set_tape_output(bool) { // TODO } -bool BinaryTapePlayer::get_input() const { +bool BinaryTapePlayer::input() const { return motor_is_running_ && input_level_; } @@ -177,7 +177,7 @@ void BinaryTapePlayer::set_delegate(Delegate *delegate) { delegate_ = delegate; } -void BinaryTapePlayer::process_input_pulse(const Storage::Tape::Pulse &pulse) { +void BinaryTapePlayer::process(const Storage::Tape::Pulse &pulse) { bool new_input_level = pulse.type == Pulse::High; if(input_level_ != new_input_level) { input_level_ = new_input_level; diff --git a/Storage/Tape/Tape.hpp b/Storage/Tape/Tape.hpp index 6442a1a02..8771d577d 100644 --- a/Storage/Tape/Tape.hpp +++ b/Storage/Tape/Tape.hpp @@ -31,9 +31,12 @@ struct Pulse { Pulse() = default; }; +/*! + Provdes the means for tape serialiserion. +*/ class TapeSerialiser { public: - virtual Pulse get_next_pulse() = 0; + virtual Pulse next_pulse() = 0; virtual void reset() = 0; virtual bool is_at_end() const = 0; }; @@ -44,10 +47,6 @@ public: - high pulses exit from zero upward before returning to it; - low pulses exit from zero downward before returning to it; - zero pulses run along zero. - - Subclasses should implement at least @c get_next_pulse and @c reset to provide a serial feeding - of pulses and the ability to return to the start of the feed. They may also implement @c seek if - a better implementation than a linear search from the @c reset time can be implemented. */ class Tape { public: @@ -58,7 +57,7 @@ public: @returns the pulse that begins at the current cursor position. */ - Pulse get_next_pulse(); + Pulse next_pulse(); /// Returns the tape to the beginning. void reset(); @@ -71,7 +70,7 @@ public: required to be at least to the whole pulse. Greater numbers are later than earlier numbers, but not necessarily continuous. */ - uint64_t get_offset() const; + uint64_t offset() const; /*! Moves the tape to the first time at which the specified offset would be returned by get_offset. @@ -81,7 +80,7 @@ public: /*! Calculates and returns the amount of time that has elapsed since the time began. Potentially expensive. */ - Time get_current_time(); + Time current_time(); /*! Seeks to @c time. Potentially expensive. @@ -101,33 +100,32 @@ private: Provides a helper for: (i) retaining a reference to a tape; and (ii) running the tape at a certain input clock rate. - Will call @c process_input_pulse instantaneously upon reaching *the end* of a pulse. Therefore a subclass - can decode pulses into data within process_input_pulse, using the supplied pulse's @c length and @c type. + Will call @c process(Pulse) instantaneously upon reaching *the end* of a pulse. Therefore a subclass + can decode pulses into data within @c process, using the supplied pulse's @c length and @c type. */ class TapePlayer: public TimedEventLoop, public ClockingHint::Source { public: TapePlayer(int input_clock_rate); virtual ~TapePlayer() = default; - void set_tape(std::shared_ptr tape); + void set_tape(std::shared_ptr); bool has_tape() const; - std::shared_ptr get_tape(); + std::shared_ptr tape(); void run_for(const Cycles cycles); - void run_for_input_pulse(); ClockingHint::Preference preferred_clocking() const override; - Pulse get_current_pulse() const; + Pulse current_pulse() const; void complete_pulse(); protected: virtual void process_next_event() override; - virtual void process_input_pulse(const Pulse &pulse) = 0; + virtual void process(const Pulse &) = 0; private: - inline void get_next_pulse(); + inline void next_pulse(); std::shared_ptr tape_; Pulse current_pulse_; @@ -144,26 +142,26 @@ private: class BinaryTapePlayer : public TapePlayer { public: BinaryTapePlayer(int input_clock_rate); - void set_motor_control(bool enabled); - bool get_motor_control() const; + void set_motor_control(bool); + bool motor_control() const; - void set_tape_output(bool set); - bool get_input() const; + void set_tape_output(bool); + bool input() const; void run_for(const Cycles cycles); struct Delegate { - virtual void tape_did_change_input(BinaryTapePlayer *tape_player) = 0; + virtual void tape_did_change_input(BinaryTapePlayer *) = 0; }; void set_delegate(Delegate *delegate); ClockingHint::Preference preferred_clocking() const final; - void set_activity_observer(Activity::Observer *observer); + void set_activity_observer(Activity::Observer *); protected: Delegate *delegate_ = nullptr; - void process_input_pulse(const Storage::Tape::Pulse &pulse) final; + void process(const Pulse &) final; bool input_level_ = false; bool motor_is_running_ = false; From f804c32eeeb6058f8cad2239620722595b7f05e6 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Tue, 3 Dec 2024 22:57:38 -0500 Subject: [PATCH 11/11] Opportunistically `const`. --- Storage/Tape/Formats/CSW.cpp | 6 +++--- Storage/Tape/Formats/TZX.cpp | 21 +++++++++++++-------- Storage/Tape/Formats/TapeUEF.cpp | 4 ++-- 3 files changed, 18 insertions(+), 13 deletions(-) diff --git a/Storage/Tape/Formats/CSW.cpp b/Storage/Tape/Formats/CSW.cpp index 12b90e6dd..8263aa39e 100644 --- a/Storage/Tape/Formats/CSW.cpp +++ b/Storage/Tape/Formats/CSW.cpp @@ -94,9 +94,9 @@ CSW::Serialiser::Serialiser(const std::string &file_name) : source_data_pointer_ CSW::Serialiser::Serialiser( const std::vector &&data, - CompressionType compression_type, - bool initial_level, - uint32_t sampling_rate + const CompressionType compression_type, + const bool initial_level, + const uint32_t sampling_rate ) : compression_type_(compression_type) { pulse_.length.clock_rate = sampling_rate; pulse_.type = initial_level ? Pulse::High : Pulse::Low; diff --git a/Storage/Tape/Formats/TZX.cpp b/Storage/Tape/Formats/TZX.cpp index 03ee816cb..8f108afce 100644 --- a/Storage/Tape/Formats/TZX.cpp +++ b/Storage/Tape/Formats/TZX.cpp @@ -113,7 +113,12 @@ void TZX::Serialiser::get_csw_recording_block() { std::vector raw_block = file_.read(block_length - 10); - CSW csw(std::move(raw_block), (compression_type == 2) ? CSW::CompressionType::ZRLE : CSW::CompressionType::RLE, current_level_, sampling_rate); + CSW csw( + std::move(raw_block), + (compression_type == 2) ? CSW::CompressionType::ZRLE : CSW::CompressionType::RLE, + current_level_, + sampling_rate + ); while(!csw.is_at_end()) { Pulse next_pulse = csw.next_pulse(); current_level_ = (next_pulse.type == Pulse::High); @@ -146,10 +151,10 @@ void TZX::Serialiser::get_generalised_data_block() { } void TZX::Serialiser::get_generalised_segment( - uint32_t output_symbols, - uint8_t max_pulses_per_symbol, - uint8_t number_of_symbols, - bool is_data + const uint32_t output_symbols, + const uint8_t max_pulses_per_symbol, + const uint8_t number_of_symbols, + const bool is_data ) { if(!output_symbols) return; @@ -402,15 +407,15 @@ void TZX::Serialiser::get_kansas_city_block() { // MARK: - Output -void TZX::Serialiser::post_pulses(unsigned int count, unsigned int length) { +void TZX::Serialiser::post_pulses(unsigned int count, const unsigned int length) { while(count--) post_pulse(length); } -void TZX::Serialiser::post_pulse(unsigned int length) { +void TZX::Serialiser::post_pulse(const unsigned int length) { post_pulse(Storage::Time(length, StandardTZXClock)); } -void TZX::Serialiser::post_gap(unsigned int milliseconds) { +void TZX::Serialiser::post_gap(const unsigned int milliseconds) { if(!milliseconds) return; if(milliseconds > 1 && !current_level_) { post_pulse(Storage::Time(TZXClockMSMultiplier, StandardTZXClock)); diff --git a/Storage/Tape/Formats/TapeUEF.cpp b/Storage/Tape/Formats/TapeUEF.cpp index 97ce557a7..34be96dca 100644 --- a/Storage/Tape/Formats/TapeUEF.cpp +++ b/Storage/Tape/Formats/TapeUEF.cpp @@ -178,7 +178,7 @@ void UEF::Serialiser::queue_implicit_bit_pattern(uint32_t length) { } } -void UEF::Serialiser::queue_explicit_bit_pattern(uint32_t length) { +void UEF::Serialiser::queue_explicit_bit_pattern(const uint32_t length) { const std::size_t length_in_bits = (length << 3) - size_t(gzget8(file_)); uint8_t current_byte = 0; for(std::size_t bit = 0; bit < length_in_bits; bit++) { @@ -298,7 +298,7 @@ void UEF::Serialiser::queue_implicit_byte(uint8_t byte) { queue_bit(1); } -void UEF::Serialiser::queue_bit(int bit) { +void UEF::Serialiser::queue_bit(const int bit) { int number_of_cycles; Time duration; duration.clock_rate = time_base_ * 4;