#include <clip.h>

#define RECORD 0 /* 0:スピーカ出力/1:ファイル出力 */

#if(RECORD == 1)
unsigned char out_buf[32 * 1024 * 1024];
int out_size;
typedef struct _WAVHDR {
	char riff_chunk_id[4];
	int riff_chunk_size;
	char wave_tag[4];
	char fmt_chunk_id[4];
	int fmt_chunk_size;
	short fmt_tag;
	short channels;
	int samples_per_sec;
	int avg_bytes_per_sec;
	short block_align;
	short bits_per_sample;
	char data_chunk_id[4];
	int data_chunk_size;
} WAVHDR;
WAVHDR wav;
#endif /*RECORD*/

/***************************************************************************/
/* DO change */

//#define FILENAME "c:/home/share/select.gym"
//#define FILENAME "c:/home/share/clotho.gym"
//#define FILENAME "c:/home/share/GleyLancer Song - 02.gym"
//#define FILENAME "c:/home/share/MDsorcer01.gym"
//#define FILENAME "c:/home/share/MDsorcer02.gym"
#define FILENAME "c:/home/share/04 - Mission 1 Sol-Deace.gym"
//#define FILENAME "c:/home/share/06 - Mission 4 Enemy Cruiseship.gym"
//#define FILENAME "c:/home/share/Puyo Puyo - Final.gym"
//#define FILENAME "c:/home/share/Puyo Puyo - Memories.gym"
//#define FILENAME "c:/home/share/Puyo Puyo - Baroque.gym"
//#define FILENAME "c:/home/share/Ys3/16-Valestein Castle.gym"

#define BUFLEN		(GYMBUFLEN * GYMFRAME)
#define INIT()		gym_init(&driver, fname);
#define stream_callback	gym_stream_callback

/***************************************************************************/
/* do NOT change */

#define NWHDR		8	/* これ以上増やすとwaveOutWriteでエラーになるみたい */
HWAVEOUT g_wout;
WAVEFORMATEX g_fmt;
WAVEHDR g_whdr[NWHDR];
short g_wbuff[NWHDR][BUFLEN];
GYMDRIVER driver;

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

void CALLBACK
waveOutProc(HWAVEOUT hwo, UINT uMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2)
{
	static int I;
	int retval;

	if(uMsg != WOM_DONE) return;

	retval = stream_callback(g_wbuff[I], (int)&driver);
	if(retval != 0) {
		memset(g_wbuff[I], 0, sizeof(short) * BUFLEN);
	}
	retval = waveOutWrite(hwo, &g_whdr[I], sizeof g_whdr[I]);
	assert(retval == 0);

	I = (I + 1) % NWHDR;
}

int
main(int argc, char* argv[])
{
	int retval;
	int i;
	const char* fname;
	FILE* fp;

	if(argc >= 1 + 1) {
		fname = argv[1];
	} else {
		fname = FILENAME;
	}

	/* init driver */
	retval = INIT();
	if(retval != 0) {
		fprintf(stderr, "init failed (%d)\n", retval);
		exit(1);
	}

#if(RECORD == 0)

	/* init stream */
	memset(&g_fmt, 0, sizeof g_fmt);
	g_fmt.wFormatTag = WAVE_FORMAT_PCM;
	g_fmt.nChannels = 1;
	g_fmt.nSamplesPerSec = 16000;
	g_fmt.nAvgBytesPerSec = 16000 * 2;
	g_fmt.nBlockAlign = 2;
	g_fmt.wBitsPerSample = 16;
	retval = waveOutOpen(&g_wout, WAVE_MAPPER, &g_fmt, (DWORD)waveOutProc, 0, CALLBACK_FUNCTION);
	assert(retval == 0);
	for(i = 0; i < NWHDR; i++) {
		memset(&g_whdr[i], 0, sizeof g_whdr[i]);
		g_whdr[i].lpData = (char*)g_wbuff[i];
		g_whdr[i].dwBufferLength = sizeof g_wbuff[i];
		retval = waveOutPrepareHeader(g_wout, &g_whdr[i], sizeof g_whdr[i]);
		assert(retval == 0);
	}

	/* start playing */
	for(i = 0; i < NWHDR; i++) {
		retval = waveOutWrite(g_wout, &g_whdr[i], sizeof g_whdr[i]);
		assert(retval == 0);
	}
	Sleep(INFINITE);

#else

	for(;;) {
		if(out_size + BUFLEN * sizeof(short) > sizeof out_buf) {
			break;
		}
		retval = stream_callback((short*)&out_buf[out_size], (int)&driver);
		if(retval != 0) {
			break;
		}
		out_size += BUFLEN * sizeof(short);
	}

	/* ヘッダ作成。 */
	memset(&wav, 0, sizeof wav);
	memcpy(wav.riff_chunk_id, "RIFF", 4);
	wav.riff_chunk_size	= 36 + out_size;
	memcpy(wav.wave_tag, "WAVE", 4);
	memcpy(wav.fmt_chunk_id, "fmt ", 4);
	wav.fmt_chunk_size	= 16;
	wav.fmt_tag		= 1/*WAVE_FORMAT_PCM*/;
	wav.channels		= 1;
	wav.samples_per_sec	= SPEAKER_FREQUENCY;
	wav.avg_bytes_per_sec	= SPEAKER_FREQUENCY * sizeof(short);
	wav.block_align		= 1/*ch*/ * sizeof(short);
	wav.bits_per_sample	= 8/*bit*/ * sizeof(short);
	memcpy(wav.data_chunk_id, "data", 4);
	wav.data_chunk_size	= out_size;

	/* 書き込み。 */
	fp = fopen("out.wav", "wb");
	if(!fp) DIE();
	fwrite(&wav, sizeof wav, 1, fp);
	fwrite(out_buf, 1, out_size, fp);
	fclose(fp);

#endif

	return 0;
}

