summaryrefslogtreecommitdiffstatshomepage
path: root/trunk/src/lib/formats/kim1_cas.c
diff options
context:
space:
mode:
Diffstat (limited to 'trunk/src/lib/formats/kim1_cas.c')
-rw-r--r--trunk/src/lib/formats/kim1_cas.c194
1 files changed, 194 insertions, 0 deletions
diff --git a/trunk/src/lib/formats/kim1_cas.c b/trunk/src/lib/formats/kim1_cas.c
new file mode 100644
index 00000000000..290a0095c99
--- /dev/null
+++ b/trunk/src/lib/formats/kim1_cas.c
@@ -0,0 +1,194 @@
+#include "kim1_cas.h"
+
+#define SMPLO -32768
+#define SMPHI 32767
+
+
+static int cas_size;
+
+
+INLINE int kim1_output_signal( INT16 *buffer, int sample_pos, int high )
+{
+ int sample_count, i, j;
+
+ sample_count = 0;
+
+ if ( high )
+ {
+ /* high frequency (~3600Hz) */
+ for ( i = 0; i < 9; i++ )
+ {
+ if ( buffer )
+ {
+ for ( j = 0; j < 6; j++ )
+ buffer[ sample_pos + sample_count + j ] = SMPHI;
+ }
+ sample_count += 6;
+
+ if ( buffer )
+ {
+ for ( j = 0; j < 6; j++ )
+ buffer[ sample_pos + sample_count + j ] = SMPLO;
+ }
+ sample_count += 6;
+ }
+ }
+ else
+ {
+ /* low frequency (~2400Hz) */
+ for ( i = 0; i < 6; i++ )
+ {
+ if ( buffer )
+ {
+ for ( j = 0; j < 9; j++ )
+ buffer[ sample_pos + sample_count + j ] = SMPHI;
+ }
+ sample_count += 9;
+
+ if ( buffer )
+ {
+ for ( j = 0; j < 9; j++ )
+ buffer[ sample_pos + sample_count + j ] = SMPLO;
+ }
+ sample_count += 9;
+ }
+ }
+
+ return sample_count;
+}
+
+
+INLINE int kim1_output_byte( INT16 *buffer, int sample_pos, UINT8 byte )
+{
+ int i;
+ int sample_count = 0;
+
+ for ( i = 0; i < 8; i++ )
+ {
+ sample_count += kim1_output_signal( buffer, sample_pos + sample_count, 1 );
+ sample_count += kim1_output_signal( buffer, sample_pos + sample_count, byte & 0x01 ? 0 : 1 );
+ sample_count += kim1_output_signal( buffer, sample_pos + sample_count, 0 );
+ byte >>= 1;
+ }
+ return sample_count;
+}
+
+
+static int kim1_handle_kim(INT16 *buffer, const UINT8 *casdata)
+{
+ static const UINT8 encoding[16] = { 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46 };
+ int i, data_pos, sample_count;
+ UINT16 size, address, file_id, checksum;
+
+ if ( cas_size < 9 ) return -1;
+ if ( memcmp( casdata, "KIM1", 4 ) ) return -1;
+
+ address = casdata[4] | ( casdata[5] << 8 );
+ size = casdata[6] | ( casdata[7] << 8 );
+ file_id = casdata[8];
+
+ data_pos = 9;
+ sample_count = 0;
+ checksum = casdata[4] + casdata[5];
+
+ /* First output a sync header: 100 x 16h */
+ for ( i = 0; i < 100; i++ )
+ sample_count += kim1_output_byte( buffer, sample_count, 0x16 );
+
+ /* Output end of sync: 2Ah */
+ sample_count += kim1_output_byte( buffer, sample_count, 0x2A );
+
+ /* Output ID */
+ sample_count += kim1_output_byte( buffer, sample_count, encoding[ file_id >> 4 ] );
+ sample_count += kim1_output_byte( buffer, sample_count, encoding[ file_id & 0x0f ] );
+
+ /* Output starting address */
+ sample_count += kim1_output_byte( buffer, sample_count, encoding[ ( address & 0xff ) >> 4 ] );
+ sample_count += kim1_output_byte( buffer, sample_count, encoding[ address & 0x0f ] );
+ sample_count += kim1_output_byte( buffer, sample_count, encoding[ address >> 12 ] );
+ sample_count += kim1_output_byte( buffer, sample_count, encoding[ ( address >> 8 ) & 0x0f ] );
+
+ /* Output the data */
+ while( data_pos < cas_size && data_pos < ( size + 9 ) )
+ {
+ UINT8 data = casdata[data_pos];
+
+ sample_count += kim1_output_byte( buffer, sample_count, encoding[ data >> 4 ] );
+ sample_count += kim1_output_byte( buffer, sample_count, encoding[ data & 0x0f ] );
+ checksum += data;
+ data_pos++;
+ }
+
+ /* Output end of data marker: 2Fh */
+ sample_count += kim1_output_byte( buffer, sample_count, 0x2F );
+
+ /* Output checksum */
+ sample_count += kim1_output_byte( buffer, sample_count, encoding[ ( checksum & 0xff ) >> 4 ] );
+ sample_count += kim1_output_byte( buffer, sample_count, encoding[ checksum & 0x0f ] );
+ sample_count += kim1_output_byte( buffer, sample_count, encoding[ checksum >> 12 ] );
+ sample_count += kim1_output_byte( buffer, sample_count, encoding[ ( checksum >> 8 ) & 0x0f ] );
+
+ /* Output end of transmission marker: 2 x 04h */
+ sample_count += kim1_output_byte( buffer, sample_count, 0x04 );
+ sample_count += kim1_output_byte( buffer, sample_count, 0x04 );
+
+ return sample_count;
+}
+
+
+/*******************************************************************
+ Generate samples for the tape image
+********************************************************************/
+static int kim1_kim_fill_wave(INT16 *buffer, int sample_count, UINT8 *bytes)
+{
+ return kim1_handle_kim( buffer, bytes );
+}
+
+
+/*******************************************************************
+ Calculate the number of samples needed for this tape image
+********************************************************************/
+static int kim1_kim_to_wav_size(const UINT8 *casdata, int caslen)
+{
+ cas_size = caslen;
+
+ return kim1_handle_kim( NULL, casdata );
+}
+
+static const struct CassetteLegacyWaveFiller kim1_kim_legacy_fill_wave =
+{
+ kim1_kim_fill_wave, /* fill_wave */
+ -1, /* chunk_size */
+ 0, /* chunk_samples */
+ kim1_kim_to_wav_size, /* chunk_sample_calc */
+ 44100, /* sample_frequency */
+ 0, /* header_samples */
+ 0 /* trailer_samples */
+};
+
+
+static casserr_t kim1_kim_identify(cassette_image *cassette, struct CassetteOptions *opts)
+{
+ return cassette_legacy_identify(cassette, opts, &kim1_kim_legacy_fill_wave);
+}
+
+
+static casserr_t kim1_kim_load(cassette_image *cassette)
+{
+ return cassette_legacy_construct(cassette, &kim1_kim_legacy_fill_wave);
+}
+
+
+static const struct CassetteFormat kim1_kim_format =
+{
+ "kim,kim1",
+ kim1_kim_identify,
+ kim1_kim_load,
+ NULL
+};
+
+
+CASSETTE_FORMATLIST_START(kim1_cassette_formats)
+ CASSETTE_FORMAT(kim1_kim_format)
+CASSETTE_FORMATLIST_END
+