1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-12-13 00:29:14 +00:00

Improve interface.

This commit is contained in:
Thomas Harte 2024-12-03 22:54:29 -05:00
parent 6d4ff0b89a
commit b89ecadc3a
33 changed files with 168 additions and 165 deletions

View File

@ -454,7 +454,7 @@ public:
int cycles_left_while_plausibly_in_data = 50; int cycles_left_while_plausibly_in_data = 50;
tape_.clear_interrupts(Interrupt::ReceiveDataFull); tape_.clear_interrupts(Interrupt::ReceiveDataFull);
while(!tape_.get_tape()->is_at_end()) { while(!tape_.tape()->is_at_end()) {
tape_.run_for_input_pulse(); tape_.run_for_input_pulse();
--cycles_left_while_plausibly_in_data; --cycles_left_while_plausibly_in_data;
if(!cycles_left_while_plausibly_in_data) fast_load_is_in_data_ = false; if(!cycles_left_while_plausibly_in_data) fast_load_is_in_data_ = false;

View File

@ -68,7 +68,7 @@ uint8_t Tape::get_data_register() {
return uint8_t(data_register_ >> 2); 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); shifter_.process_pulse(pulse);
} }

View File

@ -43,10 +43,10 @@ public:
inline void set_is_enabled(bool is_enabled) { is_enabled_ = is_enabled; } inline void set_is_enabled(bool is_enabled) { is_enabled_ = is_enabled; }
void set_is_in_input_mode(bool is_in_input_mode); 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: 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 push_tape_bit(uint16_t bit);
inline void get_next_tape_pulse(); inline void get_next_tape_pulse();

View File

@ -721,7 +721,7 @@ public:
case 0: return ay_.ay().get_data_output(); // Port A is wired to the AY case 0: return ay_.ay().get_data_output(); // Port A is wired to the AY
case 1: return case 1: return
(crtc_.get_bus_state().vsync ? 0x01 : 0x00) | // Bit 0 returns CRTC vsync. (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: 0x7e; // Bits unimplemented:
// //
// Bit 6: printer ready (1 = not) // Bit 6: printer ready (1 = not)
@ -899,8 +899,8 @@ public:
// Seed with the current pulse; the CPC will have finished the // 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 // preceding symbol and be a short way into the pulse that should determine the
// first bit of this byte. // first bit of this byte.
parser.process_pulse(tape_player_.get_current_pulse()); parser.process_pulse(tape_player_.current_pulse());
const auto byte = parser.get_byte(tape_player_.get_tape()); const auto byte = parser.get_byte(tape_player_.tape());
auto flags = z80_.value_of(CPU::Z80::Register::Flags); auto flags = z80_.value_of(CPU::Z80::Register::Flags);
if(byte) { if(byte) {

View File

@ -526,9 +526,9 @@ class ConcreteMachine:
// Address 0xf7b2 contains a JSR to 0xf8c0 that will fill the tape buffer with the next header. // 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. // So cancel that via a double NOP and fill in the next header programmatically.
Storage::Tape::Commodore::Parser parser; Storage::Tape::Commodore::Parser parser;
std::unique_ptr<Storage::Tape::Commodore::Header> header = parser.get_next_header(tape_->get_tape()); std::unique_ptr<Storage::Tape::Commodore::Header> 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) { if(header) {
// serialise to wherever b2:b3 points // serialise to wherever b2:b3 points
const uint16_t tape_buffer_pointer = uint16_t(ram_[0xb2]) | uint16_t(ram_[0xb3] << 8); 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"); logger.info().append("Found header");
} else { } else {
// no header found, so pretend this hack never interceded // 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; hold_tape_ = false;
logger.info().append("Didn't find header"); 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)); uint8_t x = uint8_t(m6502_.value_of(CPU::MOS6502::Register::X));
if(x == 0xe) { if(x == 0xe) {
Storage::Tape::Commodore::Parser parser; Storage::Tape::Commodore::Parser parser;
const uint64_t tape_position = tape_->get_tape()->get_offset(); const auto tape_position = tape_->tape()->offset();
const std::unique_ptr<Storage::Tape::Commodore::Data> data = parser.get_next_data(tape_->get_tape()); const std::unique_ptr<Storage::Tape::Commodore::Data> data = parser.get_next_data(tape_->tape());
if(data) { if(data) {
uint16_t start_address, end_address; uint16_t start_address, end_address;
start_address = uint16_t(ram_[0xc1] | (ram_[0xc2] << 8)); start_address = uint16_t(ram_[0xc1] | (ram_[0xc2] << 8));
@ -582,7 +582,7 @@ class ConcreteMachine:
hold_tape_ = true; hold_tape_ = true;
logger.info().append("Found data"); logger.info().append("Found data");
} else { } else {
tape_->get_tape()->set_offset(tape_position); tape_->tape()->set_offset(tape_position);
hold_tape_ = false; hold_tape_ = false;
logger.info().append("Didn't find data"); logger.info().append("Didn't find data");
} }
@ -670,7 +670,7 @@ class ConcreteMachine:
} }
void tape_did_change_input(Storage::Tape::BinaryTapePlayer *tape) final { 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 { KeyboardMapper *get_keyboard_mapper() final {

View File

@ -82,7 +82,7 @@ class AYPortHandler: public GI::AY38910::PortHandler {
return return
(static_cast<Joystick *>(joysticks_[selected_joystick_].get())->get_state() & 0x3f) | (static_cast<Joystick *>(joysticks_[selected_joystick_].get())->get_state() & 0x3f) |
0x40 | 0x40 |
(tape_player_.get_input() ? 0x00 : 0x80); (tape_player_.input() ? 0x00 : 0x80);
} }
return 0xff; return 0xff;
} }
@ -893,7 +893,7 @@ class ConcreteMachine:
activity_observer_ = observer; activity_observer_ = observer;
if(activity_observer_) { if(activity_observer_) {
activity_observer_->register_led("Tape motor"); 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());
} }
} }

