/***************************************************************************
 *
 *	CRI Middleware SDK
 *
 *	Copyright (c) 2003-2004 CRI-MW
 *
 *	Appli.	: ADX Library
 *	Module	: ADX Cinematic Sound System sample
 *	File	: adxcsply.c
 *
 ***************************************************************************/

/***************************************************************************
 *      インクルードファイル
 *      Include files
 ***************************************************************************/
#include <stdio.h>
#include <string.h>

#include <cri_mw.h>
#include <cri_ut.h>
#include "usr/usr.h"


/***************************************************************************
 *      定数マクロ
 *      Macro Constants
 ***************************************************************************/
/*	BGM数				*/
/*	The number of BGM	*/
#define	NUM_BGM		(2)

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

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

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

/*	最大トラック数		*/
/*	The number of maximum tracks	*/
#define	MAX_TRACK	(4)

/*	フェードアウト時間	*/
/*	Fade-out time		*/
#define FADE_OUT_TIME				(180)			/*	3sec	*/
/*	フェードイン時間	*/
/*	Fade-in time		*/
#define FADE_IN_TIME				(180)			/*	3sec	*/
/*	ボリューム変更時間	*/
/*	Volume change time	*/
#define VOL_CHANGE_TIME				(180)			/*	3sec	*/
/*	フェードイン開始オフセット	*/
/*	Fade-in start offset		*/
#define FADE_IN_START_OFFSET		(0)
/*	フェード後のディレイ時間	*/
/*	Fade-end delay				*/
#define FADE_END_DELAY				(ADXCS_DEF_FADE_END_DELAY)

/*	ボイスハイライトのボリューム減少時間		*/
/*	Volume decrease time of Voice-Highlight		*/
#define VHL_DEC_TIME				(30)			/*	0.5sec	*/
/*	ボイスハイライトのボリューム増加時間	*/
/*	Volume increase time of Voice-Highlight	*/
#define VHL_INC_TIME				(60)			/*	1sec	*/
/*	ボイスハイライトのボリューム減少量			*/
/*	Volume decrease amount of Voice-Highlight	*/
#define VHL_DEC_VOL					(120)			/*	12dB	*/

/***************************************************************************
 *      処理マクロ
 *      Macro Functions
 ***************************************************************************/
/*	フラグON/OFFの反転		*/
/*	Turn over flag(ON/OFF)	*/
#define NOT_FLAG(flag)		(((flag) == OFF) ? ON : OFF)

/*	未使用変数		*/
/*	Unused variable	*/
#define UNUSED(val)			((val) = (val))

/***************************************************************************
 *      データ型宣言
 *      Data Type Declarations
 ***************************************************************************/

/***************************************************************************
 *      変数宣言
 *      Prototype Functions
 ***************************************************************************/
/*	アプリケーション構造体											*/
/*	Application structure											*/
typedef struct {
	Sint32	disp_flag;				/*	Display information flag	*/
	ADXCS 	adxcs_bgm;				/*	ADXCS handle				*/
	ADXCS 	adxcs_voice;			/*	ADXCS handle				*/
	Sint8 	*work_bgm;				/*	Work area					*/
	Sint8 	*work_voice;			/*	Work area					*/
	Sint32	fname_index;			/*	Index of filename array		*/
	Char8	*fname_bgm[NUM_BGM];	/*	BGM Filenames				*/
	Char8	*fname_voice;			/*	Voice Filenames				*/
} AP_OBJ;

/***************************************************************************
 *      関数宣言
 *      Prototype Functions
 ***************************************************************************/
void ap_adx_err_func(void *obj, Char8 *msg);
void ap_disp_info(AP_OBJ *ap);
void ApInitMw(AP_OBJ *ap);
void ApFinishMw(AP_OBJ *ap);
void ApStart(AP_OBJ *ap);
void ApStop(AP_OBJ *ap);
Sint32 ApExec(AP_OBJ *ap);

/***************************************************************************
 *      変数定義
 *      Variable Declarations
 ***************************************************************************/
/*	アプリケーションオブジェクト								*/
/*	Application Object											*/
AP_OBJ ap_obj = {
	ON,							/*	Display information flag	*/
	NULL,						/*	ADXCS handle				*/
	NULL,						/*	Work area					*/
	NULL,						/*	ADXCS handle				*/
	NULL,						/*	Work area					*/
	0,							/*	Index of filename array		*/
	{
		"music48a.adx",			/*	ADX file name				*/
		"music48b.adx",			/*	ADX file name				*/
	},
	"voice24a.ahx"				/*	AHX file name				*/
};

