/*
 *	app.c
 *
 *	P/ECEアプリケーションの雛型（CLiPライブラリ版）
 *
 *	* Tue Jul 23 21:01:00 JST 2002 Naoyuki Sawa
 *	- 作成開始。
 */
#include "app.h"

/****************************************************************************
 *	
 ****************************************************************************/

#ifdef USE_SOUND
const void* sound_table[SOUND_COUNT];
#endif /*USE_SOUND*/

#ifdef USE_TEXTURE
TEXTURE texture_table[TEXTURE_COUNT];
#endif /*USE_TEXTURE*/

#ifdef USE_SPRITE
#define SPRITE_ SPRITE_INIT2
const SPRITE sprite_table[SPRITE_COUNT] = {
#include "sprite.h"
};
#undef SPRITE_
#endif /*USE_SPRITE*/

/****************************************************************************
 *	main
 ****************************************************************************/

int main() {
#ifdef  USE_ARGS
	static char cmdline[128] = PRESCAN_STRINGIFY(PROJECT);	//「r.exe」にコマンドライン引数を指定した場合、ここが書き換えられます。
	char** const argv = strsplit(cmdline, " ", 0);
	int    const argc = strv_length(argv);
#else //USE_ARGS
	char** const argv = (char*[]){ PRESCAN_STRINGIFY(PROJECT), NULL };
	int    const argc = 1;
#endif//USE_ARGS
	/* 呼び出し元プログラムの起動に使用された名前を設定します。 */
	program_invocation_short_name = basename((program_invocation_name = argv[0]));
	/* 捕捉されなかった例外を捕えるための、例外フレームを初期化します。 */
	SEH_init();
	/* アプリケーションを初期化します。 */
	app_init(argc, argv);
	/* メインループを実行します。 */
	return app_main(argc, argv);
}

/****************************************************************************
 *	app_init
 ****************************************************************************/

#ifdef  USE_SOUND_MANAGER
static void sound_play_stub(int iCh, int iData, int iLoop) {
	if((unsigned)iData >= SOUND_COUNT) { DIE(); }
	sound_play(iCh, sound_table[iData], iLoop);
}
#endif/*USE_SOUND_MANAGER*/

#ifdef  USE_SOUND_MIXER
//【注意】
//│配列TBL_TapMxrChMask[]は必ずint配列として定義して下さい。
//│ミキサーチャネルが少なくてビット数が足りたとしても、配列TBL_TapMxrChMask[]をuint8_t配列やuint16_t配列として定義してはいけません。
//│この下のset_att()にて配列TBL_TapMxrChMask[]の要素へのポインタをTapMxr_GetAtt()の引数aMxrChMaskとして引き渡しており、TapMxr_GetAtt()は引数aMxrChMaskがint境界に整列している事を前提としてアクセスしているからです。
//│もし配列TBL_TapMxrChMask[]をuint8_t配列やuint16_t配列として定義してしまうと、この下のset_att()から呼び出したTapMxr_GetAtt()の中でアドレスエラーが発生します。
static const int TBL_TapMxrChMask[(TapLogCh_Max+1)]={
BIN8(00000111),	//論理ﾁｬﾈﾙ0に適用するﾐｷｻｰﾁｬﾈﾙのﾋﾞｯﾄﾏｽｸ	ｽﾃｰｼﾞBGM
BIN8(00000110),	//論理ﾁｬﾈﾙ1に適用するﾐｷｻｰﾁｬﾈﾙのﾋﾞｯﾄﾏｽｸ	演出BGM
BIN8(00000110),	//論理ﾁｬﾈﾙ2に適用するﾐｷｻｰﾁｬﾈﾙのﾋﾞｯﾄﾏｽｸ	演出SE
BIN8(00000110),	//論理ﾁｬﾈﾙ3に適用するﾐｷｻｰﾁｬﾈﾙのﾋﾞｯﾄﾏｽｸ	演出SE
BIN8(00000110),	//論理ﾁｬﾈﾙ4に適用するﾐｷｻｰﾁｬﾈﾙのﾋﾞｯﾄﾏｽｸ	演出SE
BIN8(00000110),	//論理ﾁｬﾈﾙ5に適用するﾐｷｻｰﾁｬﾈﾙのﾋﾞｯﾄﾏｽｸ	UI
BIN8(00000110),	//論理ﾁｬﾈﾙ6に適用するﾐｷｻｰﾁｬﾈﾙのﾋﾞｯﾄﾏｽｸ	UI
BIN8(00000100)};//論理ﾁｬﾈﾙ7に適用するﾐｷｻｰﾁｬﾈﾙのﾋﾞｯﾄﾏｽｸ	ｴﾗｰ音
//        ||+--- TAPﾐｷｻｰﾁｬﾈﾙ1:演出BGM再生中	減音対象論理ﾁｬﾈﾙ:ｽﾃｰｼﾞBGM
//        |+---- TAPﾐｷｻｰﾁｬﾈﾙ2:ｴﾗｰ音再生中	減音対象論理ﾁｬﾈﾙ:ｴﾗｰ音以外
//        +----- TAPﾐｷｻｰﾁｬﾈﾙ0:ﾄｰﾀﾙﾚﾍﾞﾙ		減音対象論理ﾁｬﾈﾙ:全て
static void set_att(int iLogCh, ST_TapLogCh* pLogCh) {	//この論理ﾁｬﾈﾙの減衰量と､この論理ﾁｬﾈﾙに適用するﾐｷｻｰﾁｬﾈﾙの合計減衰量を､この論理ﾁｬﾈﾙが制御しているﾃﾞﾊﾞｲｽﾁｬﾈﾙに適用する｡	(pLogCh->iDevCh==UINT8_MAX)の時に呼び出してはいけない｡
	int iAtt=pLogCh->iAtt;					//この論理ﾁｬﾈﾙの減衰量				//2次ﾎﾞﾘｭｰﾑ相当
	iAtt+=TapMxr_GetAtt(pTapMxr,&TBL_TapMxrChMask[iLogCh]);	//この論理ﾁｬﾈﾙに適用するﾐｷｻｰﾁｬﾈﾙの合計減衰量	//1次ﾎﾞﾘｭｰﾑ相当
	sound_att(pLogCh->iDevCh,iAtt);				//この論理ﾁｬﾈﾙが制御しているﾃﾞﾊﾞｲｽﾁｬﾈﾙに､上記2点の合計減衰量を適用する｡
}
static void TapMxr_TimerProc(void* iTime) {	//TAPﾐｷｻｰ用ﾀｲﾏ割込処理
	int iDevCh,iLogCh;
	if(TapSeq_GetLogCh(pTapSeq,TapLogCh_Bg2)->iPhr!=UINT16_MAX){TapMxrCh_SetAtt(pTapMxr,TapMxrCh_Stg,64, 0,  0);}	//論理ﾁｬﾈﾙ1で演出BGMが再生中ならば､ｽﾃｰｼﾞBGMを即消音する｡		┐
	else                                                       {TapMxrCh_SetAtt(pTapMxr,TapMxrCh_Stg, 0,64,500);}	//論理ﾁｬﾈﾙ1で演出BGMが停止中ならば､ｽﾃｰｼﾞBGMを0.5秒で復帰する｡		├{{TODO:ｱﾌﾟﾘｹｰｼｮﾝ調整}}
	if(TapSeq_GetLogCh(pTapSeq,TapLogCh_Err)->iPhr!=UINT16_MAX){TapMxrCh_SetAtt(pTapMxr,TapMxrCh_Err,64, 0,  0);}	//論理ﾁｬﾈﾙ7でｴﾗｰ音が再生中ならば､ｽﾃｰｼﾞBGM,演出BGM,SEを即消音する｡	│
	else                                                       {TapMxrCh_SetAtt(pTapMxr,TapMxrCh_Err, 0, 0,  0);}	//論理ﾁｬﾈﾙ7でｴﾗｰ音が停止中ならば､ｽﾃｰｼﾞBGM,演出BGM,SEを即復帰する｡	┘
	TapMxr_Exec(pTapMxr,(int)iTime);	//TAPﾐｷｻｰを実行する｡
	for(iDevCh=0;iDevCh<pTapSeq->pInfo->nDevCh;iDevCh++){	//ﾃﾞﾊﾞｲｽﾁｬﾈﾙの減衰量を設定する｡
		iLogCh=TapSeq_GetDevCh(pTapSeq,iDevCh)->iLogCh;
		if(iLogCh!=UINT8_MAX){		//このﾃﾞﾊﾞｲｽﾁｬﾈﾙを制御している論理ﾁｬﾈﾙが有れば…
			ST_TapLogCh* pLogCh=TapSeq_GetLogCh(pTapSeq,iLogCh);
			set_att(iLogCh,pLogCh);	//この論理ﾁｬﾈﾙの減衰量と､この論理ﾁｬﾈﾙに適用するﾐｷｻｰﾁｬﾈﾙの合計減衰量を､ﾃﾞﾊﾞｲｽﾁｬﾈﾙに適用する｡
		}
	}
}
#endif/*USE_SOUND_MIXER*/

#ifdef  USE_SOUND_SEQUENCER
static void TapSeq_fnPlay(ST_TapSeq* pTapSeq, int iLogCh, ST_TapLogCh* pLogCh) {
	if(pLogCh->iDevCh==UINT8_MAX){return;}
	set_att(iLogCh,pLogCh);
	sound_play(pLogCh->iDevCh,sound_table[pLogCh->iPhr],pLogCh->iLoop?pLogCh->iLoop:-1);
}
static void TapSeq_fnStop(ST_TapSeq* pTapSeq, int iLogCh, ST_TapLogCh* pLogCh) {
	if(pLogCh->iDevCh==UINT8_MAX){return;}
	sound_stop(pLogCh->iDevCh);
}
static void TapSeq_fnLoop(ST_TapSeq* pTapSeq, int iLogCh, ST_TapLogCh* pLogCh) {
	/** no job **/
}
static void TapSeq_fnEnd(ST_TapSeq* pTapSeq, int iLogCh, ST_TapLogCh* pLogCh) {
	/** no job **/
}
static void TapSeq_fnNext(ST_TapSeq* pTapSeq, int iLogCh, ST_TapLogCh* pLogCh) {
	if(pLogCh->iDevCh==UINT8_MAX){return;}
	set_att(iLogCh,pLogCh);
	sound_play(pLogCh->iDevCh,sound_table[pLogCh->iPhr],pLogCh->iLoop?pLogCh->iLoop:-1);
}
static void TapSeq_fnCtrl(ST_TapSeq* pTapSeq, int iLogCh, ST_TapLogCh* pLogCh) {
	if(pLogCh->iDevCh==UINT8_MAX){return;}
	set_att(iLogCh,pLogCh);
}
static int TapSeq_fnGetPhrTime(ST_TapSeq* pTapSeq, int iPhr) {
	return ppd_playback_time(sound_table[iPhr]);
}
static int TapSeq_fnGetPhrNext(ST_TapSeq* pTapSeq, int iPhr) {
#ifdef  USE_REG
    #ifdef  RegKey_Next
	//フレーズシーケンスをレジストリから取得する場合。
	iPhr++;			//sound.hは0ベース,フレーズシーケンスは1ベースなので、一時的に1ベースに変換する。詳細は、/clip/tool/dPhrDefC/winapp.c を参照せよ。
	iPhr = REG_get_value_l(TBL_RegTbl,RegKey_PhrDef,iPhr,RegKey_Next,-1)<<8>>8;	//通常フレーズ(-1),中間フレーズ(<>iPhr),ループフレーズ(=iPhr),完全フレーズ(-2)
	if(iPhr>=0){iPhr--;}	//通常フレーズ(-1),又は,完全フレーズ(-2)以外ならば、sound.hの値(=0ベース)に戻す。
	return iPhr;
    #else //RegKey_Next
	//フレーズシーケンスをレジストリから取得するが、全て通常フレーズである場合は'RegKey_Next'が定義されない。
	return -1;
    #endif//RegKey_Next
#else /*USE_REG*/
	//フレーズシーケンスをプログラムで処理する場合。
	return (iPhr==SND_BGM_1G)||(iPhr==SND_BGM_ST)?iPhr:-1;
#endif/*USE_REG*/
}
static void TapSeq_TimerProc(void* iTime) {
	TapSeq_Exec(pTapSeq,(int)iTime);
}
#endif/*USE_SOUND_SEQUENCER*/

