summaryrefslogtreecommitdiffstatshomepage
path: root/trunk/src/lib/formats/svi_cas.c
diff options
context:
space:
mode:
Diffstat (limited to 'trunk/src/lib/formats/svi_cas.c')
-rw-r--r--trunk/src/lib/formats/svi_cas.c209
1 files changed, 209 insertions, 0 deletions
diff --git a/trunk/src/lib/formats/svi_cas.c b/trunk/src/lib/formats/svi_cas.c
new file mode 100644
index 00000000000..08e3915ac1c
--- /dev/null
+++ b/trunk/src/lib/formats/svi_cas.c
@@ -0,0 +1,209 @@
+#include "svi_cas.h"
+
+#define CAS_PERIOD_0 (37)
+#define CAS_PERIOD_1 (18)
+#define CAS_HEADER_PERIODS (1600)
+#define CAS_EMPTY_SAMPLES (24220)
+#define CAS_INIT_SAMPLES (200)
+
+static const UINT8 CasHeader[17] =
+{
+ 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
+ 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x7f
+};
+
+#define SMPLO -32768
+#define SMPHI 32767
+
+static int cas_size;
+
+/*******************************************************************
+ Generate samples for the tape image
+********************************************************************/
+static int svi_cas_fill_wave(INT16 *buffer, int sample_count, UINT8 *bytes)
+{
+ int cas_pos, samples_pos, n, i;
+
+ cas_pos = 17;
+ samples_pos = 0;
+
+ /* write CAS_INIT_SAMPLES of silence */
+ n = CAS_INIT_SAMPLES; while (n--) buffer[samples_pos++] = 0;
+
+ while (samples_pos < sample_count && cas_pos < cas_size)
+ {
+ /* write CAS_HEADER_PERIODS of header */
+ for (i=0;i<CAS_HEADER_PERIODS;i++)
+ {
+ /* write a "0" */
+ n = !(i % 4) ? 21 : 18;
+ while (n--) buffer[samples_pos++] = SMPHI;
+ n = 19; while (n--) buffer[samples_pos++] = SMPLO;
+ /* write a "1" */
+ n = 9; while (n--) buffer[samples_pos++] = SMPHI;
+ n = 9; while (n--) buffer[samples_pos++] = SMPLO;
+ }
+
+ /* write "0x7f" */
+ /* write a "0" */
+ n = 21; while (n--) buffer[samples_pos++] = SMPHI;
+ n = 19; while (n--) buffer[samples_pos++] = SMPLO;
+
+ for (i=0;i<7;i++)
+ {
+ /* write a "1" */
+ n = 9; while (n--) buffer[samples_pos++] = SMPHI;
+ n = 9; while (n--) buffer[samples_pos++] = SMPLO;
+ }
+
+ while (samples_pos < sample_count && cas_pos < cas_size)
+ {
+ n = 21; while (n--) buffer[samples_pos++] = SMPHI;
+ n = 19; while (n--) buffer[samples_pos++] = SMPLO;
+
+ for (i=0;i<8;i++)
+ {
+ int bit = (bytes[cas_pos] & (0x80 >> i) );
+
+ /* write this one bit */
+ if (bit)
+ {
+ /* write a "1" */
+ n = 9; while (n--) buffer[samples_pos++] = SMPHI;
+ n = 9; while (n--) buffer[samples_pos++] = SMPLO;
+ }
+ else
+ {
+ /* write a "0" */
+ n = 18; while (n--) buffer[samples_pos++] = SMPHI;
+ n = 19; while (n--) buffer[samples_pos++] = SMPLO;
+ }
+ }
+
+ cas_pos++;
+
+ /* check if we've hit a new header (or end of block) */
+ if ( (cas_pos + 17) < cas_size)
+ {
+ if (!memcmp (bytes + cas_pos, CasHeader, 17) )
+ {
+ cas_pos += 17;
+
+ /* end of block marker */
+ n = CAS_EMPTY_SAMPLES; while (n--) buffer[samples_pos++] = SMPHI;
+
+ break; /* falls back to loop above; plays header again */
+ }
+ }
+ }
+ }
+
+ /* end of block marker */
+ n = CAS_EMPTY_SAMPLES; while (n--) buffer[samples_pos++] = SMPHI;
+
+ return samples_pos;
+}
+
+
+/*******************************************************************
+ Calculate the number of samples needed for this tape image
+********************************************************************/
+static int svi_cas_to_wav_size(const UINT8 *casdata, int caslen)
+{
+ int cas_pos, samples_pos, size, i;
+
+ if (caslen < 17) return -1;
+ if (memcmp (casdata, CasHeader, sizeof (CasHeader) ) ) return -1;
+
+ cas_size = caslen;
+
+ cas_pos = 17;
+
+ samples_pos = CAS_INIT_SAMPLES;
+
+ while (cas_pos < caslen)
+ {
+ size = CAS_HEADER_PERIODS * ( CAS_PERIOD_0 + CAS_PERIOD_1 ) +
+ ( CAS_HEADER_PERIODS / 4 ) * 3;
+
+ samples_pos += size;
+
+ samples_pos += 21 + 19 + 7 * CAS_PERIOD_1;
+
+ while (cas_pos < caslen)
+ {
+ samples_pos += 21;
+ samples_pos += 19;
+
+ for (i=0;i<8;i++)
+ {
+ int bit = (casdata[cas_pos] & (0x80 >> i) );
+
+ samples_pos += bit ? CAS_PERIOD_1 : CAS_PERIOD_0;
+ }
+
+ cas_pos++;
+
+ /* check if we've hit a new header (or end of block) */
+ if ( (cas_pos + 17) < caslen)
+ {
+ if (!memcmp (casdata + cas_pos, CasHeader, 17) )
+ {
+ cas_pos += 17;
+
+ /* end of block marker */
+ samples_pos += CAS_EMPTY_SAMPLES;
+
+ break; /* falls back to loop above; plays header again */
+ }
+ }
+ }
+ }
+
+ /* end of block marker */
+ samples_pos += CAS_EMPTY_SAMPLES;
+
+ return samples_pos;
+}
+
+
+static const struct CassetteLegacyWaveFiller svi_legacy_fill_wave =
+{
+ svi_cas_fill_wave, /* fill_wave */
+ -1, /* chunk_size */
+ 0, /* chunk_samples */
+ svi_cas_to_wav_size, /* chunk_sample_calc */
+ 44100, /* sample_frequency */
+ 0, /* header_samples */
+ 0 /* trailer_samples */
+};
+
+
+
+static casserr_t svi_cas_identify(cassette_image *cassette, struct CassetteOptions *opts)
+{
+ return cassette_legacy_identify(cassette, opts, &svi_legacy_fill_wave);
+}
+
+
+
+static casserr_t svi_cas_load(cassette_image *cassette)
+{
+ return cassette_legacy_construct(cassette, &svi_legacy_fill_wave);
+}
+
+
+
+static const struct CassetteFormat svi_cas_format =
+{
+ "cas",
+ svi_cas_identify,
+ svi_cas_load,
+ NULL
+};
+
+
+
+CASSETTE_FORMATLIST_START(svi_cassette_formats)
+ CASSETTE_FORMAT(svi_cas_format)
+CASSETTE_FORMATLIST_END