#include "driver.h"
#include "sound/logwave.h"

//#define VERBOSE(s)	printf s;
#define VERBOSE(s)

#ifdef LSB_FIRST
#define intel_long(x) (x)
#define intel_short(x) (x)
#else
#define intel_long(x) (((x << 24) | (((unsigned long) x) >> 24) | (( x & 0x0000ff00) << 8) | (( x & 0x00ff0000) >> 8)))
#define intel_short(x) (((x) << 8) | ((x) >> 8))
#endif

// Buffer size: 2 Sec.
#define BUFFERSIZE	(sample_rate * channels * 2)

static int file_no;
static mame_file *file;
static UINT32 total_offs;
static UINT32 data_offs;

static UINT16 channels;
static UINT32 sample_rate;
static UINT16 sample_bits;

static int is_recording;
static int recording_enabled;

static INT16 *buf;
static UINT32 length;
static UINT32 saved_len;
static UINT32 mute_count;

static void open_wave_file(void)
{
	char fname[256];
	UINT32 bps, temp32;
	UINT16 align, temp16;

	strcpy(fname, Machine->gamedrv->name);
	if (mame_faccess(fname, FILETYPE_WAVE))
	{
		do
		{
			sprintf(fname, "%s_%04d", Machine->gamedrv->name, file_no++);
		} while (mame_faccess(fname, FILETYPE_WAVE));
	}

	file = mame_fopen(NULL, fname, FILETYPE_WAVE, 1);
	if (file == NULL)
		return;

	/* write the 'RIFF' header */
	mame_fwrite_lsbfirst(file, "RIFF", 4);

	/* write the total size */
	total_offs = mame_ftell(file);
	temp32 = 0;
	mame_fwrite_lsbfirst(file, &temp32, 4);

	/* write the 'WAVE' type */
	mame_fwrite_lsbfirst(file, "WAVE", 4);

	/* write the 'fmt ' tag */
	mame_fwrite_lsbfirst(file, "fmt ", 4);

	/* write the format length */
	temp32 = 16;
	mame_fwrite_lsbfirst(file, &temp32, 4);

	/* write the format (PCM) */
	temp16 = 1;
	mame_fwrite_lsbfirst(file, &temp16, 2);

	/* write the channels */
	mame_fwrite_lsbfirst(file, &channels, 2);

	/* write the sample rate */
	mame_fwrite_lsbfirst(file, &sample_rate, 4);

	/* write the bytes/second */
	bps = sample_rate * ((sample_bits + 7) / 8) * channels;
	mame_fwrite_lsbfirst(file, &bps, 4);

	/* write the block align */
	align = ((sample_bits + 7) / 8) * channels;
	mame_fwrite_lsbfirst(file, &align, 2);

	/* write the bits/sample */
	mame_fwrite_lsbfirst(file, &sample_bits, 2);

	/* write the 'data' tag */
	mame_fwrite_lsbfirst(file, "data", 4);

	/* write the data length */
	data_offs = mame_ftell(file);
	temp32 = 0;
	mame_fwrite_lsbfirst(file, &temp32, 4);

	VERBOSE(("Wave open: %s\n", fname))

	is_recording = 1;
}

static void close_wave_file(void)
{
	UINT32 total = mame_ftell(file);
	UINT32 temp32;

	/* update the total file size */
	mame_fseek(file, total_offs, SEEK_SET);
	temp32 = total - (total_offs + 4);
	mame_fwrite_lsbfirst(file, &temp32, 4);

	/* update the data size */
	mame_fseek(file, data_offs, SEEK_SET);
	temp32 = total - (data_offs + 4);
	mame_fwrite_lsbfirst(file, &temp32, 4);

	mame_fclose(file);
	file = NULL;

	VERBOSE(("Wave close\n"))

	is_recording = 0;
	mute_count = length = saved_len = 0;
}

static void write_wave_data(void)
{
	INT32 len;

	len = length - (mute_count / channels) * channels;

	mame_fwrite(file, buf, (sample_bits / 8) * (len - saved_len));

	saved_len = len;
}

static int update_wave_rec(INT16 *data, int len)
{
	INT32 pos;

	if (!buf)
		return 0;

	len *= channels;

	if (!length) {
		if (channels == 1)
			while ((len > 0) && (*data == 0)) {
				data++;
				len--;
			}
		else
			while (len >= 2) {
				if ((data[0] != 0) || (data[1] != 0))
					break;
				data += 2;
				len -= 2;
			}
	}

	if (len && !is_recording)
		open_wave_file();

	pos = length - saved_len;
	if (pos + len > BUFFERSIZE) {
		int i;

		write_wave_data();
		pos = length - saved_len;

		for (i = 0; i < pos; i++)
			buf[i] = 0;
	}

	while (len-- > 0) {
		if ((buf[pos++] = intel_short(*data)) != 0)
			mute_count = 0;
		else
			mute_count++;

		data++;
		length++;
	}

	// Check 1 Sec.
	return mute_count > sample_rate * channels;
}


int logwave_start(int stereo)
{
	channels = stereo ? 2 : 1;
	sample_rate = Machine->sample_rate;
	sample_bits = 16;

	file_no = 0;

	recording_enabled = is_recording = 0;
	mute_count = length = saved_len = 0;

	buf  = (INT16 *)auto_malloc(sizeof (*buf) * BUFFERSIZE);

	return !buf;
}

void logwave_update(INT16 *data, unsigned samples)
{
	if (recording_enabled && update_wave_rec(data, samples))
		close_wave_file();
}

void logwave_stop(void)
{
	if (is_recording)
		close_wave_file();
}

void logwave_enable(int enable)
{
	if (is_recording)
		close_wave_file();

	recording_enabled = enable;
}

int logwave_is_recording(void)
{
	return is_recording;
}
