/*
 *	wav2adp2.c
 *
 *	dppcmcnv - WAV to PPD コンバータ
 *	Copyright (C) 2002-2006 Naoyuki Sawa
 *
 *	* Tue Dec 19 18:05:32 JST 2006 Naoyuki Sawa
 *	- 作成開始。
 *	- clip/keep/2-bit ADPCMの参考資料.7z/Adpcm2bit/main.cも参照してください。
 *	* Wed Dec 20 16:59:20 JST 2006 Naoyuki Sawa
 *	- 2bitADPCM可変周波数(独自拡張)のエンコードにおいて、⊿値が大きくなりすぎないよう、制限を設けました。
 *	* Fri Dec 22 00:19:41 JST 2006 Naoyuki Sawa
 *	- P/ECE上のデコーダ実装を簡単にするため、係数テーブルを変更しました。
 */
#include "app.h"

/*{{2006/12/19追加: 2bitADPCM可変周波数(独自拡張)*/

/****************************************************************************
 *	encode2
 ****************************************************************************/

/* [NOTE]
 *	デコード後の出力PCM値が-32768～32767に収まるよう調整することは行いません。
 *	どうせ実行時には、複数チャネルを合成した後に-32768～32767に切り詰める必要があるので、
 *	チャネル単位のPCM出力が-32768～32767をオーバーしても構わないことにします。
 */
