diff options
Diffstat (limited to 'trunk/src/lib/formats/sord_cas.c')
-rw-r--r-- | trunk/src/lib/formats/sord_cas.c | 138 |
1 files changed, 138 insertions, 0 deletions
diff --git a/trunk/src/lib/formats/sord_cas.c b/trunk/src/lib/formats/sord_cas.c new file mode 100644 index 00000000000..cab593d66e8 --- /dev/null +++ b/trunk/src/lib/formats/sord_cas.c @@ -0,0 +1,138 @@ +/************************************************************************** + + sord_cas.c + + Format code for Sord M5 cassette files + +**************************************************************************/ + +#include <string.h> +#include "sord_cas.h" + +#define SORDM5_WAVESAMPLES_HEADER 1 +#define SORDM5_WAVESAMPLES_TRAILER 1 +#define SORDM5_WAVESAMPLES_BLOCK 1 + +static const UINT8 SORDM5_CAS_HEADER[6] = { 'S', 'O', 'R', 'D', 'M', '5'}; + +static const struct CassetteModulation sordm5_cas_modulation = +{ + CASSETTE_MODULATION_SINEWAVE, + 1575.0 - 300, 1575.0, 1575.0 + 300, + 3150.0 - 600, 3150.0, 3150.0 + 600 +}; + +static UINT8 cassette_image_read_uint8( cassette_image *cassette, UINT64 offset) +{ + UINT8 data; + cassette_image_read( cassette, &data, offset, 1); + return data; +} + +static casserr_t sordm5_tap_identify( cassette_image *cassette, struct CassetteOptions *opts) +{ + return cassette_modulation_identify( cassette, &sordm5_cas_modulation, opts); +} + +static casserr_t sordm5_tap_load( cassette_image *cassette) +{ + casserr_t err; + UINT64 image_size; + double time_index = 0.0; + double time_displacement; + UINT8 header[16]; + UINT64 image_pos; + UINT8 block_type, byte, bit; + UINT32 block_size, i, j; + size_t filler_length; + // init + image_size = cassette_image_size(cassette); + image_pos = 0; + // read/check header + if (image_size < 16) return CASSETTE_ERROR_INVALIDIMAGE; + cassette_image_read( cassette, &header, image_pos, 16); + image_pos += 16; + if (memcmp( header, SORDM5_CAS_HEADER, sizeof(SORDM5_CAS_HEADER)) != 0) return CASSETTE_ERROR_INVALIDIMAGE; + // add silence (header) + err = cassette_put_sample( cassette, 0, time_index, SORDM5_WAVESAMPLES_HEADER, 0); + if (err) return err; + time_index += SORDM5_WAVESAMPLES_HEADER; + // process blocks + while (image_pos < image_size) + { + // read block type + block_type = cassette_image_read_uint8( cassette, image_pos + 0); + if ((block_type != 'H') && (block_type != 'D')) return CASSETTE_ERROR_INVALIDIMAGE; + // read block size + block_size = cassette_image_read_uint8( cassette, image_pos + 1); + if (block_size == 0) block_size = 0x100; + block_size += 3; + // add silence (header block) + if (block_type == 'H') + { + err = cassette_put_sample( cassette, 0, time_index, SORDM5_WAVESAMPLES_BLOCK, 0); + if (err) return err; + time_index += SORDM5_WAVESAMPLES_BLOCK; + } + // add sync + if (block_type == 'H') filler_length = 2.4 * (3150 / 8); else filler_length = 0.15 * (3150 / 8); + err = cassette_put_modulated_filler(cassette, 0, time_index, 0xFF, filler_length, &sordm5_cas_modulation, &time_displacement); + if (err) return err; + time_index += time_displacement; + // process block + for (i=0;i<block_size;i++) + { + // read byte + byte = cassette_image_read_uint8( cassette, image_pos + i); + // calc/check checksum + #if 0 + if (i == block_size) + { + if (byte != (crc & 0xFF)) return CASSETTE_ERROR_INVALIDIMAGE; + } + if (i > 2) crc += byte; + #endif + // process byte + for (j=0;j<10;j++) + { + // get bit + if (j < 2) + { + bit = ((j==0)?1:0); + } + else + { + bit = (byte >> (j-2)) & 1; + } + // add bit + err = cassette_put_modulated_data_bit( cassette, 0, time_index, bit, &sordm5_cas_modulation, &time_displacement); + if (err) return err; + time_index += time_displacement; + } + } + // mark end of block + err = cassette_put_modulated_data_bit( cassette, 0, time_index, 1, &sordm5_cas_modulation, &time_displacement); + if (err) return err; + time_index += time_displacement; + // next block + image_pos += block_size; + } + // add silence (trailer) + err = cassette_put_sample( cassette, 0, time_index, SORDM5_WAVESAMPLES_TRAILER, 0); + if (err) return err; + time_index += SORDM5_WAVESAMPLES_TRAILER; + // + return CASSETTE_ERROR_SUCCESS; +} + +static const struct CassetteFormat sordm5_cas_format = +{ + "cas", + sordm5_tap_identify, + sordm5_tap_load, + NULL +}; + +CASSETTE_FORMATLIST_START(sordm5_cassette_formats) + CASSETTE_FORMAT(sordm5_cas_format) +CASSETTE_FORMATLIST_END |