/*
 *	clipsnds.h
 *
 *	サウンドシーケンサ
 *
 *	CLiP - Common Library for P/ECE
 *	Copyright (C) 2001-2015 Naoyuki Sawa
 *
 *	* Thu Oct 03 00:19:14 JST 2013 Naoyuki Sawa
 *	- 1st リリース。
 *	* Sat Oct 05 15:05:45 JST 2013 Naoyuki Sawa
 *	- パターンコマンドに、4バイトウェイトを追加しました。
 *	  4バイトウェイトにはオフセットが無く全範囲をカバーするので、手作業でデータを作成する時は4バイトウェイトだけを使用すると直感的に作成できます。
 *	  ただし1〜3バイトウェイトの方がメモリを節約できるので、ツールでデータを作成する時はウェイト時間によって1〜4バイトウェイトを生成してください。
 *	* Fri Nov 01 17:54:30 JST 2013 Naoyuki Sawa
 *	- SndSeq_Play()が、パターンデータ先頭の0msタイミングに相当する処理を即実行するように、修正しました。
 *	* Sun Jun 01 22:15:15 JST 2014 Naoyuki Sawa
 *	- SndSeqCmd_Vol,SndSeqCmd_Panのマクロ定義が間違っていたので、修正しました。
 *	* Tue Jul 01 22:19:13 JST 2014 Naoyuki Sawa
 *	- イントロループ構成の再生制御を追加しました。
 *	* Mon Jul 07 01:54:09 JST 2014 Naoyuki Sawa
 *	- SndSeq_Stop()とSndSeq_StopAll()の引数に、bForce(強制停止)を追加しました。
 *	* Tue May 05 17:15:43 JST 2015 Naoyuki Sawa
 *	- SndSeq_PlayNo()を追加しました。
 *	* Thu Jun 04 21:32:16 JST 2015 Naoyuki Sawa
 *	- 4バイトウェイトに実質無限として0xFFFFFFFFのような大きな値を指定した場合に、pSndSeqCh->Waitがオーバーフローしてウェイトしない不具合があったのを修正しました。
 *	* Mon Jun 08 21:18:30 JST 2015 Naoyuki Sawa
 *	- ST_SndSeqInfo.fnPlay()の引数にループ回数(iLop)を追加しました。
 */
#ifndef __CLIP_SNDS_H__
#define __CLIP_SNDS_H__
/****************************************************************************
 *	定数、構造体
 ****************************************************************************/