void
encode2(unsigned char* adp, signed short* wave, int size)
{
	int delta = 16; /* 調整可。ただし、デコーダと一致させること */
	int pcm = 0;
	//
	int i;
	int j;
	//
	int a;
	int b;
	//int d[4/*ADPCM*/][2]; /* [0] = 出力PCM値への加算値候補, [1] = 新しい⊿値の候補 */
	//↓* Fri Dec 22 00:19:41 JST 2006 Naoyuki Sawa
	int d[4/*ADPCM*/][2]; /* [0] = 新しい⊿値の候補, [1] = 出力PCM値への加算値候補 */

	/* tbl[][0]	前回の⊿値にこの値を掛けて、出力PCM値に加算します。
	 *		入力ADPCM値が0の場合	NewPCM = OldPCM + Old⊿*0.5 = OldPCM + ((Old⊿* 128)>>8)
	 *		入力ADPCM値が1の場合	NewPCM = OldPCM + Old⊿*1.5 = OldPCM + ((Old⊿* 384)>>8)
	 *		入力ADPCM値が2の場合	NewPCM = OldPCM - Old⊿*0.5 = OldPCM + ((Old⊿*-128)>>8)
	 *		入力ADPCM値が3の場合	NewPCM = OldPCM - Old⊿*1.5 = OldPCM + ((Old⊿*-384)>>8)
	 *
	 * tbl[][1]	前回の⊿値にこの値を掛けて、新しい⊿値とします。
	 *		入力ADPCM値が0,2の場合	New⊿ = Old⊿*(1.1^-1) = Old⊿*0.909 = (Old⊿*233)>>8
	 *		入力ADPCM値が1,3の場合	New⊿ = Old⊿*(1.1^ 4) = Old⊿*1.464 = (Old⊿*375)>>8
	 *
	 * 注意①	上述のとおり、⊿値の増加方向への更新は、1.464を掛けることによって行われます。
	 *		もし⊿値が2以下になると、1.464を掛けても2のままで変化しなくなってしまいます。
	 *		⊿値が常に3以上となるよう、エンコード時に出力ADPCM値を調整する必要があります。
	 *
	 * 注意②	2-bit ADPCMにおいて音質を良く保つためのポイントは、⊿値を減少させすぎないことです。
	 *		もし、⊿値の減少率を0.909→0.5、増加率を1.464→1.5に変更することができれば、
	 *		⊿値の変化率と出力PCMへの加算値の処理が共通化できるので、そうしたくなるところです。
	 *		しかし、⊿値の減少率を0.909→0.5に変化すると、雑音が増えて音質が非常に低下します。
	 *		増加率を1.464→1.5に変更してもさほど影響はないので、こちらは変更しても構いません。
	 *
	 * 注意③	Wed Dec 20 16:46:31 JST 2006 Naoyuki Sawa 追記
	 *		注意①で、⊿値を3以上に保つことを述べましたが、さらに、上限の制限も必要なようです。
	 *		本アルゴリズムでは、入力データによっては、⊿値が70000を超えてしまうこともあります。
	 *		P/ECE上のデコータでmlt.hを使い高速化できるよう、⊿値を32767以下に保つことにします。
	 *		この制限を設けても、音質の低下は気づかない程度であるようです。
	 */
	//static const short tbl[4/*ADPCM値*/][2] = {
	//	{  128, 233 },
	//	{  384, 375 },
	//	{ -128, 233 },
	//	{ -384, 375 },
	//};
	//↓* Fri Dec 22 00:19:41 JST 2006 Naoyuki Sawa
	//↓- P/ECE上のデコーダ実装を簡単にするため、係数テーブルを変更しました。
	//↓- 変更前は、以下のような処理の流れでした。
	//↓	① 旧い⊿値に係数αを掛けて、出力PCM値への加算値を求める。
	//↓	② 旧い⊿値に係数βを掛けて、新しい⊿値とする。
	//↓  この流れでは、②の時点まで旧い⊿値を保持する必要があり、レジスタを多く必要とします。
	//↓  もし以下のような流れに変更できれば、旧い⊿値を保持する必要が無くなり、レジスタが節約できます。
	//↓	① 旧い⊿値に係数βを掛けて、新しい⊿値とする。
	//↓	② 新しい⊿値に係数γを掛けて、出力PCM値への加算値を求める。
	//↓  新しい⊿値には既に係数βが掛かっていることを考えると、係数γは以下のように定められます。
	//↓	係数γ = 係数α / 係数β
	//↓- 変更前と変更後で①②の処理が逆になったので、tbl[][*]の意味も入れ替えることにしました。
	//↓  この入れ替えは必須ではなく、コードを読みやすくするためだけの入れ替えです。
	//↓- 以上の変更を行ってもエンコードアルゴリズムは同じなので、演算誤差以外の音質の違いは生じません。
	#define A	233	/* =(    1.1^-1)*256 */
	#define B	375	/* =(    1.1^ 4)*256 */
	#define C	141	/* =(0.5/1.1^-1)*256 */
	#define D	263	/* =(1.5/1.1^ 4)*256 */
	static const short tbl[4/*ADPCM値*/][2] = {
		{ A,  C },
		{ B,  D },
		{ A, -C },
		{ B, -D },
	};
	#undef A
	#undef B
	#undef C
	#undef D

	/* 入力ファイル全体について、4サンプルづつ処理します。
	 * 入力ファイルは16000Hz・16ビットと仮定しているので、4サンプル当たり8バイト進みます。
	 */
	for(i = 0; i < size; i += 8) {
		for(j = 0; j < 4; j++) {

			/* 0～3のADPCM値に対応する、出力PCM値への加算値候補と、新しい⊿値の候補を作成します。 */
			for(a = 0; a < 4; a++) {
				//d[a][0] = (delta * tbl[a][0]) >> 8;	/* ① 旧い⊿値に係数αを掛けて、出力PCM値への加算値を求める。 */
				//d[a][1] = (delta * tbl[a][1]) >> 8;	/* ② 旧い⊿値に係数βを掛けて、新しい⊿値とする。 */
				//↓* Fri Dec 22 00:19:41 JST 2006 Naoyuki Sawa
				d[a][0] = (delta   * tbl[a][0]) >> 8;	/* ① 旧い⊿値に係数βを掛けて、新しい⊿値とする。 */
				d[a][1] = (d[a][0] * tbl[a][1]) >> 8;	/* ② 新しい⊿値に係数γを掛けて、出力PCM値への加算値を求める。 */
			}

			/* ⊿値が3以上である、最初のADPCM値候補を検索します。 */
			for(a = 0; a < 4 - 1; a++) {
				//if(d[a][1] >= 3) {
				//↓2006/12/20変更
				//if((d[a][1] >= 3) && (d[a][1] <= 32767)) {
				//↓* Fri Dec 22 00:19:41 JST 2006 Naoyuki Sawa
				if((d[a][0] >= 3) && (d[a][0] <= 32767)) {
					break;
				}
			}

			/* 以降の候補から、⊿値が3以上で、より良い出力PCM値が得られる候補があるか検索します。 */
			for(b = a + 1; b < 4; b++) {
				//if(d[b][1] >= 3) {
				//↓2006/12/20変更
				//if((d[b][1] >= 3) && (d[b][1] <= 32767)) {
				//	if(abs((pcm + d[b][0]) - *pos) <
				//	   abs((pcm + d[a][0]) - *pos)) {
				//		a = b;
				//	}
				//}
				//↓* Fri Dec 22 00:19:41 JST 2006 Naoyuki Sawa
				if((d[b][0] >= 3) && (d[b][0] <= 32767)) {
					if(abs((pcm + d[b][1]) - *wave) <
					   abs((pcm + d[a][1]) - *wave)) {
						a = b;
					}
				}
			}

			/* 出力PCM値と⊿値を更新します。 */
			//pcm  += d[a][0];
			//delta = d[a][1];
			//↓* Fri Dec 22 00:19:41 JST 2006 Naoyuki Sawa
			delta = d[a][0];
			pcm  += d[a][1];

			/* 4サンプル単位の、#0サンプルがbit0-1、#3サンプルがbit6-7に格納されるようにします。
			 * P/ECE標準の4bit ADPCMとは逆の並びですが、扱い易さを優先してこのように定めました。
			 */
			*adp = (*adp>>2) | (a<<6);

			wave++;
		}
		adp++;
	}
}

/*}}2006/12/19追加: 2bitADPCM可変周波数(独自拡張)*/