#ifdef  USE_EVENT_TIMER
static void EvtTmr_onEvent(int iEvtTmrCh, int iEvent) { //ｲﾍﾞﾝﾄﾀｲﾏ用ｲﾍﾞﾝﾄ処理関数
	TRACE("%d:%d:%d\n", now/FPS, iEvtTmrCh, iEvent);
}
#endif/*USE_EVENT_TIMER*/

#ifdef  USE_LOG_BUFFER
static int LogBuf_fnDraw(int x, int y, const char* Str) { //ｱﾌﾟﾘｹｰｼｮﾝ定義の文字列描画関数
	render_reduced_string(&render, x, y, Str, 3);
	return 10;
}
#endif/*USE_LOG_BUFFER*/

#ifdef  USE_NVLOG
void nvlog_(const char* fmt, ...) {
	va_list ap;
	va_start(ap, fmt);
	nvlog_vprintf(nvlog, fmt, ap);
	va_end(ap);
	pceFileWriteSct(&faNvLog, nvlog, 0, NVLOG_SIZE);
}
#endif//USE_NVLOG

#ifdef  USE_TCL
//srand seed
static int Tcl_SrandCmd(Tcl_Interp* iPtr) {
	if((iPtr->argc < 1) || (iPtr->argc > 2)) { DIE(); }
	srand((iPtr->argc == 2) ? atoi(iPtr->argv[1]) : time(NULL));
	return TCL_OK;
}
//rand
static int Tcl_RandCmd(Tcl_Interp* iPtr) {
	if(iPtr->argc != 1) { DIE(); }
	iPtr->result = strdup_printf("%d", rand());
	return TCL_OK;
}
//log string
static int Tcl_LogCmd(Tcl_Interp* iPtr) {
	if(iPtr->argc != 2) { DIE(); }
#ifdef  USE_LOG_BUFFER
	LogBuf_Print(pLogBuf, iPtr->argv[1]);
	update();
#else //USE_LOG_BUFFER
	TRACE("%s\n", iPtr->argv[1]);
#endif//USE_LOG_BUFFER
	return TCL_OK;
}
//schedule
static int Tcl_ScheduleCmd(Tcl_Interp* iPtr) {
	if(iPtr->argc != 1) { DIE(); }
	schedule();
	return TCL_OK;
}
#endif//USE_TCL

