/*	
 *	clipgym.c
 *
 *	P/ECE GYM Driver
 *
 *	CLiP - Common Library for P/ECE
 *	Copyright (C) 2001-2004 Naoyuki Sawa
 *
 *	* Thu Dec 9 18:16:00 JST 2004 Naoyuki Sawa
 *	- 作成開始。
 */
#include "clip.h"

/****************************************************************************
 *	GYMドライバ内部関数
 ****************************************************************************/

#define MD_CLOCK	53693100	/* NTSC版MegaDriveの源振クロック */
#define YM2612_CLOCK	(MD_CLOCK / 7)	/* 7分周してYM2612へ供給 */
#define SN76489_CLOCK	(MD_CLOCK / 15)	/* 15分周してSN76489へ供給 */

int
gym_init(GYMDRIVER* driver, const char* fname)
{
	int retval;
	GYMHEADER header;

	/* まずクリアします。 */
	memset(driver, 0, sizeof(GYMDRIVER));

	/* YM2612 chipを初期化します。 */
	{
		extern YM2612 gym_ym2612; /* 高速RAMに配置 */
		driver->ym2612 = &gym_ym2612;
	}
	ym2612_init(driver->ym2612, YM2612_CLOCK);

	/* SN76489 chipを初期化します。 */
	{
		static SN76489 gym_sn76489; /* SRAMに配置 */
		driver->sn76489 = &gym_sn76489;
	}
	sn76489_reset(driver->sn76489, SN76489_CLOCK);

	/* ファイルを開きます。 */
	driver->fp = fopen(fname, "rb");
	if(!driver->fp) {
		goto L_ERR;
	}

	/* ヘッダを読み込みます。 */
	retval = fread(&header, sizeof(GYMHEADER), 1, driver->fp);
	if(retval != 1) {
		goto L_ERR;
	}

	/* シグネチャを検査します。 */
	if(memcmp(header.identifier, "GYMX", 4) != 0) {
		goto L_ERR;
	}

	/* 圧縮形式には未対応です。 */
	if(header.uncompressed_size) {
		goto L_ERR;
	}

	/* ループ開始位置までの残りフレーム数を初期化します。(非ループ曲ならば初期値0) */
	driver->loopcnt = header.loop_integer;

	return 0; /* 成功 */

L_ERR:
	/* 確実にファイルを閉じます。 */
	gym_free(driver);

	return -1; /* 失敗 */
}

void
gym_free(GYMDRIVER* driver)
{
	/* 確実にファイルを閉じます。 */
	if(driver->fp) {
		fclose(driver->fp);
		driver->fp = NULL;
	}
}

int
gym_stream_callback(short* wbuff, int param)
{
	int retval;
	int i;

	i = GYMFRAME;
	do {
		retval = gym_mix((GYMDRIVER*)param, wbuff);
		if(retval != 0) {
			break;
		}
		wbuff += GYMBUFLEN;
	} while(--i);

	return retval;
}

/****************************************************************************
 *	アプリケーション用関数
 ****************************************************************************/

static GYMDRIVER driver; /* ＳＴＡＴＩＣです！ */

int
gym_play(const char* fname)
{
	/* まず確実に停止します。 */
	gym_stop();

	/* ドライバを初期化します。 */
	if(gym_init(&driver, fname) != 0) {
		return -1;
	}

	/* ストリーム再生を開始します。 */
	stream_play(GYMBUFLEN * GYMFRAME, gym_stream_callback, (int)&driver, 1/*スタック切換使用*/);

	return 0;
}

void
gym_stop()
{
	/* ストリーム再生を停止します。 */
	stream_stop();

	/* GYMドライバを解放します。(必須!!) */
	gym_free(&driver);
}
