/*
 *	clipadp.h
 *
 *	2-bit ADPCM Decoder
 *
 *	CLiP - Common Library for P/ECE
 *	Copyright (C) 2001-2017 Naoyuki Sawa
 *
 *	* Wed Dec 20 00:13:10 JST 2006 Naoyuki Sawa
 *	- 作成開始。
 *	* Wed Dec 20 17:31:02 JST 2006 Naoyuki Sawa
 *	- 1st リリース。
 *	* Thu Dec 21 11:18:32 JST 2006 Naoyuki Sawa
 *	- ADPCMCHANNEL構造体を扱い易く並び替えて、ASM版adpcm_mix1()を最適化しました。
 *	* Thu Mar 01 01:53:43 JST 2007 Naoyuki Sawa
 *	- adpcm_stat()を追加しました。
 *	* Mon Jul 15 20:32:11 JST 2013 Naoyuki Sawa
 *	- ADPCMCHANNEL構造体を並び替え、volフィールドを追加しました。
 *	- 音量設定機能に対応するため、adpcm_att()関数を追加しました。
 *	- 高速RAMを節約するため、係数テーブルをframadp.cからclipadp.cへ移動しました。
 *	* Wed Nov 18 21:37:53 JST 2015 Naoyuki Sawa
 *	- 'extern "C" {'～'}'で囲みました。.cppを含むWin32プロジェクトからもインクルード出来るようにするためです。
 *	* Mon Jun 26 22:31:39 JST 2017 Naoyuki Sawa
 *	- adpcm_play()にて、volatile指定が不足していたが偶然動作していたコードを、きちんとvolatileを付けるように修正しました。
 *	- adpcm_rate()関数を追加しました。
 *	* Tue Jun 27 22:55:03 JST 2017 Naoyuki Sawa
 *	- 2017/06/26の変更によって最終ループの停止直前の1サンプルが出力されなくなっていた問題を修正しました。
 *	- ループ時もprogressをリセットせずに引き継ぐ事にしました。
 */
#ifndef __CLIP_ADP_H__
#define __CLIP_ADP_H__