void app_init(int argc, char* argv[]) {
#ifdef  USE_USBSUSPEND_PROBLEMWORKAROUND
	//「USBがサスペンドした時にP/ECEがハングアップする事が有る問題」を回避する処理を設定します。
	Intel915G_WindowsXp_UsbSuspend_ProblemWorkaround_init();
#endif//USE_USBSUSPEND_PROBLEMWORKAROUND

	/* 一般的な初期化。 */
	pceAppSetProcPeriod(1000 / FPS);
#ifdef V_SCREEN
	pceLCDSetBuffer(_def_vbuff);
#else /*V_SCREEN*/
	pceLCDSetBuffer(vbuff);
#endif /*V_SCREEN*/
//不要	pceLCDDispStart();	//{{2014/12/31削除:cstart.cのpceAppInit00()でpceLCDDispStart()を呼び出し、液晶画面の表示を開始するようにしました。}}

#ifdef USE_REPEAT
	/* オートリピートを設定します。 */
    #ifdef  V_SCREEN
	pad_set_repeat(((REPEAT_PAD) & ~(PAD_LF|PAD_RI|PAD_UP|PAD_DN))	//縦画面用設定変換(schedule()にて行っている縦画面用入力変換の逆の変換です。)
	             | ((REPEAT_PAD) & PAD_LF ? PAD_DN : 0)
	             | ((REPEAT_PAD) & PAD_RI ? PAD_UP : 0)
	             | ((REPEAT_PAD) & PAD_UP ? PAD_LF : 0)
	             | ((REPEAT_PAD) & PAD_DN ? PAD_RI : 0), REPEAT_DELAY, REPEAT_INTERVAL);
    #else //V_SCREEN
	pad_set_repeat(REPEAT_PAD, REPEAT_DELAY, REPEAT_INTERVAL);
    #endif//V_SCREEN
#endif /*USE_REPEAT*/

	/* 描画環境初期化。 */
	surface.w = DISP_X;
	surface.h = DISP_Y;
	surface.vbuff = vbuff;
#ifdef USE_3D
	surface.zbuff = zbuff;
	render_init_3d(&render, &surface, 0, 0, 0, 0, FRONT, BACK, FOVY);
#else /*USE_3D*/
	render_init_2d(&render, &surface, 0, 0, 0, 0);
#endif /*USE_3D*/
#ifdef USE_RENDF
	surface.zbuff = zbuff;
	rendf_init(&rendf, &surface, 0, 0, 0, 0, FRONT, BACK, FOVY);
#endif /*USE_RENDF*/

#if defined(TRACE_ON) && (TRACE_ON)
	/* 標準エラー出力を開きます。 */
	stderr_open(9/*標準エラー出力モニタ接続待ち時間(調整可)*/);
#endif /*TRACE_ON*/

#ifdef USE_UFE
	/* USBファイルシステムエミュレーションを開始します。 */
	ufe_setup(9/*PC側ファイルサーバ接続待ち時間(調整可)*/);
#endif /*USE_UFE*/

#ifdef USE_RESOURCE
	/* pexファイル添付リソースを取得します。 */
	resource = resource_address(PRESCAN_STRINGIFY(PROJECT) ".pex");
#endif /*USE_RESOURCE*/

#ifdef TURBO
	/* クロック・メモリウェイトを切替えます。 */
	turbo(TURBO);
#endif /*TURBO*/

#ifdef USE_DBG
	/* DBGユニットを設定します。 */
	dbg_init();
#endif /*USE_DBG*/

#ifdef GC_LEVEL
	/* ガーベージコレクターを初期化します。 */
	gc_init(GC_LEVEL);
#endif /*GC_LEVEL*/

#ifdef BITMAP_GC_UNIT
	/* Bitmap GCを初期化します。 */
	BitmapGC_Init(BITMAP_GC_UNIT);
#endif /*BITMAP_GC_UNIT*/

#ifdef  USE_PCL
	/* コルーチンを初期化します。 */
	co_thread_init();
#endif//USE_PCL

#ifdef LDIRECT_INTERVAL
	/* 高速切替・16階調表示を初期化します。 */
	ldirect_init(LDIRECT_INTERVAL);
#endif /*LDIRECT_INTERVAL*/

#ifdef USE_VQTC
	/* VQ圧縮テクスチャ描画を初期化します。 */
	VqTc_InitDrawing();
#endif /*USE_VQTC*/

#ifdef USE_MUSIC
	/* 音楽ライブラリを初期化します。 */
	InitMusic();
#if defined(USE_2BIT_ADPCM) || defined(USE_TRUESPEECH)
	/* - 2-bit ADPCM Decoder,又は,DSP Group TrueSpeech Decoderと、音楽ライブラリを併用する場合は、音楽ライブラリ側の使用チャネルをずらすことにしました。
	 *   この対策を行わないと、両方がチャネル0を使用しようとして、ハングアップしてしまいます。
	 * - 2-bit ADPCM Decoder,又は,DSP Group TrueSpeech Decoderに限らず、stream_play()を利用する機能と、音楽ライブラリと併用する場合は、同様の対策が必要です。
	 * //{{2015/01/15コメント削除:muslib.c版のInitMusic()は「music_wch = 0;」を行わないようにしたので、どのタイミングでmusic_wchを変更しても構いません。
	 * //- music_wchを変更する処理は、InitMusic()よりも後で行う必要があります。
	 * //  InitMusic()が、「music_wch = 0;」を行っているからです。InitMusic()よりも先に変更すると、0に戻ってしまいます。
	 * //- 尚、music_loudness()の機能もmusic_wchを参照していますが、
	 * //  随時、値を取得しているので、music_loudness()を呼び出した後にmusic_wchを変更しても、問題はありません。
	 * //}}2015/01/15コメント削除:muslib.c版のInitMusic()は「music_wch = 0;」を行わないようにしたので、どのタイミングでmusic_wchを変更しても構いません。 */
	music_wch = 3; /* チャネル0=2-bit ADPCM Decoder,又は,DSP Group TrueSpeech Decoder、チャネル1-2=アプリケーション使用、チャネル3=音楽ライブラリとする */
#endif /*defined(USE_2BIT_ADPCM) || defined(USE_TRUESPEECH)*/
#endif /*USE_MUSIC*/

	/* クリーンアップ関数を登録。 */
	atexit(app_exit);

#ifdef USE_2BIT_ADPCM
	/* 2-bit ADPCM Decoderを起動します。 */
	adpcm_init(SOUND_MAXCH);
#endif /*USE_2BIT_ADPCM*/

#ifdef USE_TRUESPEECH
	/* DSP Group TrueSpeech Decoderを起動します。 */
	TrueSpeech_Init(SOUND_MAXCH);
#endif /*USE_TRUESPEECH*/

	/* サウンドを初期化します。 */
#ifdef USE_SOUND
	{
#define SOUND_(name) { extern const unsigned char name[]; sound_table[SND_##name] = name; }
#define SOUND_RESOURCE_(name,fname) { sound_table[SND_##name] = fpk_address(resource, fname, NULL); }
#include "sound.h"
#undef SOUND_
#undef SOUND_RESOURCE_
	}
#endif /*USE_SOUND*/

	/* Sound Managerを初期化します。 */
#ifdef  USE_SOUND_MANAGER
	{
		static const ST_SndMgrInfo stSndMgrInfo = { sound_play_stub, sound_stop, sound_stat, sound_att };
		pSndMgrBgm = SndMgr_Init(&stSndMgrInfo, SOUND_MANAGER_BGM_MINCH, SOUND_MANAGER_BGM_MAXCH); /* BGM Sound Manager */
		pSndMgrSe1 = SndMgr_Init(&stSndMgrInfo, SOUND_MANAGER_SE1_MINCH, SOUND_MANAGER_SE1_MAXCH); /* SE1 Sound Manager */
		pSndMgrSe2 = SndMgr_Init(&stSndMgrInfo, SOUND_MANAGER_SE2_MINCH, SOUND_MANAGER_SE2_MAXCH); /* SE2 Sound Manager */
	}
#endif/*USE_SOUND_MANAGER*/

	/* TAPﾐｷｻｰを初期化します｡ */
#ifdef  USE_SOUND_MIXER
	{
		pTapMxr=TapMxr_New(TapMxrCh_Max+1);
		timer_start(100,TapMxr_TimerProc,(void*)100);	//TAPﾐｷｻｰ用ﾀｲﾏ割込処理を開始する｡
	}
#endif/*USE_SOUND_MIXER*/

	/* TAPｼｰｹﾝｻを初期化します｡ */
#ifdef  USE_SOUND_SEQUENCER
	{
		static const uint8_t* const TBL_TapSet[]={
			(uint8_t[]){TapDevCh_Bg1,-1},			//ｽﾃｰｼﾞBGM
			(uint8_t[]){TapDevCh_Bg2,-1},			//演出BGM
			(uint8_t[]){TapDevCh_Se1,TapDevCh_Se2,-1},	//演出SE
			(uint8_t[]){TapDevCh_Se1,TapDevCh_Se2,-1},	//演出SE
			(uint8_t[]){TapDevCh_Se1,TapDevCh_Se2,-1},	//演出SE
			(uint8_t[]){TapDevCh_Ui1,TapDevCh_Ui2,-1},	//UI
			(uint8_t[]){TapDevCh_Ui1,TapDevCh_Ui2,-1},	//UI
			(uint8_t[]){TapDevCh_Ui1,TapDevCh_Ui2,-1},	//ｴﾗｰ音
		};
		static const uint8_t TBL_BaseCh[]={
			0,	//ｽﾃｰｼﾞ	┐
			0,	//演出	│2017/02/09現在のsnd/TapDef.txtでは、シーケンサデータの中で論理チャネル番号を直接指定しているので、TBL_BaseCh[]によるオフセットは0としてあります。
			0,	//UI	│もし今後、シーケンサデータの中で論理チャネル番号を相対指定するように変更した場合は、TBL_BaseCh[]によるオフセットも適切に変更して下さい。
			0,	//ｴﾗｰ	┘
		};
		static const ST_TapSeqInfo stTapSeqInfo={
			SOUND_COUNT,			//nPhr
			TapDevCh_Max+1,			//nDevCh
			TapLogCh_Max+1,			//nLogCh
			TapSeqCh_Max+1,			//nSeqCh
			1000/FPS,			//iCont
			0,				//iPrep
			31/*調整可*/,			//nEvt
			~(1<<TapEvt_Ctrl)/*変更可*/,	//iEvtMsk
			TapSeq_fnPlay,
			TapSeq_fnStop,
			TapSeq_fnLoop,
			TapSeq_fnEnd,
			TapSeq_fnNext,
			TapSeq_fnCtrl,
			NULL,				//fnPrep
			TapSeq_fnGetPhrTime,
			TapSeq_fnGetPhrNext,
			TBL_TapSet,
			TBL_BaseCh,
		};
		if(ARRAY_SIZE(TBL_TapSet) != (TapLogCh_Max+1)) { DIE(); }
		if(ARRAY_SIZE(TBL_BaseCh) != (TapSeqCh_Max+1)) { DIE(); }
		pTapSeq=TapSeq_New(&stTapSeqInfo);
		timer_start(10,TapSeq_TimerProc,(void*)10);	//ｻｳﾝﾄﾞｼｰｹﾝｻ用ﾀｲﾏ割込処理を開始する｡
	}
#endif/*USE_SOUND_SEQUENCER*/

	/* LEDシーケンサを初期化します。 */
#ifdef  USE_LED
	pLedSeq = LedSeq_New(LedCh_Max + 1, LedSeqCh_Max + 1);
#endif//USE_LED

	/* イベントタイマを初期化します。 */
#ifdef  USE_EVENT_TIMER
	{
		static ST_EvtTmrFunc stEvtTmrFunc = { EvtTmr_onEvent };
		pEvtTmr = EvtTmr_New(EvtTmrNo_Max+1);	//ｲﾍﾞﾝﾄﾀｲﾏを初期化する｡
		EvtTmr_AddFunc(pEvtTmr, &stEvtTmrFunc);	//ｲﾍﾞﾝﾄ処理関数を登録する｡
	}
#endif/*USE_EVENT_TIMER*/

	/* 汎用カウンタ管理を初期化します。 */
#ifdef  USE_COUNTER_MANAGER
	pCntMgr = CntMgr_New(CntCh_Max+1);
#endif/*USE_COUNTER_MANAGER*/

	/* 存続カウンタを初期化します。 */
#ifdef  USE_DURATION_COUNTER
	pDurCnt = DurCnt_New();
#endif/*USE_DURATION_COUNTER*/

	/* ログバッファを初期化します。 */
#ifdef  USE_LOG_BUFFER
	pLogBuf = LogBuf_Init((DISP_Y+9)/10, LogBuf_fnDraw);
#endif/*USE_LOG_BUFFER*/

	//不揮発性ログバッファを初期化します。
#ifdef  USE_NVLOG
	{
		time_t t;
		pceFileCreate("nvlog.bin", NVLOG_SIZE);
		pceFileOpen(&faNvLog, "nvlog.bin", FOMD_WR);
		pceFileReadSct(&faNvLog, nvlog, 0, NVLOG_SIZE);	//前回のログに追加する事にした。毎回空の状態から開始したい場合はこの行を削除せよ。
		time(&t);
		NVLOG("Start at %s", strstrip(ctime(&t)));
	}
#endif//USE_NVLOG

#ifdef  USE_TCL
	//Tclインタプリタを高速化するために、定期的にガーベージコレクションを行う。
#if     defined(GC_LEVEL)
/*必須*/timer_start(500/*調整可*/, gc_run, NULL);//cliptcl.cのコメント参照。通常のGCでTclインタプリタを使用する場合は、この行を実行しないと極端に遅くなる。
#elif   defined(BITMAP_GC_UNIT)
//任意	timer_start(500/*調整可*/, gc_run, NULL);//cliptcl.cのコメント参照。Bitmap GCを使用する場合は極端に遅くはないが、この行を実行する方が高速ではある。
#else //defined(GC_LEVEL)||defined(BITMAP_GC_UNIT)
	#error Tclインタプリタはガーベージコレクターの併用が必須です。
#endif//defined(GC_LEVEL)||defined(BITMAP_GC_UNIT)
	//Tclインタプリタを作成する。
	iPtr = Tcl_CreateInterp();
	//汎用的なアプリケーション定義のコマンドを登録する。
	Tcl_CreateCommand(iPtr, "srand",    Tcl_SrandCmd,    NULL);
	Tcl_CreateCommand(iPtr, "rand",     Tcl_RandCmd,     NULL);
	Tcl_CreateCommand(iPtr, "log",      Tcl_LogCmd,      NULL);
	Tcl_CreateCommand(iPtr, "schedule", Tcl_ScheduleCmd, NULL);
#endif//USE_TCL

	/* テクスチャを初期化します。 */
#ifdef USE_TEXTURE
	{
#define TEXTURE_(name) extern const unsigned char name[];
#define TEXTURE_RESOURCE_(name,fname) const void* const name = fpk_address(resource, fname, NULL);
#include "texture.h"
#undef TEXTURE_
#undef TEXTURE_RESOURCE_
		texture_table_init(texture_table, TEXTURE_COUNT,
#define TEXTURE_(name) name,
#define TEXTURE_RESOURCE_(name,fname) name,
#include "texture.h"
#undef TEXTURE_
#undef TEXTURE_RESOURCE_
		NULL/*最後の','を吸収するためのダミー。texture_table_init()に対しては無意味です。*/);
	}
#endif /*USE_TEXTURE*/

#ifdef USE_SPRITE
	/* 簡易スプライトドライバを初期化します。 */
	sprite_init(&render, sprite_table, SPRITE_COUNT, texture_table, TEXTURE_COUNT);
#endif /*USE_SPRITE*/

#ifdef  USE_CBKQUE
	/* コールバックキューを初期化します。 */
	pCbkQue = DynamicCbkQue_New(2048/*調整可*/);	//2048でCbkQue_sprite_draw()x100回分ぐらいです。CbkQue_render_printf()等を使うともっと消費します。動的コールバックキューなので小さな値でも(0でも)構いません。
#endif//USE_CBKQUE

#ifdef  USE_DLYQUE
	/* 遅延コールバックキューを初期化します。 */
	pDlyQue = DlyQue_New();
#endif//USE_DLYQUE

#ifdef USE_TCPIP
	/* TCP/IPプロトコルスイートを開始します。 */
	tcpip_start(0/*Ethernetドライバ送信バッファサイズ(調整可)*/);
#endif /*USE_TCPIP*/

#ifdef USE_VIDREC
	/* 画面出力を初期化します。 */
	yield(); /* runで実行した場合の実行確認に応答するため、USB機能の切り替えを僅かに遅らせる */
#ifdef LDIRECT_INTERVAL
	cdcacm_start(0, sizeof vbuff / 2, NULL, NULL);
#else /*LDIRECT_INTERVAL*/
	cdcacm_start(0, sizeof vbuff / 4, NULL, NULL);
#endif /*LDIRECT_INTERVAL*/
#endif /*USE_VIDREC*/

#ifdef  USE_TASK
	/* タスクスケジューラを初期化します。
	 * - アイドルスレッドと併用する場合は、idle_proc()の中で初期化してください。
	 *   アイドルスレッドと併用する方法は、task_yield()の[note]を参照してください。 */
	task_init(INT_MIN);//{{TODO:ｼｽﾃﾑｱｲﾄﾞﾙﾀｽｸの実行優先度はｱﾌﾟﾘｹｰｼｮﾝ調整}}
#endif/*USE_TASK*/

#if     (defined(USE_ENM)&&defined(USE_REG))
	/* 列挙定義キーを取得します。 */
	pEnmKey = REG_open_key(TBL_RegTbl, RegKey_EnmDef);
#endif//(defined(USE_ENM)&&defined(USE_REG))

#ifdef  USE_PRP
	/* プロパティテーブルキーを取得します。 */
	pPrpKey = REG_open_key(TBL_RegTbl, RegKey_PrpTbl);
	if(!pPrpKey) { DIE(); }
	/* プロパティヘッダを初期化します。 */
	PrpHdr_init(phApp, pPrpKey, PrpTbl_App);	//ﾃﾝﾌﾟﾚｰﾄとして1個だけ定義しました｡必要に応じて定義を追加して下さい｡
#endif//USE_PRP

#ifdef  USE_FSM
	/* 有限状態機械マップキーを取得します。 */
	pFsmKey = REG_open_key(TBL_RegTbl, RegKey_FsmMap);
	if(!pFsmKey) { DIE(); }
	/* 有限状態機械を初期化します。 */
	FsmObj_Init(&foApp, pFsmKey, FsmMap_App, NULL);	//ﾃﾝﾌﾟﾚｰﾄとして1個だけ定義しました｡必要に応じて定義を追加して下さい｡
#endif//USE_FSM

#ifdef  USE_ACT
	/* アクターオブジェクトを初期化します。 */
	aoApp = ActObj_New(NULL);
#endif//USE_ACT

#ifdef  USE_RRS
	/* Round Robin Scheduler (RRS)を初期化します。 */
	RRS_new_l(&pRRS, 0/*stacksize*/,	//{{TODO:変更可}}
		//{{TODO:ここにジョブ関数を列挙して下さい。}}
		NULL/*終端*/);
#endif//USE_RRS
#ifdef  USE_MSGHSK
	//メッセージハンドシェイクを初期化する。
	MsgHsk_Init(&stMsgHsk, pRRS);
#endif//USE_MSGHSK

#ifdef  USE_NUKLEAR
	//Nuklearコンテキストを作成する。
	ctx = nk_piece_new();
#endif//USE_NUKLEAR

/*{{アプリケーション特有の初期化*/
	srand(pceTimerGetCount());
/*}}アプリケーション特有の初期化*/
}

