/***************************************************************************
 *
 * CRI Middleware SDK
 *
 * Copyright (c) 2001-2004 CRI-MW
 *
 * Appli.   : ADXT Sample Program 
 * Module   : Main function.(Playing from memory & memory index)
 * File     : adxmem.c
 *
 ***************************************************************************/

/***************************************************************************
 *		インクルードファイル
 *		Include file
 ***************************************************************************/
#include <stdio.h>
#include <string.h>
#include <cri_mw.h>
#include "usr/usr.h"

/***************************************************************************
 *		定数マクロ
 *		Constant Macro
 ***************************************************************************/
/*	最大チャンネル数				*/
/*	The number of maximum channels	*/
#define	MAX_ADXT		(4)

/*	最大チャンネル数				*/
/*	The number of maximum channels	*/
#define	MAX_CH			(2)

/*	同時再生最大ストリーム数									*/
/*	The number of maximum disc streams playing at the same time	*/
#define	MAX_STM			(1)

/*	最高サンプリング周波数		*/
/*	Maximum sampling frequency	*/
#define	MAX_SFREQ		(48000)

/*	ファイル再生用ワーク領域の大きさ	*/
/*	Work area size of disc stream play	*/
#define	WKSIZE		(ADXT_CALC_WORK(MAX_CH, 1, MAX_STM, MAX_SFREQ))

/***************************************************************************
 *		処理マクロ
 *		Process MACRO
 ***************************************************************************/

/*	フラグON/OFFの反転		*/
/*	Turn over flag(ON/OFF)	*/
#define NOT_FLAG(flag)		(((flag) == OFF) ? ON : OFF)

#define UNUSED(x)				((x) = (x))

#if 1
#define ALIGN(x) 	(Sint8 *)(((Uint32)x + 63) & 0xffffffffc0) // Align64
#else
#define ALIGN(x) 	(Sint8 *)(((Uint32)x + 31) & 0xffffffffe0) // Align32
#endif

/***************************************************************************
 *		変数定義
 *		Variable Definition
 ***************************************************************************/
/*	アプリケーション構造体											*/
/*	Application structure											*/
typedef struct {
	Sint32	disp_flag;				//	Display information flag
	Sint32	pause_flag;				//	Pause flag
	void 	*adxptr;				//	ADX data pointer
	void 	*acxptr;				//	ACX data pointar
	void 	*adxdat;				//	ADX data pointer(Aligned)
	void 	*acxdat;				//	ACX data pointar(Aligned)
	Char8	*adxfname;				//	ADX File name
	Char8	*acxfname;				//	ACX File name
	ADXT	adxt[MAX_ADXT];			//	ADXT handle
	char	work[MAX_ADXT][WKSIZE];	//	Work area
} AP_OBJ;

/*	アプリケーションオブジェクト1									*/
/*	Application Object												*/
AP_OBJ ap_obj = {
	ON,							//	Display Info.
	OFF,						//	not puase
	NULL,						//	ADX data pointer
	NULL,						//	ACX data pointar
	NULL,						//	ADX data pointer(Aligned)
	NULL,						//	ACX data pointar(Aligned)
	"voice48a.adx",				//	ADX File name
	"smpse48.acx",				//	ACX File name
	{NULL, NULL, NULL, NULL}	//	ADXT handle
};

/***************************************************************************
 *		関数宣言
 *		Function Declaration
 ***************************************************************************/
void ap_adx_err_func(void *obj, Char8 *msg);
void ApInitMw(AP_OBJ *ap);
void ApFinishMw(AP_OBJ *ap);
void *ap_load_file(Char8 *fname, void **ptr);
void ApStart(AP_OBJ *ap);
void ApStop(AP_OBJ *ap);
void ap_disp_info(AP_OBJ *ap);
Sint32 ApExec(AP_OBJ *ap);

/***************************************************************************
 *		関数定義
 *		Function Definition
 ***************************************************************************/

/***
 *			ミドルウェアの再生
 *			Playing middleware
 ***/

