#include "zx_tape.h" #include "zx_ula.h" #include "zx_screen.h" #include "z80debug.h" #include #include #include namespace zx_tape { #define PULSE_PILOT 0 #define PULSE_SYNC1 1 #define PULSE_SYNC2 2 #define PULSE_DATA 3 #define PULSE_CHECKSUM 4 #define PULSE_SYNC3 5 #define PULSE_WAIT 6 #define PULSE_LEN_ZERO 855 #define PULSE_LEN_ONE 1710 #define PULSE_LEN_PILOT 2168 #define PULSE_LEN_SYNC1 667 #define PULSE_LEN_SYNC2 735 #define PULSE_LEN_SYNC3 954 #define PULSE_COUNT_PILOT_HEADER 8063 #define PULSE_COUNT_PILOT_DATA 3223 struct block_t { uint16_t length; uint8_t *data; }; bool playing = false; bool loaded = false; bool options[ZXTAPE_NUM_OPTIONS] = { true, true }; std::vector blocks; uint8_t current_block = 0; uint16_t block_pos=0; uint8_t current_bit=0; uint8_t current_section = PULSE_PILOT; uint16_t current_pulse = 0; uint32_t pulse_pos = 0; uint8_t pulse_level = 0; void load(const char* filename) { if (!blocks.empty()) for (auto block : blocks) free(block.data); blocks.clear(); FILE *f = fopen(filename, "rb"); if (!f) return; while (!feof(f)) { block_t block; fread(&block.length, 2, 1, f); //fread(&block.flag, 1, 1, f); //block.length -= 2; // substract flag and checksum block.data = (uint8_t *)malloc(block.length); fread(block.data, block.length, 1, f); //fread(&block.checksum, 1, 1, f); blocks.push_back(block); } fclose(f); loaded = true; playing = false; rewind(); } void play() { if (!loaded) return; playing = !playing; //true; } void stop() { playing = false; //berserk_mode = false; } void rewind() { if (!loaded) return; current_block = block_pos = current_bit = 0; current_section = PULSE_PILOT; current_pulse = pulse_pos = 0; pulse_level = 1; } void update(const uint8_t dt) { if (!playing) return; pulse_pos += dt; if (current_section == PULSE_PILOT) { const uint16_t pulse_count = blocks[current_block].data[0]<128 ? PULSE_COUNT_PILOT_HEADER : PULSE_COUNT_PILOT_DATA; if (pulse_pos >= PULSE_LEN_PILOT ) { pulse_pos -= PULSE_LEN_PILOT; current_pulse++; pulse_level = pulse_level?0:1; if (current_pulse == pulse_count && pulse_level==0) { pulse_level = 0; } else if (current_pulse >= pulse_count) { current_pulse = 0; pulse_level = 1; current_section = PULSE_SYNC1; printf("going to pulse_sync1..%i.\n", current_block); } } } if (current_section == PULSE_SYNC1) { if (pulse_pos >= PULSE_LEN_SYNC1) { pulse_pos -= PULSE_LEN_SYNC1; pulse_level = 0; current_section = PULSE_SYNC2; printf("going to pulse_sync2..%i.\n", current_block); } } if (current_section == PULSE_SYNC2) { if (pulse_pos >= PULSE_LEN_SYNC2) { pulse_pos -= PULSE_LEN_SYNC2; pulse_level = 1; current_section = PULSE_DATA; printf("going to pulse_data..%i.\n", current_block); } } static int level[2] = {0, 0}; if (current_section == PULSE_DATA) { level[pulse_level]+=dt; const uint8_t datum = blocks[current_block].data[block_pos]; const uint16_t pulse_len = (datum & (0x80>>current_bit)) == 0 ? PULSE_LEN_ZERO : PULSE_LEN_ONE; if (pulse_pos >= pulse_len) { pulse_pos =0;//-= pulse_len; pulse_level--; if (pulse_level>=2) { pulse_level = 1; //printf("%i\n",current_bit); level[0]=level[1]=0; current_bit++; if (current_bit>=8) { current_bit = 0; block_pos++; if (block_pos>=blocks[current_block].length) { block_pos = 0; current_section = PULSE_SYNC3; printf("going to pulse_sync3..%i.\n", current_block); } } } } } /*if (current_section == PULSE_CHECKSUM) { const uint8_t datum = 1;//blocks[current_block].checksum; const uint16_t pulse_len = (datum & (0x80>>current_bit)) == 0 ? PULSE_LEN_ZERO : PULSE_LEN_ONE; if (pulse_pos >= pulse_len) { pulse_pos -= pulse_len; pulse_level--; if (pulse_level>=2) { pulse_level = 1; current_bit++; if (current_bit>=8) { current_bit = 0; current_section = PULSE_SYNC3; } } } }*/ if (current_section == PULSE_SYNC3) { if (pulse_pos >= PULSE_LEN_SYNC3) { pulse_pos -= PULSE_LEN_SYNC3; pulse_level = 0; current_section = PULSE_WAIT; printf("going to pulse_wait..%i.\n", current_block); } } if (current_section == PULSE_WAIT) { pulse_level = 0; if (pulse_pos >= 3500000) { pulse_pos = 0; current_section = PULSE_PILOT; pulse_level = 1; current_block++; if (current_block>=blocks.size()) { printf("end\n"); stop(); rewind(); if (options[ZXTAPE_OPTION_STOP_AT_END]) z80debug::stop(); } else { //zxscreen::fullrefresh(); printf("going to pulse_pilot on block %i...\n", current_block); } } } zx_ula::set_ear(pulse_level); } const bool getplaying() { return playing; } void report() { if (current_block >= blocks.size()) return; const int percent = (float(block_pos)/float(blocks[current_block].length))*100; printf("tape loading: %i%\n", percent); } const bool getOption(const int option) { return options[option]; } void setOption(const int option, const bool value) { options[option] = value; } void toggleOption(const int option) { options[option] = !options[option]; } }