diff --git a/Storage/FileHolder.hpp b/Storage/FileHolder.hpp index 458927608..a2be837bd 100644 --- a/Storage/FileHolder.hpp +++ b/Storage/FileHolder.hpp @@ -71,6 +71,49 @@ class FileHolder { */ void ensure_file_is_at_least_length(long length); + class BitStream { + public: + BitStream(FILE *f, bool lsb_first) : + file_(f), + lsb_first_(lsb_first), + next_value_(0), + bits_remaining_(0) {} + + uint8_t get_bits(int q) { + uint8_t result = 0; + while(q--) { + result = (uint8_t)((result << 1) | get_bit()); + } + return result; + } + + private: + FILE *file_; + bool lsb_first_; + uint8_t next_value_; + int bits_remaining_; + + uint8_t get_bit() { + if(!bits_remaining_) { + bits_remaining_ = 8; + next_value_ = (uint8_t)fgetc(file_); + } + + uint8_t bit; + if(lsb_first_) { + bit = next_value_ & 1; + next_value_ >>= 1; + } else { + bit = next_value_ >> 7; + next_value_ <<= 1; + } + + bits_remaining_--; + + return bit; + } + }; + FILE *file_; struct stat file_stats_; bool is_read_only_; diff --git a/Storage/Tape/Formats/TZX.cpp b/Storage/Tape/Formats/TZX.cpp index f2cc1f62a..4100996c8 100644 --- a/Storage/Tape/Formats/TZX.cpp +++ b/Storage/Tape/Formats/TZX.cpp @@ -77,12 +77,12 @@ void TZX::get_generalised_data_block() { uint8_t maximum_pulses_per_data_symbol = (uint8_t)fgetc(file_); uint8_t symbols_in_data_table = (uint8_t)fgetc(file_); - get_generalised_segment(total_pilot_symbols, maximum_pulses_per_pilot_symbol, symbols_in_pilot_table); - get_generalised_segment(total_data_symbols, maximum_pulses_per_data_symbol, symbols_in_data_table); + 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); emplace_back(Tape::Pulse::Zero, Storage::Time((unsigned int)pause_after_block, 1000u)); } -void TZX::get_generalised_segment(uint32_t output_symbols, uint8_t max_pulses_per_symbol, uint8_t number_of_symbols) { +void TZX::get_generalised_segment(uint32_t output_symbols, uint8_t max_pulses_per_symbol, uint8_t number_of_symbols, bool is_data) { if(!output_symbols) return; // Construct the symbol table. @@ -97,27 +97,48 @@ void TZX::get_generalised_segment(uint32_t output_symbols, uint8_t max_pulses_pe for(int ic = 0; ic < max_pulses_per_symbol; ic++) { symbol.pulse_lengths.push_back(fgetc16le()); } + symbol_table.push_back(symbol); } // Hence produce the output. + BitStream stream(file_, false); + int base = 2; + int bits = 1; + while(base < number_of_symbols) { + base <<= 1; + bits++; + } for(int c = 0; c < output_symbols; c++) { - uint8_t symbol_value = (uint8_t)fgetc(file_); + uint8_t symbol_value; + int count; + if(is_data) { + symbol_value = stream.get_bits(bits); + count = 1; + } else { + symbol_value = (uint8_t)fgetc(file_); + count = fgetc16le(); + } + if(symbol_value > number_of_symbols) { + continue; + } Symbol &symbol = symbol_table[symbol_value]; - // Mutate initial output level. - switch(symbol.flags & 3) { - case 0: break; - case 1: is_high_ ^= true; break; - case 2: is_high_ = true; break; - case 3: is_high_ = false; break; - } + while(count--) { + // Mutate initial output level. + switch(symbol.flags & 3) { + case 0: break; + case 1: is_high_ ^= true; break; + case 2: is_high_ = true; break; + case 3: is_high_ = false; break; + } - // Output waves. - for(auto length : symbol.pulse_lengths) { - if(!length) break; + // Output waves. + for(auto length : symbol.pulse_lengths) { + if(!length) break; - is_high_ ^= true; - emplace_back(is_high_ ? Tape::Pulse::High : Tape::Pulse::Low, Storage::Time((unsigned int)length, StandardTZXClock)); + is_high_ ^= true; + emplace_back(is_high_ ? Tape::Pulse::High : Tape::Pulse::Low, Storage::Time((unsigned int)length, StandardTZXClock)); + } } } } diff --git a/Storage/Tape/Formats/TZX.hpp b/Storage/Tape/Formats/TZX.hpp index 174109556..e2e055c66 100644 --- a/Storage/Tape/Formats/TZX.hpp +++ b/Storage/Tape/Formats/TZX.hpp @@ -38,7 +38,7 @@ class TZX: public PulseQueuedTape, public Storage::FileHolder { bool is_high_; void get_generalised_data_block(); - void get_generalised_segment(uint32_t output_symbols, uint8_t max_pulses_per_symbol, uint8_t number_of_symbols); + void get_generalised_segment(uint32_t output_symbols, uint8_t max_pulses_per_symbol, uint8_t number_of_symbols, bool is_data); }; }