/***************************************************************************
 *      関数定義
 *      Function Declarations
 ***************************************************************************/

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

	UsrDbgPrintf(msg);

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

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

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

	/*	ADXCS初期化			*/
	/*	Initialize ADXCS	*/
	ADXCS_Init();

	/*	ボイスハイライトのボリューム減少時間を設定	*/
	/*	Set volume decrease time of Voice-Highlight	*/
	ADXCS_SetVhlDecTime(VHL_DEC_TIME);
	/*	ボイスハイライトのボリューム増加時間を設定	*/
	/*	Set volume increase time of Voice-Highlight	*/
	ADXCS_SetVhlIncTime(VHL_INC_TIME);
	/*	ボイスハイライトのボリューム減少量を設定		*/
	/*	Set volume deccrease amount of Voice-Highlight	*/
	ADXCS_SetVhlDecVol(VHL_DEC_VOL);

	/*	ボイスハイライトを有効にする	*/
	/*	Enable Voice-Highlight			*/
	ADXCS_EnableVhl();
}

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

	ADXCS_Finish();

	ADXT_Finish();
}

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

	ap->adxcs_bgm	= NULL;
	ap->adxcs_voice	= NULL;

	/*	ADXCS ハンドルの生成	*/
	/*	Create ADXCS handle		*/
	memset(&cprm, 0, sizeof(cprm));
	cprm.max_stm		= MAX_STM;
	cprm.max_ch			= MAX_CH;
	cprm.max_sfreq		= MAX_SFREQ;
	cprm.max_aix_track	= MAX_TRACK;
	cprm.play_method	= ADXT_PLY_STM;
	cprm.sound_type		= ADXCS_SND_TYPE_BGM;
	cprm.use_crossfade	= TRUE;
	cprm.use_ahx		= FALSE;
	cprm.use_aix		= FALSE;
	
	/*	BGM	*/
	work_size = ADXCS_CalcWorkCprm(&cprm);
	ap->work_bgm = (Sint8 *)UsrMalloc((Uint32)work_size);
	ap->adxcs_bgm = ADXCS_Create(&cprm, ap->work_bgm, work_size);
	if (ap->adxcs_bgm == NULL) {
		ap_adx_err_func(NULL, "can't create ADXCS \n");
		for (;;) ;
	}
	if (cprm.use_ahx == TRUE) {
		ADXCS_AttachAhx(ap->adxcs_bgm);
	}

	/*	VOICE	*/
	cprm.sound_type		= ADXCS_SND_TYPE_VOICE;
	cprm.use_ahx		= TRUE;
	work_size = ADXCS_CalcWorkCprm(&cprm);
	ap->work_voice = (Sint8 *)UsrMalloc((Uint32)work_size);
	ap->adxcs_voice = ADXCS_Create(&cprm, ap->work_voice, work_size);
	if (ap->adxcs_voice == NULL) {
		ap_adx_err_func(NULL, "can't create ADXCS \n");
		for (;;) ;
	}
	if (cprm.use_ahx == TRUE) {
		ADXCS_AttachAhx(ap->adxcs_voice);
	}

	/*	フェードアウト時間の設定	*/
	/*	Set fade-out time			*/
	ADXCS_SetFadeOutTime(ap->adxcs_bgm, FADE_OUT_TIME);
	/*	フェードイン時間の設定	*/
	/*	Set fade-in time		*/
	ADXCS_SetFadeInTime(ap->adxcs_bgm, FADE_IN_TIME);
	/*	フェードボリューム変更時間の設定	*/
	/*	Set volume change time				*/
	ADXCS_SetVolChangeTime(ap->adxcs_bgm, VOL_CHANGE_TIME);
	/*	フェードイン開始オフセットの設定	*/
	/*	Set fade-in start offset			*/
	ADXCS_SetFadeInStartOffset(ap->adxcs_bgm, FADE_IN_START_OFFSET);
	/*	フェード終了後ディレイの設定	*/
	/*	Set fade-end delay				*/
	ADXCS_SetFadeEndDelay(ap->adxcs_bgm, FADE_END_DELAY);
	ADXCS_SetFadeEndDelay(ap->adxcs_voice, 0);

	/*	再生開始		*/
	/*	Start to play	*/
	ADXCS_StartFname(ap->adxcs_bgm, ap->fname_bgm[ap->fname_index]);
}

