summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
author Nigel Barnes <Pernod70@users.noreply.github.com>2020-10-08 17:58:32 +0100
committer Nigel Barnes <Pernod70@users.noreply.github.com>2020-10-08 18:01:04 +0100
commit1a17e59008c77850060279cbb38680753bc7fcb8 (patch)
tree95d1b335a2ebb13f71231e0d5ae64c1d1edf93f8
parentb66477a24ff1e807592b12924877d54253eb5471 (diff)
csw_cas: Added support for v1.xx format, non-compressed RLE, and removed LegacyWaveFiller.
-rw-r--r--src/lib/formats/csw_cas.cpp411
1 files changed, 167 insertions, 244 deletions
diff --git a/src/lib/formats/csw_cas.cpp b/src/lib/formats/csw_cas.cpp
index 916817fee97..3db3eb70c34 100644
--- a/src/lib/formats/csw_cas.cpp
+++ b/src/lib/formats/csw_cas.cpp
@@ -1,25 +1,23 @@
// license:BSD-3-Clause
-// copyright-holders:Gordon Jefferyes
+// copyright-holders:Nigel Barnes
/*
-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
-
-
-
+ 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 Encoding application description
+ 0x34 BYTE Header extension data (if present HDR>0)
+ 0x34+HDR CSW data
*/
#include "csw_cas.h"
@@ -31,263 +29,188 @@ Offset Value Type Description
#include <cstring>
-#define CSW_WAV_FREQUENCY 44100
-
static const uint8_t CSW_HEADER[] = { "Compressed Square Wave" };
-static uint32_t get_leuint32(const void *ptr)
-{
- uint32_t value;
- memcpy(&value, ptr, sizeof(value));
- return little_endianize_int32(value);
-}
-static int mycaslen;
+/*-------------------------------------------------
+ csw_cassette_identify - identify cassette
+-------------------------------------------------*/
-static int csw_cas_to_wav_size( const uint8_t *casdata, int caslen )
+static cassette_image::error csw_cassette_identify(cassette_image *cassette, cassette_image::Options *opts)
{
- uint8_t MajorRevision;
- uint8_t MinorRevision;
- uint8_t HeaderExtensionLength;
- std::vector<uint8_t> gz_ptr;
-
- int total_size;
- z_stream d_stream;
- int err;
- uint8_t *in_ptr;
- int bsize=0;
-
- if ( memcmp( casdata, CSW_HEADER, sizeof(CSW_HEADER)-1 ) )
- {
- 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);
+ uint8_t header[0x34];
- if (casdata[0x17]!=2)
- {
- LOG_FORMATS( "csw_cas_to_wav_size: Unsuported Major Version\n" );
- goto cleanup;
+ cassette->image_read(header, 0, sizeof(header));
+ if (memcmp(&header[0], CSW_HEADER, sizeof(CSW_HEADER) - 1)) {
+ return cassette_image::error::INVALID_IMAGE;
}
- HeaderExtensionLength=casdata[0x23];
-
- mycaslen=caslen;
- //from here on down for now I am assuming it is compressed csw file.
- in_ptr = (uint8_t*) casdata+0x34+HeaderExtensionLength;
-
- gz_ptr.resize( 8 );
+ opts->bits_per_sample = 8;
+ opts->channels = 1;
+ opts->sample_frequency = little_endianize_int16(*(uint32_t*)(header + 0x19));
+ return cassette_image::error::SUCCESS;
+}
- 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[0];
- d_stream.avail_out = 1;
- d_stream.total_out=0;
+/*-------------------------------------------------
+ csw_cassette_load - load cassette
+-------------------------------------------------*/
- d_stream.zalloc = nullptr;
- d_stream.zfree = nullptr;
- d_stream.opaque = nullptr;
- d_stream.data_type=0;
+static cassette_image::error csw_cassette_load(cassette_image *cassette)
+{
+ uint8_t header[0x34];
+ uint64_t image_size = cassette->image_size();
+ std::vector<uint8_t> image_data(image_size);
+
+ int8_t bit;
+ uint8_t compression;
+ int bsize = 0;
+ size_t csw_data = 0;
+ size_t sample_count = 0;
+ uint32_t sample_rate;
+ std::vector<int8_t> samples;
+
+ /* csw header */
+ cassette->image_read(header, 0, sizeof(header));
- err = inflateInit( &d_stream );
- if ( err != Z_OK )
+ if (header[0x16] != 0x1a)
{
- LOG_FORMATS( "inflateInit2 error: %d\n", err );
- goto cleanup;
+ LOG_FORMATS("csw_cassette_load: Terminator Code Not Found\n");
+ return cassette_image::error::INVALID_IMAGE;
}
-
- total_size=1;
- do
+ LOG_FORMATS("CSW Version %d.%d\n", header[0x17], header[0x18]);
+ switch (header[0x17])
{
- d_stream.next_out = &gz_ptr[0];
- d_stream.avail_out=1;
- err=inflate( &d_stream, Z_SYNC_FLUSH );
- if (err==Z_OK)
+ case 1:
+ sample_rate = little_endianize_int16(*(uint32_t*)(header + 0x19));
+ compression = header[0x1b];
+ bit = (header[0x1c] & 1) ? 127 : -128;
+ csw_data = 0x20;
+
+ LOG_FORMATS("Sample Rate: %u\n", sample_rate);
+ LOG_FORMATS("CompressionType: %u Flags: %u\n", header[0x1b], header[0x1c]);
+ break;
+
+ case 2:
+ sample_rate = little_endianize_int32(*(uint32_t*)(header + 0x19));
+ compression = header[0x21];
+ bit = (header[0x22] & 1) ? 127 : -128;
+ csw_data = (size_t) header[0x23] + 0x34;
+
+ LOG_FORMATS("Sample Rate: %u\n", sample_rate);
+ LOG_FORMATS("Number of Pulses: %u\n", little_endianize_int32(*(uint32_t *)(header + 0x1d)));
+ LOG_FORMATS("CompressionType: %u Flags: %u\n", header[0x21], header[0x22]);
+ LOG_FORMATS("Encoder: ");
+ for (int i = 0; i < 16; i++)
+ LOG_FORMATS("%c", header[0x24 + i]);
+ LOG_FORMATS("\n");
+ break;
+
+ default:
+ LOG_FORMATS("Unsupported Major Version\n");
+ return cassette_image::error::INVALID_IMAGE;
+ }
+
+ /* csw data */
+ switch (compression)
+ {
+ case 0x01:
+ /* RLE (Run Length Encoding) */
+ for (size_t pos = csw_data; pos < image_size; pos++)
{
- bsize=gz_ptr[0];
- if (bsize==0)
+ bsize = image_data[pos];
+ if (bsize == 0)
+ {
+ bsize = little_endianize_int32(*(uint32_t *)(&image_data[pos + 1]));
+ pos += 4;
+ }
+ for (int i = 0; i < bsize; i++)
{
- d_stream.avail_out=4;
- d_stream.next_out = &gz_ptr[0];
- err=inflate( &d_stream, Z_SYNC_FLUSH );
- bsize=get_leuint32(&gz_ptr[0]);
+ samples.resize(sample_count + 1);
+ samples[sample_count++] = bit;
}
- total_size=total_size+bsize;
+ bit ^= 0xff;
}
- }
- 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;
- }
-
- return total_size;
-
-cleanup:
- return -1;
-}
-
-static int csw_cas_fill_wave( int16_t *buffer, int length, uint8_t *bytes )
-{
- uint32_t SampleRate;
- uint32_t NumberOfPulses;
- uint8_t CompressionType;
- uint8_t Flags;
- uint8_t HeaderExtensionLength;
- int8_t Bit;
-
- std::vector<uint8_t> gz_ptr;
- int total_size;
- z_stream d_stream;
- int err;
- uint8_t *in_ptr;
- int bsize=0;
- int i;
-
- LOG_FORMATS("Length %d\n",length);
-
- SampleRate=get_leuint32(bytes+0x19);
- LOG_FORMATS("Sample rate %u\n",SampleRate);
-
- NumberOfPulses=get_leuint32(bytes+0x1d);
- LOG_FORMATS("Number Of Pulses %u\n",NumberOfPulses);
-
- CompressionType=bytes[0x21];
- Flags=bytes[0x22];
- HeaderExtensionLength=bytes[0x23];
-
- Bit = (Flags & 1) ? 100 : -100;
-
- LOG_FORMATS("CompressionType %u Flags %u HeaderExtensionLength %u\n",CompressionType,Flags,HeaderExtensionLength);
-
- LOG_FORMATS("Encoder: ");
- for (i = 0; i < 16; i++)
- LOG_FORMATS("%c", bytes[0x24 + i]);
- LOG_FORMATS("\n");
-
- LOG_FORMATS("Header: ");
- for (i = 0; i < HeaderExtensionLength; i++)
- LOG_FORMATS("%c", bytes[0x34 + i]);
- LOG_FORMATS("\n");
-
- //from here on down for now I am assuming it is compressed csw file.
- in_ptr = (uint8_t*) bytes+0x34+HeaderExtensionLength;
-
- gz_ptr.resize( 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[0];
- d_stream.avail_out = 1;
- d_stream.total_out=0;
-
- d_stream.zalloc = nullptr;
- d_stream.zfree = nullptr;
- d_stream.opaque = nullptr;
- d_stream.data_type=0;
+ break;
+
+ case 0x02:
+ /* Z-RLE (CSW v2.xx only) */
+ cassette->image_read(&image_data[0], 0, image_size);
+
+ std::vector<uint8_t> gz_ptr;
+ z_stream d_stream;
+ int err;
+
+ gz_ptr.resize(8);
+
+ d_stream.next_in = (unsigned char *) &image_data[csw_data];
+ d_stream.avail_in = image_size - 0x34 - header[0x23];
+ d_stream.total_in = 0;
+
+ d_stream.next_out = &gz_ptr[0];
+ d_stream.avail_out = 1;
+ d_stream.total_out = 0;
- err = inflateInit( &d_stream );
- if ( err != Z_OK )
- {
- LOG_FORMATS( "inflateInit2 error: %d\n", err );
- goto cleanup;
- }
+ d_stream.zalloc = nullptr;
+ d_stream.zfree = nullptr;
+ d_stream.opaque = nullptr;
+ d_stream.data_type = 0;
- total_size=0;
+ err = inflateInit(&d_stream);
+ if (err != Z_OK)
+ {
+ LOG_FORMATS("inflateInit error: %d\n", err);
+ return cassette_image::error::INVALID_IMAGE;
+ }
- do
- {
- d_stream.next_out = &gz_ptr[0];
- d_stream.avail_out=1;
- err=inflate( &d_stream, Z_SYNC_FLUSH );
- if (err==Z_OK)
+ do
{
- bsize=gz_ptr[0];
- if (bsize==0)
- {
- d_stream.avail_out=4;
- d_stream.next_out = &gz_ptr[0];
- err=inflate( &d_stream, Z_SYNC_FLUSH );
- bsize=get_leuint32(&gz_ptr[0]);
- }
- for (i=0;i<bsize;i++)
+ d_stream.next_out = &gz_ptr[0];
+ d_stream.avail_out = 1;
+ err = inflate(&d_stream, Z_SYNC_FLUSH);
+ if (err == Z_OK)
{
- buffer[total_size++]=Bit;
+ bsize = gz_ptr[0];
+ if (bsize == 0)
+ {
+ d_stream.avail_out = 4;
+ d_stream.next_out = &gz_ptr[0];
+ err = inflate(&d_stream, Z_SYNC_FLUSH);
+ bsize = little_endianize_int32(*(uint32_t *)(&gz_ptr[0]));
+ }
+ for (int i = 0; i < bsize; i++)
+ {
+ samples.resize(sample_count + 1);
+ samples[sample_count++] = bit;
+ }
+ bit ^= 0xff;
}
- Bit=-Bit;
- }
- }
- while (err==Z_OK);
+ }
+ while (err == Z_OK);
- if ( err != Z_STREAM_END )
- {
- LOG_FORMATS( "inflate error: %d\n", err );
- goto cleanup;
- }
+ if (err != Z_STREAM_END)
+ {
+ LOG_FORMATS("inflate error: %d\n", err);
+ return cassette_image::error::INVALID_IMAGE;
+ }
- err = inflateEnd( &d_stream );
- if ( err != Z_OK )
- {
- LOG_FORMATS( "inflateEnd error: %d\n", err );
- goto cleanup;
+ err = inflateEnd(&d_stream);
+ if (err != Z_OK)
+ {
+ LOG_FORMATS("inflateEnd error: %d\n", err);
+ return cassette_image::error::INVALID_IMAGE;
+ }
+ break;
}
- return length;
-
-cleanup:
- return -1;
+ return cassette->put_samples(0, 0.0, (double) sample_count / sample_rate, sample_count, 1, &samples[0], cassette_image::WAVEFORM_8BIT);
}
-static const cassette_image::LegacyWaveFiller 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 cassette_image::error csw_cassette_identify( cassette_image *cassette, cassette_image::Options *opts )
-{
- uint8_t header[22];
-
- cassette->image_read(header, 0, sizeof(header));
- if (memcmp(&header[0], CSW_HEADER, sizeof(CSW_HEADER) - 1)) {
- return cassette_image::error::INVALID_IMAGE;
- }
- return cassette->legacy_identify( opts, &csw_legacy_fill_wave );
-}
-
-static cassette_image::error csw_cassette_load( cassette_image *cassette )
-{
- return cassette->legacy_construct( &csw_legacy_fill_wave );
-}
+/*-------------------------------------------------
+ CassetteFormat csw_cassette_format
+-------------------------------------------------*/
const cassette_image::Format csw_cassette_format = {
"csw",