diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/xcshareddata/xcschemes/Clock Signal.xcscheme b/OSBindings/Mac/Clock Signal.xcodeproj/xcshareddata/xcschemes/Clock Signal.xcscheme index 2cfe830df..6609a35c0 100644 --- a/OSBindings/Mac/Clock Signal.xcodeproj/xcshareddata/xcschemes/Clock Signal.xcscheme +++ b/OSBindings/Mac/Clock Signal.xcodeproj/xcshareddata/xcschemes/Clock Signal.xcscheme @@ -68,7 +68,7 @@ 16384) throw ErrorNotZX80O; + + // skip the system area + fseek(file_, 8, SEEK_SET); + + // read the pointer to VARS and the alleged pointer to end of file + uint16_t vars = fgetc16le(); + end_of_file_ = fgetc16le(); + + // VARs should be before end of file + if(vars > end_of_file_) throw ErrorNotZX80O; + + // end of file should be no further than the actual file size + if(end_of_file_ - 0x4000 > file_stats_.st_size) throw ErrorNotZX80O; + + // TODO: does it make sense to inspect the tokenised BASIC? + // It starts at 0x4028 and proceeds as [16-bit line number] [tokens] [0x76], + // but I'm as yet unable to find documentation of the tokens. + // then rewind and start again virtual_reset(); } void ZX80O::virtual_reset() { fseek(file_, 0, SEEK_SET); + is_past_silence_ = false; + is_high_ = true; + bit_pointer_ = 9; } bool ZX80O::is_at_end() { - return feof(file_); + return ftell(file_) == end_of_file_ - 0x4000; } Tape::Pulse ZX80O::virtual_get_next_pulse() { Tape::Pulse pulse; + // Start with 1 second of silence. + if(!is_past_silence_) { + pulse.type = Pulse::Type::Zero; + pulse.length.length = 1; + pulse.length.clock_rate = 1; + is_past_silence_ = true; + return pulse; + } + + // For each byte, output 8 bits and then silence. + if(bit_pointer_ == 9) { + byte_ = (uint8_t)fgetc(file_); + bit_pointer_ = 0; + wave_pointer_ = 0; + } + + // Bytes are stored MSB first. + if(bit_pointer_ < 8) { + // waves are of length 150µs + pulse.length.length = 3; + pulse.length.clock_rate = 20000; + + if(is_high_) { + pulse.type = Pulse::Type::High; + is_high_ = false; + } else { + pulse.type = Pulse::Type::Low; + is_high_ = true; + + int wave_count = (byte_ & (0x80 >> bit_pointer_)) ? 9 : 4; + wave_pointer_++; + if(wave_pointer_ == wave_count) { + bit_pointer_++; + wave_pointer_ = 0; + } + } + } else { + // post-waves silence is 1300µs + pulse.length.length = 13; + pulse.length.clock_rate = 10000; + pulse.type = Pulse::Type::Zero; + + bit_pointer_++; + } + return pulse; } diff --git a/Storage/Tape/Formats/ZX80O.hpp b/Storage/Tape/Formats/ZX80O.hpp index e486c0b96..5535adea5 100644 --- a/Storage/Tape/Formats/ZX80O.hpp +++ b/Storage/Tape/Formats/ZX80O.hpp @@ -38,6 +38,14 @@ class ZX80O: public Tape, public Storage::FileHolder { private: void virtual_reset(); Pulse virtual_get_next_pulse(); + + uint8_t byte_; + int bit_pointer_; + int wave_pointer_; + bool is_past_silence_; + bool is_high_; + + uint16_t end_of_file_; }; }