/*	ADXTエラー発生時に起動する関数					*/
/*	Callback function when an error occur in ADXT	*/
void ap_adx_err_func(void *obj, Char8 *msg)
{
	UNUSED(obj);		// 未使用変数

	UsrDbgPrintf(msg);

	for (;;) {		/*	リリース時には無くす					*/
		;			/*	Delete when you release application.	*/
	}
}

/*	ミドルウェアの初期化				*/
/*	Initialize Middleware				*/
void ApInitMw(AP_OBJ *ap)
{
	UNUSED(ap);

	/*	ADXライブラリ初期化		*/
	/*	Initialize ADX library	*/
	ADXT_Init();
}

/*	ミドルウェアの終了					*/
/*	Finalize Middleware					*/
void ApFinishMw(AP_OBJ *ap)
{
	UNUSED(ap);

	ADXT_Finish();
}

/*	メモリアロケート＆ファイルのロード	*/
/*	Memory Allocating & File Loading	*/
void *ap_load_file(Char8 *fname, void **ptr)
{
	ADXF 	adxf;
	Uint32	fsize;
	Sint8	*retptr;
	
	adxf = ADXF_Open(fname, NULL);
	fsize = (Uint32)ADXF_GetFsizeSct(adxf) * 2048 + 2048;
	
	*ptr = UsrMalloc(fsize);
	if (*ptr == NULL) {
		for (;;) ;
	}
	memset(*ptr, 0, fsize);	

	retptr = (Sint8 *)(((UintPtr)(*ptr) + 63) & 0xffffffc0);

	ADXF_ReadNw(adxf, (Sint32)fsize/2048, retptr);
	UsrInitSync(2);
	while (ADXF_GetStat(adxf) != ADXF_STAT_READEND) {
		UsrSyncFrame();
		ADXM_ExecMain();
		UsrWaitVBlank();
	}

	ADXF_Close(adxf);
	
	return retptr;
}

/*	アプリケーション開始処理	*/
/*	Start application			*/
void ApStart(AP_OBJ *ap)
{
	Sint32	i;

	/*	ADX データの読み込み	*/
	/*	Load ADX data			*/
	ap->adxdat = ap_load_file(ap->adxfname, &ap->adxptr);
	/*	ACX データの読み込み	*/
	/*	Load ACX data			*/
	ap->acxdat = ap_load_file(ap->acxfname, &ap->acxptr);

	/*	ADXT ハンドルの生成	*/
	/*	Create ADXT handle	*/
	for (i = 0; i < MAX_ADXT; i++) {
		if ((ap->adxt[i]=ADXT_Create(2, ap->work[i], WKSIZE)) == NULL)
			for (;;) {
				;
			}
	}

	/*	パンの設定		*/
	/*	Ppanpot setting	*/
	ADXT_SetOutPan(ap->adxt[2], 0, ADXT_PAN_LEFT);
	ADXT_SetOutPan(ap->adxt[3], 0, ADXT_PAN_RIGHT);
}

/*	アプリケーション停止処理	*/
/*	Stop application		*/
void ApStop(AP_OBJ *ap)
{
	Sint32	i;

	/*	ADXT ハンドルの消去	*/
	/*	Destroy ADXT handle	*/
	for (i=0; i<MAX_ADXT; i++) {
		ADXT_Destroy(ap->adxt[i]);
		ap->adxt[i] = NULL;
	}

	/*	ADX/ACXデータの解放	*/
	/*	Free ADX/ACX datas	*/
	UsrFree(ap->adxptr);
	UsrFree(ap->acxptr);

}

/*	情報の表示			*/
/*	Display infomation	*/
void ap_disp_info(AP_OBJ *ap)
{
	char			*ststr[6] =
		{"STOP   ", "DECINFO   ", "PREP   ", "PLAYING", "DECEND ", "PLAYEND"};
	Sint32 			i, stat, sfreq, cnt;
	Sint32 			hh, mm, ss, ff;

	UsrPrintf(3, 3, "ADX Sample Program");
	UsrPrintf(3, 4, "   ADX Playing Multi-Stream from Memory");
	for (i = 0; i < MAX_ADXT; i++) {
		stat = ADXT_GetStat(ap->adxt[i]);
		UsrPrintf(3, 6+i*2, "ADXT%2d: Stat=%s", i, ststr[stat]);
		ADXT_GetTime(ap->adxt[i], &cnt, &sfreq);
		UsrSfcnt2time(sfreq,  cnt, &hh, &mm, &ss, &ff);
		UsrPrintf(26, 6+i*2, "Time=%2d:%02d:%02d.%02d", hh, mm, ss, ff);
	}
}