#ifdef  __cplusplus
extern "C" {
#endif//__cplusplus

/****************************************************************************
 *	定数、構造体
 ****************************************************************************/

#ifdef  PIECE
#define ADPCM_ASM
#endif/*PIECE*/

/* PCEWAVEINFO.type の独自拡張 */
#define PW_TYPE_2BITADPCM	3
#define PW_TYPE_ADPCM_X		(PW_TYPE_2BITADPCM|PW_TYPE_VR|PW_TYPE_ADP_INI)
#define PW_TYPE_ADPCM_X_NI	(PW_TYPE_2BITADPCM|PW_TYPE_VR)

#define ADPCMBUFLEN		320	/* =16000/50 … 1[tick](=1/50[sec])当たりのサンプル数 */

/* アセンブラコードから直接参照するため、レイアウト固定です!! */
//typedef struct _ADPCMCHANNEL {
//	int loop;			/* + 0,4: 0=停止, 1～=残りループ回数, -1=無限ループ */
//	int pcm;			/* + 4,4: 出力PCM値 */
//	short data;			/* + 8,2: 入力ADPCM値のバッファ */
//	short delta;			/* +10,2: ⊿値 */
//	short progress;			/* +12,2: 進行カウンタ */
//	short rate;			/* +14,2: サンプリングレート */
//	int len;			/* +16,4: 残り出力サンプル数 */
//	const unsigned char* ptr;	/* +20,4: ADPCMデータ走査位置 */
//	int init_len;			/* +24,4: 残り出力サンプル数のリセット値 */
//	const unsigned char* init_ptr;	/* +28,4: ADPCMデータ走査位置のリセット値 */
//} ADPCMCHANNEL;				/* =32 */
//↓* Thu Dec 21 11:18:32 JST 2006 Naoyuki Sawa
//↓- ADPCMCHANNEL構造体を扱い易く並び替えて、ASM版adpcm_mix1()を最適化しました。
//typedef struct _ADPCMCHANNEL {
//	int pcm;			/* + 0,4: 出力PCM値 */
//	short data;			/* + 4,2: 入力ADPCM値のバッファ */
//	short delta;			/* + 6,2: ⊿値 */
//	short progress;			/* + 8,2: 進行カウンタ */
//	short rate;			/* +10,2: サンプリングレート */
//	int len;			/* +12,4: 残り出力サンプル数 */
//	const unsigned char* ptr;	/* +16,4: ADPCMデータ走査位置 */
//	int loop;			/* +20,4: 0=停止, 1～=残りループ回数, -1=無限ループ */
//	int init_len;			/* +24,4: 残り出力サンプル数のリセット値 */
//	const unsigned char* init_ptr;	/* +28,4: ADPCMデータ走査位置のリセット値 */
//} ADPCMCHANNEL;				/* =32 */
//↓* Mon Jul 15 20:32:11 JST 2013 Naoyuki Sawa
//↓- ADPCMCHANNEL構造体のフィールドを並び替えました。理由は、以下のとおりです:
//↓  1. これまでadpcm_mix1()にて、rateは書き戻し不要であるのに、書き戻していた無駄がありました。
//↓     書き戻し不要なフィールドを後ろにまとめて並び替え、rateを書き戻さないように改良しました。
//↓  2. 音量設定機能に対応するため、volフィールドを追加しました。
//↓     既存のloopフィールドをint⇒shortに縮小し、余った隙間にvolフィールドを追加しました。
//↓     従って、ADPCMCHANNEL構造体全体のサイズは、これまでと変わっていません。
//↓     ※補足 loopフィールドを縮小したため、loop値として32768～-2の値は使用できなくなりました。
//↓            実際にloop値として上記のような値を使うことはまず無いので、大丈夫と思います。
typedef struct _ADPCMCHANNEL {
	const unsigned char* ptr;	/* + 0,4: ADPCMデータ走査位置 */
	int len;			/* + 4,4: 残り出力サンプル数 */			//{{2017/06/26コメント追記:2017/06/26以前は、PCEWAVEINFO.resvと同じ値(16000Hz換算でのサンプル数)をそのまま格納していました。2017/06/26以降は、adpcm_play()にて実サンプル数に変換して格納するようになりました。}}
	int pcm;			/* + 8,4: 出力PCM値 */
	short data;			/* +12,2: 入力ADPCM値のバッファ */
	short delta;			/* +14,2: ⊿値 */
	short progress;			/* +16,2: 進行カウンタ */
//{{2017/06/26コメント変更:adpcm_rate()関数を追加しました。
//	short rate;			/* +18,2: サンプリングレート */
//↓2017/06/26コメント変更:adpcm_rate()関数を追加しました。
	short rate;			/* +18,2: 再生レート */
//}}2017/06/26コメント変更:adpcm_rate()関数を追加しました。
	short vol;			/* +20,2: 音量 */
	short loop;			/* +22,2: 0=停止, 1～=残りループ回数, -1=無限ループ */
	const unsigned char* init_ptr;	/* +24,4: ADPCMデータ走査位置のリセット値 */
	int init_len;			/* +28,4: 残り出力サンプル数のリセット値 */	//{{2017/06/26コメント追記:2017/06/26以前は、PCEWAVEINFO.resvと同じ値(16000Hz換算でのサンプル数)をそのまま格納していました。2017/06/26以降は、adpcm_play()にて実サンプル数に変換して格納するようになりました。}}
} ADPCMCHANNEL;				/* =32 */

typedef struct _ADPCMDRIVER {
	int nch;			/* チャネル数 */
	ADPCMCHANNEL* pch/*[nch]*/;	/* チャネル構造体 */
} ADPCMDRIVER;

/* clipadp.c */
extern const short adpcm_tbl[4/*ADPCM値*/][2];	//{{2013/07/15追加:高速RAMを節約するため、係数テーブルをframadp.cからclipadp.cへ移動しました。}}

/* framadp.c */
void adpcm_mix1(ADPCMCHANNEL* pch, int mixbuf[/*ADPCMBUFLEN*/]);
void adpcm_mix2(short wbuff[/*ADPCMBUFLEN*/], int mixbuf[/*ADPCMBUFLEN*/]);

/****************************************************************************
 *	アプリケーション用関数
 ****************************************************************************/

/* 2-bit ADPCM Decoderを起動します。
 * [in]
 *	nch		チャネル数。
 * [note]
 *	* adpcm_play()を使う前にadpcm_init()を呼び出して、2-bit ADPCM Decoderを起動しておいてください。
 *	* この関数は、内部でstream_play()を呼び出しています。
 *	  stream_play()を呼ぶと、サウンド割り込みベクタがフックされます。
 *	  プログラム終了前にadpcm_exit()を呼び出して、ベクタを復元してください。
 *	  ただし、ライブラリが終了時に自動的にフックを復元するので、adpcm_exit()を呼ばずに終了しても安全です。
 */
void adpcm_init(int nch);

/* 2-bit ADPCM Decoderを停止します。
 * [note]
 *	* 2-bit ADPCM Decoderが起動していなければ、この関数は何も行いません。
 */
void adpcm_exit();

/* 2-bit ADPCM形式のppdデータを再生します。
 * [in]
 *	ch		チャネル番号。(1～nch-1)
 *	data		2-bit ADPCM形式のppdデータ。(ファイルイメージの先頭アドレス)
 *	loop		1～ = ループ回数, -1 = 無限ループ。
 * [note]
 *	* この関数の使い方は、sound_play()と同じです。
 *	  clippce.hのsound_play()のコメントを参照してください。
 *	* この関数は、2-bit ADPCM形式のppdデータの再生にのみ利用できます。
 *	  2-bit ADPCM形式以外のppdを指定すると、エラー終了します。
 *	  2-bit ADPCM形式以外のppdを再生するには、sound_play()を利用してください。
 */
void adpcm_play(int ch, const void* data, int loop);

/* 2-bit ADPCM形式のppdデータ再生を停止します。
 * [in]
 *	ch		チャネル番号。(1～nch-1)
 * [note]
 *	* 指定されたチャネルが再生中でない場合は、この関数は何も行いません。
 */
void adpcm_stop(int ch);

/* 指定された2-bit ADPCMチャネルが、再生中か停止中かを調べます。
 * [in]
 *	ch		チャネル番号。(1～nch-1)
 * [out]
 *	戻り値		再生中ならば0以外の値を返します。
 *			停止中ならば0を返します。
 * [note]
 *	* 2007/03/01現在の実装は、ADPCMCHANNEL.loopの値をそのまま返しているので、
 *	  戻り値は、{0=停止, 1～=残りループ回数, -1=無限ループ} となっています。
 *	  ただし、今後もし実装を変更した場合に、戻り値が変わる可能性があります。
 *	  戻り値を、上のように仮定してコーディングしないよう、注意してください。
 */
int adpcm_stat(int ch);

//{{2013/07/15追加
/* 指定された2-bit ADPCMチャネルの、減衰量を設定します。
 * [in]
 *	ch		チャネル番号。(1～nch-1)
 *	att		減衰量。(0～64)
 * [note]
 *	* 減衰量は 減衰無し:0～64:消音 です。
 *	  数値範囲は、P/ECE APIのpceWaveSetMasterAtt()とpceWaveSetChAtt()に倣いました。
 *	- pceWaveSetMasterAtt()とpceWaveSetChAtt()のAPIリファレンスには、最大:0～127:最小 と書いてありますが、
 *	  実際の動作は、減衰無し:0～64:消音 であり、64以上は全て消音です。
 *	  ⇒ /usr/PIECE/sysdev/pcekn/snd.c volcalc() 参照
 *	  本関数も、pceWaveSetMasterAtt()とpceWaveSetChAtt()の実際の動作に倣い、0～64 で指定することしました。
 */
void adpcm_att(int ch, int att);
//}}2013/07/15追加

//{{2017/06/26追加:adpcm_rate()関数を追加しました。
/* 指定された2-bit ADPCMチャネルの、再生レートを設定します。
 * [in]
 *	ch		チャネル番号。(1～nch-1)
 *	rate		再生レート。(0～SPEAKER_FREQUENCY)	⇒{{2017/06/30コメント追記:引数rateに指定する再生レートは、絶対値である事に注意して下さい。サウンドデータのサンプリングレートに相対的な再生レートで再生したい場合は、ppd_playback_rate()と組み合わせて使用して下さい。使用例は、clippce.hのppd_playback_rate()の説明を参照して下さい。}}
 * [note]
 *	- 停止しているチャネルに対する、当関数の呼び出しは、ダミー処理となり、安全です。			┬重要
 *	  何も行われず、エラーも発生しません。									│
 *	- 当関数で設定した再生レートは、当該チャネルの再生が継続している間のみ有効です。			│
 *	  当該チャネルにて次の再生が行われた時には、再生するサウンドデータの既定の再生レートが使用されます。	┘
 *	- 当関数は、2-bit ADPCM Decoder特有の機能です。
 *	  他のサウンドドライバ(cliptsp.cモジュールや、P/ECE標準のpceWave*())には、再生レートを設定する機能は有りません。
 *	  2-bit ADPCM Decoderだけに、再生レートを設定する機能を追加した理由は、2-bit ADPCM Decoderの既存のコードだけが、再生レートの設定に対応し易い実装になっていたからです。
 *	- 再生レートを設定する機能を追加した理由は、以下の通りです。
 *	  この度、レースゲームのエンジン音を、再生レートを変化しながら再生したい要件が発生し、2-bit ADPCM Decoderにその機能を追加して対応する事にしました。
 *	  又は、別の案として、既に再生レートの設定に対応しているclipmod.cモジュールを使用したり(例としてはclipmidi.cがその方法を取っています)、
 *	  アプリケーションが直接stream_play()を使用して、アプリケーションが直接エンジン音のデータを再生レートを変化しながらストリームに引き渡す案も考えたのですが、それらの方法は取りませんでした。
 *	  前者の案を取らなかった理由は、ゲームの効果音の再生レートを変えるためだけにclipmod.cモジュールを使用するのは、clipmod.cモジュールの機能が多過ぎて無駄が多いからです。
 *	  後者の案を取らなかった理由は、アプリケーションが直接stream_play()を使用すると、他のサウンドドライバと併用出来ず、再生レートを変える必要の無い効果音までアプリケーション側でミキシングする必要が生じ、実装の手間が掛かるからです。
 *	  上記の理由により、2-bit ADPCM Decoderに再生レートを設定する機能を追加するのが適切だと判断しました。
 *	  今後、ゲームの効果音等で再生レートを変化する必要が有る場合は、サウンドドライバとして、2-bit ADPCM Decoderを選択して下さい。
 *	- 本当は、一番データ容量を小さく出来るcliptsp.cモジュールに、再生レートを設定する機能を追加したかったのですが、それは出来ませんでした。
 *	  cliptsp.cモジュールの実装は、TrueSpeechのデータが8KHzである事に依存していて、再生レートを変え易いような仕組みになっていないからです。
 *	  また、P/ECE標準のpceWave*()は、内部処理的には当モジュール(2-bit ADPCM Decoder)と同じで、少ない変更で再生レートの設定に対応出来るのですが、pceWave*()はフラッシュメモリ上のP/ECEカーネル内に有って手が出せないので、対応不可です。
 */
void adpcm_rate(int ch, int rate);
//}}2017/06/26追加:adpcm_rate()関数を追加しました。

#ifdef  __cplusplus
}//extern "C"
#endif//__cplusplus

#endif /*__CLIP_ADP_H__*/
