summaryrefslogtreecommitdiffstatshomepage
path: root/trunk/src/lib/formats/csw_cas.c
diff options
context:
space:
mode:
Diffstat (limited to 'trunk/src/lib/formats/csw_cas.c')
-rw-r--r--trunk/src/lib/formats/csw_cas.c329
1 files changed, 329 insertions, 0 deletions
diff --git a/trunk/src/lib/formats/csw_cas.c b/trunk/src/lib/formats/csw_cas.c
new file mode 100644
index 00000000000..13ba77faca6
--- /dev/null
+++ b/trunk/src/lib/formats/csw_cas.c
@@ -0,0 +1,329 @@
+/*
+CSW format
+----------
+Header Description
+
+Offset Value Type Description
+0x00 (note) ASCII 22 bytes "Compressed Square Wave" signature
+0x16 0x1A BYTE Terminator code
+0x17 0x02 BYTE CSW major revision number
+0x18 0x00 BYTE CSW minor revision number
+0x19 DWORD Sample rate
+0x1D DWORD Total number of pulses (after decompression)
+0x21 BYTE Compression type 0x01: RLE 0x02: Z-RLE
+0x22 BYTE Flags b0: initial polarity: if set, the signal starts at logical high
+0x23 HDR BYTE Header extension length in bytes (0x00)
+0x24 ASCII 16 bytes free use
+0x34 BYTE Start of Header is HDR>0
+
+
+
+*/
+
+#include <string.h>
+
+#include "zlib.h"
+#include "uef_cas.h"
+#include "csw_cas.h"
+
+
+#define CSW_WAV_FREQUENCY 44100
+
+static const UINT8 CSW_HEADER[] = { "Compressed Square Wave" };
+
+static UINT32 get_leuint32(const void *ptr)
+{
+ UINT32 value;
+ memcpy(&value, ptr, sizeof(value));
+ return LITTLE_ENDIANIZE_INT32(value);
+}
+
+static int mycaslen;
+
+static int csw_cas_to_wav_size( const UINT8 *casdata, int caslen ) {
+UINT32 SampleRate;
+UINT32 NumberOfPulses;
+UINT8 MajorRevision;
+UINT8 MinorRevision;
+UINT8 CompressionType;
+UINT8 Flags;
+UINT8 HeaderExtensionLength;
+UINT8 *gz_ptr = NULL;
+
+int total_size;
+z_stream d_stream;
+int err;
+UINT8 *in_ptr;
+int bsize=0;
+
+ if ( memcmp( casdata, CSW_HEADER, sizeof(CSW_HEADER) ) ) {
+ LOG_FORMATS( "csw_cas_to_wav_size: cassette image has incompatible header\n" );
+ goto cleanup;
+ }
+
+ if (casdata[0x16]!=0x1a) {
+ LOG_FORMATS( "csw_cas_to_wav_size: Terminator Code Not Found\n" );
+ goto cleanup;
+ }
+
+ MajorRevision=casdata[0x17];
+ MinorRevision=casdata[0x18];
+
+ LOG_FORMATS("Version %d : %d\n",MajorRevision,MinorRevision);
+
+ if (casdata[0x17]!=2){
+ LOG_FORMATS( "csw_cas_to_wav_size: Unsuported Major Version\n" );
+ goto cleanup;
+ }
+
+ SampleRate=get_leuint32(casdata+0x19);
+ LOG_FORMATS("Sample rate %d\n",SampleRate);
+
+ NumberOfPulses=get_leuint32(casdata+0x1d);
+ LOG_FORMATS("Number Of Pulses %d\n",NumberOfPulses);
+
+
+ CompressionType=casdata[0x21];
+ Flags=casdata[0x22];
+ HeaderExtensionLength=casdata[0x23];
+
+ LOG_FORMATS("CompressionType %d Flast %d HeaderExtensionLength %d\n",CompressionType,Flags,HeaderExtensionLength);
+
+ mycaslen=caslen;
+ //from here on down for now I am assuming it is compressed csw file.
+ in_ptr = (UINT8*) casdata+0x34+HeaderExtensionLength;
+
+ gz_ptr = (UINT8*)malloc( 8 );
+
+
+ d_stream.next_in = (unsigned char *)in_ptr;
+ d_stream.avail_in = caslen - ( in_ptr - casdata );
+ d_stream.total_in=0;
+
+ d_stream.next_out = gz_ptr;
+ d_stream.avail_out = 1;
+ d_stream.total_out=0;
+
+ d_stream.zalloc = 0;
+ d_stream.zfree = 0;
+ d_stream.opaque = 0;
+ d_stream.data_type=0;
+
+ err = inflateInit( &d_stream );
+ if ( err != Z_OK ) {
+ LOG_FORMATS( "inflateInit2 error: %d\n", err );
+ goto cleanup;
+ }
+
+
+ total_size=1;
+ do
+ {
+ d_stream.next_out = gz_ptr;
+ d_stream.avail_out=1;
+ err=inflate( &d_stream, Z_SYNC_FLUSH );
+ if (err==Z_OK) {
+ bsize=gz_ptr[0];
+ if (bsize==0) {
+ d_stream.avail_out=4;
+ d_stream.next_out = gz_ptr;
+ err=inflate( &d_stream, Z_SYNC_FLUSH );
+ bsize=get_leuint32(gz_ptr);
+ }
+ total_size=total_size+bsize;
+ }
+ }
+ while (err==Z_OK);
+
+ if ( err != Z_STREAM_END ) {
+ LOG_FORMATS( "inflate error: %d\n", err );
+ goto cleanup;
+ }
+
+ err = inflateEnd( &d_stream );
+ if ( err != Z_OK ) {
+ LOG_FORMATS( "inflateEnd error: %d\n", err );
+ goto cleanup;
+ }
+
+
+
+
+
+
+ if ( gz_ptr ) {
+ free( gz_ptr );
+ gz_ptr = NULL;
+ }
+
+
+
+ return total_size;
+
+cleanup:
+ if ( gz_ptr ) {
+ free( gz_ptr );
+ gz_ptr = NULL;
+ }
+ return -1;
+
+}
+
+static int csw_cas_fill_wave( INT16 *buffer, int length, UINT8 *bytes ) {
+UINT32 SampleRate;
+UINT32 NumberOfPulses;
+UINT8 CompressionType;
+UINT8 Flags;
+UINT8 HeaderExtensionLength;
+INT8 Bit;
+
+UINT8 *gz_ptr = NULL;
+int total_size;
+z_stream d_stream;
+int err;
+UINT8 *in_ptr;
+int bsize=0;
+int i;
+
+
+ LOG_FORMATS("Length %d\n",length);
+
+ SampleRate=get_leuint32(bytes+0x19);
+ LOG_FORMATS("Sample rate %d\n",SampleRate);
+
+ NumberOfPulses=get_leuint32(bytes+0x1d);
+ LOG_FORMATS("Number Of Pulses %d\n",NumberOfPulses);
+
+ CompressionType=bytes[0x21];
+ Flags=bytes[0x22];
+ HeaderExtensionLength=bytes[0x23];
+
+ if ((Flags&0)==0)
+ {
+ Bit=-100;
+ } else {
+ Bit=100;
+ }
+
+ LOG_FORMATS("CompressionType %d Flast %d HeaderExtensionLength %d\n",CompressionType,Flags,HeaderExtensionLength);
+
+
+ //from here on down for now I am assuming it is compressed csw file.
+ in_ptr = (UINT8*) bytes+0x34+HeaderExtensionLength;
+
+ gz_ptr = (UINT8*)malloc( 8 );
+
+
+ d_stream.next_in = (unsigned char *)in_ptr;
+ d_stream.avail_in = mycaslen - ( in_ptr - bytes );
+ d_stream.total_in=0;
+
+ d_stream.next_out = gz_ptr;
+ d_stream.avail_out = 1;
+ d_stream.total_out=0;
+
+ d_stream.zalloc = 0;
+ d_stream.zfree = 0;
+ d_stream.opaque = 0;
+ d_stream.data_type=0;
+
+ err = inflateInit( &d_stream );
+ if ( err != Z_OK ) {
+ LOG_FORMATS( "inflateInit2 error: %d\n", err );
+ goto cleanup;
+ }
+
+ total_size=0;
+
+ do
+ {
+ d_stream.next_out = gz_ptr;
+ d_stream.avail_out=1;
+ err=inflate( &d_stream, Z_SYNC_FLUSH );
+ if (err==Z_OK) {
+ bsize=gz_ptr[0];
+ if (bsize==0) {
+ d_stream.avail_out=4;
+ d_stream.next_out = gz_ptr;
+ err=inflate( &d_stream, Z_SYNC_FLUSH );
+ bsize=get_leuint32(gz_ptr);
+ }
+ for (i=0;i<bsize;i++)
+ {
+ buffer[total_size++]=Bit;
+ }
+ Bit=-Bit;
+ }
+ }
+ while (err==Z_OK);
+
+ if ( err != Z_STREAM_END ) {
+ LOG_FORMATS( "inflate error: %d\n", err );
+ goto cleanup;
+ }
+
+ err = inflateEnd( &d_stream );
+ if ( err != Z_OK ) {
+ LOG_FORMATS( "inflateEnd error: %d\n", err );
+ goto cleanup;
+ }
+
+
+
+
+
+
+ if ( gz_ptr ) {
+ free( gz_ptr );
+ gz_ptr = NULL;
+ }
+
+
+
+
+ return length;
+
+
+
+ cleanup:
+ if ( gz_ptr ) {
+ free( gz_ptr );
+ gz_ptr = NULL;
+ }
+ return -1;
+}
+
+
+static const struct CassetteLegacyWaveFiller csw_legacy_fill_wave = {
+ csw_cas_fill_wave, /* fill_wave */
+ -1, /* chunk_size */
+ 0, /* chunk_samples */
+ csw_cas_to_wav_size, /* chunk_sample_calc */
+ CSW_WAV_FREQUENCY, /* sample_frequency */
+ 0, /* header_samples */
+ 0 /* trailer_samples */
+};
+
+static casserr_t csw_cassette_identify( cassette_image *cassette, struct CassetteOptions *opts ) {
+ return cassette_legacy_identify( cassette, opts, &csw_legacy_fill_wave );
+}
+
+static casserr_t csw_cassette_load( cassette_image *cassette ) {
+ return cassette_legacy_construct( cassette, &csw_legacy_fill_wave );
+}
+
+static const struct CassetteFormat csw_cassette_format = {
+ "csw",
+ csw_cassette_identify,
+ csw_cassette_load,
+ NULL
+};
+
+CASSETTE_FORMATLIST_START(csw_cassette_formats)
+ CASSETTE_FORMAT(csw_cassette_format)
+CASSETTE_FORMATLIST_END
+
+CASSETTE_FORMATLIST_START(bbc_cassette_formats)
+ CASSETTE_FORMAT(csw_cassette_format)
+ CASSETTE_FORMAT(uef_cassette_format)
+CASSETTE_FORMATLIST_END