/*
 *
 *		Middleware MPEG/Audio Player Sample
 *
 */

/***************************************************************************
 *      インクルードファイル
 *      Include file
 ***************************************************************************/
#include	<shinobi.h>
#include	<sg_sd.h>
#include	<sg_mw.h>

/***************************************************************************
 *      変数定義
 *		Variable Declaration
 ***************************************************************************/

/*	エラー発生回数		*/
/*	The number of error	*/
Sint32	errcnt;

/*	サウンドドライバのバージョン	*/
/*	Version of sound driver			*/
Sint32	drvver;

/*	サウンドライブラリのバージョン	*/
/*	Version of sound library		*/
Sint32	libver;

/***************************************************************************
 *      関数定義
 *      Function Declaration
 ***************************************************************************/
/***
 *		サウンド環境の初期化
 *		Initialize sound section
 ***/

/*	サウンドドライバの転送・初期化					*/
/*	Initialize sound library and load sound driver	*/
void SoundInit(void *ptr)
{
	SDMEMBLK	memblk = NULL;

	/*	サウンドライブラリの初期化				*/
	/*	Initialize Sound library				*/
	sdLibInit(NULL, 0, 0);
	/*	メモリブロックハンドル生成				*/
	/*	Create Memory block handle  			*/
	sdMemBlkCreate(&memblk);
	/*	メモリブロックハンドル設定				*/
	/*  Setting Memory block handle  			*/
	sdMemBlkSetPrm(memblk, ptr, 0, SDD_MEMBLK_SYNC_FUNC, NULL);
	/*	サウンドドライバ初期化					*/
	/*	Initialize Sound driver  				*/
	sdDrvInit(memblk);
	/*	メモリブロック解放						*/
	/*	Destroy Memory block handle				*/
	sdMemBlkDestroy(memblk);
}

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

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

	if ( (gdfs=gdFsOpen(fname, NULL)) == NULL )
		for (;;);
	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;
}

/*	時間への変換															*/
/*	Convert form sampling frequency and counter to time(hour,min,sec,frame)	*/
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;
}

/*	サウンドライブラリ・ドライバのバージョン取得	*/
/*	Getting sound library and sound driver			*/
void getVer(Sint32 *drvver, Sint32 *libver)
{
	Sint32	tmp;
	SDS_VER drv_ver, lib_ver;

	sdDrvGetVer(&drv_ver);
	sdLibGetVer(&lib_ver);

	tmp = (Sint32)(drv_ver.m_MajorVer);
	*drvver = tmp << 16;
	tmp = (Sint32)drv_ver.m_MinorVer;
	*drvver |= tmp << 8;
	*drvver |= (Sint32)drv_ver.m_DebugVer;

	tmp = (Sint32)(lib_ver.m_MajorVer);
	*libver = tmp << 16;
	tmp = (Sint32)lib_ver.m_MinorVer;
	*libver |= tmp << 8;
	*libver |= (Sint32)lib_ver.m_DebugVer;
	return;
}

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

/*	サンプルプログラムの情報表示		*/
/*	Show infomation of sample program	*/
void showSmpInfo(Uint32 cnt)
{
	njPrint(NJM_LOCATION( 5,  2), "[MPEG/Audio]");
	njPrint(NJM_LOCATION( 5,  4), "Snd Drv   : %06x", drvver);
	njPrint(NJM_LOCATION( 5,  5), "Snd Lib   : %06x", libver);
	njPrint(NJM_LOCATION( 5,  6), "Prg Cnt   : %d", cnt);
	njPrint(NJM_LOCATION( 5,  8), "File Name : SAMPLE.MP2");
	return;
}

/*	再生状態の表示						*/
/*	Show status of middleware handle	*/
void showStat(MWPLY ply)
{
	Sint32	stat, tscl, cnt;
	Sint32	hh, mm, ss, ff;
	Sint8	*strstat[5] = {"STOP","PREP","EXEC","END ","ERROR"};

	hh = mm = ss = ff = 0;
	stat = mwPlyGetStat(ply);
	mwPlyGetTime(ply, &cnt, &tscl);
	sfcnt2time(tscl, cnt, &hh, &mm, &ss, &ff);
	njPrint(NJM_LOCATION( 5,  9), "Frequency : %d", tscl);
	njPrint(NJM_LOCATION( 5, 10), "Status    : %s", strstat[stat]);
	njPrint(NJM_LOCATION( 5, 11), "Time      : %02d:%02d.%02d", mm, ss, ff);
	return;
}

Sint32 pause = OFF;