#define SndTrk_Max	31	/* トラック番号の最大値(この値も含む)。0以上で調整可能。 */			//ハードウェアに依存
#define SndPhr_Max	8191	/* フレーズ番号の最大値(この値も含む)。0以上で調整可能。 */			//ハードウェアに依存
#define SndLop_Max	255	/* ループ回数の最大値(この値も含む)。0以上で調整可能。 */			//ハードウェアに依存		//{{2015/06/08追加:ST_SndSeqInfo.fnPlay()の引数にループ回数(iLop)を追加しました。}}
#define SndVol_Max	128	/* ボリュームの最大値(この値も含む)。0以上で調整可能。 */			//ハードウェアに依存
#define SndPan_Max	128	/* パンの最大値(この値も含む)。0以上で調整可能。 */				//ハードウェアに依存
#define SndSeqCh_Max	15	/* サウンドシーケンサチャネル番号の最大値(この値も含む)。0以上で調整可能。 */	//アプリケーションに依存
/*--------------------------------------------------------------------------*/
/* 初期化情報 */
typedef struct _ST_SndSeqInfo {
	int  (*fnTime)();
    //{{2015/06/08変更:ST_SndSeqInfo.fnPlay()の引数にループ回数(iLop)を追加しました。
    //	void (*fnPlay)(int iTrk, int iPhr, int iVol, int iPan);	/* ステレオ再生時は、iPanは無効値(-1)である。アプリケーション側は、iPanが(-1)ならばステレオ再生と判断して、ステレオ再生ならばiPanの値を無視せよ。 */
    //↓2015/06/08変更:ST_SndSeqInfo.fnPlay()の引数にループ回数(iLop)を追加しました。
	void (*fnPlay)(int iTrk, int iPhr, int iLop, int iVol, int iPan);	/* ステレオ再生時は、iPanは無効値(-1)である。アプリケーション側は、iPanが(-1)ならばステレオ再生と判断して、ステレオ再生ならばiPanの値を無視せよ。iLopは、無限ループ(-1),又は,ループ回数(1〜SndLop_Max)である。 */
    //}}2015/06/08変更:ST_SndSeqInfo.fnPlay()の引数にループ回数(iLop)を追加しました。
	void (*fnStop)(int iTrk);
	void (*fnVol)(int iTrk, int iVol);	/* ステレオ再生時は、左トラックのみ呼び出される。アプリケーション側で、モノラル再生中かステレオ再生中かを記憶し、必要に応じて右トラックのボリュームも連動させよ。 */
	void (*fnPan)(int iTrk, int iPan);	/* ステレオ再生時は、呼び出されることは無い。 */
	int  (*fnLen)(int iPhr);		/* フレーズの再生時間を、[ミリ秒]単位で返せ。 */	//イントロループ構成の再生制御に使用している。イントロフレーズ以外に対しては、ダミーの値を返しても構わない。
	int  (*fnNext)(int iPhr);		/* iPhrがイントロループ構成のイントロフレーズならば、遷移先ループフレーズ番号(0〜SndPhr_Max)を返せ。iPhrがイントロループ構成のループフレーズならば、iPhrをそのまま返せ。iPhrが単独ループフレーズならば、iPhrをそのまま返せ。iPhrが通常フレーズならば、(-1)を返せ。 */		//┬この説明だけでは判り辛いと思うので、
	int  (*fnPrev)(int iPhr);		/* iPhrがイントロループ構成のイントロフレーズならば、iPhrをそのまま返せ。iPhrがイントロループ構成のループフレーズならば、遷移元イントロフレーズ番号(0〜SndPhr_Max)を返せ。iPhrが単独ループフレーズならば、iPhrをそのまま返せ。iPhrが通常フレーズならば、(-1)を返せ。 */		//┘下表の説明も併せて参照してください。
} ST_SndSeqInfo;
//	□構成:ｲﾝﾄﾛﾙｰﾌﾟ					□構成:単独ﾙｰﾌﾟ				□構成:通常ﾌﾚｰｽﾞ			
//	┌─────┬─────┬─────┬─	┌─────┬─────┬─		┌─────┐				
//	│ｲﾝﾄﾛﾌﾚｰｽﾞ │ﾙｰﾌﾟﾌﾚｰｽﾞ │ﾙｰﾌﾟﾌﾚｰｽﾞ │…	│ﾙｰﾌﾟﾌﾚｰｽﾞ │ﾙｰﾌﾟﾌﾚｰｽﾞ │…		│通常ﾌﾚｰｽﾞ │				
//	└─────┴─────┴─────┴─	└─────┴─────┴─		└─────┘				
//	↓ｱﾌﾟﾘｹｰｼｮﾝ定義の関数が返すべき値		↓ｱﾌﾟﾘｹｰｼｮﾝ定義の関数が返すべき値	↓ｱﾌﾟﾘｹｰｼｮﾝ定義の関数が返すべき値	
//	┌───┬─────┬─────┐		┌───┬─────┐			┌───┬─────┐			
//	│ 引数 │ｲﾝﾄﾛﾌﾚｰｽﾞ │ﾙｰﾌﾟﾌﾚｰｽﾞ │		│ 引数 │ﾙｰﾌﾟﾌﾚｰｽﾞ │			│ 引数 │通常ﾌﾚｰｽﾞ │			
//	├───┼─────┼─────┤		├───┼─────┤			├───┼─────┤			
//	│fnNext│ﾙｰﾌﾟﾌﾚｰｽﾞ │ﾙｰﾌﾟﾌﾚｰｽﾞ │		│fnNext│ﾙｰﾌﾟﾌﾚｰｽﾞ │			│fnNext│    -1    │			
//	│fnPrev│ｲﾝﾄﾛﾌﾚｰｽﾞ │ｲﾝﾄﾛﾌﾚｰｽﾞ │		│fnPrev│ﾙｰﾌﾟﾌﾚｰｽﾞ │			│fnPrev│    -1    │			
//	└───┴─────┴─────┘		└───┴─────┘			└───┴─────┘			
//							~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//							ｲﾝﾄﾛﾙｰﾌﾟ構成を使用しない場合は､単純化できる｡fnNextとfnPrevの実装が､共通でも良い｡
/* トラック情報 */
typedef struct _ST_SndTrk {
	short iSndSeqCh;	/* 現在このトラックを制御しているサウンドシーケンサチャネル番号(0-SndSeqCh_Max)。(-1)ならば「このトラックはサウンドシーケンサによって制御されていない」と見なす。以降、この状態を「無制御」と称す。 */	//ステレオ再生時の情報は左トラックのみに格納する。右トラックは便宜上、無制御とする。パターンデータが正常ならば、この扱いで問題ない。
	short iPhr;		/* フレーズ番号(0-SndPhr_Max)。無制御ならば(-1)を格納する。 */																		//ステレオ再生時の情報は左トラックのみに格納する。右トラックは便宜上、無制御とする。
	short iVol;		/* ボリューム  (0-SndVol_Max)。無制御ならば(-1)を格納する。 */																		//ステレオ再生時の情報は左トラックのみに格納する。右トラックは便宜上、無制御とする。
	short iPan;		/* パン        (0-SndPan_Max)。無制御ならば(-1)を格納する。ステレオ再生時も(-1)を格納する。 */														//ステレオ再生時の情報は左トラックのみに格納する。右トラックは便宜上、無制御とする。
	int   Intr;		/* イントロカウンタ[ms]。フレーズ開始時に、イントロフレーズならば再生時間(≧0)を格納する。イントロフレーズ以外ならば(-1)を格納する。イントロフレーズならば、実時間経過時に(-)する。イントロカウンタが0以下ならば、ループフレーズを開始する。 */
} ST_SndTrk;
/* サウンドシーケンサチャネル */
typedef struct _ST_SndSeqCh {
	const unsigned char* pData;	/* パターンデータの現在アドレス。(NULL=停止中) */
	int Wait;			/* ウェイトカウンタ[ms]。ウェイトコマンド実行時に(+)する。実時間経過時に(-)する。ウェイトカウンタが0以下ならば、コマンドを実行する。 */
} ST_SndSeqCh;
/* サウンドシーケンサ */
typedef struct _ST_SndSeq {
	const ST_SndSeqInfo* pSndSeqInfo;	/* 初期化情報 */
	int Time;				/* 前回時刻[ms] */
	ST_SndTrk SndTrk[SndTrk_Max + 1];	/* トラック情報 */
	ST_SndSeqCh SndSeqCh[SndSeqCh_Max + 1];	/* サウンドシーケンサチャネル */
} ST_SndSeq;
/****************************************************************************
 *	アプリケーション用関数
 ****************************************************************************/