View File

@ -168,7 +168,7 @@ class TapePlayer: public Storage::Tape::BinaryTapePlayer {
@returns The next byte from the tape. @returns The next byte from the tape.
*/ */
uint8_t get_next_byte(bool use_fast_encoding) { 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: private:
@ -469,7 +469,7 @@ template <Analyser::Static::Oric::Target::DiskInterface disk_interface, CPU::MOS
use_fast_tape_hack_ && use_fast_tape_hack_ &&
operation == CPU::MOS6502::BusOperation::ReadOpcode && operation == CPU::MOS6502::BusOperation::ReadOpcode &&
tape_player_.has_tape() && tape_player_.has_tape() &&
!tape_player_.get_tape()->is_at_end()) { !tape_player_.tape()->is_at_end()) {
uint8_t next_byte = tape_player_.get_next_byte(!ram_[tape_speed_address_]); uint8_t next_byte = tape_player_.get_next_byte(!ram_[tape_speed_address_]);
m6502_.set_value_of(CPU::MOS6502Esque::A, next_byte); m6502_.set_value_of(CPU::MOS6502Esque::A, next_byte);
@ -632,8 +632,8 @@ template <Analyser::Static::Oric::Target::DiskInterface disk_interface, CPU::MOS
// set CB1 // set CB1
via_.set_control_line_input( via_.set_control_line_input(
MOS::MOS6522::Port::B, MOS::MOS6522::Line::One, MOS::MOS6522::Port::B, MOS::MOS6522::Line::One,
tape_player_.get_motor_control() ? tape_player_.motor_control() ?
!tape_player_.get_input() : !tape_player_.input() :
!video_->vsync() !video_->vsync()
); );
} }

View File

@ -185,7 +185,7 @@ template<bool is_zx81> class ConcreteMachine:
if(!nmi_is_enabled_) set_vsync(true); if(!nmi_is_enabled_) set_vsync(true);
value &= keyboard_.read(address); 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. // The below emulates the ZonX AY expansion device.
@ -232,8 +232,8 @@ template<bool is_zx81> class ConcreteMachine:
case CPU::Z80::PartialMachineCycle::ReadOpcode: case CPU::Z80::PartialMachineCycle::ReadOpcode:
// Check for use of the fast tape hack. // Check for use of the fast tape hack.
if(use_fast_tape_hack_ && address == tape_trap_address_) { if(use_fast_tape_hack_ && address == tape_trap_address_) {
const uint64_t prior_offset = tape_player_.get_tape()->get_offset(); const uint64_t prior_offset = tape_player_.tape()->offset();
const int next_byte = parser_.get_next_byte(tape_player_.get_tape()); const int next_byte = parser_.get_next_byte(tape_player_.tape());
if(next_byte != -1) { if(next_byte != -1) {
const uint16_t hl = z80_.value_of(CPU::Z80::Register::HL); const uint16_t hl = z80_.value_of(CPU::Z80::Register::HL);
ram_[hl & ram_mask_] = uint8_t(next_byte); ram_[hl & ram_mask_] = uint8_t(next_byte);
@ -246,7 +246,7 @@ template<bool is_zx81> class ConcreteMachine:
tape_advance_delay_ = 1000; tape_advance_delay_ = 1000;
return 0; return 0;
} else { } else {
tape_player_.get_tape()->set_offset(prior_offset); tape_player_.tape()->set_offset(prior_offset);
} }
} }
@ -365,7 +365,7 @@ template<bool is_zx81> class ConcreteMachine:
} }
bool get_tape_is_playing() final { bool get_tape_is_playing() final {
return tape_player_.get_motor_control(); return tape_player_.motor_control();
} }
// MARK: - Typer timing // MARK: - Typer timing

View File

