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

    cassimg.h

    Cassette tape image abstraction code

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

#ifndef CASSIMG_H
#define CASSIMG_H

#include "osdcore.h"
#include "pool.h"
#include "ioprocs.h"

#ifndef LOG_FORMATS
#define LOG_FORMATS if (0) printf
#endif

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

    Constants

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

#define CASSETTE_FLAG_READWRITE			0
#define CASSETTE_FLAG_READONLY			1
#define CASSETTE_FLAG_NOSAVEONEXIT		0
#define CASSETTE_FLAG_SAVEONEXIT		2

#define CASSETTE_WAVEFORM_8BIT			0
#define CASSETTE_WAVEFORM_16BIT			2
#define CASSETTE_WAVEFORM_16BIT_FLIP	3
#define CASSETTE_WAVEFORM_32BIT			4
#define CASSETTE_WAVEFORM_32BIT_FLIP	5
#define CASSETTE_WAVEFORM_ENDIAN_FLIP	1

#define CASSETTE_MODULATION_SQUAREWAVE	0
#define CASSETTE_MODULATION_SINEWAVE	1


#ifdef LSB_FIRST
#define CASSETTE_WAVEFORM_16BITBE		CASSETTE_WAVEFORM_16BIT_FLIP
#define CASSETTE_WAVEFORM_16BITLE		CASSETTE_WAVEFORM_16BIT
#define CASSETTE_WAVEFORM_32BITBE		CASSETTE_WAVEFORM_32BIT_FLIP
#define CASSETTE_WAVEFORM_32BITLE		CASSETTE_WAVEFORM_32BIT
#else
#define CASSETTE_WAVEFORM_16BITBE		CASSETTE_WAVEFORM_16BIT
#define CASSETTE_WAVEFORM_16BITLE		CASSETTE_WAVEFORM_16BIT_FLIP
#define CASSETTE_WAVEFORM_32BITBE		CASSETTE_WAVEFORM_32BIT
#define CASSETTE_WAVEFORM_32BITLE		CASSETTE_WAVEFORM_32BIT_FLIP
#endif


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

    Type definitions

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

typedef enum
{
	CASSETTE_ERROR_SUCCESS,			/* no error */
	CASSETTE_ERROR_INTERNAL,		/* fatal internal error */
	CASSETTE_ERROR_UNSUPPORTED,		/* this operation is unsupported */
	CASSETTE_ERROR_OUTOFMEMORY,		/* ran out of memory */
	CASSETTE_ERROR_INVALIDIMAGE,	/* invalid image */
	CASSETTE_ERROR_INVALIDARG
}
casserr_t;

struct sample_block
{
	INT32 *block;
	size_t sample_count;
};

struct CassetteOptions
{
	int channels;
	int bits_per_sample;
	UINT32 sample_frequency;
};

struct CassetteInfo
{
	int channels;
	int bits_per_sample;
	UINT32 sample_frequency;
	size_t sample_count;
};

struct _cassette_image
{
	const struct CassetteFormat *format;
	struct io_generic io;
	object_pool *pool;

	int channels;
	int flags;
	UINT32 sample_frequency;

	struct sample_block *blocks;
	size_t block_count;
	size_t sample_count;
};

typedef struct _cassette_image cassette_image;

struct CassetteFormat
{
	const char *extensions;
	casserr_t (*identify)(cassette_image *cassette, struct CassetteOptions *opts);
	casserr_t (*load)(cassette_image *cassette);
	casserr_t (*save)(cassette_image *cassette, const struct CassetteInfo *info);
};

/* used for the core modulation code */
struct CassetteModulation
{
	int flags;
	double zero_frequency_low;
	double zero_frequency_cannonical;
	double zero_frequency_high;
	double one_frequency_low;
	double one_frequency_cannonical;
	double one_frequency_high;
};

/* code to adapt existing legacy fill_wave functions */
struct CassetteLegacyWaveFiller
{
	int (*fill_wave)(INT16 *, int, UINT8 *);
	int chunk_size;
	int chunk_samples;
	int (*chunk_sample_calc)(const UINT8 *bytes, int length);
	UINT32 sample_frequency;
	int header_samples;
	int trailer_samples;
};

/* builtin formats */
extern const struct CassetteFormat wavfile_format;

