summaryrefslogtreecommitdiffstatshomepage
path: root/trunk/src/lib/formats/vg5k_cas.c
diff options
context:
space:
mode:
Diffstat (limited to 'trunk/src/lib/formats/vg5k_cas.c')
-rw-r--r--trunk/src/lib/formats/vg5k_cas.c234
1 files changed, 234 insertions, 0 deletions
diff --git a/trunk/src/lib/formats/vg5k_cas.c b/trunk/src/lib/formats/vg5k_cas.c
new file mode 100644
index 00000000000..68ae6b4a026
--- /dev/null
+++ b/trunk/src/lib/formats/vg5k_cas.c
@@ -0,0 +1,234 @@
+/********************************************************************
+
+ Support for VG-5000 .k7 cassette images
+
+********************************************************************/
+#include "vg5k_cas.h"
+
+
+#define SMPLO -32768
+#define SILENCE 0
+#define SMPHI 32767
+
+
+static int k7_size;
+
+/*******************************************************************
+ Generate one high-low cycle of sample data
+********************************************************************/
+INLINE int vg5k_cas_cycle(INT16 *buffer, int sample_pos, int len)
+{
+ int i = 0;
+
+ if (buffer)
+ {
+ while( i < len)
+ {
+ buffer[ sample_pos + i ] = SMPHI;
+ i++;
+ }
+
+ while( i < len * 2 )
+ {
+ buffer[ sample_pos + i ] = SMPLO;
+ i++;
+ }
+ }
+ return len * 2;
+}
+
+
+/*******************************************************************
+ Generate n samples of silence
+********************************************************************/
+INLINE int vg5k_cas_silence(INT16 *buffer, int sample_pos, int len)
+{
+ int i = 0;
+
+ if ( buffer )
+ for( i = 0; i < len; i++)
+ buffer[ sample_pos + i ] = SILENCE;
+
+ return len;
+}
+
+
+/*******************************************************************
+ Generate the end-byte samples
+********************************************************************/
+INLINE int vg5k_cas_eob(INT16 *buffer, int sample_pos)
+{
+ int i, samples = 0;
+
+ for (i = 0; i < 4; i++)
+ samples += vg5k_cas_cycle( buffer, sample_pos + samples, 5);
+
+ samples += vg5k_cas_cycle( buffer, sample_pos + samples, 10);
+
+ return samples;
+}
+
+
+INLINE int vg5k_cas_byte(INT16 *buffer, int sample_pos, UINT8 data)
+{
+/* Writing an entire byte */
+ int i, samples;
+
+ samples = 0;
+ for ( i = 0; i < 8; i++ )
+ {
+ if ( data & 0x01 )
+ {
+ samples += vg5k_cas_cycle( buffer, sample_pos + samples, 5 );
+ samples += vg5k_cas_cycle( buffer, sample_pos + samples, 5 );
+ }
+ else
+ {
+ samples += vg5k_cas_cycle( buffer, sample_pos + samples, 10 );
+ }
+
+ data >>= 1;
+ }
+ return samples;
+}
+
+
+/*******************************************************************
+ Generate n sample of synchro
+********************************************************************/
+INLINE int vg5k_k7_synchro(INT16 *buffer, int sample_pos, int len)
+{
+
+ int i, samples = 0;
+
+ for ( i = 0; i < len ; i++ )
+ samples += vg5k_cas_cycle( buffer, sample_pos + samples, 5);
+
+ samples += vg5k_cas_eob( buffer, sample_pos + samples);
+
+ return samples;
+}
+
+
+static int vg5k_handle_tap(INT16 *buffer, const UINT8 *casdata)
+{
+ int data_pos, sample_count;
+
+ data_pos = 0;
+ sample_count = 0;
+
+ /* file has to start with an head block */
+ if (casdata[0] != 0xd3 || casdata[1] != 0xd3 || casdata[2] != 0xd3)
+ return -1;
+
+ /* on the entire file*/
+ while( data_pos < k7_size )
+ {
+ UINT16 block_size = 0;
+
+ /* Identify type of block */
+ if (casdata[data_pos] == 0xd3)
+ {
+ /* head block have fixed size of 32 byte */
+ block_size = 0x20;
+
+ /* 1 sec of silence before the head block */
+ sample_count += vg5k_cas_silence(buffer, sample_count, 44100);
+
+ /* head block starts with 30000 samples of synchro */
+ sample_count += vg5k_k7_synchro( buffer, sample_count, 30000 );
+ }
+ else if (casdata[data_pos] == 0xd6)
+ {
+ /* data block size is defined in head block */
+ block_size = (casdata[data_pos - 4] | casdata[data_pos - 3]<<8) + 20;
+
+ /* 10000 samples of silence before the data block */
+ sample_count += vg5k_cas_silence(buffer, sample_count, 10000);
+
+ /* data block starts with 7200 samples of synchro */
+ sample_count += vg5k_k7_synchro( buffer, sample_count, 7200);
+ }
+ else
+ {
+ /* tries to handle files that do not respect the size declared in the head block */
+ while (data_pos < k7_size && casdata[data_pos] != 0xd3 && casdata[data_pos] != 0xd6)
+ data_pos++;
+ }
+
+ /* Data samples */
+ for ( ; block_size ; data_pos++, block_size-- )
+ {
+ /* Make sure there are enough bytes left */
+ if (data_pos > k7_size)
+ return -1;
+
+ sample_count += vg5k_cas_byte( buffer, sample_count, casdata[data_pos] );
+
+ /* generate the end-byte samples */
+ sample_count += vg5k_cas_eob( buffer, sample_count);
+ }
+ }
+
+ /* Finish with 10000 samples of silence */
+ sample_count += vg5k_cas_silence(buffer, sample_count, 10000);
+
+ return sample_count;
+}
+
+
+/*******************************************************************
+ Generate samples for the tape image
+********************************************************************/
+static int vg5k_k7_fill_wave(INT16 *buffer, int sample_count, UINT8 *bytes)
+{
+ return vg5k_handle_tap(buffer, bytes);
+}
+
+
+/*******************************************************************
+ Calculate the number of samples needed for this tape image classical
+********************************************************************/
+static int vg5k_k7_to_wav_size(const UINT8 *casdata, int caslen)
+{
+ k7_size = caslen ;
+
+ return vg5k_handle_tap( NULL, casdata );
+}
+
+
+static const struct CassetteLegacyWaveFiller vg5k_legacy_fill_wave =
+{
+ vg5k_k7_fill_wave, /* fill_wave */
+ -1, /* chunk_size */
+ 0, /* chunk_samples */
+ vg5k_k7_to_wav_size, /* chunk_sample_calc */
+ 44100, /* sample_frequency */
+ 0, /* header_samples */
+ 0 /* trailer_samples */
+};
+
+static casserr_t vg5k_k7_identify(cassette_image *cassette, struct CassetteOptions *opts)
+{
+ return cassette_legacy_identify(cassette, opts, &vg5k_legacy_fill_wave);
+}
+
+
+static casserr_t vg5k_k7_load(cassette_image *cassette)
+{
+ return cassette_legacy_construct(cassette, &vg5k_legacy_fill_wave);
+}
+
+
+static const struct CassetteFormat vg5k_k7_format =
+{
+ "k7",
+ vg5k_k7_identify,
+ vg5k_k7_load,
+ NULL
+};
+
+
+CASSETTE_FORMATLIST_START(vg5k_cassette_formats)
+ CASSETTE_FORMAT(vg5k_k7_format)
+CASSETTE_FORMATLIST_END