From 18b6f17e86da1527c19de0b88988b0b2cffdf7dd Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Thu, 6 Jan 2022 17:24:31 -0500 Subject: [PATCH] With some refactoring makes some minor steps towards supporting gaps. --- Storage/Disk/DiskImage/Formats/IPF.cpp | 131 ++++++++++++++----------- Storage/Disk/DiskImage/Formats/IPF.hpp | 8 +- 2 files changed, 77 insertions(+), 62 deletions(-) diff --git a/Storage/Disk/DiskImage/Formats/IPF.cpp b/Storage/Disk/DiskImage/Formats/IPF.cpp index ad7024207..a610564d0 100644 --- a/Storage/Disk/DiskImage/Formats/IPF.cpp +++ b/Storage/Disk/DiskImage/Formats/IPF.cpp @@ -8,7 +8,6 @@ #include "IPF.hpp" -#include "../../Track/PCMTrack.hpp" #include "../../Encodings/MFM/Encoder.hpp" #include @@ -258,19 +257,22 @@ std::shared_ptr IPF::get_track_at_position([[maybe_unused]] Track::Addres } type = Type(gap_header & 0x1f); const size_t length = block_size(file_, gap_header); - // TODO: write the gap. switch(type) { case Type::GapLength: - printf("Unhandled gap length %zu bytes\n", length); + printf("Adding gap length %zu bits\n", length); + add_gap(segments, length_of_a_bit, length, block.default_gap_value); break; default: case Type::SampleLength: - printf("Unhandled sampled gap length %zu bytes\n", length); - file_.seek(long(length >> 3), SEEK_CUR); + printf("Adding sampled gap length %zu bits\n", length); + add_raw_data(segments, length_of_a_bit, length); +// file_.seek(long(length >> 3), SEEK_CUR); break; } } + } else if(block.gap_bits) { + add_gap(segments, length_of_a_bit, block.gap_bits, block.default_gap_value); } if(block.data_offset) { @@ -288,65 +290,16 @@ std::shared_ptr IPF::get_track_at_position([[maybe_unused]] Track::Addres const auto next_chunk = file_.tell() + long(length >> 3); #endif - // TODO: write the data. switch(type) { - /*case Type::Gap: { - auto &segment = segments.emplace_back(); - segment.length_of_a_bit = length_of_a_bit; - segment.data.reserve(size_t(length + 31) & size_t(~31)); - auto encoder = Storage::Encodings::MFM::GetMFMEncoder(segment.data); - while(segment.data.size() < length) { - encoder->add_byte(uint8_t(block.default_gap_value >> 24)); - encoder->add_byte(uint8_t(block.default_gap_value >> 16)); - encoder->add_byte(uint8_t(block.default_gap_value >> 8)); - encoder->add_byte(uint8_t(block.default_gap_value >> 0)); - } - segment.data.resize(length); - } break;*/ - case Type::Gap: - case Type::Data: { - printf("Handling data type %d, length %zu bits\n", int(type), length); - auto &segment = segments.emplace_back(); - segment.length_of_a_bit = length_of_a_bit; - - // Length appears to be in pre-encoded bits; double that to get encoded bits. - const auto byte_length = (length + 7) >> 3; - segment.data.reserve(byte_length * 16); - - auto encoder = Storage::Encodings::MFM::GetMFMEncoder(segment.data); - for(size_t c = 0; c < length; c += 8) { - encoder->add_byte(file_.get8()); - } - - assert(segment.data.size() <= (byte_length * 16)); - segment.data.resize(length * 2); - } break; + case Type::Data: + add_unencoded_data(segments, length_of_a_bit, length); + break; case Type::Sync: - case Type::Raw: { - printf("Handling data type %d, length %zu bits\n", int(type), length); - auto &segment = segments.emplace_back(); - segment.length_of_a_bit = length_of_a_bit; - - const auto bit_length = size_t(length + 7) & size_t(~7); - segment.data.reserve(bit_length); - - for(size_t bit = 0; bit < length; bit += 8) { - const uint8_t next = file_.get8(); - segment.data.push_back(next & 0x80); - segment.data.push_back(next & 0x40); - segment.data.push_back(next & 0x20); - segment.data.push_back(next & 0x10); - segment.data.push_back(next & 0x08); - segment.data.push_back(next & 0x04); - segment.data.push_back(next & 0x02); - segment.data.push_back(next & 0x01); - } - - assert(segment.data.size() <= bit_length); - segment.data.resize(length); - } break; + case Type::Raw: + add_raw_data(segments, length_of_a_bit, length); + break; default: printf("Unhandled data type %d, length %zu bits\n", int(type), length); @@ -424,3 +377,61 @@ Storage::Time IPF::bit_length(TrackDescription::Density density, int block) { return us200; // i.e. default to 2µs. } + +void IPF::add_gap(std::vector &track, Time bit_length, size_t num_bits, uint32_t value) { + auto &segment = track.emplace_back(); + segment.length_of_a_bit = bit_length; + + // Empirically, I think gaps require MFM encoding. + const auto byte_length = (num_bits + 7) >> 3; + segment.data.reserve(byte_length * 16); + + auto encoder = Storage::Encodings::MFM::GetMFMEncoder(segment.data); + while(segment.data.size() < num_bits) { + encoder->add_byte(uint8_t(value >> 24)); + value = (value << 8) | (value >> 24); + } + + assert(segment.data.size() <= (byte_length * 16)); + segment.data.resize(num_bits); +} + +void IPF::add_unencoded_data(std::vector &track, Time bit_length, size_t num_bits) { + auto &segment = track.emplace_back(); + segment.length_of_a_bit = bit_length; + + // Length appears to be in pre-encoded bits; double that to get encoded bits. + const auto byte_length = (num_bits + 7) >> 3; + segment.data.reserve(num_bits * 16); + + auto encoder = Storage::Encodings::MFM::GetMFMEncoder(segment.data); + for(size_t c = 0; c < num_bits; c += 8) { + encoder->add_byte(file_.get8()); + } + + assert(segment.data.size() <= (byte_length * 16)); + segment.data.resize(num_bits * 2); +} + +void IPF::add_raw_data(std::vector &track, Time bit_length, size_t num_bits) { + auto &segment = track.emplace_back(); + segment.length_of_a_bit = bit_length; + + const auto num_bits_ceiling = size_t(num_bits + 7) & size_t(~7); + segment.data.reserve(num_bits_ceiling); + + for(size_t bit = 0; bit < num_bits; bit += 8) { + const uint8_t next = file_.get8(); + segment.data.push_back(next & 0x80); + segment.data.push_back(next & 0x40); + segment.data.push_back(next & 0x20); + segment.data.push_back(next & 0x10); + segment.data.push_back(next & 0x08); + segment.data.push_back(next & 0x04); + segment.data.push_back(next & 0x02); + segment.data.push_back(next & 0x01); + } + + assert(segment.data.size() <= num_bits_ceiling); + segment.data.resize(num_bits); +} diff --git a/Storage/Disk/DiskImage/Formats/IPF.hpp b/Storage/Disk/DiskImage/Formats/IPF.hpp index 1ce1e74c7..fa29aafa8 100644 --- a/Storage/Disk/DiskImage/Formats/IPF.hpp +++ b/Storage/Disk/DiskImage/Formats/IPF.hpp @@ -10,6 +10,7 @@ #define IPF_hpp #include "../DiskImage.hpp" +#include "../../Track/PCMTrack.hpp" #include "../../../FileHolder.hpp" #include "../../../TargetPlatforms.hpp" @@ -68,8 +69,6 @@ class IPF: public DiskImage, public TargetPlatform::TypeDistinguisher { bool has_fuzzy_bits = false; }; - Time bit_length(TrackDescription::Density, int block); - int head_count_; int track_count_; std::map tracks_; @@ -79,6 +78,11 @@ class IPF: public DiskImage, public TargetPlatform::TypeDistinguisher { return TargetPlatform::Type(platform_type_); } TargetPlatform::IntType platform_type_ = TargetPlatform::Amiga; + + Time bit_length(TrackDescription::Density, int block); + void add_gap(std::vector &, Time bit_length, size_t num_bits, uint32_t value); + void add_unencoded_data(std::vector &, Time bit_length, size_t num_bits); + void add_raw_data(std::vector &, Time bit_length, size_t num_bits); }; }