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

Taken from nocash ZX81 docs by Martin Korth.

ZX81 Cassette File Structure
  5 seconds    pilot
  1-127 bytes  name (bit7 set in last char)
  LEN bytes    data, loaded to address 4009h, LEN=(4014h)-4009h.
  1 pulse      video retrace signal (only if display was enabled)
The data field contains the system area, the basic program, the video memory,
and VARS area.

ZX80 Cassette File Structure
  5 seconds    pilot
  LEN bytes    data, loaded to address 4000h, LEN=(400Ah)-4000h.
ZX80 files do not have filenames, and video memory is not included in the file.

Bits and Bytes
Each byte consists of 8 bits (MSB first) without any start and stop bits,
directly followed by the next byte. A "0" bit consists of four high pulses,
a "1" bit of nine pulses, either one followed by a silence period.
  0:  /\/\/\/\________
  1:  /\/\/\/\/\/\/\/\/\________
Each pulse is split into a 150us High period, and 150us Low period. The
duration of the silence between each bit is 1300us. The baud rate is thus 400
bps (for a "0" filled area) downto 250 bps (for a "1" filled area). Average
medium transfer rate is approx. 307 bps (38 bytes/sec) for files that contain
50% of "0" and "1" bits each.

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

#include "zx81_p.h"
#include "osdepend.h"
#include "devices/cassette.h"

#define WAVEENTRY_LOW	-32768
#define WAVEENTRY_HIGH	 32767
#define WAVEENTRY_ZERO	     0

#define ZX81_WAV_FREQUENCY	44100

/* all following are in samples */
#define ZX81_PULSE_LENGTH	16
#define ZX81_PAUSE_LENGTH	56
#define ZX81_PILOT_LENGTH	220500

#define ZX81_LOW_BIT_LENGTH	(ZX81_PULSE_LENGTH*4+ZX81_PAUSE_LENGTH)
#define ZX81_HIGH_BIT_LENGTH	(ZX81_PULSE_LENGTH*9+ZX81_PAUSE_LENGTH)

#define ZX81_START_LOAD_ADDRESS	0x4009
#define ZX80_START_LOAD_ADDRESS	0x4000
#define ZX81_DATA_LENGTH_OFFSET	0x0b

static UINT8 zx_file_name[128];
static UINT16 real_data_length = 0;
static UINT8 zx_file_name_length = 0;

/* common functions */

static INT16 *zx81_emit_level(INT16 *p, int count, int level)
{
	int i;

	for (i=0; i<count; i++)	*(p++) = level;

	return p;
}

static INT16* zx81_emit_pulse(INT16 *p)
{
	p = zx81_emit_level (p, ZX81_PULSE_LENGTH/8, WAVEENTRY_LOW);
	p = zx81_emit_level (p, ZX81_PULSE_LENGTH/8, WAVEENTRY_LOW);
	p = zx81_emit_level (p, ZX81_PULSE_LENGTH/8, WAVEENTRY_ZERO);
	p = zx81_emit_level (p, ZX81_PULSE_LENGTH/8, WAVEENTRY_HIGH);
	p = zx81_emit_level (p, ZX81_PULSE_LENGTH/8, WAVEENTRY_HIGH);
	p = zx81_emit_level (p, ZX81_PULSE_LENGTH/8, WAVEENTRY_ZERO);
	p = zx81_emit_level (p, ZX81_PULSE_LENGTH/8, WAVEENTRY_LOW);
	p = zx81_emit_level (p, ZX81_PULSE_LENGTH/8, WAVEENTRY_LOW);

	return p;
}

static INT16* zx81_emit_pause(INT16 *p)
{
	p = zx81_emit_level (p, ZX81_PAUSE_LENGTH, WAVEENTRY_ZERO);

	return p;
}

static INT16* zx81_output_bit(INT16 *p, UINT8 bit)
{
	int i;

	if (bit)
		for (i=0; i<9; i++)
			p = zx81_emit_pulse (p);
	else
		for (i=0; i<4; i++)
			p = zx81_emit_pulse (p);

	p = zx81_emit_pause(p);

    	return p;
}

static INT16* zx81_output_byte(INT16 *p, UINT8 byte)
{
	int i;

	for (i=0; i<8; i++)
		p = zx81_output_bit(p,(byte>>(7-i)) & 0x01);

	return p;
}

static UINT16 zx81_cassette_calculate_number_of_1(const UINT8 *bytes, UINT16 length)
{
	UINT16 number_of_1 = 0;
	int i,j;

	for (i=0; i<length; i++)
		for (j=0; j<8; j++)
			if ((bytes[i]>>j)&0x01)
				number_of_1++;

	return number_of_1;
}

/* ZX-81 functions */

static UINT8 zx81_chars[]={ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /*00h-07h*/
		     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /*08h-0fh*/
		     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /*10h-17h*/
		     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /*18h-1fh*/
		     0x00, 0x00, 0x0b, 0x00, 0x0d, 0x00, 0x00, 0x00, /*20h-27h*/
		     0x10, 0x11, 0x17, 0x15, 0x1a, 0x16, 0x1b, 0x18, /*28h-2fh*/
		     0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, /*30h-37h*/
		     0x24, 0x25, 0x0e, 0x19, 0x13, 0x14, 0x12, 0x0f, /*38h-3fh*/
		     0x00, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, /*40h-47h*/
		     0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, /*48h-4fh*/
		     0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, /*50h-57h*/
		     0x3d, 0x3e, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, /*58h-5fh*/
		     0x00, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, /*60h-67h*/
		     0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, /*68h-6fh*/
		     0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, /*70h-77h*/
		     0x3d, 0x3e, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, /*78h-7fh*/};