@ -541,7 +541,7 @@ template<Model model> class ConcreteMachine:
// b6: tape input // b6: tape input
*cycle.value &= keyboard_.read(address); *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. // Add Joystick input on top.
if(!(address&0x1000)) *cycle.value &= static_cast<Joystick *>(joysticks_[0].get())->get_sinclair(0); if(!(address&0x1000)) *cycle.value &= static_cast<Joystick *>(joysticks_[0].get())->get_sinclair(0);
@ -716,7 +716,7 @@ template<Model model> class ConcreteMachine:
} }
bool get_tape_is_playing() final { bool get_tape_is_playing() final {
return tape_player_.get_motor_control(); return tape_player_.motor_control();
} }
// MARK: - Configuration options. // MARK: - Configuration options.
@ -921,7 +921,7 @@ template<Model model> class ConcreteMachine:
if(!(flags & 1)) return false; if(!(flags & 1)) return false;
const uint8_t block_type = uint8_t(z80_.value_of(Register::ADash)); 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; if(!block || block_type != (*block).type) return false;
uint16_t length = z80_.value_of(Register::DE); uint16_t length = z80_.value_of(Register::DE);
@ -930,7 +930,7 @@ template<Model model> class ConcreteMachine:
flags = 0x93; flags = 0x93;
uint8_t parity = 0x00; uint8_t parity = 0x00;
while(length--) { while(length--) {
auto next = parser.get_byte(tape_player_.get_tape()); auto next = parser.get_byte(tape_player_.tape());
if(!next) { if(!next) {
flags &= ~1; flags &= ~1;
break; break;
@ -941,7 +941,7 @@ template<Model model> class ConcreteMachine:
++target; ++target;
} }
auto stored_parity = parser.get_byte(tape_player_.get_tape()); auto stored_parity = parser.get_byte(tape_player_.tape());
if(!stored_parity) { if(!stored_parity) {
flags &= ~1; flags &= ~1;
} else { } else {

View File

@ -181,7 +181,7 @@ void CAS::Serialiser::reset() {
distance_into_bit_ = 0; distance_into_bit_ = 0;
} }
Pulse CAS::Serialiser::get_next_pulse() { Pulse CAS::Serialiser::next_pulse() {
Pulse pulse; Pulse pulse;
pulse.length.clock_rate = 9600; pulse.length.clock_rate = 9600;
// Clock rate is four times the baud rate (of 2400), because the quickest thing that might need // Clock rate is four times the baud rate (of 2400), because the quickest thing that might need

View File

@ -40,7 +40,7 @@ private:
private: private:
bool is_at_end() const override; bool is_at_end() const override;
void reset() override; void reset() override;
Pulse get_next_pulse() override; Pulse next_pulse() override;
// Storage for the array of data blobs to transcribe into audio; // 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 // each chunk is preceded by a header which may be long, and is optionally

View File

@ -21,8 +21,7 @@ CSW::CSW(const std::vector<uint8_t> &&data, CompressionType type, bool initial_l
serialiser_(std::move(data), type, initial_level, sampling_rate) {} serialiser_(std::move(data), type, initial_level, sampling_rate) {}
CSW::Serialiser::Serialiser(const std::string &file_name) : CSW::Serialiser::Serialiser(const std::string &file_name) : source_data_pointer_(0) {
source_data_pointer_(0) {
Storage::FileHolder file(file_name, FileHolder::FileMode::Read); Storage::FileHolder file(file_name, FileHolder::FileMode::Read);
if(file.stats().st_size < 0x20) throw ErrorNotCSW; 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; if(file.get8() != 0x1a) throw ErrorNotCSW;
// Get version file number. // Get version file number.
uint8_t major_version = file.get8(); const uint8_t major_version = file.get8();
uint8_t minor_version = file.get8(); const uint8_t minor_version = file.get8();
// Reject if this is an unknown version. // Reject if this is an unknown version.
if(major_version > 2 || !major_version || minor_version > 1) throw ErrorNotCSW; 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. // Grab all data remaining in the file.
std::vector<uint8_t> file_data; std::vector<uint8_t> 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_data.resize(remaining_data);
file.read(file_data.data(), remaining_data); file.read(file_data.data(), remaining_data);
@ -93,7 +92,12 @@ CSW::Serialiser::Serialiser(const std::string &file_name) :
invert_pulse(); invert_pulse();
} }
CSW::Serialiser::Serialiser(const std::vector<uint8_t> &&data, CompressionType compression_type, bool initial_level, uint32_t sampling_rate) : compression_type_(compression_type) { CSW::Serialiser::Serialiser(
const std::vector<uint8_t> &&data,
CompressionType compression_type,
bool initial_level,
uint32_t sampling_rate
) : compression_type_(compression_type) {
pulse_.length.clock_rate = sampling_rate; pulse_.length.clock_rate = sampling_rate;
pulse_.type = initial_level ? Pulse::High : Pulse::Low; pulse_.type = initial_level ? Pulse::High : Pulse::Low;
source_data_ = std::move(data); source_data_ = std::move(data);
@ -101,14 +105,16 @@ CSW::Serialiser::Serialiser(const std::vector<uint8_t> &&data, CompressionType c
uint8_t CSW::Serialiser::get_next_byte() { uint8_t CSW::Serialiser::get_next_byte() {
if(source_data_pointer_ == source_data_.size()) return 0xff; 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_++; source_data_pointer_++;
return result; return result;
} }
uint32_t CSW::Serialiser::get_next_int32le() { uint32_t CSW::Serialiser::get_next_int32le() {
if(source_data_pointer_ > source_data_.size() - 4) return 0xffff; 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_ + 0] << 0) |
(source_data_[source_data_pointer_ + 1] << 8) | (source_data_[source_data_pointer_ + 1] << 8) |
(source_data_[source_data_pointer_ + 2] << 16) | (source_data_[source_data_pointer_ + 2] << 16) |
@ -129,7 +135,7 @@ void CSW::Serialiser::reset() {
source_data_pointer_ = 0; source_data_pointer_ = 0;
} }
Pulse CSW::Serialiser::get_next_pulse() { Pulse CSW::Serialiser::next_pulse() {
invert_pulse(); invert_pulse();
pulse_.length.length = get_next_byte(); pulse_.length.length = get_next_byte();
if(!pulse_.length.length) pulse_.length.length = get_next_int32le(); if(!pulse_.length.length) pulse_.length.length = get_next_int32le();

View File

@ -51,7 +51,7 @@ private:
// implemented to satisfy @c Tape // implemented to satisfy @c Tape
bool is_at_end() const override; bool is_at_end() const override;
void reset() override; void reset() override;
Pulse get_next_pulse() override; Pulse next_pulse() override;
Pulse pulse_; Pulse pulse_;
CompressionType compression_type_; CompressionType compression_type_;

View File

@ -51,14 +51,14 @@ bool CommodoreTAP::Serialiser::is_at_end() const {
return is_at_end_; return is_at_end_;
} }
Storage::Tape::Pulse CommodoreTAP::Serialiser::get_next_pulse() { Storage::Tape::Pulse CommodoreTAP::Serialiser::next_pulse() {
if(is_at_end_) { if(is_at_end_) {
return current_pulse_; return current_pulse_;
} }
if(current_pulse_.type == Pulse::High) { if(current_pulse_.type == Pulse::High) {
uint32_t next_length; uint32_t next_length;
uint8_t next_byte = file_.get8(); const uint8_t next_byte = file_.get8();
if(!updated_layout_ || next_byte > 0) { if(!updated_layout_ || next_byte > 0) {
next_length = uint32_t(next_byte) << 3; next_length = uint32_t(next_byte) << 3;
} else { } else {

View File

@ -39,7 +39,7 @@ private:
private: private:
bool is_at_end() const override; bool is_at_end() const override;
void reset() override; void reset() override;
Pulse get_next_pulse() override; Pulse next_pulse() override;
Storage::FileHolder file_; Storage::FileHolder file_;

View File

@ -44,7 +44,7 @@ void OricTAP::Serialiser::reset() {
pulse_counter_ = 0; 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. // Each byte byte is written as 13 bits: 0, eight bits of data, parity, three 1s.
if(bit_count_ == 13) { if(bit_count_ == 13) {
if(next_phase_ != phase_) { if(next_phase_ != phase_) {

View File

@ -39,7 +39,7 @@ private:
private: private:
bool is_at_end() const override; bool is_at_end() const override;
void reset() override; void reset() override;
Pulse get_next_pulse() override; Pulse next_pulse() override;
Storage::FileHolder file_; Storage::FileHolder file_;

View File

@ -32,8 +32,8 @@ TZX::Serialiser::Serialiser(const std::string &file_name) :
if(file_.get8() != 0x1a) throw ErrorNotTZX; if(file_.get8() != 0x1a) throw ErrorNotTZX;
// Get version number // Get version number
uint8_t major_version = file_.get8(); const uint8_t major_version = file_.get8();
uint8_t minor_version = file_.get8(); const uint8_t minor_version = file_.get8();
// Reject if an incompatible version // Reject if an incompatible version
if(major_version != 1 || minor_version > 21) throw ErrorNotTZX; if(major_version != 1 || minor_version > 21) throw ErrorNotTZX;
@ -53,9 +53,9 @@ void TZX::Serialiser::reset() {
post_gap(500); post_gap(500);
} }
void TZX::Serialiser::get_next_pulses() { void TZX::Serialiser::push_next_pulses() {
while(empty()) { while(empty()) {
uint8_t chunk_id = file_.get8(); const uint8_t chunk_id = file_.get8();
if(file_.eof()) { if(file_.eof()) {
set_is_at_end(true); set_is_at_end(true);
return; 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); CSW csw(std::move(raw_block), (compression_type == 2) ? CSW::CompressionType::ZRLE : CSW::CompressionType::RLE, current_level_, sampling_rate);
while(!csw.is_at_end()) { 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); current_level_ = (next_pulse.type == Pulse::High);
push_back(next_pulse); push_back(next_pulse);
} }
@ -125,17 +125,17 @@ void TZX::Serialiser::get_csw_recording_block() {
} }
void TZX::Serialiser::get_generalised_data_block() { void TZX::Serialiser::get_generalised_data_block() {
uint32_t block_length = file_.get32le(); const uint32_t block_length = file_.get32le();
long endpoint = file_.tell() + long(block_length); const long endpoint = file_.tell() + long(block_length);
uint16_t pause_after_block = file_.get16le(); const uint16_t pause_after_block = file_.get16le();
uint32_t total_pilot_symbols = file_.get32le(); const uint32_t total_pilot_symbols = file_.get32le();
uint8_t maximum_pulses_per_pilot_symbol = file_.get8(); const uint8_t maximum_pulses_per_pilot_symbol = file_.get8();
uint8_t symbols_in_pilot_table = file_.get8(); const uint8_t symbols_in_pilot_table = file_.get8();
uint32_t total_data_symbols = file_.get32le(); const uint32_t total_data_symbols = file_.get32le();
uint8_t maximum_pulses_per_data_symbol = file_.get8(); const uint8_t maximum_pulses_per_data_symbol = file_.get8();
uint8_t symbols_in_data_table = 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_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); 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(); data_block.data.data_length = file_.get16le();
if(!data_block.data.data_length) return; 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; data_block.length_of_pilot_tone = (first_byte < 128) ? 8063 : 3223;
file_.seek(-1, SEEK_CUR); 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() { void TZX::Serialiser::get_pure_tone_data_block() {
uint16_t length_of_pulse = file_.get16le(); const uint16_t length_of_pulse = file_.get16le();
uint16_t nunber_of_pulses = file_.get16le(); const uint16_t nunber_of_pulses = file_.get16le();
post_pulses(nunber_of_pulses, length_of_pulse); post_pulses(nunber_of_pulses, length_of_pulse);
} }
@ -330,7 +330,7 @@ void TZX::Serialiser::get_pulse_sequence() {
} }
void TZX::Serialiser::get_pause() { void TZX::Serialiser::get_pause() {
uint16_t duration = file_.get16le(); const uint16_t duration = file_.get16le();
if(!duration) { if(!duration) {
// TODO (maybe): post a 'pause the tape' suggestion // TODO (maybe): post a 'pause the tape' suggestion
} else { } else {
@ -428,7 +428,7 @@ void TZX::Serialiser::post_pulse(const Storage::Time &time) {
// MARK: - Flow control; currently ignored // MARK: - Flow control; currently ignored
void TZX::Serialiser::ignore_group_start() { void TZX::Serialiser::ignore_group_start() {
uint8_t length = file_.get8(); const uint8_t length = file_.get8();
file_.seek(length, SEEK_CUR); file_.seek(length, SEEK_CUR);
} }
@ -436,12 +436,12 @@ void TZX::Serialiser::ignore_group_end() {
} }
void TZX::Serialiser::ignore_jump_to_block() { void TZX::Serialiser::ignore_jump_to_block() {
uint16_t target = file_.get16le(); const uint16_t target = file_.get16le();
(void)target; (void)target;
} }
void TZX::Serialiser::ignore_loop_start() { 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; (void)number_of_repetitions;
} }
@ -449,7 +449,7 @@ void TZX::Serialiser::ignore_loop_end() {
} }
void TZX::Serialiser::ignore_call_sequence() { 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); 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() { 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); 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() { void TZX::Serialiser::ignore_custom_info_block() {
file_.seek(0x10, SEEK_CUR); file_.seek(0x10, SEEK_CUR);
uint32_t length = file_.get32le(); const uint32_t length = file_.get32le();
file_.seek(length, SEEK_CUR); file_.seek(length, SEEK_CUR);
} }
// MARK: - Messaging // MARK: - Messaging
void TZX::Serialiser::ignore_text_description() { void TZX::Serialiser::ignore_text_description() {
uint8_t length = file_.get8(); const uint8_t length = file_.get8();
file_.seek(length, SEEK_CUR); file_.seek(length, SEEK_CUR);
} }
void TZX::Serialiser::ignore_message_block() { void TZX::Serialiser::ignore_message_block() {
uint8_t time_for_display = file_.get8(); const uint8_t time_for_display = file_.get8();
uint8_t length = file_.get8(); const uint8_t length = file_.get8();
file_.seek(length, SEEK_CUR); file_.seek(length, SEEK_CUR);
(void)time_for_display; (void)time_for_display;
} }
void TZX::Serialiser::ignore_archive_info() { void TZX::Serialiser::ignore_archive_info() {
uint16_t length = file_.get16le(); const uint16_t length = file_.get16le();
file_.seek(length, SEEK_CUR); file_.seek(length, SEEK_CUR);
} }
void TZX::Serialiser::get_hardware_type() { void TZX::Serialiser::get_hardware_type() {
// TODO: pick a way to retain and communicate this. // 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); file_.seek(number_of_machines * 3, SEEK_CUR);
} }

View File

@ -39,7 +39,7 @@ private:
Storage::FileHolder file_; Storage::FileHolder file_;
void reset() override; void reset() override;
void get_next_pulses() override; void push_next_pulses() override;
bool current_level_; bool current_level_;

View File

@ -65,7 +65,7 @@ PRG::Serialiser::Serialiser(const std::string &file_name) :
throw ErrorBadFormat; throw ErrorBadFormat;
} }
Storage::Tape::Pulse PRG::Serialiser::get_next_pulse() { Storage::Tape::Pulse PRG::Serialiser::next_pulse() {
// these are all microseconds per pole // these are all microseconds per pole
constexpr unsigned int leader_zero_length = 179; constexpr unsigned int leader_zero_length = 179;
constexpr unsigned int zero_length = 169; 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 // determine whether a new byte needs to be queued up
int block_offset = phase_offset_ - block_leadin_length; const int block_offset = phase_offset_ - block_leadin_length;
int bit_offset = block_offset % 10; const int bit_offset = block_offset % 10;
int byte_offset = block_offset / 10; const int byte_offset = block_offset / 10;
phase_offset_++; phase_offset_++;
if(!bit_offset && if(!bit_offset &&

View File

@ -38,7 +38,7 @@ private:
Serialiser(const std::string &file_name); Serialiser(const std::string &file_name);
private: private:
bool is_at_end() const override; bool is_at_end() const override;
Pulse get_next_pulse() override; Pulse next_pulse() override;
void reset() override; void reset() override;
FileHolder file_; FileHolder file_;

View File

@ -28,8 +28,7 @@ float gzgetfloat(gzFile file) {
was the first byte read from the UEF, Float[1] the second, etc */ was the first byte read from the UEF, Float[1] the second, etc */
/* decode mantissa */ /* decode mantissa */
int mantissa; const int mantissa = bytes[0] | (bytes[1] << 8) | ((bytes[2]&0x7f)|0x80) << 16;
mantissa = bytes[0] | (bytes[1] << 8) | ((bytes[2]&0x7f)|0x80) << 16;
float result = float(mantissa); float result = float(mantissa);
result = float(ldexp(result, -23)); result = float(ldexp(result, -23));
@ -82,7 +81,7 @@ UEF::Serialiser::Serialiser(const std::string &file_name) {
file_ = gzopen(file_name.c_str(), "rb"); file_ = gzopen(file_name.c_str(), "rb");
char identifier[10]; 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!")) { if(bytes_read < 10 || std::strcmp(identifier, "UEF File!")) {
throw ErrorNotUEF; throw ErrorNotUEF;
} }
@ -127,7 +126,7 @@ bool UEF::Serialiser::get_next_chunk(Chunk &result) {
return true; return true;
} }
void UEF::Serialiser::get_next_pulses() { void UEF::Serialiser::push_next_pulses() {
while(empty()) { while(empty()) {
// read chunk details // read chunk details
Chunk next_chunk; Chunk next_chunk;

View File

@ -60,7 +60,7 @@ private:
}; };
bool get_next_chunk(Chunk &); 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_implicit_bit_pattern(uint32_t length);
void queue_explicit_bit_pattern(uint32_t length); void queue_explicit_bit_pattern(uint32_t length);

View File

@ -52,7 +52,7 @@ bool ZX80O81P::Serialiser::is_at_end() const {
return has_finished_data() && has_ended_final_byte_; return has_finished_data() && has_ended_final_byte_;
} }
Pulse ZX80O81P::Serialiser::get_next_pulse() { Pulse ZX80O81P::Serialiser::next_pulse() {
Pulse pulse; Pulse pulse;
// Start with 1 second of silence. // Start with 1 second of silence.

View File

@ -46,7 +46,7 @@ private:
private: private:
bool is_at_end() const override; bool is_at_end() const override;
void reset() override; void reset() override;
Pulse get_next_pulse() override; Pulse next_pulse() override;
bool has_finished_data() const; bool has_finished_data() const;
TargetPlatform::Type platform_type_; TargetPlatform::Type platform_type_;

View File

@ -49,7 +49,7 @@ void ZXSpectrumTAP::Serialiser::reset() {
read_next_block(); read_next_block();
} }
Pulse ZXSpectrumTAP::Serialiser::get_next_pulse() { Pulse ZXSpectrumTAP::Serialiser::next_pulse() {
// Adopt a general pattern of high then low. // Adopt a general pattern of high then low.
Pulse pulse; Pulse pulse;
pulse.type = (distance_into_phase_ & 1) ? Pulse::Type::High : Pulse::Type::Low; pulse.type = (distance_into_phase_ & 1) ? Pulse::Type::High : Pulse::Type::Low;

View File

@ -53,7 +53,7 @@ private:
// Implemented to satisfy @c Tape. // Implemented to satisfy @c Tape.
bool is_at_end() const override; bool is_at_end() const override;
void reset() override; void reset() override;
Pulse get_next_pulse() override; Pulse next_pulse() override;
} serialiser_; } serialiser_;
}; };

View File

@ -13,7 +13,7 @@
using namespace Storage::Tape::MSX; using namespace Storage::Tape::MSX;
std::unique_ptr<Parser::FileSpeed> Parser::find_header(Storage::Tape::BinaryTapePlayer &tape_player) { std::unique_ptr<Parser::FileSpeed> Parser::find_header(Storage::Tape::BinaryTapePlayer &tape_player) {
if(!tape_player.get_motor_control()) { if(!tape_player.motor_control()) {
return nullptr; return nullptr;
} }
@ -21,17 +21,17 @@ std::unique_ptr<Parser::FileSpeed> Parser::find_header(Storage::Tape::BinaryTape
"When 1,111 cycles have been found with less than 35 microseconds "When 1,111 cycles have been found with less than 35 microseconds
variation in their lengths a header has been located." 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<float>::max(); float low = std::numeric_limits<float>::max();
float high = std::numeric_limits<float>::min(); float high = std::numeric_limits<float>::min();
int samples = 0; int samples = 0;
while(!tape_player.get_tape()->is_at_end()) { while(!tape_player.tape()->is_at_end()) {
float next_length = 0.0f; float next_length = 0.0f;
do { do {
next_length += float(tape_player.get_cycles_until_next_event()) / float(tape_player.get_input_clock_rate()); next_length += float(tape_player.get_cycles_until_next_event()) / float(tape_player.get_input_clock_rate());
tape_player.run_for_input_pulse(); tape_player.run_for_input_pulse();
} while(last_level == tape_player.get_input()); } while(last_level == tape_player.input());
last_level = tape_player.get_input(); last_level = tape_player.input();
low = std::min(low, next_length); low = std::min(low, next_length);
high = std::max(high, next_length); high = std::max(high, next_length);
samples++; samples++;
@ -43,24 +43,24 @@ std::unique_ptr<Parser::FileSpeed> Parser::find_header(Storage::Tape::BinaryTape
if(samples == 1111*2) break; // Cycles are read, not half-cycles. 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." "The next 256 cycles are then read (1B34H) and averaged to determine the cassette HI cycle length."
*/ */
float total_length = 0.0f; float total_length = 0.0f;
samples = 512; 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()); 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--; samples--;
if(!samples) break; if(!samples) break;
last_level = tape_player.get_input(); last_level = tape_player.input();
} }
tape_player.run_for_input_pulse(); 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 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::FileSpeed> Parser::find_header(Storage::Tape::BinaryTape
-1 otherwise. -1 otherwise.
*/ */
int Parser::get_byte(const FileSpeed &speed, Storage::Tape::BinaryTapePlayer &tape_player) { 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; 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; const float minimum_start_bit_duration = float(speed.minimum_start_bit_duration) * 0.00001145f * 0.5f;
int input = 0; int input = 0;
while(!tape_player.get_tape()->is_at_end()) { while(!tape_player.tape()->is_at_end()) {
// Find next transition. // Find next transition.
bool level = tape_player.get_input(); bool level = tape_player.input();
float duration = 0.0; 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()); duration += float(tape_player.get_cycles_until_next_event()) / float(tape_player.get_input_clock_rate());
tape_player.run_for_input_pulse(); 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()) float(tape_player.get_input_clock_rate())
); );
int bits_left = 8; int bits_left = 8;
bool level = tape_player.get_input(); bool level = tape_player.input();
while(!tape_player.get_tape()->is_at_end() && bits_left--) { while(!tape_player.tape()->is_at_end() && bits_left--) {
// Count number of transitions within cycles_per_window. // Count number of transitions within cycles_per_window.
int transitions = 0; int transitions = 0;
int cycles_remaining = cycles_per_window; 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_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); const int cycles_to_run_for = std::min(cycles_until_next_event, cycles_remaining);
cycles_remaining -= cycles_to_run_for; cycles_remaining -= cycles_to_run_for;
tape_player.run_for(Cycles(cycles_to_run_for)); tape_player.run_for(Cycles(cycles_to_run_for));
if(level != tape_player.get_input()) { if(level != tape_player.input()) {
level = tape_player.get_input(); level = tape_player.input();
transitions++; transitions++;
} }
} }
if(tape_player.get_tape()->is_at_end()) return -1; if(tape_player.tape()->is_at_end()) return -1;
int next_bit = 0; int next_bit = 0;
switch(transitions) { switch(transitions) {
@ -170,16 +170,16 @@ int Parser::get_byte(const FileSpeed &speed, Storage::Tape::BinaryTapePlayer &ta
transition count two more." transition count two more."
*/ */
int required_transitions = 2 - (transitions&1); 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(); tape_player.run_for_input_pulse();
if(level != tape_player.get_input()) { if(level != tape_player.input()) {
level = tape_player.get_input(); level = tape_player.input();
required_transitions--; required_transitions--;
if(!required_transitions) break; 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; return result;
} }

View File

@ -29,7 +29,7 @@ public:
*/ */
SymbolType get_next_symbol(const std::shared_ptr<Storage::Tape::Tape> &tape) { SymbolType get_next_symbol(const std::shared_ptr<Storage::Tape::Tape> &tape) {
while(!has_next_symbol_ && !tape->is_at_end()) { 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(); if(!has_next_symbol_ && tape->is_at_end()) mark_end();
has_next_symbol_ = false; has_next_symbol_ = false;

View File

@ -35,7 +35,7 @@ void PulseQueuedSerialiser::push_back(const Pulse pulse) {
queued_pulses_.push_back(pulse); queued_pulses_.push_back(pulse);
} }
Pulse PulseQueuedSerialiser::get_next_pulse() { Pulse PulseQueuedSerialiser::next_pulse() {
const auto silence = [] { const auto silence = [] {
return Pulse(Pulse::Type::Zero, Storage::Time(1, 1)); return Pulse(Pulse::Type::Zero, Storage::Time(1, 1));
}; };
@ -46,7 +46,7 @@ Pulse PulseQueuedSerialiser::get_next_pulse() {
if(pulse_pointer_ == queued_pulses_.size()) { if(pulse_pointer_ == queued_pulses_.size()) {
clear(); clear();
get_next_pulses(); push_next_pulses();
if(is_at_end_ || pulse_pointer_ == queued_pulses_.size()) { if(is_at_end_ || pulse_pointer_ == queued_pulses_.size()) {
return silence(); return silence();

View File

@ -16,11 +16,11 @@ namespace Storage::Tape {
/*! /*!
Provides a @c Tape with a queue of upcoming pulses and an is-at-end flag. 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 If is-at-end is set then @c next_pulse() returns a second of silence and
is_at_end() returns true. @c is_at_end() returns @c true.
Otherwise get_next_pulse() returns something from the pulse queue if there is Otherwise @c next_pulse() returns something from the pulse queue if there is
anything there, and otherwise calls get_next_pulses(). get_next_pulses() is anything there, and otherwise calls @c push_next_pulses() which is
virtual, giving subclasses a chance to provide the next batch of pulses. virtual, giving subclasses a chance to provide the next batch of pulses.
*/ */
class PulseQueuedSerialiser: public TapeSerialiser { class PulseQueuedSerialiser: public TapeSerialiser {
@ -31,10 +31,10 @@ public:
bool empty() const; bool empty() const;
void set_is_at_end(bool); void set_is_at_end(bool);
Pulse get_next_pulse() override; Pulse next_pulse() override;
bool is_at_end() const override; bool is_at_end() const override;
virtual void get_next_pulses() = 0; virtual void push_next_pulses() = 0;
private: private:
std::vector<Pulse> queued_pulses_; std::vector<Pulse> queued_pulses_;

View File

@ -24,17 +24,17 @@ void Storage::Tape::Tape::seek(const Time seek_time) {
Time next_time(0); Time next_time(0);
reset(); reset();
while(next_time <= seek_time) { while(next_time <= seek_time) {
get_next_pulse(); next_pulse();
next_time += pulse_.length; next_time += pulse_.length;
} }
} }
Storage::Time Tape::get_current_time() { Storage::Time Tape::current_time() {
Time time(0); Time time(0);
uint64_t steps = get_offset(); uint64_t steps = offset();
reset(); reset();
while(steps--) { while(steps--) {
get_next_pulse(); next_pulse();
time += pulse_.length; time += pulse_.length;
} }
return time; return time;
@ -45,13 +45,13 @@ void Storage::Tape::Tape::reset() {
serialiser_.reset(); serialiser_.reset();
} }
Pulse Tape::get_next_pulse() { Pulse Tape::next_pulse() {
pulse_ = serialiser_.get_next_pulse(); pulse_ = serialiser_.next_pulse();
offset_++; offset_++;
return pulse_; return pulse_;
} }
uint64_t Tape::get_offset() const { uint64_t Tape::offset() const {
return offset_; return offset_;
} }
@ -61,7 +61,7 @@ void Tape::set_offset(uint64_t offset) {
reset(); reset();
} }
offset -= offset_; offset -= offset_;
while(offset--) get_next_pulse(); while(offset--) next_pulse();
} }
bool Tape::is_at_end() const { bool Tape::is_at_end() const {
@ -78,11 +78,11 @@ ClockingHint::Preference TapePlayer::preferred_clocking() const {
void TapePlayer::set_tape(std::shared_ptr<Storage::Tape::Tape> tape) { void TapePlayer::set_tape(std::shared_ptr<Storage::Tape::Tape> tape) {
tape_ = tape; tape_ = tape;
reset_timer(); reset_timer();
get_next_pulse(); next_pulse();
update_clocking_observer(); update_clocking_observer();
} }
std::shared_ptr<Storage::Tape::Tape> TapePlayer::get_tape() { std::shared_ptr<Storage::Tape::Tape> TapePlayer::tape() {
return tape_; return tape_;
} }
@ -90,10 +90,10 @@ bool TapePlayer::has_tape() const {
return bool(tape_); return bool(tape_);
} }
void TapePlayer::get_next_pulse() { void TapePlayer::next_pulse() {
// get the new pulse // get the new pulse
if(tape_) { if(tape_) {
current_pulse_ = tape_->get_next_pulse(); current_pulse_ = tape_->next_pulse();
if(tape_->is_at_end()) update_clocking_observer(); if(tape_->is_at_end()) update_clocking_observer();
} else { } else {
current_pulse_.length.length = 1; current_pulse_.length.length = 1;
@ -104,7 +104,7 @@ void TapePlayer::get_next_pulse() {
set_next_event_time_interval(current_pulse_.length); set_next_event_time_interval(current_pulse_.length);
} }
Pulse TapePlayer::get_current_pulse() const { Pulse TapePlayer::current_pulse() const {
return current_pulse_; return current_pulse_;
} }
@ -123,8 +123,8 @@ void TapePlayer::run_for_input_pulse() {
} }
void TapePlayer::process_next_event() { void TapePlayer::process_next_event() {
process_input_pulse(current_pulse_); process(current_pulse_);
get_next_pulse(); next_pulse();
} }
// MARK: - Binary Player // 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_; return motor_is_running_;
} }
@ -165,7 +165,7 @@ void BinaryTapePlayer::set_tape_output(bool) {
// TODO // TODO
} }
bool BinaryTapePlayer::get_input() const { bool BinaryTapePlayer::input() const {
return motor_is_running_ && input_level_; return motor_is_running_ && input_level_;
} }
@ -177,7 +177,7 @@ void BinaryTapePlayer::set_delegate(Delegate *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; bool new_input_level = pulse.type == Pulse::High;
if(input_level_ != new_input_level) { if(input_level_ != new_input_level) {
input_level_ = new_input_level; input_level_ = new_input_level;

View File

@ -31,9 +31,12 @@ struct Pulse {
Pulse() = default; Pulse() = default;
}; };
/*!
Provdes the means for tape serialiserion.
*/
class TapeSerialiser { class TapeSerialiser {
public: public:
virtual Pulse get_next_pulse() = 0; virtual Pulse next_pulse() = 0;
virtual void reset() = 0; virtual void reset() = 0;
virtual bool is_at_end() const = 0; virtual bool is_at_end() const = 0;
}; };
@ -44,10 +47,6 @@ public:
- high pulses exit from zero upward before returning to it; - high pulses exit from zero upward before returning to it;
- low pulses exit from zero downward before returning to it; - low pulses exit from zero downward before returning to it;
- zero pulses run along zero. - 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 { class Tape {
public: public:
@ -58,7 +57,7 @@ public:
@returns the pulse that begins at the current cursor position. @returns the pulse that begins at the current cursor position.
*/ */
Pulse get_next_pulse(); Pulse next_pulse();
/// Returns the tape to the beginning. /// Returns the tape to the beginning.
void reset(); void reset();
@ -71,7 +70,7 @@ public:
required to be at least to the whole pulse. Greater numbers are later than earlier numbers, required to be at least to the whole pulse. Greater numbers are later than earlier numbers,
but not necessarily continuous. 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. 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. 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. 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 Provides a helper for: (i) retaining a reference to a tape; and (ii) running the tape at a certain
input clock rate. input clock rate.
Will call @c process_input_pulse instantaneously upon reaching *the end* of a pulse. Therefore a subclass Will call @c process(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. 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 { class TapePlayer: public TimedEventLoop, public ClockingHint::Source {
public: public:
TapePlayer(int input_clock_rate); TapePlayer(int input_clock_rate);
virtual ~TapePlayer() = default; virtual ~TapePlayer() = default;
void set_tape(std::shared_ptr<Storage::Tape::Tape> tape); void set_tape(std::shared_ptr<Storage::Tape::Tape>);
bool has_tape() const; bool has_tape() const;
std::shared_ptr<Storage::Tape::Tape> get_tape(); std::shared_ptr<Storage::Tape::Tape> tape();
void run_for(const Cycles cycles); void run_for(const Cycles cycles);
void run_for_input_pulse(); void run_for_input_pulse();
ClockingHint::Preference preferred_clocking() const override; ClockingHint::Preference preferred_clocking() const override;
Pulse get_current_pulse() const; Pulse current_pulse() const;
void complete_pulse(); void complete_pulse();
protected: protected:
virtual void process_next_event() override; virtual void process_next_event() override;
virtual void process_input_pulse(const Pulse &pulse) = 0; virtual void process(const Pulse &) = 0;
private: private:
inline void get_next_pulse(); inline void next_pulse();
std::shared_ptr<Storage::Tape::Tape> tape_; std::shared_ptr<Storage::Tape::Tape> tape_;
Pulse current_pulse_; Pulse current_pulse_;
@ -144,26 +142,26 @@ private:
class BinaryTapePlayer : public TapePlayer { class BinaryTapePlayer : public TapePlayer {
public: public:
BinaryTapePlayer(int input_clock_rate); BinaryTapePlayer(int input_clock_rate);
void set_motor_control(bool enabled); void set_motor_control(bool);
bool get_motor_control() const; bool motor_control() const;
void set_tape_output(bool set); void set_tape_output(bool);
bool get_input() const; bool input() const;
void run_for(const Cycles cycles); void run_for(const Cycles cycles);
struct Delegate { 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); void set_delegate(Delegate *delegate);
ClockingHint::Preference preferred_clocking() const final; ClockingHint::Preference preferred_clocking() const final;
void set_activity_observer(Activity::Observer *observer); void set_activity_observer(Activity::Observer *);
protected: protected:
Delegate *delegate_ = nullptr; Delegate *delegate_ = nullptr;
void process_input_pulse(const Storage::Tape::Pulse &pulse) final; void process(const Pulse &) final;
bool input_level_ = false; bool input_level_ = false;
bool motor_is_running_ = false; bool motor_is_running_ = false;