/*	MP2ファイルの再生	*/
/*	Playing MP2 file	*/
void mpaPlay(char *fname)
{
	MWPLY			ply;
	MWS_PLY_CPRM	cprm;
	Sint32			stat;
	Sint32			cnt;
	const PDS_PERIPHERAL	*per;

	/*	ハンドル生成						*/
	/*	Create handle						*/
	cprm.size  = MWD_PLY_CALC_AWORK(MWD_PLY_MIN_AWORK);
	cprm.buf = syMalloc(cprm.size);
	cprm.libwork = syMalloc(MWD_MPA_CALC_WORK(1));
	ply = mwPlyCreateMpa(&cprm);
	if (ply == NULL)
		for (;;) ;

	/*	再生開始							*/
	/*	Start to play middleware			*/
	mwPlyStartFname(ply, fname);
	for (cnt=0;;cnt++) {
		per = pdGetPeripheral(PDD_PORT_A0);
		if (per->press & PDD_DGT_TX) {
			pause = ON;
			mwPlyPause(ply, ON);		/*	一時停止				*/
										/*	Pause					*/
		}
		if (per->press & PDD_DGT_TY) {
			pause = OFF;
			mwPlyPause(ply, OFF);		/*	一時停止解除			*/
										/*	Release pause status	*/
		}
		if (per->press & PDD_DGT_ST) {
			break;
		}
		/*	再生状態の確認						*/
	    /*	Check status of middleware			*/
		stat = mwPlyGetStat(ply);
		if ((stat == MWE_PLY_STAT_PLAYEND) || (stat == MWE_PLY_STAT_ERROR)) {
			break;
		}

		showSmpInfo(cnt);
		showStat(ply);

		/*	ミドルウェアのサーバ関数			*/
		/*	Server function of middleware		*/
		mwPlyExecServer();
		njWaitVSync();
	}
	/*	ハンドル消去						*/
	/*	Destroy handle						*/
	mwPlyDestroy(ply);
	njWaitVSync();
	syFree(cprm.libwork);
	syFree(cprm.buf);
	return;
}

/***
 *		メイン処理
 *		MAIN
 ***/

/*	アプリケーション終了処理	*/
/*	Finalize application		*/
void usrExit(void)
{
	/*	ライブラリ終了処理					*/
	mwPlyFinishMpa();
	/*	忍ライブラリの終了処理				*/
	sbExitSystem();
	/*	シンプルプレイヤへジャンプ			*/
	syBtExit();
}

/*	GDファイルシステムのエラー発生時に起動する関数			*/
/*	Callback function when an error occur in GD file system	*/
void usrGdErrFunc(void *obj, Sint32 errcode)
{
	if (errcode == GDD_ERR_TRAYOPEND || errcode == GDD_ERR_UNITATTENT) {
		/*	アプリケーション終了処理	*/
		/*	Finalize application		*/
		usrExit();
 	}
 	return;
}

/*	ユーザがV-SYNC割り込みに登録する関数	*/
/*	Function that user entry into V-Int		*/
void usrVsyncFunc(void)
{
	Sint32 dstat;

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

/*	ミドルウェアのエラー発生時に起動する関数			*/
/*	Callback function when an error occur in middleware	*/
void usrMwErrFunc(void *obj, Sint32 ecode)
{
    if (ecode != MWD_PLY_ERR_OK) {
		errcnt++;
    }
}

void	main(void)
{
	void	*snddrv;

#ifdef __GNUC__
	shinobi_workaround();
#endif
	/*	忍ライブラリの初期化	*/
	/*	Initialize SHINOBI		*/
    njSetBorderColor(0x00000000) ;
	sbInitSystem(NJD_RESOLUTION_320x240_NTSCNI,NJD_FRAMEBUFFER_MODE_RGB565,1);
	njInitVertexBuffer(30000, 0, 30000, 0, 0);
    njInitPrint(NULL, 0, 0);
	/*	GDファイルシステムエラーコールバック関数の登録	*/
	/*	Entry callback function of GD file system error	*/
	gdFsEntryErrFuncAll((void *)usrGdErrFunc, NULL);

	/*	サウンドライブラリの準備	*/
	/*	Prepare sound library		*/
	snddrv = loadFile("manatee.drv", NULL);
	SoundInit(snddrv);
	getVer(&drvver, &libver);
	/*	DMA 転送モード				*/
	/*	Set transfer mode to DMA  	*/
	sdMemBlkSetTransferMode(SDE_MEMBLK_TRANSFER_MODE_DMA);

	njSetVSyncFunction((void *)usrVsyncFunc);

	mwPlyInitMpa(MWD_PLY_SVR_VSYNC);
	mwPlyEntryErrFunc((void *)usrMwErrFunc, NULL);

	for (;;) {
		mpaPlay("SAMPLE.MP2");				/*	MP2ファイルの再生	*/
											/*	Playing MP2 file	*/
	}

	/*	アプリケーション終了処理	*/
	/*	Finalize application		*/
	usrExit();
}
