mirror of
https://github.com/TomHarte/CLK.git
synced 2024-12-13 00:29:14 +00:00
Improve interface.
This commit is contained in:
parent
6d4ff0b89a
commit
b89ecadc3a
@ -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;
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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();
|
||||||
|
|
||||||
|
@ -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) {
|
||||||
|
@ -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 {
|
||||||
|
@ -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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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 {
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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();
|
||||||
|
@ -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_;
|
||||||
|
@ -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 {
|
||||||
|
@ -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_;
|
||||||
|
|
||||||
|
@ -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_) {
|
||||||
|
@ -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_;
|
||||||
|
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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_;
|
||||||
|
|
||||||
|
@ -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 &&
|
||||||
|
@ -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_;
|
||||||
|
@ -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;
|
||||||
|
@ -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);
|
||||||
|
@ -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.
|
||||||
|
@ -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_;
|
||||||
|
@ -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;
|
||||||
|
@ -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_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
@ -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();
|
||||||
|
@ -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_;
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user