/*
 *			ADXT サンプルプログラム No.2
 *				(メモリ再生 & メモリインデックス再生)
 */

#include	<math.h>
#include	<string.h>

#include	"cri_adxf.h"
#include	"cri_adxt.h"

/***
*		定義部
***/

/*	同時再生最大チャンネル数	*/
#define	MAX_CH			(2)
/*	最高サンプリング周波数	*/
#define	MAX_SFREQ		(44100)
/*	最大ADXTハンドル数	*/
#define	MAX_ADXT		(4)

/***
*		サウンド環境の初期化
***/

#include	"shinobi.h"
#include	"sg_sd.h"

/* サウンドドライバの転送・初期化 */
Void	sound_init(Void *ptr)
{
	SDMEMBLK	memblk = NULL;

	/*	Initialize Sound library	 */
	sdLibInit(NULL, 0, 0);		/*	This api's argument is dummy now.  */

	/* 	Download and Initialize Sound driver.	 */
	/*	Create Memory block handle  */
	sdMemBlkCreate(&memblk);
	/*  Setting Memoby block handle  */
	sdMemBlkSetPrm(memblk, ptr, 0, SDD_MEMBLK_SYNC_FUNC, NULL);
	/*	Initialize Sound driver  */
	sdDrvInit(memblk);
	sdMemBlkDestroy(memblk);
}

/***
*			ユーティリティ関数
***/

/*	データの読み込み	*/
void *load_file(char *fname, long *len)
{
	GDFS gdfs;
	long fsize, nsct;
	void *dat=NULL;

	if ( (gdfs=gdFsOpen(fname, NULL)) == NULL ) {
		for (;;) {
			njPrint(NJM_LOCATION(3, 5), "can't open %s", fname);
			njWaitVSync();
		}
	}
	gdFsGetFileSize(gdfs, &fsize);
	nsct = (fsize+2047)/2048;
	if ( (dat=syMalloc(nsct*2048)) != NULL ) {
		gdFsRead(gdfs, nsct, dat);
	}
	gdFsClose(gdfs);
	if ( len != NULL )
		*len = fsize;

	return dat;
}

/*	時間の変換	*/
void sfcnt2time(long sf, long ncnt, long *hh, long *mm, long *ss, long *ff)
{
	register long nf = (long)((double)ncnt/(double)sf*100.0);

	*hh = nf/(60*60*100);
	*mm = nf/(60*100) - *hh*60;
	*ss = nf/100 - *hh*60*60 - *mm*60;
	*ff = nf%100;
}

/* GDファイルシステムのエラー発生時に起動する関数 */
void usr_gd_err_func(void *obj, Sint32 errcode)
{
	if (errcode == GDD_ERR_TRAYOPEND || errcode == GDD_ERR_UNITATTENT) {
		/*	ライブラリ終了処理					*/
		ADXT_Finish();
		/*	忍ライブラリの終了処理				*/
		sbExitSystem();
		/*	シンプルプレイヤへジャンプ			*/
		syBtExit();
 	}
 	return;
}

/* ユーザのVSYNC割り込み登録関数 */
static void usr_vsync_func(void)
{
	Sint32 dstat;

    /* サウンドライブラリのサーバ */
    sdSysServer();
	/* GDドライブの状態チェック */
	dstat = gdFsGetDrvStat();
	if (dstat == GDD_DRVSTAT_OPEN || dstat == GDD_DRVSTAT_BUSY) {
		gdFsReqDrvStat();
	}
	return;
}

/***
*			サンプルプログラム
***/

/*	動作状態の表示	*/
void adxtst_disp_stat(ADXT *adxt, long nadxt)
{
	char *ststr[6] =
		{"STOP   ", "DECINFO   ", "PREP   ", "PLAYING", "DECEND ", "PLAYEND"};
	long i, stat, sfreq, cnt;
	long hh, mm, ss, ff;

		njPrint(NJM_LOCATION(3, 3), "ADX Sample Program No.2");
		njPrint(NJM_LOCATION(3, 4), "   ( Memory Play )");
	for (i=0; i<nadxt; i++) {
		stat = ADXT_GetStat(adxt[i]);
		njPrint(NJM_LOCATION(3, 6+i*3), "ADXT %2d: Stat=%s", i, ststr[stat]);

		ADXT_GetTime(adxt[i], &cnt, &sfreq);
		sfcnt2time(sfreq,  cnt, &hh, &mm, &ss, &ff);
		njPrint(NJM_LOCATION(12, 7+i*3), "Time = %2d:%2d:%2d.%2d", hh, mm, ss, ff);
	}
}

/*	ファイル再生用ワーク領域の大きさ	*/
#define	WKSIZE		(ADXT_CALC_WORK(MAX_CH, 0, 0, MAX_SFREQ))
/*	ファイル再生用 ADXT ワーク領域	*/
char work[MAX_ADXT][WKSIZE];