/****************************************************************************
 *	app_exit
 ****************************************************************************/

void app_exit() {
/*{{アプリケーション特有のクリーンアップ*/
	/** no job **/
/*}}アプリケーション特有のクリーンアップ*/

#ifdef USE_VIDREC
	/* 画面出力を終了します。 */
	cdcacm_stop();
#endif /*USE_VIDREC*/

#ifdef USE_TCPIP
	/* TCP/IPプロトコルスイートを終了します。 */
	tcpip_stop();
#endif /*USE_TCPIP*/

#ifdef USE_VQTC
	/* VQ圧縮テクスチャ描画を解除します。 */
	VqTc_ExitDrawing();
#endif /*USE_VQTC*/

#ifdef LDIRECT_INTERVAL
	/* 高速切替・16階調表示を解除します。 */
	ldirect_free();
#endif /*LDIRECT_INTERVAL*/

#ifdef  USE_PCL
	/* コルーチンを終了します。 */
	co_thread_cleanup();
#endif//USE_PCL

#ifdef BITMAP_GC_UNIT
	/* Bitmap GCを解除します。 */
	BitmapGC_Free();
#endif /*BITMAP_GC_UNIT*/

#ifdef GC_LEVEL
	/* ガーベージコレクターを解除します。 */
	gc_free();
#endif /*GC_LEVEL*/

#ifdef USE_DBG
	/* DBGユニットの設定を解除します。 */
	dbg_free();
#endif /*USE_DBG*/

#ifdef USE_UFE
	/* USBファイルシステムエミュレーションを終了します。 */
	ufe_stop();
#endif /*USE_UFE*/

#ifdef  USE_USBSUSPEND_PROBLEMWORKAROUND
	//「USBがサスペンドした時にP/ECEがハングアップする事が有る問題」を回避する処理を解除します。
	Intel915G_WindowsXp_UsbSuspend_ProblemWorkaround_free();
#endif//USE_USBSUSPEND_PROBLEMWORKAROUND
}

/****************************************************************************
 *	update
 ****************************************************************************/

/* * Mon Mar 10 13:29:56 JST 2008 Naoyuki Sawa
 * - update()から、画面更新処理を分離し、高速化しました。
 */
