mirror of
https://github.com/TomHarte/CLK.git
synced 2025-01-11 08:30:55 +00:00
Made a quick first attempt at getting a file name from Acorn tape, failing terribly but at least formalising tapes being able to signal their end.
This commit is contained in:
parent
0032ad2634
commit
963a479908
@ -8,6 +8,8 @@
|
||||
|
||||
#include "AcornAnalyser.hpp"
|
||||
|
||||
#include "Tape.hpp"
|
||||
|
||||
using namespace StaticAnalyser::Acorn;
|
||||
|
||||
static std::list<std::shared_ptr<Storage::Cartridge::Cartridge>>
|
||||
@ -68,8 +70,7 @@ void StaticAnalyser::Acorn::AddTargets(
|
||||
if(tapes.size() > 0)
|
||||
{
|
||||
std::shared_ptr<Storage::Tape::Tape> tape = tapes.front();
|
||||
|
||||
tape->reset();
|
||||
|
||||
GetNextFile(tape);
|
||||
}
|
||||
}
|
||||
|
@ -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<Storage::Tape::Tape> &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<Storage::Tape::Tape> &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<File> StaticAnalyser::Acorn::GetNextFile(const std::shared_ptr<Storage::Tape::Tape> &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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user