/*	サンプル	*/
void adxsmp(void)
{
	const NJS_PERIPHERAL* per;
	ADXT adxt[MAX_ADXT];
	void *adxdat, *acxdat;
	long i;

	/*	ACX データの読み込み	*/
	adxdat = load_file("SAMPLE.ADX", NULL);
	/*	ACX データの読み込み	*/
	acxdat = load_file("SMPL_MEM.ACX", NULL);
	/*	メモリ再生用 ADXT ハンドルの生成	*/
	for (i=0; i<MAX_ADXT; i++) {
		if ( (adxt[i]=ADXT_Create(2, work[i], WKSIZE)) == NULL ) {
			for (;;) {
				njPrint(NJM_LOCATION(1, 27), "can't create ADXT\n");
				njWaitVSync();
			}
		}
	}

	ADXT_SetOutPan(adxt[2], 0, ADXT_PAN_LEFT);
	ADXT_SetOutPan(adxt[3], 0, ADXT_PAN_RIGHT);

	for (;;) {
		per = njGetPeripheral(NJD_PORT_A0);
		/*	メモリ再生	*/
		if (per->press & NJD_DGT_TA)
			ADXT_StartMem(adxt[0], adxdat);
		/*	メモリインデックス再生	*/
		if (per->press & NJD_DGT_TB)
			ADXT_StartMemIdx(adxt[0], acxdat, 0);
		if (per->press & NJD_DGT_TX)
			ADXT_StartMemIdx(adxt[1], acxdat, 1);
		if (per->press & NJD_DGT_TY)
			ADXT_StartMemIdx(adxt[1], acxdat, 2);
		if (per->press & NJD_DGT_KR)
			ADXT_StartMemIdx(adxt[2], acxdat, 3);
		if (per->press & NJD_DGT_KL)
			ADXT_StartMemIdx(adxt[2], acxdat, 4);
		if (per->press & NJD_DGT_KD)
			ADXT_StartMemIdx(adxt[3], acxdat, 5);
		if (per->press & NJD_DGT_KU)
			ADXT_StartMemIdx(adxt[3], acxdat, 6);
		if (per->press & NJD_DGT_ST)
			for (i=0; i<MAX_ADXT; i++) ADXT_Stop(adxt[i]);
		adxtst_disp_stat(adxt, MAX_ADXT);
		njWaitVSync();
	}
	for (i=0; i<MAX_ADXT; i++)
		ADXT_Destroy(adxt[i]);
	syFree(acxdat);
	syFree(adxdat);
}

/*	ADXライブラリでエラーが発生したときのコールバック関数	*/
void userAdxErrFunc(void *obj, char *msg)
{
	/*	エラーが発生するとこの関数が呼び出されます。						*/
	/*	msg にエラーメッセージが渡されます。								*/
	/*	msgは、R5レジスタに格納されているので、R5レジスタのアドレスを		*/
	/*	ダンプすることによってエラーメッセージを知ることができます。		*/
	/*	この関数は、V-Sync割り込みから呼び出されることがありますので、		*/
	/*	Ninjaの関数は使用しないでください。									*/
	/*	また、アプリケーションをリリースするときは、何もせずに戻るような	*/		/*	関数にしてください。												*/

	for (;;);		/*	リリース時には無くす								*/

}

void main(void)
{
	void *snddrv;

	/* 表示周りの初期化 */
    njSetBorderColor( 0x00000000 ) ;
	sbInitSystem(NJD_RESOLUTION_320x240_NTSCNI,
										NJD_FRAMEBUFFER_MODE_RGB565, 1 );
	njInitVertexBuffer( -30000, 0, 30000, 0, 0);
    njInitPrint(NULL, 0, 0);
	njSetBackColor(0x00000000,0x00000000,0x000000FF);
	/* GDファイルシステムエラーコールバック関数の登録	*/
	gdFsEntryErrFuncAll((void *)usr_gd_err_func, NULL);

	/* サウンドライブラリの準備 */
	snddrv = load_file("manatee.drv", NULL);
	sound_init(snddrv);
	/* DMA 転送モード	*/
	sdMemBlkSetTransferMode(SDE_MEMBLK_TRANSFER_MODE_DMA);
	njSetVSyncFunction((void (*)(void))usr_vsync_func);

	/*	ライブラリ初期化	*/
	ADXT_Init();
	/*	エラーコールバック関数の登録	*/
	ADXT_EntryErrFunc(userAdxErrFunc, NULL);

	for (;;)
		adxsmp();

	/*	ライブラリ終了処理					*/
	ADXT_Finish();
	/*	忍ライブラリの終了処理				*/
	sbExitSystem();
	/*	シンプルプレイヤへジャンプ			*/
	syBtExit();
}