/*	ADFXの再生			*/
/*	Playing the ADXT	*/
Sint32 ApExec(AP_OBJ *ap)
{
	Sint32					i;
	const USR_PERIPHERAL	*per;

	per = UsrGetPeripheral(0);	
	/*	メモリ再生					*/
	/*	Start to memory play		*/
	if (per->press & UTPAD_BUTTON1)
		ADXT_StartMem(ap->adxt[0], ap->adxdat);
	/*	メモリインデックス再生			*/
	/*	Start to memory index play		*/
	if (per->press & UTPAD_BUTTON2)
		ADXT_StartMemIdx(ap->adxt[0], ap->acxdat, 0);
	if (per->press & UTPAD_BUTTON3)
		ADXT_StartMemIdx(ap->adxt[1], ap->acxdat, 1);
	if (per->press & UTPAD_BUTTON4)
		ADXT_StartMemIdx(ap->adxt[1], ap->acxdat, 2);
	if (per->press & UTPAD_RIGHT)
		ADXT_StartMemIdx(ap->adxt[2], ap->acxdat, 3);
	if (per->press & UTPAD_LEFT)
		ADXT_StartMemIdx(ap->adxt[2], ap->acxdat, 4);
	if (per->press & UTPAD_DOWN)
		ADXT_StartMemIdx(ap->adxt[3], ap->acxdat, 5);
	if (per->press & UTPAD_UP)
		ADXT_StartMemIdx(ap->adxt[3], ap->acxdat, 6);
	if (per->press & UTPAD_START) {
		for (i = 0; i < MAX_ADXT; i++) 
			ADXT_Stop(ap->adxt[i]);
	}

	/*	情報の表示			*/
	/*	Display infomation	*/
	ap_disp_info(ap);

	/* CRI Middleware Library's Server function */
	ADXM_ExecMain();

	return TRUE;
}

/***
 *		メイン処理
 *		MAIN
 ***/
int main(void)
{
	AP_OBJ	*ap;
	Sint32	term_flag = OFF;
	Bool	ret;

	ap = &ap_obj;

	/*	エラーコールバック関数の登録		*/
	/*	Entry ADX error callback function	*/
	ADXM_SetCbErr(ap_adx_err_func, NULL);
	
	/*	システムの初期化										*/
	/*	Initialize System										*/
	UsrInitSystem(NULL, NULL);
	
	/*	ビデオの初期化											*/
	/*	Initialize Video System									*/
	UsrInitVideo(NULL, NULL);
	
	/*	サウンドの初期化										*/
	/*	Initialize Sound System									*/
	UsrInitSound(NULL, NULL);

	ApInitMw(ap);

	while (term_flag == OFF) {
		ApStart(ap);
		/*	cnt :frame count						*/
		/*	cnt=0:interlace	/ cnt>0:non interlace	*/
		UsrInitSync(2);
		for (;;) {
			UsrSyncFrame();
			UsrBeginDraw();
			ret = ApExec(ap);
			UsrEndDraw();

			/* 終了するかどうかの確認					*/
			/* Checks whether Usr module is terminated	*/
			if (UsrIsTerminated() == TRUE) {
				term_flag = ON;
			}
			
			if (ret == FALSE || term_flag == ON) {
				break;
			}
		}
		ApStop(ap);
	}
	/*	アプリケーション終了処理	*/
	/*	Finalize application		*/
	ApFinishMw(ap);			/*	ミドルウェアの終了				*/
							/*	Finalize Middleware				*/
	UsrFinishSound();		/*	サウンドシステムの終了処理		*/
							/*	Finalize sound system			*/
	UsrFinishVideo();		/*	ビデオの終了処理				*/
							/*	Finalize Video system			*/
	UsrFinishSystem();		/*	システムの終了処理				*/
							/*	Finalize system					*/
	return 0;
}

/* end of file */