static void zx81_fill_file_name(const char* name)
{
	for (zx_file_name_length=0; (zx_file_name_length<128) && name[zx_file_name_length]; zx_file_name_length++)
		zx_file_name[zx_file_name_length] = ((UINT8) name[zx_file_name_length]<0x80) ? zx81_chars[(UINT8) name[zx_file_name_length]] : 0x00;
	zx_file_name[zx_file_name_length-1] |= 0x80;
}

static int zx81_cassette_calculate_size_in_samples(const UINT8 *bytes, int length)
{
	unsigned int number_of_0_data = 0;
	unsigned int number_of_1_data = 0;
	unsigned int number_of_0_name = 0;
	unsigned int number_of_1_name = 0;

	real_data_length = bytes[ZX81_DATA_LENGTH_OFFSET] + bytes[ZX81_DATA_LENGTH_OFFSET+1]*256 - ZX81_START_LOAD_ADDRESS;

	number_of_1_data = zx81_cassette_calculate_number_of_1(bytes, real_data_length);
	number_of_0_data = length*8-number_of_1_data;

	number_of_1_name = zx81_cassette_calculate_number_of_1(zx_file_name, zx_file_name_length);
	number_of_0_name = zx_file_name_length*8-number_of_1_name;

	return (number_of_0_data+number_of_0_name)*ZX81_LOW_BIT_LENGTH + (number_of_1_data+number_of_0_name)*ZX81_HIGH_BIT_LENGTH + ZX81_PILOT_LENGTH;
}

static int zx81_cassette_fill_wave(INT16 *buffer, int length, UINT8 *bytes)
{
	INT16 * p = buffer;
	int i;

	/* pilot */
	p = zx81_emit_level (p, ZX81_PILOT_LENGTH, WAVEENTRY_ZERO);

	/* name */
	for (i=0; i<zx_file_name_length; i++)
		p = zx81_output_byte(p, zx_file_name[i]);

	/* data */
	for (i=0; i<real_data_length; i++)
		p = zx81_output_byte(p, bytes[i]);

	return p - buffer;
}

static const struct CassetteLegacyWaveFiller zx81_legacy_fill_wave =
{
	zx81_cassette_fill_wave,			/* fill_wave */
	-1,						/* chunk_size */
	0,						/* chunk_samples */
	zx81_cassette_calculate_size_in_samples,	/* chunk_sample_calc */
	ZX81_WAV_FREQUENCY,				/* sample_frequency */
	0,						/* header_samples */
	0						/* trailer_samples */
};

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

static casserr_t zx81_p_load(cassette_image *cassette)
{
	zx81_fill_file_name (image_basename_noext (image_from_devtype_and_index(IO_CASSETTE, 0)));
	return cassette_legacy_construct(cassette, &zx81_legacy_fill_wave);
}

static const struct CassetteFormat zx81_p_image_format =
{
	"p,81",
	zx81_p_identify,
	zx81_p_load,
	NULL
};

CASSETTE_FORMATLIST_START(zx81_p_format)
	CASSETTE_FORMAT(zx81_p_image_format)
CASSETTE_FORMATLIST_END

/* ZX-80 functions */

static int zx80_cassette_calculate_size_in_samples(const UINT8 *bytes, int length)
{
	unsigned int number_of_0_data = 0;
	unsigned int number_of_1_data = 0;

	real_data_length = bytes[ZX81_DATA_LENGTH_OFFSET] + bytes[ZX81_DATA_LENGTH_OFFSET+1]*256 - ZX81_START_LOAD_ADDRESS;

	number_of_1_data = zx81_cassette_calculate_number_of_1(bytes, real_data_length);
	number_of_0_data = length*8-number_of_1_data;

	return number_of_0_data*ZX81_LOW_BIT_LENGTH + number_of_1_data*ZX81_HIGH_BIT_LENGTH + ZX81_PILOT_LENGTH;
}

static int zx80_cassette_fill_wave(INT16 *buffer, int length, UINT8 *bytes)
{
	INT16 * p = buffer;
	int i;

	/* pilot */
	p = zx81_emit_level (p, ZX81_PILOT_LENGTH, WAVEENTRY_ZERO);

	/* data */
	for (i=0; i<real_data_length; i++)
		p = zx81_output_byte(p, bytes[i]);

	return p - buffer;
}

static const struct CassetteLegacyWaveFiller zx80_legacy_fill_wave =
{
	zx80_cassette_fill_wave,			/* fill_wave */
	-1,											/* chunk_size */
	0,											/* chunk_samples */
	zx80_cassette_calculate_size_in_samples,	/* chunk_sample_calc */
	ZX81_WAV_FREQUENCY,										/* sample_frequency */
	0,											/* header_samples */
	0											/* trailer_samples */
};

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

static casserr_t zx80_o_load(cassette_image *cassette)
{
	return cassette_legacy_construct(cassette, &zx80_legacy_fill_wave);
}

static const struct CassetteFormat zx80_o_image_format =
{
	"o,80",
	zx80_o_identify,
	zx80_o_load,
	NULL
};

CASSETTE_FORMATLIST_START(zx80_o_format)
	CASSETTE_FORMAT(zx80_o_image_format)
CASSETTE_FORMATLIST_END