/* macros for specifying format lists */
#define CASSETTE_FORMATLIST_EXTERN(name)	\
	extern const struct CassetteFormat *const name[]

#define CASSETTE_FORMATLIST_START(name)		\
	const struct CassetteFormat *const name[] =	\
	{										\
		&wavfile_format,					\

#define CASSETTE_FORMAT(name)				\
		&(name),							\

#define CASSETTE_FORMATLIST_END				\
		NULL								\
	};

CASSETTE_FORMATLIST_EXTERN(cassette_default_formats);

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

    Prototypes

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

casserr_t cassette_open(void *file, const struct io_procs *procs,
	const struct CassetteFormat *format, int flags, cassette_image **outcassette);
casserr_t cassette_open_choices(void *file, const struct io_procs *procs, const char *extension,
	const struct CassetteFormat *const *formats, int flags, cassette_image **outcassette);
casserr_t cassette_create(void *file, const struct io_procs *procs, const struct CassetteFormat *format,
	const struct CassetteOptions *opts, int flags, cassette_image **outcassette);
casserr_t cassette_save(cassette_image *cassette);
void cassette_close(cassette_image *cassette);
void cassette_change(cassette_image *cassette, void *file, const struct io_procs *procs, const struct CassetteFormat *format, int flags);
void cassette_get_info(cassette_image *cassette, struct CassetteInfo *info);

/* calls for accessing the raw cassette image */
void cassette_image_read(cassette_image *cassette, void *buffer, UINT64 offset, size_t length);
void cassette_image_write(cassette_image *cassette, const void *buffer, UINT64 offset, size_t length);
UINT64 cassette_image_size(cassette_image *cassette);

/* waveform accesses */
casserr_t cassette_get_samples(cassette_image *cassette, int channel,
	double time_index, double sample_period, size_t sample_count, size_t sample_bytes,
	void *samples, int waveform_flags);
casserr_t cassette_put_samples(cassette_image *cassette, int channel,
	double time_index, double sample_period, size_t sample_count, size_t sample_bytes,
	const void *samples, int waveform_flags);
casserr_t cassette_get_sample(cassette_image *cassette, int channel,
	double time_index, double sample_period, INT32 *sample);
casserr_t cassette_put_sample(cassette_image *cassette, int channel,
	double time_index, double sample_period, INT32 sample);

/* waveform accesses to/from the raw image */
casserr_t cassette_read_samples(cassette_image *cassette, int channels, double time_index,
	double sample_period, size_t sample_count, UINT64 offset, int waveform_flags);
casserr_t cassette_write_samples(cassette_image *cassette, int channels, double time_index,
	double sample_period, size_t sample_count, UINT64 offset, int waveform_flags);

/* modulation support */
casserr_t cassette_modulation_identify(cassette_image *cassette, const struct CassetteModulation *modulation,
	struct CassetteOptions *opts);
casserr_t cassette_put_modulated_data(cassette_image *cassette, int channel, double time_index,
	const void *data, size_t data_length, const struct CassetteModulation *modulation,
	double *time_displacement);
casserr_t cassette_put_modulated_filler(cassette_image *cassette, int channel, double time_index,
	UINT8 filler, size_t filler_length, const struct CassetteModulation *modulation,
	double *time_displacement);
casserr_t cassette_read_modulated_data(cassette_image *cassette, int channel, double time_index,
	UINT64 offset, UINT64 length, const struct CassetteModulation *modulation,
	double *time_displacement);
casserr_t cassette_put_modulated_data_bit(cassette_image *cassette, int channel, double time_index,
	UINT8 data, const struct CassetteModulation *modulation,
	double *time_displacement);

/* debug calls */
void cassette_dump(cassette_image *image, const char *filename);

/* legacy code support */
#define CODE_HEADER 	((UINT8*)-1)
#define CODE_TRAILER	((UINT8*)-2)
casserr_t cassette_legacy_identify(cassette_image *cassette, struct CassetteOptions *opts,
	const struct CassetteLegacyWaveFiller *legacy_args);
casserr_t cassette_legacy_construct(cassette_image *cassette,
	const struct CassetteLegacyWaveFiller *legacy_args);

#endif /* CASSIMG_H */
