mame/src/lib/formats/a26_cas.c

167 lines
3.8 KiB
C

/*
Atari 2600 SuperCharger support
*/
#include "formats/a26_cas.h"
#define A26_CAS_SIZE 8448
#define A26_WAV_FREQUENCY 44100
#define BIT_ZERO_LENGTH 10
#define BIT_ONE_LENGTH 15
#define ZEROS_ONES 2755
static const UINT16 one_wave[BIT_ONE_LENGTH] = {
0x2AE5, 0x4E60, 0x644E, 0x68E4, 0x5B56, 0x3DFE, 0x15ED, 0xEA13, 0xC202, 0xA4AA,
0x971C, 0x9BB2, 0xB1A0, 0xD51B, 0x0000
};
static const UINT16 zero_wave[BIT_ZERO_LENGTH] = {
0x3DFE, 0x644E, 0x644E, 0x3DFE, 0x0000, 0xC202, 0x9BB2, 0x9BB2, 0xC202, 0x0000
};
static int a26_cas_output_wave( INT16 **buffer, INT16 wave_data, int length ) {
int i;
if ( buffer ) {
for ( i = 0 ; i < length; i++ ) {
**buffer = wave_data;
*buffer = *buffer + 1;
}
}
return length;
}
static int a26_cas_output_bit( INT16 **buffer, int bit ) {
int size = 0;
int bit_size = bit ? BIT_ONE_LENGTH : BIT_ZERO_LENGTH;
const INT16 *p = bit ? (const INT16 *)one_wave : (const INT16 *)zero_wave;
int i;
for ( i = 0; i < bit_size; i++ ) {
size += a26_cas_output_wave( buffer, p[i], 1 );
}
return size;
}
static int a26_cas_output_byte( INT16 **buffer, UINT8 byte ) {
int size = 0;
int i;
for( i = 0; i < 8; i++, byte <<= 1 ) {
size += a26_cas_output_bit( buffer, ( ( byte & 0x80 ) ? 1 : 0 ) );
}
return size;
}
static int a26_cas_clearing_tone( INT16 **buffer ) {
int size = 0;
size += a26_cas_output_wave( buffer, 0, 44100 );
return size;
}
static int a26_cas_zeros_ones( INT16 **buffer ) {
int size = 0;
int i;
for ( i = 0; i < ZEROS_ONES; i++ ) {
size += a26_cas_output_bit( buffer, 0 );
size += a26_cas_output_bit( buffer, 1 );
}
size += a26_cas_output_bit( buffer, 0 );
size += a26_cas_output_bit( buffer, 0 );
return size;
}
static int a26_cas_output_contents( INT16 **buffer, const UINT8 *bytes ) {
int size = 0;
int i, pages, j;
/* There are 8 header bytes */
for( i = 0; i < 8; i++ ) {
size += a26_cas_output_byte( buffer, bytes[ 0x2000 + i ] );
}
pages = bytes[0x2003];
/* Output each page prefixed with a small page header */
for ( i = 0; i < pages; i++ ) {
size += a26_cas_output_byte( buffer, bytes[ 0x2010 + i ] );
size += a26_cas_output_byte( buffer, bytes[ 0x2040 + i ] );
for ( j = 0; j < 256; j++ ) {
size += a26_cas_output_byte( buffer, bytes[ i * 256 + j ] );
}
}
return size;
}
static int a26_cas_do_work( INT16 **buffer, const UINT8 *bytes ) {
int size = 0;
/* Output clearing tone */
size += a26_cas_clearing_tone( buffer );
/* Output header tone, alternating 1s and 0s for about a second ending with two 0s */
size += a26_cas_zeros_ones( buffer );
/* Output the actual contents of the tape */
size += a26_cas_output_contents( buffer, bytes );
/* Output footer tone, alternating 1s and 0s for about a second ending with two 0s */
size += a26_cas_zeros_ones( buffer );
return size;
}
static int a26_cas_fill_wave( INT16 *buffer, int length, UINT8 *bytes ) {
INT16 *p = buffer;
return a26_cas_do_work( &p, (const UINT8 *)bytes );
}
static int a26_cas_to_wav_size( const UINT8 *casdata, int caslen ) {
return a26_cas_do_work( NULL, casdata );
}
static const struct CassetteLegacyWaveFiller a26_legacy_fill_wave = {
a26_cas_fill_wave,
-1,
0,
a26_cas_to_wav_size,
A26_WAV_FREQUENCY,
0,
0
};
static casserr_t a26_cassette_identify( cassette_image *cassette, struct CassetteOptions *opts ) {
UINT64 size;
size = cassette_image_size( cassette );
if ( size == A26_CAS_SIZE ) {
return cassette_legacy_identify( cassette, opts, &a26_legacy_fill_wave );
}
return CASSETTE_ERROR_INVALIDIMAGE;
}
static casserr_t a26_cassette_load( cassette_image *cassette ) {
return cassette_legacy_construct( cassette, &a26_legacy_fill_wave );
}
static const struct CassetteFormat a26_cassette_format = {
"a26",
a26_cassette_identify,
a26_cassette_load,
NULL
};
CASSETTE_FORMATLIST_START(a26_cassette_formats)
CASSETTE_FORMAT(a26_cassette_format)
CASSETTE_FORMATLIST_END