summaryrefslogblamecommitdiffstatshomepage
path: root/src/lib/formats/cgen_cas.c
blob: 242e833ceb2e5dfd49f2ec72f48b9fa0a9434b6d (plain) (tree)
















































                                                                                 
                                      































































                                                                                              






                                                                       


























                                                                                            
/********************************************************************

Support for EACA Colour Genie .cas cassette images

Current state: Not working. Only the sync signal and 0x66 byte get
               recognized.

********************************************************************/

#include "formats/cgen_cas.h"

#define TAPE_HEADER "Colour Genie - Virtual Tape File"

#define SMPLO   -32768
#define SMPHI   32767


static int cas_size;
static int level;


static int cgenie_output_byte(INT16 *buffer, int sample_count, UINT8 data)
{
	int i;
	int samples = 0;

	for ( i = 0; i < 8; i++ )
	{
		/* Output bit boundary */
		level ^= 1;
		if ( buffer )
			buffer[ sample_count + samples ] = level ? SMPHI : SMPLO;
		samples++;

		/* Output bit */
		if ( data & 0x80 )
			level ^= 1;
		if ( buffer )
			buffer[ sample_count + samples ] = level ? SMPHI : SMPLO;
		samples++;

		data <<= 1;
	}
	return samples;
}


static int cgenie_handle_cas(INT16 *buffer, const UINT8 *casdata)
{
	int i, data_pos, sample_count;

	data_pos = 0;
	sample_count = 0;
	level = 0;

	/* Check for presence of optional header */
	if ( ! memcmp( casdata, TAPE_HEADER, sizeof(TAPE_HEADER) - 1 ) )
	{
		/* Search for 0x00 or end of file */
		while ( data_pos < cas_size && casdata[data_pos] )
			data_pos++;

		/* If we're at the end of the file it's not a valid .cas file */
		if ( data_pos == cas_size )
			return -1;

		/* Skip the 0x00 byte */
		data_pos++;
	}

	/* If we're at the end of the file it's not a valid .cas file */
	if ( data_pos == cas_size )
		return -1;

	/* Check for beginning of tape file marker */
	if ( casdata[data_pos] != 0x66 )
		return -1;

	/* Create header */
	for ( i = 0; i < 256; i++ )
		sample_count += cgenie_output_byte( buffer, sample_count, 0xaa );

	/* Start outputting data */
	while( data_pos < cas_size )
	{
		sample_count += cgenie_output_byte( buffer, sample_count, casdata[data_pos] );
		data_pos++;
	}
	sample_count += cgenie_output_byte( buffer, sample_count, 0x00 );

	return sample_count;
}

/*******************************************************************
   Generate samples for the tape image
********************************************************************/
static int cgenie_cas_fill_wave(INT16 *buffer, int sample_count, UINT8 *bytes)
{
	return cgenie_handle_cas( buffer, bytes );
}


/*******************************************************************
   Calculate the number of samples needed for this tape image
********************************************************************/
static int cgenie_cas_to_wav_size(const UINT8 *casdata, int caslen)
{
	cas_size = caslen;

	return cgenie_handle_cas( NULL, casdata );
}

static const struct CassetteLegacyWaveFiller cgenie_cas_legacy_fill_wave =
{
	cgenie_cas_fill_wave,                   /* fill_wave */
	-1,                                     /* chunk_size */
	0,                                      /* chunk_samples */
	cgenie_cas_to_wav_size,                 /* chunk_sample_calc */
	2400,                                   /* sample_frequency */
	0,                                      /* header_samples */
	0                                       /* trailer_samples */
};


static casserr_t cgenie_cas_identify(cassette_image *cassette, struct CassetteOptions *opts)
{
	return cassette_legacy_identify(cassette, opts, &cgenie_cas_legacy_fill_wave);
}


static casserr_t cgenie_cas_load(cassette_image *cassette)
{
	return cassette_legacy_construct(cassette, &cgenie_cas_legacy_fill_wave);
}


static const struct CassetteFormat cgenie_cas_format =
{
	"cas",
	cgenie_cas_identify,
	cgenie_cas_load,
	NULL
};


CASSETTE_FORMATLIST_START(cgenie_cassette_formats)
	CASSETTE_FORMAT(cgenie_cas_format)
CASSETTE_FORMATLIST_END