summaryrefslogtreecommitdiffstatshomepage
path: root/trunk/src/lib/formats/sord_cas.c
diff options
context:
space:
mode:
Diffstat (limited to 'trunk/src/lib/formats/sord_cas.c')
-rw-r--r--trunk/src/lib/formats/sord_cas.c138
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