#ifdef V_SCREEN
/* vbuff(縦画面)→_def_vbuff(横画面)変換 */
//static void rotate_screen() {
//	unsigned char *src = &vbuff[88 - 1];	/* 転送先の横画面は左上から走査開始します */
//	unsigned char *dst = &_def_vbuff[0];	/* 転送元の縦画面は右上から走査開始します */
//	int x = 88;
//	do {
//		int y = 128;
//		do {
//			*dst++ = *src;		/* 横画面を右方向に走査します */
//			src += 88;		/* 縦画面を下方向に走査します */
//		} while(--y);
//						/* 横画面は既に次の行へ移動しています */
//		src -= 88 * 128 + 1;		/* 縦画面を左の列の一番上へ移動します */
//	} while(--x);
//}
//↓高速化 (C版 = 9.2ms/1call → ASM版 = 3.2ms/1call)
/*static*/ void rotate_screen();
asm("
	.code
	.align	1
rotate_screen:
	xld.w	%r12, 0x0e00			; %r12 := FRAM4_START
	xld.w	%r13, rotate_screen_DOX		; %r13 := DOY
	xld.w	%r14, rotate_screen_END		; %r14 := END
	xcall.d	memcpy				; %r10 := FRAM4_START = memcpy(FRAM4_START, DOX, END - DOX)
	sub	%r14, %r13			; %r14 := END - DOY			*delay*
	xld.w	%r4, vbuff+87			; %r4  := src = &vbuff[88 - 1]
	xld.w	%r5, _def_vbuff			; %r5  := dst = &_def_vbuff[0]
	xld.w	%r6, 88				; %r6  := 88
	xld.w	%r7, 128			; %r7  := 128
	xld.w	%r11, 11265			; %r11 := 88 * 128 + 1
	ld.w	%r12, %r6			; %r12 := x = 88
	jp	%r10				; goto FRAM4_START			(jp.dは不可!!)
;//{{ここからFRAM4領域へ転送
rotate_screen_DOX:				; do {
	ld.w	%r13, %r7			;   %r13 := y = 128
rotate_screen_DOY:				;   do {
	ld.ub	%r9, [%r4]			;     %r9  := c = *src
	sub	%r13, 1				;     %r13 := --y			*anti-interlock*
	ld.b	[%r5]+, %r9			;     %r5  := *dst++ = c
	jrne.d	rotate_screen_DOY		;   } while(--y)
	add	%r4, %r6			;     %r4  := src += 88			*delay*
	sub	%r12, 1				;   %r12 := --x
	jrne.d	rotate_screen_DOX		; } while(--x)
	sub	%r4, %r11			;   %r4  := src -= 88 * 128 + 1		*delay*
	ret
rotate_screen_END:
;//}}ここまでFRAM4領域へ転送
");
#endif /*V_SCREEN*/

/* * Mon Nov 06 17:37:17 JST 2006 Naoyuki Sawa
 * - schedule()から、画面更新処理だけを分離しました。
 *   フレーム待ち無し画面更新だけを行う場合は、この関数を呼び出してください。
 * * Thu Dec 21 21:17:56 JST 2014 Naoyuki Sawa
 * - ログバッファ描画を、これまではschedule()で行っていましたが、update()で行うように変更しました。
 *   それに加えて、ログバッファ描画前後で、仮想VRAMを保存するようにしました。
 *   この変更によって、アプリケーションは、ログバッファ描画の影響を無視して、オーバーレイと見なせるようになりました。
 *   以下のような処理が可能となります。
 *   □例1
 *   │void app_main(){
 *   │  surface_clear(&surface,0);
 *   │  render_ellipse(&render,0,0,DISP_X,DISP_Y,3);//円を描画する｡
 *   │  for(;;){
 *   │    schedule();//円を破壊せずにﾛｸﾞﾊﾞｯﾌｧ描画のみをｽｸﾛｰﾙできる｡
 *   │    LogBuf_Printf(pLogBuf,"%d",now);
 *   │} }
 *   □例2
 *   │void test(){
 *   │  //〜何か処理〜
 *   │  LogBuf_Printf(pLogBuf,"some message");
 *   │  update();//ﾛｸﾞﾊﾞｯﾌｧ描画のみを更新する｡
 *   │  //〜何か処理〜
 *   │} }
 * - 今回の変更に伴い、ログバッファ描画が、録画と、PCからの画面キャプチャに含まれなくなったことに、注意してください。
 *   録画はschedule()の中のvidrec()で，キャプチャはschedule()の中のyield()内で行われる処理です。
 *   vidrec()やyield()が呼ばれる時点では、仮想VRAMは復元されており、ログバッファ描画は残っていないからです。
 *   ログバッファ描画は、主にテストのための表示ですので、録画やキャプチャに含まれていなくても問題が無いと思いますが、
 *   もし必要である場合は、当関数の最後の、仮想VRAMを復元する処理を削除すれば、変更前と同様に含まれるようにできます。
 */
void update() {
#ifdef  USE_LOG_BUFFER
	/* ログバッファ描画前に仮想VRAMを退避する。 */
    #ifdef  V_SCREEN
	static unsigned char tmpbuf[sizeof vbuff];	//ログバッファと縦画面を併用する場合は、仮想VRAMを退避する一時的なバッファとして_def_vbuffを使えない。rotate_screen()が_def_vbuffを破壊するからである。tmpbuf[]の分メモリ使用量が増えることに注意せよ。
	memcpy(tmpbuf, vbuff, sizeof vbuff);
    #else //V_SCREEN
	memcpy(_def_vbuff, vbuff, sizeof vbuff);	//ログバッファと縦画面を併用しない場合は、仮想VRAMを退避する一時的なバッファとして_def_vbuffを使う。
    #endif//V_SCREEN
	/* ログバッファ描画。 */
	LogBuf_Draw(pLogBuf, 0, 0);
#endif/*USE_LOG_BUFFER*/

#ifdef V_SCREEN
	rotate_screen();
#endif /*V_SCREEN*/

	/* 画面転送 */
	pceLCDTrans();

#ifdef  USE_LOG_BUFFER
	/* ログバッファ描画前に退避した仮想VRAMを復元する。 */
    #ifdef  V_SCREEN
	memcpy(vbuff, tmpbuf, sizeof vbuff);		//ログバッファと縦画面を併用する場合
    #else //V_SCREEN
	memcpy(vbuff, _def_vbuff, sizeof vbuff);	//ログバッファと縦画面を併用しない場合
    #endif//V_SCREEN
#endif/*USE_LOG_BUFFER*/
}

/****************************************************************************
 *	vidrec
 ****************************************************************************/

#ifdef USE_VIDREC
static void vidrec() {
#ifdef LDIRECT_INTERVAL
	static const unsigned char hdr[4] = { DISP_X,DISP_Y,4/*[bpp]*/,FPS };
#else /*LDIRECT_INTERVAL*/
	static const unsigned char hdr[4] = { DISP_X,DISP_Y,2/*[bpp]*/,FPS };
#endif /*LDIRECT_INTERVAL*/
	static int active;
	//
	unsigned char buf[128/*調整可*/]; /* (sizeof vbuff)/Nのサイズとすること */
	const unsigned char* src;
	unsigned char* dst;

	if(cdcacm_recv(buf, 1) > 0) {
		switch(buf[0]) {
		case 0:
			active = 0; /* 画面出力停止 */
			break;
		case 1:
			active = 1; /* 画面出力開始 */
			src = hdr;
			do {
				if(pcePadGetDirect() & PAD_SELECT) {
					exit(0); /* 送信待ちに割り込んで強制終了 */
				}
				src += cdcacm_send(src, &hdr[sizeof hdr] - src);
			} while(src < &hdr[sizeof hdr]);
			break;
		}
	}
	if(active) {
		src = vbuff;
		do {
			dst = buf;
			do {
#ifdef LDIRECT_INTERVAL
				*dst++ = src[0]|(src[1]<<4); 
				src += 2;
#else /*LDIRECT_INTERVAL*/
				*dst++ = src[0]|(src[1]<<2)|(src[2]<<4)|(src[3]<<6);
				src += 4;
#endif /*LDIRECT_INTERVAL*/
			} while(dst < &buf[sizeof buf]);
			dst = buf;
			do {
				if(pcePadGetDirect() & PAD_SELECT) {
					exit(0); /* 送信待ちに割り込んで強制終了 */
				}
				dst += cdcacm_send(dst, &buf[sizeof buf] - dst);
			} while(dst < &buf[sizeof buf]);
		} while(src < &vbuff[sizeof vbuff]);
	}
}
#endif /*USE_VIDREC*/

/****************************************************************************
 *	schedule
 ****************************************************************************/

/* * Fri Dec 15 00:49:15 JST 2006 Naoyuki Sawa
 * - schedule()関数に、サウンドポーズ対応コードを追加しました。
 *   少し試した限りでは上手く動作しているようですが、スリープからの復帰時に問題が起きないか未確認です。
 * - もし、ポーズ状態のまま、すなわち、サウンドポーズ状態のままでアプリケーションを終了してしまった場合にも、
 *   CLiPライブラリ内のpceAppExit()でpceWaveStop(1)を呼び出しており、サウンド状態がリセットされるので、大丈夫です。
 */

void schedule() {
#ifdef  USE_RRS
	/* Round Robin Scheduler (RRS)処理。 */
	RRS_yield(pRRS);
#endif//USE_RRS

#ifdef  USE_EVENT_TIMER
	/* イベントタイマ処理。 */
	EvtTmr_Exec(pEvtTmr);
#endif/*USE_EVENT_TIMER*/

#ifdef  USE_COUNTER_MANAGER
	/* 汎用カウンタ管理処理。 */
	CntMgr_Exec(pCntMgr);
#endif/*USE_COUNTER_MANAGER*/

#ifdef  USE_DURATION_COUNTER
	/* 存続カウンタ処理。 */
	DurCnt_Exec(pDurCnt);
#endif/*USE_DURATION_COUNTER*/

#ifdef  USE_LED
	/* LEDシーケンサ処理。 */
	{
		unsigned char Buffer[LedCh_Max + 1];
		memset(Buffer, 1/*消灯*/, sizeof Buffer);
		LedSeq_Exec(pLedSeq, Buffer, NULL);
		//{{TODO:ここでBuffer[]を画面に描画してください｡}}
	}
#endif//USE_LED

#ifdef  USE_DLYQUE
	/* 遅延コールバックキュー処理。 */
	DlyQue_Exec(pDlyQue);
#endif//USE_DLYQUE

#ifdef  USE_CBKQUE
	/* コールバックキュー処理。 */
	CbkQue_Invoke(pCbkQue);	//登録されているノードを全て呼び出す。アプリケーションによっては、他の処理を挟んでCbkQue_InvokePri()を複数回分けて呼び出すように変更して下さい。
	CbkQue_Clear(pCbkQue);	//コールバックキューを空の状態に戻す。アプリケーションによっては、一度登録したコールバックキューを何度も使い回す場合は、この行を削除して下さい。
#endif//USE_CBKQUE

#ifdef  USE_NUKLEAR
	//Nuklearの描画処理。
	// - GUIの表示優先度は、直接描画やコールバックキュー描画よりも上，PAUSEメッセージよりも下が適切だと思うので、ここでNuklearの描画処理を行う事にした。
	nk_piece_render(ctx, &render);
#endif//USE_NUKLEAR

#ifdef USE_PAUSE
	{
		/* PAUSEメッセージ領域のイメージ退避用バッファは、324バイト必要です。
		 * スタック上に取るのは危険ですし、staticに取るのもメモリの無駄です。
		 * そこで、PAUSE時にのみヒープから確保することにします。
		 */
		//unsigned char save[PAUSE_H][PAUSE_W];
		unsigned char (*save)[PAUSE_W] = NULL/*警告抑制*/;
		int pause = 0;
		/*{{2006/12/15:サウンドポーズ対応*/
		int sound_pause = 0/*警告抑制*/;
		/*}}2006/12/15:サウンドポーズ対応*/
		int x, y;
		for(;;) {
#endif /*USE_PAUSE*/

			/* 画面更新。 */
			update();

#ifdef USE_VIDREC
			/* 画面出力。 */
			vidrec();
#endif /*USE_VIDREC*/

#ifdef  USE_SOUND_MANAGER
			/* Sound Manager処理。 */
			SndMgr_Exec(pSndMgrBgm); /* BGM Sound Manager */
			SndMgr_Exec(pSndMgrSe1); /* SE1 Sound Manager */
			SndMgr_Exec(pSndMgrSe2); /* SE2 Sound Manager */
#endif/*USE_SOUND_MANAGER*/

#ifdef USE_IDLE
			/* アイドル処理+システム処理。 */
			idle_yield();
#else /*USE_IDLE*/
			/* システム処理。 */
			yield();
#endif /*USE_IDLE*/

			/* パッド状態更新。 */
			joy = pad_get();
#ifdef V_SCREEN
			joy = (joy & ~(PAD_LF | PAD_RI | PAD_UP | PAD_DN | /* 縦画面用入力変換 */
				       TRG_LF | TRG_RI | TRG_UP | TRG_DN))
				| (joy & PAD_LF ? PAD_UP : 0)
				| (joy & PAD_RI ? PAD_DN : 0)
				| (joy & PAD_UP ? PAD_RI : 0)
				| (joy & PAD_DN ? PAD_LF : 0)
				| (joy & TRG_LF ? TRG_UP : 0)
				| (joy & TRG_RI ? TRG_DN : 0)
				| (joy & TRG_UP ? TRG_RI : 0)
				| (joy & TRG_DN ? TRG_LF : 0);
#endif /*V_SCREEN*/

			/* SELECTボタンが押されたら終了する。 */ /* アプリケーションによって不要ならば、この2行を削除してください。 */
			if(joy & TRG_SELECT) exit(EXIT_SUCCESS); /* アプリケーションによって不要ならば、この2行を削除してください。 */

#ifdef USE_PAUSE
			/* PAUSE処理。 */
			if(joy & TRG_START) {
				pause = !pause;	/* PAUSE状態切り替え */
				if(pause) {	/* PAUSE IN */
					/*{{2006/12/15:サウンドポーズ対応*/
					ENTER_CS;
					sound_pause = fINT_EDMA.EHDM1;
					if(sound_pause) {
						fINT_EDMA.EHDM1 = 0;
					}
					LEAVE_CS;
					/*}}2006/12/15:サウンドポーズ対応*/
					/* PAUSEメッセージ表示部分のイメージを退避。 */
					save = (unsigned char (*)[PAUSE_W])malloc(PAUSE_W * PAUSE_H); /* イメージ退避用バッファ確保 */
					if(save == NULL) DIE();
					for(y = 0; y < PAUSE_H; y++) {
						for(x = 0; x < PAUSE_W; x++) {
							save[y][x] = vbuff[DISP_X * (PAUSE_Y + y) + (PAUSE_X + x)];
						}
					}
				} else {	/* PAUSE OUT */
					/*{{2006/12/15:サウンドポーズ対応*/
					ENTER_CS;
					if(sound_pause) {
						fINT_EDMA.EHDM1 = 1;
					}
					LEAVE_CS;
					/*}}2006/12/15:サウンドポーズ対応*/
					/* PAUSEメッセージ表示部分のイメージを復帰。 */
					for(y = 0; y < PAUSE_H; y++) {
						for(x = 0; x < PAUSE_W; x++) {
							vbuff[DISP_X * (PAUSE_Y + y) + (PAUSE_X + x)] = save[y][x];
						}
					}
					free(save); /* イメージ退避用バッファ開放 */
				}
			}
			if(!pause) break;
			/* PAUSEメッセージ点滅表示。 */
			if(pceTimerGetCount() % 1000 < 750) {
				render_string_framed(&render, PAUSE_X, PAUSE_Y, PAUSE_STR, PAUSE_FONT, PAUSE_COLOR);
			} else {
				for(y = 0; y < PAUSE_H; y++) {
					for(x = 0; x < PAUSE_W; x++) {
						vbuff[DISP_X * (PAUSE_Y + y) + (PAUSE_X + x)] = save[y][x];
					}
				}
			}
		}
	}
#endif /*USE_PAUSE*/

#ifdef  USE_NUKLEAR
	//Nuklearのイベント処理。
	nk_input_begin(ctx);
	nk_piece_handle_event(ctx, joy);
	nk_input_end(ctx);
#endif//USE_NUKLEAR

	now++;	/* グローバルタイマ更新 */

/*{{アプリケーション特有の周期処理*/
    //	surface_clear(&surface, 0/*変更可*/);	//暗黙のサーフェイスクリアを行う。この処理はdemo_main()の処理と衝突するので、demo_main()と同時に使用する事は出来ない。従って、simplify.sedにてdemo_main()を削除した後に、この処理を有効化するようにした。アプリケーションによっては、暗黙のサーフェイスクリアが不要な場合は、この行を削除して下さい。
/*}}アプリケーション特有の周期処理*/
}

/****************************************************************************
 *	delay
 ****************************************************************************/

void delay(int frame) {
	while(frame > 0) {
		schedule();
		frame--;
	}
}

/****************************************************************************
 *	demo_main
 ****************************************************************************/

#ifdef USE_IDLE
static int idle_proc(void* param) {
	/* {{TODO:ここで時間のかかる処理を行う}} */
	return 0;
}
#endif /*USE_IDLE*/

#ifdef  USE_TASK
static int task_proc(void* param) {
	int* pval = param;
	for(;;) { (*pval)++; task_yield(); }
	return 0;
}
#endif/*USE_TASK*/

#ifdef  USE_LOT
static int fnRnd(int* rndval) {
	return (*rndval)++;
}
#endif//USE_LOT

#ifdef  USE_DIR
static void fnAct_Lcd(int DirLyr, int ActNo) {
	const char* s;
	switch(ActNo) {
	default: DIE(); break;
	case 0: s = ""; break;
	//--- LcdUi ---
	case LcdUi_TjUi:    s = "TjUi";   break;//通常UI
	case LcdUi_BoUi:    s = "BoUi";   break;//ﾎﾞｰﾅｽUI
	//--- LcdCmd ---
	case LcdCmd_TjBgSc: s = "TjBgSc"; break;//通常BGｽｸﾛｰﾙ
	case LcdCmd_TjBgTe: s = "TjBgTe"; break;//通常BG停止
	case LcdCmd_TjAcAl: s = "TjAcAl"; break;//通常ｱｸﾀｰ歩く
	case LcdCmd_TjAcKz: s = "TjAcKz"; break;//通常ｱｸﾀｰ気付く
	case LcdCmd_TjAcHz: s = "TjAcHz"; break;//通常ｱｸﾀｰﾊｽﾞﾚ
	case LcdCmd_TjAcBo: s = "TjAcBo"; break;//通常ｱｸﾀｰﾎﾞｰﾅｽ
	case LcdCmd_TjAcRp: s = "TjAcRp"; break;//通常ｱｸﾀｰﾘﾌﾟﾚｲ
	case LcdCmd_TjAcBe: s = "TjAcBe"; break;//通常ｱｸﾀｰﾍﾞﾙ
	case LcdCmd_TjAcSk: s = "TjAcSk"; break;//通常ｱｸﾀｰｽｲｶ
	case LcdCmd_TjAcCh: s = "TjAcCh"; break;//通常ｱｸﾀｰﾁｪﾘｰ
	case LcdCmd_Bonus:  s = "Bonus";  break;//ﾎﾞｰﾅｽBG
	case LcdCmd_BoEnd:  s = "BoEnd";  break;//ﾎﾞｰﾅｽ終了
	case LcdCmd_BoGet:  s = "BoGet";  break;//ﾎﾞｰﾅｽGet
	case LcdCmd_BoAcTe: s = "BoAcTe"; break;//ﾎﾞｰﾅｽｱｸﾀｰ停止
	case LcdCmd_BoAcKt: s = "BoAcKt"; break;//ﾎﾞｰﾅｽｱｸﾀｰ回転
	}
	render_rectangle_fill(&render, 0,10*DirLyr, DISP_X,10, 0);
	render_string(&render, 0,10*DirLyr, s, 0,3);
}
static void fnAct_Lmp(int DirLyr, int ActNo) {
	const char* s;
	switch(ActNo) {
	default: DIE(); break;
	case 0: s = ""; break;
	//--- LedCmd ---
	case LedCmd_TjAcKz: s = "TjAcKz"; break;//通常ｱｸﾀｰ気付く
	case LedCmd_TjAcHz: s = "TjAcHz"; break;//通常ｱｸﾀｰﾊｽﾞﾚ
	case LedCmd_TjAcBo: s = "TjAcBo"; break;//通常ｱｸﾀｰﾎﾞｰﾅｽ
	case LedCmd_TjAcRp: s = "TjAcRp"; break;//通常ｱｸﾀｰﾘﾌﾟﾚｲ
	case LedCmd_TjAcBe: s = "TjAcBe"; break;//通常ｱｸﾀｰﾍﾞﾙ
	case LedCmd_TjAcSk: s = "TjAcSk"; break;//通常ｱｸﾀｰｽｲｶ
	case LedCmd_TjAcCh: s = "TjAcCh"; break;//通常ｱｸﾀｰﾁｪﾘｰ
	case LedCmd_Bonus:  s = "Bonus";  break;//ﾎﾞｰﾅｽBG
	case LedCmd_BoEnd:  s = "BoEnd";  break;//ﾎﾞｰﾅｽ終了
	case LedCmd_BoGet:  s = "BoGet";  break;//ﾎﾞｰﾅｽGet
	}
	render_rectangle_fill(&render, 0,10*DirLyr, DISP_X,10, 0);
	render_string(&render, 0,10*DirLyr, s, 0,3);
}
static void fnAct_Snd(int DirLyr, int ActNo) {
	const char* s;
	switch(ActNo) {
	default: DIE(); break;
	case 0: s = ""; break;
	//--- SndBgm ---
	case SndBgm_Bonus: s = "Bonus";  break;//ﾎﾞｰﾅｽBGM
	case SndBgm_BoEnd: s = "BoEnd";  break;//ﾎﾞｰﾅｽ終了
	//--- SndSe ---
	case SndSe_TjAcKz: s = "TjAcKz"; break;//通常ｱｸﾀｰ気付く
	case SndSe_TjAcHz: s = "TjAcHz"; break;//通常ｱｸﾀｰﾊｽﾞﾚ
	case SndSe_TjAcBo: s = "TjAcBo"; break;//通常ｱｸﾀｰﾎﾞｰﾅｽ
	case SndSe_TjAcRp: s = "TjAcRp"; break;//通常ｱｸﾀｰﾘﾌﾟﾚｲ
	case SndSe_TjAcBe: s = "TjAcBe"; break;//通常ｱｸﾀｰﾍﾞﾙ
	case SndSe_TjAcSk: s = "TjAcSk"; break;//通常ｱｸﾀｰｽｲｶ
	case SndSe_TjAcCh: s = "TjAcCh"; break;//通常ｱｸﾀｰﾁｪﾘｰ
	case SndSe_BoAcKt: s = "BoAcKt"; break;//ﾎﾞｰﾅｽｱｸﾀｰ回転
	case SndSe_BoGet:  s = "BoGet";  break;//ﾎﾞｰﾅｽGet
	}
	render_rectangle_fill(&render, 0,10*DirLyr, DISP_X,10, 0);
	render_string(&render, 0,10*DirLyr, s, 0,3);
}
static void fnAct_Prg(int DirLyr, int ActNo) {
	const char* s;
	switch(ActNo) {
	default: DIE(); break;
	case 0: s = ""; break;
	}
	render_rectangle_fill(&render, 0,10*DirLyr, DISP_X,10, 0);
	render_string(&render, 0,10*DirLyr, s, 0,3);
}
void fnAct(struct _ST_DirSeq* pDirSeq, int iCh, int ActNo, int bOverFlow) {
	static void (*const TBL_fnAct[])(int DirLyr/*演出レイヤ*/, int ActNo/*演出番号*/) = {
		fnAct_Lcd,//0 液晶(UI)
		fnAct_Lcd,//1 液晶(後)
		fnAct_Lcd,//2 液晶(前)
		fnAct_Lmp,//3 ﾗﾝﾌﾟ(後)
		fnAct_Lmp,//4 ﾗﾝﾌﾟ(前)
		fnAct_Snd,//5 ｻｳﾝﾄﾞ(BGM)
		fnAct_Snd,//6 ｻｳﾝﾄﾞ(SE)
		fnAct_Prg,//7 ﾌﾟﾛｸﾞﾗﾑ
	};
	int DirLyr = (unsigned char)(ActNo >> 16);
	if(bOverFlow) { return; }//オーバーフロー時に送信されたコマンドは処理しない事にした。この判断はアフリケーション次第であり処理しても構わない。ただし演出シーケンサの関数を再帰的に呼び出してはいけない。
	if((unsigned)DirLyr >= ARRAY_SIZE(TBL_fnAct)) { DIE(); }
	(*TBL_fnAct[DirLyr])(DirLyr, (unsigned short)ActNo);
}
#endif//USE_DIR

#ifdef  USE_FSM
typedef struct _ST_FsmTest {
	int x,y;
	ST_FsmObj stFsmObj;
} ST_FsmTest;
static ST_FsmTest stFsmTest;
FSMFUNC_(Map1_init_act) { TRACE("Map1_init_act(%s)\n",pParam); }
FSMFUNC_(Map1_State1_entry) { TRACE("FsmFunc_Map1_State1_entry\n"); }
FSMFUNC_(Map1_State1_exit) { TRACE("FsmFunc_Map1_State1_exit\n"); }
FSMFUNC_(Map1_State1_Trans1_guard) {
	ST_FsmTest* const pFsmTest = CONTAINING_RECORD(pFsmObj,ST_FsmTest,stFsmObj);
	TRACE("FsmFunc_Map1_State1_Trans1_guard\n"); return pFsmTest->x == 0; }
FSMFUNC_(Map1_State2_Trans2_guard) {
	ST_FsmTest* const pFsmTest = CONTAINING_RECORD(pFsmObj,ST_FsmTest,stFsmObj);
	TRACE("FsmFunc_Map1_State2_Trans2_guard\n"); return pFsmTest->y != 0; }
FSMFUNC_(Map1_State1_Trans1_act) { TRACE("FsmFunc_Map1_State1_Trans1_act\n"); }
FSMFUNC_(Map1_State2_Trans2_act) { TRACE("FsmFunc_Map1_State2_Trans2_act\n"); }
FSMFUNC_(Map1_default_act) {
	TRACE("FsmFunc_Map1_default_act\n");
	FsmObj_SetState(pFsmObj,FsmState_State1); }
#endif//USE_FSM

int demo_main() {
#ifdef USE_IDLE
	idle_init(idle_proc, NULL, 0);
#endif /*USE_IDLE*/

#ifdef  USE_TASK
	{
		int val = 0;
		TASK* task = task_create(INT_MIN, task_proc, &val, 0);
		for(;;) {
			schedule();
			if(joy & TRG_A) { break; }
			surface_clear(&surface, 0);
			render_printf(&render, 0,0, 0,3, "%d", val);
			task_yield();
		}
		task_kill(task);
	}
#endif/*USE_TASK*/

#ifdef USE_MUSIC
	{
		/* SAMPLE */
		extern /*const*/ unsigned char C350[];
		PlayMusic(C350);
	}
#endif /*USE_MUSIC*/

#ifdef  USE_BISON_FLEX
	{
		/* SAMPLE */
		FILE* fp = fopen("program.txt", "r");
#if     (YYDEBUG!=0)
	//	yydebug = 1; /* nonzero means print parse trace */
#endif/*(YYDEBUG!=0)*/
		yylex_init(fp);
		if((yyparse() != 0) || (yynerrs != 0)) DIE();
		fclose(fp);
	}
#endif/*USE_BISON_FLEX*/

#ifdef  USE_LOT
	{
		/* SAMPLE */
		int hitcnt[(Sym_Max+1)]={0};
		int rndval=0;
		LotRom_Init(TBL_LotTblNo, fnRnd, &rndval);//抽選表ROM管理を開始する｡
	    #if     defined(TRACE_ON) && (TRACE_ON)
		LotRom_BeginLog();//ﾛｸﾞを開始する｡
	    #endif//defined(TRACE_ON) && (TRACE_ON)
		while(rndval <= USHRT_MAX) {
			int hitval = LotRom_draw_l(LotTblNo_Nor/*通常時*/, 2/*ｽﾍﾟｯｸV*/,6/*設定6*/,-1/*終端*/);
			if(hitval == -1) { hitval = Sym_Mis; }
			if((unsigned)hitval >= ARRAY_SIZE(hitcnt)) { DIE(); }
			hitcnt[hitval]++;
		}
		surface_clear(&surface, 0);
		render_printf(&render, 0,10*0, 0,3, "Sym_Mis %5d\n", hitcnt[Sym_Mis]);
		render_printf(&render, 0,10*1, 0,3, "Sym_Rep %5d\n", hitcnt[Sym_Rep]);
		render_printf(&render, 0,10*2, 0,3, "Sym_Bel %5d\n", hitcnt[Sym_Bel]);
		render_printf(&render, 0,10*3, 0,3, "Sym_Che %5d\n", hitcnt[Sym_Che]);
		render_printf(&render, 0,10*4, 0,3, "Sym_Bon %5d\n", hitcnt[Sym_Bon]);
	    #if     defined(TRACE_ON) && (TRACE_ON)
		LotRom_DumpLog(stderr);//ﾛｸﾞを出力する｡
		LotRom_EndLog();//ﾛｸﾞを終了する｡LotRom_Free()の中で自動的に行われるので､省略可能です｡
	    #endif//defined(TRACE_ON) && (TRACE_ON)
		LotRom_Free();//抽選表ROM管理を終了する｡ｱﾌﾟﾘｹｰｼｮﾝ終了と同時ならば､この処理は不要です｡
		for(;;) { schedule(); if(joy & TRG_A) { break; } }
	}
#endif/*USE_LOT*/

#ifdef  USE_DIR
	{
		/* SAMPLE */
		const unsigned char* const TBL_DirSeq = (const unsigned char*)&TBL_DirTblNo[TBL_DirTblNo[0]];
		int selDirTblNo = 0, selTrig = 1;
		ST_DirSeq* pDirSeq = DirSeq_New(fnAct, 1);
		surface_clear(&surface, 0);
		for(;;) {
			schedule();
			DirSeq_Exec(pDirSeq);
			if((joy & PAD_A) && (joy & PAD_B)) { break; }
			if(joy & TRG_UP) { if(--selDirTblNo < 0) { selDirTblNo = DirTblNo_Max; } }//演出ﾃｰﾌﾞﾙ番号選択(-)
			if(joy & TRG_DN) { if(++selDirTblNo > DirTblNo_Max) { selDirTblNo = 0; } }//演出ﾃｰﾌﾞﾙ番号選択(+)
			if(joy & TRG_LF) { if(--selTrig < 1) { selTrig = DirTrg_Max; } }//ﾄﾘｶﾞ選択(-)
			if(joy & TRG_RI) { if(++selTrig > DirTrg_Max) { selTrig = 1; } }//ﾄﾘｶﾞ選択(+)
			if(joy & TRG_A) { DirSeqCh_SetTbl(pDirSeq, 0, selDirTblNo ? &TBL_DirSeq[TBL_DirTblNo[selDirTblNo]] : NULL); selTrig = 1; }//演出ﾃｰﾌﾞﾙｾｯﾄｱｯﾌﾟ
			if(joy & TRG_B) { DirSeq_SendTrig(pDirSeq, selTrig); if(++selTrig > DirTrg_Max) { selTrig = DirTrg_Max; } }//ﾄﾘｶﾞ送信
			render_rectangle_fill(&render, 0,DISP_Y-10, DISP_X,10, 0);
			render_printf(&render, 0,DISP_Y-10, 0,3, "DirTblNo %2d / Trigger %2d", selDirTblNo, selTrig);
		}
		DirSeq_Free(pDirSeq);
	}
#endif//USE_DIR

#if     (defined(USE_SOUND_SEQUENCER)&&defined(USE_SOUND_MIXER))
	{
		TapMxrCh_SetAtt(pTapMxr,TapMxrCh_Tlv,3,0,0);	//ﾄｰﾀﾙﾚﾍﾞﾙを設定する｡(3dB減衰)
		TapSeqCh_PlayNo(pTapSeq,TapSeqCh_Stg,TBL_TapSeqNo,TapSeqNo_Bgm1g);	//ｽﾃｰｼﾞBGMをﾙｰﾌﾟ再生する｡
		for(;;){
			schedule();
			if(joy&TRG_UP){TapSeqCh_PlayNo(pTapSeq,TapSeqCh_Dir,TBL_TapSeqNo,TapSeqNo_BgmSt);}	//演出BGMをﾙｰﾌﾟ再生する｡この間､ｽﾃｰｼﾞBGMは消音する｡
			if(joy&TRG_DN){TapSeqCh_PlayNo(pTapSeq,TapSeqCh_Dir,TBL_TapSeqNo,TapSeqNo_BgmStFO);}	//演出BGMをﾌｪｰﾄﾞｱｳﾄする｡この後､ｽﾃｰｼﾞBGMが復帰する｡
			if(joy&TRG_LF){TapSeqCh_PlayNo(pTapSeq,TapSeqCh_Dir,TBL_TapSeqNo,TapSeqNo_SeBtn);}	//SEを1回再生する｡これは､他のどの音にも影響しない｡
			if(joy&TRG_RI){TapSeqCh_PlayNo(pTapSeq,TapSeqCh_Err,TBL_TapSeqNo,TapSeqNo_SeErr);}	//ｴﾗｰ音を再生する｡この間､他の音を全て消音する｡
			if(joy&TRG_A){TapLogCh_Play(pTapSeq,TapLogCh_Err,SND_SE_ERR,1,0,0);}	//ｼｰｹﾝｻﾁｬﾈﾙを使わずに､論理ﾁｬﾈﾙを指定して､再生/停止する事も出来る｡
			if(joy&TRG_B){break;}
		}
	}
#endif//(defined(USE_SOUND_SEQUENCER)&&defined(USE_SOUND_MIXER))

#ifdef  USE_EVENT_TIMER
	{
		for(;;) {
			schedule();
			if(joy & TRG_UP) { EvtTmr_StartNo(pEvtTmr,EvtTmrNo_Sample1,TBL_EvtTmrNo,EvtTmrNo_Sample1); }	//ｲﾍﾞﾝﾄﾀｲﾏﾁｬﾈﾙ#1を開始する｡
			if(joy & TRG_DN) { EvtTmr_Stop(pEvtTmr,EvtTmrNo_Sample1); }					//ｲﾍﾞﾝﾄﾀｲﾏﾁｬﾈﾙ#1を停止する｡
			if(joy & TRG_LF) { EvtTmr_StartNo(pEvtTmr,EvtTmrNo_Sample2,TBL_EvtTmrNo,EvtTmrNo_Sample2); }	//ｲﾍﾞﾝﾄﾀｲﾏﾁｬﾈﾙ#2を開始する｡
			if(joy & TRG_RI) { EvtTmr_Stop(pEvtTmr,EvtTmrNo_Sample2); }					//ｲﾍﾞﾝﾄﾀｲﾏﾁｬﾈﾙ#2を停止する｡
			if(joy & TRG_A ) { break; }
		}
	}
#endif/*USE_EVENT_TIMER*/

#ifdef  USE_COUNTER_MANAGER
	{
		//初期値設定
		CntMgr_SetVal(pCntMgr, CntCh_1P,    0, 0, 0);//初期値=   0
		CntMgr_SetVal(pCntMgr, CntCh_2P,    0, 0, 0);//初期値=   0
		CntMgr_SetVal(pCntMgr, CntCh_HI, 1000, 0, 0);//初期値=1000
		CntMgr_SetVal(pCntMgr, CntCh_CR, 1000, 0, 0);//初期値=1000
		//目標値設定
		CntMgr_SetVal(pCntMgr, CntCh_1P, 1000, 1000, SEC( 5));// 5秒で0⇒1000に変化
		CntMgr_SetVal(pCntMgr, CntCh_2P, 1000, 1000, SEC(10));//10秒で0⇒1000に変化
		CntMgr_SetVal(pCntMgr, CntCh_HI,    0, 1000, SEC( 5));// 5秒で1000⇒0に変化
		CntMgr_SetVal(pCntMgr, CntCh_CR,    0, 1000, SEC(10));//10秒で1000⇒0に変化
		for(;;) {
		    //	uint16_t ValNow[(CntCh_Max+1)];
			schedule();
			surface_clear(&surface, 0);
		    //	CntMgr_GetValAll(pCntMgr, ValNow);
			render_printf(&render, 0, 0, 0,3, "%d", CntMgr_GetVal(pCntMgr, CntCh_1P)/*ValNow[CntCh_1P]*/);
			render_printf(&render, 0,10, 0,3, "%d", CntMgr_GetVal(pCntMgr, CntCh_2P)/*ValNow[CntCh_2P]*/);
			render_printf(&render, 0,20, 0,3, "%d", CntMgr_GetVal(pCntMgr, CntCh_HI)/*ValNow[CntCh_HI]*/);
			render_printf(&render, 0,30, 0,3, "%d", CntMgr_GetVal(pCntMgr, CntCh_CR)/*ValNow[CntCh_CR]*/);
			if(joy & TRG_A) { break; }
		}
	}
#endif/*USE_COUNTER_MANAGER*/

#ifdef  USE_FSM
	{
		FsmObj_Init(&stFsmTest.stFsmObj,REG_open_key_l(TBL_RegTbl,RegKey_FsmMap,-1),FsmMap_Map1,"init param");	//⇒State1へ
		FsmObj_ApplyTrans(&stFsmTest.stFsmObj,FsmTrans_Trans1,NULL);	//⇒State1のTrans1遷移によりState2へ
		FsmObj_ApplyTrans(&stFsmTest.stFsmObj,FsmTrans_Trans2,NULL);	//⇒State2のTrans2のGuard条件によりState2のまま
		FsmObj_ApplyTrans(&stFsmTest.stFsmObj,FsmTrans_Trans1,NULL);	//⇒Map1のdefault遷移によりState1へ
	}
#endif//USE_FSM

#ifdef  USE_PRP
	//基本的な関数の使用例
	{
		//動的なプロパティテーブルの例
		void* ptTable=PrpTbl_new(pPrpKey,PrpTbl_Table1);
		//スカラ変数を設定/取得する例
		              PrpTbl_set_l( pPrpKey,PrpTbl_Table1,ptTable,0,123,PrpVar_VarA,-1);
		printf("%d\n",PrpTbl_get_l( pPrpKey,PrpTbl_Table1,ptTable,0,    PrpVar_VarA,-1));
		//配列変数を設定/取得する例
		              PrpTbl_set_l( pPrpKey,PrpTbl_Table1,ptTable,0,456,PrpVar_VarB,5,-1);
		printf("%d\n",PrpTbl_get_l( pPrpKey,PrpTbl_Table1,ptTable,0,    PrpVar_VarB,5,-1));
		              PrpTbl_set_l( pPrpKey,PrpTbl_Table1,ptTable,0,789,PrpVar_VarB,  -1);	//配列変数に対しインデクスを省略してset,及び,initが可能です。全要素に対してset,及び,initします。
		printf("%d\n",PrpTbl_get_l( pPrpKey,PrpTbl_Table1,ptTable,0,    PrpVar_VarB,9,-1));
		//タイプ変数を設定/取得/再初期化/取得する例
		              PrpTbl_set_l( pPrpKey,PrpTbl_Table1,ptTable,0,50,PrpVar_VarD,1,2,3,-1);
		printf("%d\n",PrpTbl_get_l( pPrpKey,PrpTbl_Table1,ptTable,0,   PrpVar_VarD,1,2,3,-1));
		              PrpTbl_init_l(pPrpKey,PrpTbl_Table1,ptTable,0,   PrpVar_VarD,0,1,2,-1);	//[0,1,2]を初期化しても、
		printf("%d\n",PrpTbl_get_l( pPrpKey,PrpTbl_Table1,ptTable,0,   PrpVar_VarD,1,2,3,-1));	//[1,2,3]は変わらない。
		              PrpTbl_init_l(pPrpKey,PrpTbl_Table1,ptTable,0,   PrpVar_VarD,      -1);	//全要素を変更すると、
		printf("%d\n",PrpTbl_get_l( pPrpKey,PrpTbl_Table1,ptTable,0,   PrpVar_VarD,1,2,3,-1));	//[1,2,3]も変わる。
		free(ptTable);
	}
	{
		//静的なプロパティテーブルの例
		static PrpTbl_def(Table2,ptTable2);
		PrpTbl_init(pPrpKey,PrpTbl_Table2,ptTable2,0);
		//テーブル変数を設定/取得/再初期化する例
		              PrpTbl_set_l( pPrpKey,PrpTbl_Table2,ptTable2,0,199,PrpVar_VarB,3,4,PrpVar_VarC,-1);	//ptTable2.VarB[3,4].VarCを設定
		printf("%d\n",PrpTbl_get_l( pPrpKey,PrpTbl_Table2,ptTable2,0,    PrpVar_VarB,3,4,PrpVar_VarC,-1));	//ptTable2.VarB[3,4].VarCを取得
		              PrpTbl_init_l(pPrpKey,PrpTbl_Table2,ptTable2,0,    PrpVar_VarB,3,4,PrpVar_VarC,-1);	//ptTable2.VarB[3,4].VarCを再初期化
		              PrpTbl_init_l(pPrpKey,PrpTbl_Table2,ptTable2,0,    PrpVar_VarB,3,4,            -1);	//ptTable2.VarB[3,4]を再初期化
		              PrpTbl_init_l(pPrpKey,PrpTbl_Table2,ptTable2,0,    PrpVar_VarB,                -1);	//ptTable2.VarBの全要素を再初期化
	}
	//ユーティリティ関数の使用例
	{
		//動的なプロパティテーブルの例
		ST_PrpHdr* pPrpHdr=PrpHdr_new(pPrpKey,PrpTbl_Table1);
		//スカラ変数を設定/取得する例
		              PrpHdr_set_l( pPrpHdr,123,PrpVar_VarA,-1);
		printf("%d\n",PrpHdr_get_l( pPrpHdr,    PrpVar_VarA,-1));
		//配列変数を設定/取得する例
		              PrpHdr_set_l( pPrpHdr,456,PrpVar_VarB,5,-1);
		printf("%d\n",PrpHdr_get_l( pPrpHdr,    PrpVar_VarB,5,-1));
		              PrpHdr_set_l( pPrpHdr,789,PrpVar_VarB,  -1);	//配列変数に対しインデクスを省略してset,及び,initが可能です。全要素に対してset,及び,initします。
		printf("%d\n",PrpHdr_get_l( pPrpHdr,    PrpVar_VarB,9,-1));
		//タイプ変数を設定/取得/再初期化/取得する例
		              PrpHdr_set_l( pPrpHdr,50,PrpVar_VarD,1,2,3,-1);
		printf("%d\n",PrpHdr_get_l( pPrpHdr,   PrpVar_VarD,1,2,3,-1));
		              PrpHdr_init_l(pPrpHdr,   PrpVar_VarD,0,1,2,-1);	//[0,1,2]を初期化しても、
		printf("%d\n",PrpHdr_get_l( pPrpHdr,   PrpVar_VarD,1,2,3,-1));	//[1,2,3]は変わらない。
		              PrpHdr_init_l(pPrpHdr,   PrpVar_VarD,      -1);	//全要素を変更すると、
		printf("%d\n",PrpHdr_get_l( pPrpHdr,   PrpVar_VarD,1,2,3,-1));	//[1,2,3]も変わる。
		free(pPrpHdr);
	}
	{
		//静的なプロパティテーブルの例
		static PrpHdr_def(Table2,phTable2);
		PrpHdr_init(phTable2,pPrpKey,PrpTbl_Table2);
		//テーブル変数を設定/取得/再初期化する例
		              PrpHdr_set_l( phTable2,199,PrpVar_VarB,3,4,PrpVar_VarC,-1);	//phTable2.VarB[3,4].VarCを設定
		printf("%d\n",PrpHdr_get_l( phTable2,    PrpVar_VarB,3,4,PrpVar_VarC,-1));	//phTable2.VarB[3,4].VarCを取得
		              PrpHdr_init_l(phTable2,    PrpVar_VarB,3,4,PrpVar_VarC,-1);	//phTable2.VarB[3,4].VarCを再初期化
		              PrpHdr_init_l(phTable2,    PrpVar_VarB,3,4,            -1);	//phTable2.VarB[3,4]を再初期化
		              PrpHdr_init_l(phTable2,    PrpVar_VarB,                -1);	//phTable2.VarBの全要素を再初期化
	}
	//組み込み'Double'型の使用例
	{
		//動的なプロパティテーブルの例
		ST_PrpHdr* pPrpHdr=PrpHdr_new(pPrpKey,PrpTbl_Table3);
		              PrpHdr_fset_l(pPrpHdr,1.23,PrpVar_VarA,  -1);
		printf("%g\n",PrpHdr_fget_l(pPrpHdr,     PrpVar_VarA,  -1));
		              PrpHdr_fset_l(pPrpHdr,2.34,PrpVar_VarB,0,-1);
		              PrpHdr_fset_l(pPrpHdr,3.45,PrpVar_VarB,1,-1);
		PrpHdr_dump(stderr,pPrpHdr,NULL,0);	//ダンプの使用例
		free(pPrpHdr);
	}
#endif//USE_PRP

	for(;;) {
		schedule();
		surface_clear(&surface, 1);

#ifdef USE_TCPIP
		{
			/* SAMPLE */
			if(joy & TRG_A) tcpip_config();
		}
#endif /*USE_TCPIP*/

#ifdef USE_SPRITE
		{
			/* SAMPLE */
			sprite_draw(0, 0, SPR_SPR4F/*O*/, 0);
			sprite_draw(8, 0, SPR_SPR4B/*K*/, 0);
		}
#endif /*USE_SPRITE*/

#ifdef USE_3D
		{
			/* SAMPLE */
			extern const MESH MESH_CUBE; /* mqo/cube.pmx */
			extern const WIRE WIRE_CONE; /* mqo/cone.pwx */
			render_save(&render);
				mlookat_(render.context->matrix,
					fld(0.0), fld(0.0), fld(0.0),
					fld(0.0), fld(0.0), fld(1.0),
					fld(0.0));
				render_save(&render);
#ifdef USE_TEXTURE
					render.context->texture = &texture_table[TEX_CUBE];
#endif /*USE_TEXTURE*/
					mxlate_(render.context->matrix,
						fld(-1.0), fld(0.0), fld(5.0));
					mrotq_(render.context->matrix, qslerp(
						qrot(fld(1.0), fld(0.0), fld(0.0), fld(0.0)),
						qrot(fld(1.0), fld(0.0), fld(0.0), PI),
						fidiv(fld(now % SEC(5)), SEC(5))));
					render_mesh(&render, &MESH_CUBE);
				render_restore(&render);
				render_save(&render);
					mxlate_(render.context->matrix,
						fld(1.5), fld(-1.0), fld(5.0));
					mrotq_(render.context->matrix, qslerp(
						qrot(fld(0.0), fld(1.0), fld(0.0), fld(0.0)),
						qrot(fld(0.0), fld(1.0), fld(0.0), PI),
						fidiv(fld(now % SEC(5)), SEC(5))));
					render_wire(&render, &WIRE_CONE, 3);
				render_restore(&render);
			render_restore(&render);
		}
#endif /*USE_3D*/

#ifdef  USE_LOG_BUFFER
		{
			LogBuf_Printf(pLogBuf, "now=%u", now);
		}
#endif/*USE_LOG_BUFFER*/

//#ifdef  USE_NVLOG
		{
			NVLOG("now=%u", now);	//USE_NVLOGが定義されていなければNVLOG()は(void)0に展開されるので、USE_NVLOGが定義されていなくてもNVLOG()を使用して構いません。
		}
//#endif//USE_NVLOG
	}

#ifdef USE_IDLE
	idle_wait();
#endif /*USE_IDLE*/

	return 0;
}

/****************************************************************************
 *	game_main
 ****************************************************************************/

void game_main() {
	for(;;) {
		schedule();
	}
}

/****************************************************************************
 *	app_main
 ****************************************************************************/

int app_main(int argc, char* argv[]) {
	for(;;) {
		if(demo_main() < 0) { break; }
		game_main();
	}
	return 0;
}

#if 0	//初期化関数,終了時関数を登録する場合は、このブロックを有効にして下さい。
static void InitFunc() { //初期化関数
	//※TODO:
}
static void* const TBL_InitTbl[]={(void*)FOURCC_pCRT,(void*)FOURCC_dXIU,InitFunc,NULL};
static void ExitFunc() { //終了時関数
	//※TODO:
}
static void* const TBL_ExitTbl[]={(void*)FOURCC_pCRT,(void*)FOURCC_dXTU,ExitFunc,NULL};
#endif