void SndSeq_Init(const ST_SndSeqInfo* pSndSeqInfo);
void SndSeq_Exec();
void SndSeq_Play(int iSndSeqCh, const void* pData);
void SndSeq_Stop(int iSndSeqCh, int bForce);
void SndSeq_StopAll(int bForce);
void SndSeq_GetTrk(int iTrk, ST_SndTrk* pSndTrk);
/****************************************************************************
 *	dSndSeqC.exeが出力したバイナリ形式を扱うためのユーティリティ関数
 ****************************************************************************/
#define USE_SNDDEF_BIN	//ユーティリティ関数が不要ならばこのシンボル定義をコメントアウトしてください。
#ifdef  USE_SNDDEF_BIN
void SndSeq_PlayNo(int iSndSeqCh, const void* pSndDefBin, int iSndSeqNo);
#endif//USE_SNDDEF_BIN
/****************************************************************************
 *	パターンデータ定義用マクロ
 ****************************************************************************/
#define SndSeqCmd_End()				(0x00)																		/* パターン終了 */
#define SndSeqCmd_Wait1(ms)			(0x01),((unsigned char)((ms)-0x00001))														/* 1バイトウェイト */	//1バイトウェイトの範囲 = 0x00001+(0〜0x000000FF) [ms]
#define SndSeqCmd_Wait2(ms)			(0x02),((unsigned char)((ms)-0x00101)),((unsigned char)(((ms)-0x00101)>>8))									/* 2バイトウェイト */	//2バイトウェイトの範囲 = 0x00101+(0〜0x0000FFFF) [ms]
#define SndSeqCmd_Wait3(ms)			(0x03),((unsigned char)((ms)-0x10101)),((unsigned char)(((ms)-0x10101)>>8)),((unsigned char)(((ms)-0x10101)>>16))				/* 3バイトウェイト */	//3バイトウェイトの範囲 = 0x10101+(0〜0x00FFFFFF) [ms]
#define SndSeqCmd_Wait4(ms)			(0x04),((unsigned char) (ms)         ),((unsigned char)( (ms)         >>8)),((unsigned char)( (ms)         >>16)),((unsigned char)((ms)>>24))	/* 4バイトウェイト */	//4バイトウェイトの範囲 =         (0〜0xFFFFFFFF) [ms]
#define SndSeqCmd_Stop(trk)			(0x10),(trk)																	/* トラック停止 */
//{{2015/06/08変更:ST_SndSeqInfo.fnPlay()の引数にループ回数(iLop)を追加しました。
//#define SndSeqCmd_PlayM(trk,phr,vol,pan)	(0x11),(trk),((unsigned char)(phr)),((unsigned char)((phr)>>8)),(vol),(pan)									/* モノラル再生 */
//#define SndSeqCmd_PlayS(trk,phr,vol)		(0x12),(trk),((unsigned char)(phr)),((unsigned char)((phr)>>8)),(vol)										/* ステレオ再生 */
//↓2015/06/08変更:ST_SndSeqInfo.fnPlay()の引数にループ回数(iLop)を追加しました。
#define SndSeqCmd_PlayM(trk,phr,lop,vol,pan)	(0x11),(trk),((unsigned char)(phr)),((unsigned char)((phr)>>8)),(((lop)<0)?0:(lop)),(vol),(pan)							/* モノラル再生 */
#define SndSeqCmd_PlayS(trk,phr,lop,vol)	(0x12),(trk),((unsigned char)(phr)),((unsigned char)((phr)>>8)),(((lop)<0)?0:(lop)),(vol)							/* ステレオ再生 */
//}}2015/06/08変更:ST_SndSeqInfo.fnPlay()の引数にループ回数(iLop)を追加しました。
#define SndSeqCmd_Vol(trk,vol)			(0x20),(trk),(vol)																/* ボリューム更新 */
#define SndSeqCmd_Pan(trk,pan)			(0x21),(trk),(pan)																/* パン更新 */
#endif/*__CLIP_SNDS_H__*/
