diff --git a/StaticAnalyser/Acorn/AcornAnalyser.cpp b/StaticAnalyser/Acorn/AcornAnalyser.cpp index 174934463..652cef36f 100644 --- a/StaticAnalyser/Acorn/AcornAnalyser.cpp +++ b/StaticAnalyser/Acorn/AcornAnalyser.cpp @@ -8,6 +8,8 @@ #include "AcornAnalyser.hpp" +#include "Tape.hpp" + using namespace StaticAnalyser::Acorn; static std::list> @@ -68,8 +70,7 @@ void StaticAnalyser::Acorn::AddTargets( if(tapes.size() > 0) { std::shared_ptr tape = tapes.front(); - tape->reset(); - + GetNextFile(tape); } } diff --git a/StaticAnalyser/Acorn/Tape.cpp b/StaticAnalyser/Acorn/Tape.cpp index 0c37bf498..0bb0b4fca 100644 --- a/StaticAnalyser/Acorn/Tape.cpp +++ b/StaticAnalyser/Acorn/Tape.cpp @@ -10,7 +10,110 @@ using namespace StaticAnalyser::Acorn; +struct TapeParser { + float wave_lengths[4]; + int wave_length_pointer; + + TapeParser() : wave_length_pointer(0) {} + + int GetNextBit(const std::shared_ptr &tape) + { + while(!tape->is_at_end()) + { + // skip any gaps + Storage::Tape::Tape::Pulse next_pulse = tape->get_next_pulse(); + while(next_pulse.type == Storage::Tape::Tape::Pulse::Zero) + { + next_pulse = tape->get_next_pulse(); + } + + wave_lengths[wave_length_pointer] = next_pulse.length.get_float(); + wave_length_pointer++; + + // if first wave is too short or too long, drop it + if(wave_lengths[0] < 1.0f / 4800.0f || wave_lengths[0] > 5.0f / 4800.0f) + { + rotate(1); + continue; + } + + // if first two waves add up to a correct-length cycle, pop them and this is a 0 + if(wave_length_pointer >= 2) + { + float length = wave_lengths[0] + wave_lengths[1]; + if(length >= 3.0f / 4800.0f && length < 5.0f / 4800.0f) + { + rotate(2); + return 0; + } + } + + // if all four waves add up to a correct-length cycle, pop them and this is a 1 + if(wave_length_pointer >= 4) + { + float length = wave_lengths[0] + wave_lengths[1] + wave_lengths[2] + wave_lengths[3]; + if(length >= 3.0f / 4800.0f && length < 5.0f / 4800.0f) + { + rotate(4); + return 1; + } + } + } + + return 0; + } + + int GetNextByte(const std::shared_ptr &tape) + { + int value = 0; + int c = 10; + if(GetNextBit(tape)) return -1; + while(c--) + { + value = (value >> 1) | (GetNextBit(tape) << 9); + } + if(!GetNextBit(tape)) return -1; + return c; + } + + private: + void rotate(int places) + { + wave_length_pointer -= places; + memmove(wave_lengths, &wave_lengths[places], (size_t)(4 - places) * sizeof(float)); + } +}; + std::unique_ptr StaticAnalyser::Acorn::GetNextFile(const std::shared_ptr &tape) { + int shift_register = 0; + TapeParser parser; + +#define shift() \ + shift_register = (shift_register >> 1) | (parser.GetNextBit(tape) << 9) + + // find next area of high tone + while(!tape->is_at_end() && (shift_register != 0x3ff)) + { + shift(); + } + + // find next 0x2a (swallowing stop bit) + while(!tape->is_at_end() && (shift_register != 0x055)) + { + shift(); + if(shift_register != 0x3ff) printf("%d\n", shift_register >> 9); + } + + // read out name + char name[10]; + int name_ptr = 0; + while(!tape->is_at_end() && name_ptr < 10) + { + name[name_ptr] = (char)parser.GetNextByte(tape); + if(!name[name_ptr]) break; + name_ptr++; + } + return nullptr; } diff --git a/Storage/Tape/Formats/CommodoreTAP.cpp b/Storage/Tape/Formats/CommodoreTAP.cpp index 3fc5bf669..556c55fd0 100644 --- a/Storage/Tape/Formats/CommodoreTAP.cpp +++ b/Storage/Tape/Formats/CommodoreTAP.cpp @@ -12,7 +12,7 @@ using namespace Storage::Tape; -CommodoreTAP::CommodoreTAP(const char *file_name) +CommodoreTAP::CommodoreTAP(const char *file_name) : _is_at_end(false) { _file = fopen(file_name, "rb"); @@ -62,10 +62,21 @@ void CommodoreTAP::reset() { fseek(_file, 0x14, SEEK_SET); _current_pulse.type = Pulse::High; + _is_at_end = false; +} + +bool CommodoreTAP::is_at_end() +{ + return _is_at_end; } Storage::Tape::Tape::Pulse CommodoreTAP::get_next_pulse() { + if(_is_at_end) + { + return _current_pulse; + } + if(_current_pulse.type == Pulse::High) { uint32_t next_length; @@ -81,8 +92,17 @@ Storage::Tape::Tape::Pulse CommodoreTAP::get_next_pulse() next_length |= (uint32_t)(fgetc(_file) << 16); } - _current_pulse.length.length = next_length; - _current_pulse.type = Pulse::Low; + if(feof(_file)) + { + _is_at_end = true; + _current_pulse.length.length = _current_pulse.length.clock_rate; + _current_pulse.type = Pulse::Zero; + } + else + { + _current_pulse.length.length = next_length; + _current_pulse.type = Pulse::Low; + } } else _current_pulse.type = Pulse::High; diff --git a/Storage/Tape/Formats/CommodoreTAP.hpp b/Storage/Tape/Formats/CommodoreTAP.hpp index 60fd3c369..836071447 100644 --- a/Storage/Tape/Formats/CommodoreTAP.hpp +++ b/Storage/Tape/Formats/CommodoreTAP.hpp @@ -35,6 +35,7 @@ class CommodoreTAP: public Tape { // implemented to satisfy @c Tape Pulse get_next_pulse(); void reset(); + bool is_at_end(); private: FILE *_file; @@ -42,6 +43,7 @@ class CommodoreTAP: public Tape { uint32_t _file_size; Pulse _current_pulse; + bool _is_at_end; }; } diff --git a/Storage/Tape/Formats/TapePRG.cpp b/Storage/Tape/Formats/TapePRG.cpp index d728e73e5..80d723191 100644 --- a/Storage/Tape/Formats/TapePRG.cpp +++ b/Storage/Tape/Formats/TapePRG.cpp @@ -109,6 +109,11 @@ void PRG::reset() _copy_mask = 0x80; } +bool PRG::is_at_end() +{ + return _filePhase == FilePhaseAtEnd; +} + void PRG::get_next_output_token() { static const int block_length = 192; // not counting the checksum @@ -116,10 +121,10 @@ void PRG::get_next_output_token() static const int leadin_length = 20000; static const int block_leadin_length = 5000; - if(_filePhase == FilePhaseHeaderDataGap) + if(_filePhase == FilePhaseHeaderDataGap || _filePhase == FilePhaseAtEnd) { _outputToken = Silence; - _filePhase = FilePhaseData; + if(_filePhase != FilePhaseAtEnd) _filePhase = FilePhaseData; return; } diff --git a/Storage/Tape/Formats/TapePRG.hpp b/Storage/Tape/Formats/TapePRG.hpp index 0ad03a9d3..f9159fecf 100644 --- a/Storage/Tape/Formats/TapePRG.hpp +++ b/Storage/Tape/Formats/TapePRG.hpp @@ -37,6 +37,8 @@ class PRG: public Tape { // implemented to satisfy @c Tape Pulse get_next_pulse(); void reset(); + bool is_at_end(); + private: FILE *_file; uint16_t _load_address; @@ -47,6 +49,7 @@ class PRG: public Tape { FilePhaseHeader, FilePhaseHeaderDataGap, FilePhaseData, + FilePhaseAtEnd } _filePhase; int _phaseOffset; diff --git a/Storage/Tape/Formats/TapeUEF.cpp b/Storage/Tape/Formats/TapeUEF.cpp index bac0b4627..ee2008947 100644 --- a/Storage/Tape/Formats/TapeUEF.cpp +++ b/Storage/Tape/Formats/TapeUEF.cpp @@ -45,7 +45,8 @@ static float gzgetfloat(gzFile file) UEF::UEF(const char *file_name) : _chunk_id(0), _chunk_length(0), _chunk_position(0), - _time_base(1200) + _time_base(1200), + _is_at_end(false) { _file = gzopen(file_name, "rb"); @@ -77,12 +78,26 @@ UEF::~UEF() void UEF::reset() { gzseek(_file, 12, SEEK_SET); + _is_at_end = false; +} + +bool UEF::is_at_end() +{ + return _is_at_end; } Storage::Tape::Tape::Pulse UEF::get_next_pulse() { Pulse next_pulse; + if(_is_at_end) + { + next_pulse.type = Pulse::Zero; + next_pulse.length.length = _time_base * 4; + next_pulse.length.clock_rate = _time_base * 4; + return next_pulse; + } + if(!_bit_position && chunk_is_finished()) { find_next_tape_chunk(); @@ -149,7 +164,6 @@ Storage::Tape::Tape::Pulse UEF::get_next_pulse() void UEF::find_next_tape_chunk() { - int reset_count = 0; _chunk_position = 0; _bit_position = 0; @@ -170,10 +184,8 @@ void UEF::find_next_tape_chunk() if(gzeof(_file)) { - reset_count++; - if(reset_count == 2) break; - reset(); - continue; + _is_at_end = true; + return; } switch(_chunk_id) diff --git a/Storage/Tape/Formats/TapeUEF.hpp b/Storage/Tape/Formats/TapeUEF.hpp index 12d2286c1..2b507d1b6 100644 --- a/Storage/Tape/Formats/TapeUEF.hpp +++ b/Storage/Tape/Formats/TapeUEF.hpp @@ -36,6 +36,7 @@ class UEF : public Tape { // implemented to satisfy @c Tape Pulse get_next_pulse(); void reset(); + bool is_at_end(); private: gzFile _file; @@ -59,6 +60,7 @@ class UEF : public Tape { uint8_t _current_byte; uint32_t _chunk_position; + bool _is_at_end; bool _current_bit; uint32_t _bit_position; diff --git a/Storage/Tape/Tape.hpp b/Storage/Tape/Tape.hpp index 082ff035d..2293f462d 100644 --- a/Storage/Tape/Tape.hpp +++ b/Storage/Tape/Tape.hpp @@ -36,7 +36,9 @@ class Tape { }; virtual Pulse get_next_pulse() = 0; + virtual void reset() = 0; + virtual bool is_at_end() = 0; virtual void seek(Time seek_time); // TODO };