/*	アプリケーション停止処理	*/
/*	Stop application			*/
void ApStop(AP_OBJ *ap)
{
	const AdxcsCrePrm	*cprm;
	cprm = ADXCS_GetCprm(ap->adxcs_voice);
	if (cprm->use_ahx == TRUE) {
		ADXCS_DetachAhx(ap->adxcs_voice);
	}

	/*	ADXT ハンドルの消去	*/
	/*	Destroy ADXT handle	*/
	ADXCS_Destroy(ap->adxcs_voice);
	ADXCS_Destroy(ap->adxcs_bgm);
	UsrFree(ap->work_voice);
	UsrFree(ap->work_bgm);
	ap->adxcs_bgm = NULL; 
	ap->adxcs_voice = NULL; 
}

/*	情報の表示			*/
/*	Display infomation	*/
void ap_disp_info(AP_OBJ *ap)
{
	char 		*ststr[] =
		{"STOP   ", "PREP   ", "PLAYING", "DECEND ", "PLAYEND"};
	Sint32		stat, sfreq, cnt;
	Sint32		hh, mm, ss, ff;
	Sint32		vol;
	ADXT		adxt;
	const AdxcsCrePrm	*cprm;
	
	UsrPrintf(3, 3, "ADX Sample Program");
	UsrPrintf(3, 4, "   ADX Cinematic Sound Sample ");

	/*	BGMの情報の表示				*/
	/*	Display information of BGM	*/
	stat = ADXCS_GetStat(ap->adxcs_bgm);

	UsrPrintf(3,  6, "FILE = %s", ap->fname_bgm[ap->fname_index]);
	UsrPrintf(3,  7, "STAT = %s (%d)", ststr[stat], stat);

	cprm = ADXCS_GetCprm(ap->adxcs_bgm);
	if (cprm->use_aix == TRUE) {
		adxt = AIXP_GetAdxt(ADXCS_GetActiveAixp(ap->adxcs_bgm), 0);
	} else {
		adxt = ADXCS_GetActiveAdxt(ap->adxcs_bgm);
	}
	ADXT_GetTime(adxt, &cnt, &sfreq);
	UsrSfcnt2time(sfreq,  cnt, &hh, &mm, &ss, &ff);
	UsrPrintf(3,  8, "TIME = %2d:%02d:%02d.%02d", hh, mm, ss, ff);

	vol = ADXT_GetOutVol(adxt);
	UsrPrintf(3,  10, "BGM Vol   = %-3d", vol);

	/*	Voiceの情報の表示				*/
	/*	Display information of Voice	*/
	cprm = ADXCS_GetCprm(ap->adxcs_voice);
	if (cprm->use_aix == TRUE) {
		adxt = AIXP_GetAdxt(ADXCS_GetActiveAixp(ap->adxcs_voice), 0);
	} else {
		adxt = ADXCS_GetActiveAdxt(ap->adxcs_voice);
	}
	vol = ADXT_GetOutVol(adxt);
	UsrPrintf(3,  11, "Voice Vol = %-3d", vol);
}

/*	アプリケーションメイン処理	*/
/*	Run application				*/
Sint32 ApExec(AP_OBJ *ap)
{
	const USR_PERIPHERAL	*per;

	if (ap->disp_flag == ON) {
		ap_disp_info(ap);
	}

	per = UsrGetPeripheral(0);	
	if (per->press & UTPAD_L) {
		ap->disp_flag = NOT_FLAG(ap->disp_flag);
	}
	if (per->press & UTPAD_BUTTON1) {
		ap->fname_index = 0;
		ADXCS_StartFname(ap->adxcs_bgm, ap->fname_bgm[ap->fname_index]);
	}
	if (per->press & UTPAD_BUTTON2) {
		ap->fname_index = 1;
		ADXCS_StartFname(ap->adxcs_bgm, ap->fname_bgm[ap->fname_index]);
	}
	if (per->press & UTPAD_BUTTON3) {
		ADXCS_StartFname(ap->adxcs_voice, ap->fname_voice);
	}
	if (per->press & UTPAD_BUTTON4) {
		ADXCS_Stop(ap->adxcs_voice);
	}
	if (per->press & UTPAD_DOWN) {
		ADXCS_SetOutVol(ap->adxcs_bgm, ADXT_MIN_OUTVOL);
	}
	if (per->press & UTPAD_UP) {
		ADXCS_SetOutVol(ap->adxcs_bgm, ADXT_MAX_OUTVOL);
	}
	if (per->press & UTPAD_START) {
		return FALSE;
	}

	if (ADXCS_GetStat(ap->adxcs_bgm) == ADXCS_STAT_PLAYEND) {
		return FALSE;
	}

	/* 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 */
