
/************************************************************
**	GHDSS_core.c
**
**  Private :
**
**  History :
**     2014.12.12 K.Takagi@SIF CalcSSStepSize_GHDSS の一部計算をdoubleに変更
**
**     2013.12.12 M.Takigahira libharkio3に対応
**     2013.05.14 M.Takigahira Build有無指定に対応
**     2012.12.09 kama@SIF     新規作成(V1.0)
**
**  Description
**  -----------
**  GHDSS
**  入力1　：
**  出力1　：
**
*/

///////////////////////////////////////////////////////////////
//  Include Files
#include "HA_config.h"
#include "build_modules.h"
//////////#include "header.h"
#include "HA_log.h"
#include "android_hark.h"

#ifdef ENABLE_HARKIO3
#include <complex.h>
#include <libharkio3_macros.h>
#include <libharkio3.h>
#endif

///////////////////////////////////////////////////////////////
//  Define Macros
// for switching GHDSS mode. not to used yet.
#define TF_CONJ_CALC              (0)
#define TF_CONJ_DB                (1) // 現状、TFはファイルから読む
#define MIC_POS_FIX               (0)
#define MIC_POS_SHIFT             (1)
#define SS_METHOD_FIX             (0)
#define SS_METHOD_LC_MYU          (1)
#define SS_METHOD_ADAPTIVE        (2) // 現状、SSは常にAdaptiveで計算する
#define LC_CONST_DIAG             (0)
#define LC_CONST_FULL             (1) // 現状、常にFULLとする
#define LC_METHOD_FIX             (0)
#define LC_METHOD_ADAPTIVE        (1) // 現状、LCは常にAdaptiveで計算する
#define UPDATE_METHOD_TF_CONJ_ID  (0)
#define UPDATE_METHOD_TF_CONJ_POS (1)
#define UPDATE_METHOD_W_ID        (0)
#define UPDATE_METHOD_W_POS       (1)
#define UPDATE_METHOD_W_ID_POS    (2)
#define UPDATE_STEP               (0)
#define UPDATE_TOTAL              (1)

#define SRC_NOT_EXIST             (0)
#define SRC_DETECTED              (1)
#define SRC_CONTINUE              (2)

#define	ha_iUpdate 	(0)		// SS_METHOD
#define	ha_fWmyu 	(0)		//

#define	THRESHOLD 	(1000)		//  <- あとでパラメータ化

#if !defined BUILD_MODULE_GHDSS
/******************************************************************************
**
**  History
**  -----------
**  2013.05.14 M.Takigahira 新規作成
**
**  Description
**  -----------
**  全ての関数をダミー定義
**
*/
void ClearGHDSS(void){ }
int	ChangeSrcPos_W(int num_src){ return 0; }
int	ChangeSrcPos_TF_CONJ(){ return 0; }
int GetNearestPos(int id){ return 0; }
int GetNearestTFMatrixFromDB(){ return 0; }
//int	InitTFMatrix(){ return 0; }
int	InitTFMatrix(char *tf_file_name){ return 0; }
int	MakeWMatGHDSS(int num_src){ return 0; }
int	InitSepMatrix(int num_src){ return 0; }
int	InitUpdateW(){ return 0; }
int	CalcLCStepSize_GHDSS(int num_src){ return 0; }
int	CalcSSStepSize_GHDSS(int num_src){ return 0; }
int	dUpdateSeparationMatGHDSS(int num_src, HA_Complex inputSpec[ARY_NUM_MIC][ARY_NUM_FFT]){ return 0; }
int	ExecuteGHDSS(int num_src, HA_Complex inputSpec[ARY_NUM_MIC][ARY_NUM_FFT]){ return 0; }
int SetUpdateW(){ return 0; }
int AddUpdateW(){ return 0; }
int GHDSS_core(int num_src, int num_src_pre, HA_Complex inputSpec[ARY_NUM_MIC][ARY_NUM_FFT], MICARY_Location localSrcPos[ARY_NUM_SRC], HA_Complex outputSpec[ARY_NUM_SRC][ARY_NUM_FFT]){ return 0; }
#else // #if defined BUILD_MODULE_GHDSS
///////////////////////////////////////////////////////////////
//	外部変数

MICARY_Location	locaSrcPos[ARY_NUM_SRC];				// 定位した音源位置
MICARY_Location	locaMicPos[ARY_NUM_MIC];				// マイク位置
MICARY_Location	locaTFPos[ARY_NUM_TF_POS];				// TFを求めた際の音源数 360/5 = 72

HA_Complex		csaOutputSpec[ARY_NUM_SRC][ARY_NUM_FFT];		// 分離した出力スペクトル

HA_Complex		piaFreqLine[ARY_NUM_FFT][ARY_NUM_MIC][ARY_NUM_TF_POS]; 	// 伝達関数格納用配列
HA_Complex		OutTF[ARY_NUM_SRC][ARY_NUM_FFT][ARY_NUM_MIC]; 			// 音源に近いTF

//HA_Complex		sepMat[ARY_NUM_SRC][ARY_NUM_FFT][ARY_NUM_MIC];		// 分離行列
HA_Complex		sepMat[10][ARY_NUM_FFT][ARY_NUM_MIC];		// 分離行列
HA_Complex		updateW[ARY_NUM_SRC][ARY_NUM_FFT][ARY_NUM_MIC];	// 分離行列（更新用）

int				mat_id[ARY_NUM_SRC];					// 分離行列のnum_srcに対するID
int				stat_id[10];						// IDのステータス。SRC_NOT_EXIST(0)-音源なし、SRC_DETECTED(1)-音源検出（初回）、SRC_CONTINUE(2)-音源継続

HA_Complex	A[ARY_NUM_MIC][ARY_NUM_SRC];		// 演算用配列
HA_Complex	W[ARY_NUM_SRC][ARY_NUM_MIC];		// 演算用配列（分離行列）
HA_Complex	X[ARY_NUM_MIC];					// 演算用配列（マイクの入力）
HA_Complex	Y[ARY_NUM_SRC];					// 演算用配列

HA_Complex	J_SS[ARY_NUM_SRC][ARY_NUM_MIC];		// μSS
HA_Complex	J_LC[ARY_NUM_SRC][ARY_NUM_MIC];		// μLC

HA_Complex 	PY[ARY_NUM_SRC];	// PY
HA_Complex 	QY[ARY_NUM_SRC];	// QY

int		m_bFlgIni	= TRUE;				// 初期化フラグ
int     num_tf_pos  = ARY_NUM_TF_POS;
int     num_mic = ARY_NUM_MIC;


/* 2013.02.15 初期化処理を追加 */
void ClearGHDSS(void)
{
	m_bFlgIni = TRUE;
    num_tf_pos = ARY_NUM_TF_POS; /* 2013.03.05 K.Takagi TFの数をファイルから取得するように変更 */
    num_mic = ARY_NUM_MIC; /* 2013.08.26 M.Takigahira MIC数をファイルから取得するのに関連した変更 */

	/* バッファの初期化 */
	bzero(csaOutputSpec, sizeof(csaOutputSpec));
	bzero(piaFreqLine, sizeof(piaFreqLine));
	bzero(OutTF, sizeof(OutTF));
	bzero(sepMat, sizeof(sepMat));
	bzero(updateW, sizeof(updateW));
	bzero(mat_id, sizeof(mat_id));
	bzero(stat_id, sizeof(stat_id));
	bzero(A, sizeof(A));
	bzero(W, sizeof(W));
	bzero(X, sizeof(X));
	bzero(Y, sizeof(Y));
	bzero(J_SS, sizeof(J_SS));
	bzero(J_LC, sizeof(J_LC));
	bzero(PY, sizeof(PY));
	bzero(QY, sizeof(QY));
}

///////////////////////////////////////////////////////////////
//	Wの更新
int	ChangeSrcPos_W(int num_src)
{
	InitSepMatrix(num_src);
#ifdef NEVER

	int i;
	int Npos_ini,Npos_cur,Nmic,Nfreq,iLower_f,iUpper_f;
	bool bRtn ,bRtnID;
	int iRtn = 2;

	Nmic = m_psSepMat->micary_smSeparation.ha_numInput;
	Npos_ini = m_psSepMat->micary_tdTFDB.micary_locaSource.ha_numLocation;
	iLower_f = m_psSepMat->micary_smSeparation.micary_iaFreqLinex.ha_iValue[0];
	iUpper_f = m_psSepMat->micary_smSeparation.micary_iaFreqLinex.ha_numValue + iLower_f -1;
	Nfreq = m_psSepMat->micary_smSeparation.micary_iaFreqLinex.ha_numValue;
	Npos_cur = plaSrcPosCur.ha_numLocation;

	//配列数の切りなおし
	if(Npos_ini != Npos_cur){
		iRtn = 1;
	}

	if(m_iUpdateMethodWex->ha_numValue != Npos_cur){
		IntArrayFree(m_iUpdateMethodWex);
		IntArrayAlloc(m_iUpdateMethodWex,Npos_cur);
	}
	
	// Change_Src_Pos_TF_CONJで切り直されているはず
	if(m_psSepMat->micary_smSeparation.micary_cmpaSeparation.ha_numValue != Npos_cur * Nfreq*Nmic){
		SeparationMatFree(&m_psSepMat->micary_smSeparation);
		SeparationMatAlloc(&m_psSepMat->micary_smSeparation,Nfreq,Npos_cur,Nmic);
	}

	//音源情報の更新
	Cexec ::AssignSrcPos(plaSrcPosCur);

	// 分離行列の更新
	Cexec ::InitSepMatrix(&psPrmFrame);
	
	bRtn = false;
	bRtnID = false;
	int iInherit;
	iInherit = 0;

	//分離行列の引継ぎ確認
	for(i=0; i<Npos_cur; i++){
		m_iUpdateMethodWex->ha_iValue[i] = m_iUpdateMethodW ;

		if(m_iUpdateMethodW == __UPDATE_METHOD_ID || m_iUpdateMethodW == __UPDATE_METHOD_ID_POS){
			// IDベースの確認
			bRtnID = _CheckSrcID_W(i);
			if(bRtnID == true){ iInherit++; }
		}

		//実際の更新はID or POS
		if(m_iUpdateMethodW == __UPDATE_METHOD_ID_POS){
			if(bRtnID == false){
				m_iUpdateMethodWex->ha_iValue[i] = __UPDATE_METHOD_POS;
			}
			else{
				m_iUpdateMethodWex->ha_iValue[i] = __UPDATE_METHOD_ID;
			}
		}

		if(m_iUpdateMethodWex->ha_iValue[i] == __UPDATE_METHOD_POS){
			//POSベースの確認
			bRtn = _CheckSrcPos_W(i);
			if(bRtn == true){ iInherit++; }
			else{
				if(m_iUpdateMethodW == __UPDATE_METHOD_ID_POS){
					m_iUpdateMethodWex->ha_iValue[i] = __UPDATE_METHOD_ID;
				}
			}
		}
	}
	if(iRtn == 1){	//音源数、変更
		return 1 ;
	}
	else{
		if(iInherit == Npos_cur){	//全て変更なし
			return 0 ;
		}
		else{	//一部変更
			return 2 ;
		}
	}
#endif
	return(OK);
}

///////////////////////////////////////////////////////////////
//	TFの更新
int	ChangeSrcPos_TF_CONJ()
{
	int f, m;
		//for(m=0; m<8; m++){
		//	LOGI("OutTF[0][0][m](%f, %f)\n", OutTF[0][0][m].re, OutTF[0][0][m].im);
		//}
	//InitTFMatrix();		// 座標から毎回TFを初期化
	GetNearestTFMatrixFromDB();
#ifdef NEVER
	// バックアップ
	for(n=0; n<Npos_ini; n++){
	   plaSrcPosIni.ha_idLocation[n] = m_psSepMat->micary_tdTFDB.micary_locaSource.ha_idLocation[n];
	   plaSrcPosIni.micary_Location[n].ha_fX = m_psSepMat->micary_tdTFDB.micary_locaSource.micary_Location[n].ha_fX;
	   plaSrcPosIni.micary_Location[n].ha_fY = m_psSepMat->micary_tdTFDB.micary_locaSource.micary_Location[n].ha_fY;
	   plaSrcPosIni.micary_Location[n].ha_fZ = m_psSepMat->micary_tdTFDB.micary_locaSource.micary_Location[n].ha_fZ;
	   plaSrcPosIni.micary_Location[n].ha_idPos = m_psSepMat->micary_tdTFDB.micary_locaSource.micary_Location[n].ha_idPos;
	   plaSrcPosIni.micary_Location[n].ha_fTheta = m_psSepMat->micary_tdTFDB.micary_locaSource.micary_Location[n].ha_fTheta;
	   plaSrcPosIni.micary_Location[n].ha_fPhi = m_psSepMat->micary_tdTFDB.micary_locaSource.micary_Location[n].ha_fPhi;
	}

	plaSrcPosIni.micary_Location->micary_LocationFlag = m_psSepMat->micary_tdTFDB.micary_locaSource.micary_Location->micary_LocationFlag;

	ComplexArrayAlloc(&tmp_cmpaTFDB,0);
    	ComplexArrayAlloc(&tmp_cmpaTFDB,(int)Nfreq*Npos_ini*Nmic);
    	for(n=0; n<m_psSepMat->micary_tdTFDB.micary_cmpaTF.ha_numValue;n++){
		tmp_cmpaTFDB.ha_cmpValue[n].re = m_psSepMat->micary_tdTFDB.micary_cmpaTF.ha_cmpValue[n].re ;
		tmp_cmpaTFDB.ha_cmpValue[n].im = m_psSepMat->micary_tdTFDB.micary_cmpaTF.ha_cmpValue[n].im ;
	}

	//配列数の切りなおし
	if(Npos_ini != Npos_cur){
		Initialize_Change(Nmic,Npos_cur,iLower_f,iUpper_f);
		iRtn = 1;
	}

	//音源情報・TF_CONJの更新
	Cexec ::AssignSrcPos(plaSrcPosCur);

	//TF_CONJの更新
	Cexec :: InitTFMatrix(&psPrmFrame);
	bRtn = false ; 
	if(m_iUpdateMethodTF_CONJ == __UPDATE_METHOD_ID){
		bRtn = _CheckSrcID_TF_CONJ(tmp_cmpaTFDB,plaSrcPosIni);
	}
	
	//W更新用に一度元に戻す
	Cexec :: AssignSrcPos(plaSrcPosIni);
	
	ComplexArrayFree(&tmp_cmpaTFDB);
	LocationArrayFree(&plaSrcPosIni);

	if(iRtn == 1){	//数が変更
		return 1 ;
	}
	else{
		if(bRtn == false){ //位置が変更、数は不変
			return 2 ;
		}
		else{	//位置，数変更なし
			return 0 ;
		}
	}
#endif
	return(OK);
}

///////////////////////////////////////////////////////////////
//	TFの初期化

// DBから一番近い情報のIndexを取得
int GetNearestPos(int id)
{
	HA_Float 	ha_fMaxP ,ha_fP, ha_fNorm, tmp_x, tmp_y, tmp_z;
	HA_Integer 	ha_iMax;
	HA_Float 	laCurN[3], laPosN[3];	// X=0,Y=1,Z=2
	int	k ;

	ha_fMaxP = -32768.0 ;

	// 2013.02.14
	//LOGI("GetNearestPos");
	//LOGD("  Pos(%d) : %f , %f , %f", id, locaSrcPos[id].ha_fX, locaSrcPos[id].ha_fY, locaSrcPos[id].ha_fZ);

	// 正規化
	//	ha_fNorm = √(X^2 + Y^2 + Z^2)
	//
	/*
	ha_fNorm = pow((double)locaSrcPos[id].ha_fX, 2.0)
			 + pow((double)locaSrcPos[id].ha_fY, 2.0)
			 + pow((double)locaSrcPos[id].ha_fZ, 2.0);
	ha_fNorm = pow((double)ha_fNorm, 0.5);	// 平方根
	*/
	/* 2013.03.06 powを展開 */
	laCurN[0] = locaSrcPos[id].ha_fX;
	laCurN[1] = locaSrcPos[id].ha_fY;
	laCurN[2] = locaSrcPos[id].ha_fZ;
	//ha_fNorm  = locaSrcPos[id].ha_fX * locaSrcPos[id].ha_fX;
	//ha_fNorm += locaSrcPos[id].ha_fY * locaSrcPos[id].ha_fY;
	//ha_fNorm += locaSrcPos[id].ha_fZ * locaSrcPos[id].ha_fZ;
	ha_fNorm  = laCurN[0] * laCurN[0];
	ha_fNorm += laCurN[1] * laCurN[1];
	ha_fNorm += laCurN[2] * laCurN[2];
	ha_fNorm  = sqrtf(ha_fNorm);	// 平方根
	ha_fNorm  = 1.0f / ha_fNorm;
	
	//laCurN[0] = locaSrcPos[id].ha_fX * ha_fNorm ;	// X, ha_fNorm = 1.0f / ha_fNorm
	//laCurN[1] = locaSrcPos[id].ha_fY * ha_fNorm ;	// Y, ha_fNorm = 1.0f / ha_fNorm
	//laCurN[2] = locaSrcPos[id].ha_fZ * ha_fNorm ;	// Z, ha_fNorm = 1.0f / ha_fNorm
	laCurN[0] *= ha_fNorm ;	// X, ha_fNorm = 1.0f / ha_fNorm
	laCurN[1] *= ha_fNorm ;	// Y, ha_fNorm = 1.0f / ha_fNorm
	laCurN[2] *= ha_fNorm ;	// Z, ha_fNorm = 1.0f / ha_fNorm
	
	// DB内の各ベクトルと内積をとる
	//
	for(k=0; k<num_tf_pos; k++){
		// 正規化
		/*
	  	ha_fNorm = pow((double)locaTFPos[k].ha_fX, 2.0)
				 + pow((double)locaTFPos[k].ha_fY, 2.0)
				 + pow((double)locaTFPos[k].ha_fZ, 2.0);
		ha_fNorm = pow((double)ha_fNorm, 0.5);	// 平方根
		*/
		/* 2013.03.06 powを展開 */
		laPosN[0] = locaTFPos[k].ha_fX;
		laPosN[1] = locaTFPos[k].ha_fY;
		laPosN[2] = locaTFPos[k].ha_fZ;
	  	//ha_fNorm  = locaTFPos[k].ha_fX * locaTFPos[k].ha_fX;
		//ha_fNorm += locaTFPos[k].ha_fY * locaTFPos[k].ha_fY;
		//ha_fNorm += locaTFPos[k].ha_fZ * locaTFPos[k].ha_fZ;
	  	ha_fNorm  = laPosN[0] * laPosN[0];
		ha_fNorm += laPosN[1] * laPosN[1];
		ha_fNorm += laPosN[2] * laPosN[2];
		ha_fNorm  = sqrtf(ha_fNorm);	// 平方根
		ha_fNorm  = 1.0f / ha_fNorm;
		
		//laPosN[0] = locaTFPos[k].ha_fX * ha_fNorm ;	// X, ha_fNorm = 1.0f / ha_fNorm
		//laPosN[1] = locaTFPos[k].ha_fY * ha_fNorm ;	// Y, ha_fNorm = 1.0f / ha_fNorm
		//laPosN[2] = locaTFPos[k].ha_fZ * ha_fNorm ;	// Z, ha_fNorm = 1.0f / ha_fNorm
		laPosN[0] *= ha_fNorm * laCurN[0] ;	// x・X, ha_fNorm = 1.0f / ha_fNorm
		laPosN[1] *= ha_fNorm * laCurN[1] ;	// y・Y, ha_fNorm = 1.0f / ha_fNorm
		laPosN[2] *= ha_fNorm * laCurN[2] ;	// z・Z, ha_fNorm = 1.0f / ha_fNorm

		//ha_fP = _InnerProductVec(laPosN,laCurN);	// = x・X + y・Y + z・Z
		ha_fP = laPosN[0] + laPosN[1] + laPosN[2];
		//LOGI("%f\n", ha_fP);

		if(ha_fP > ha_fMaxP){
			ha_fMaxP = ha_fP ;
			ha_iMax = k ;
		}
	}

	// add 2009.7.9
	if(ha_fMaxP <= -32768.0){
		//ha_iMax = __INVALID_SRC_ID;
		ha_iMax = ERROR;
	}
	return ha_iMax ;
}

int GetNearestTFMatrixFromDB()
{
	int		i,j,m;
	int 	iDBpos;
	
	for(i=0; i<ARY_NUM_SRC; i++){
		iDBpos = GetNearestPos(i);
		//LOGI("iDBpos = %d, %d\n",i,iDBpos);

		for(j=0; j<ARY_NUM_FFT; j++){
			for(m=0; m<num_mic; m++){
				OutTF[i][j][m].re = piaFreqLine[j][m][iDBpos].re;
				OutTF[i][j][m].im = piaFreqLine[j][m][iDBpos].im;
				//LOGI("OutTF : %d, %f, %f\n", i, OutTF[i][j][m].re, OutTF[i][j][m].im);
			}
		}
	}

	// 2013.02.14
	/*
	LOGI("GetNearestTFMatrixFromDB");
	for(i=0; i<ARY_NUM_SRC; i++){
		iDBpos = GetNearestPos(i);
		LOGI("iDBpos = %d, %d\n",i, iDBpos);
		for(j=0; j<8; j++){
			for(m=0; m<num_mic; m++){
				LOGI("OutTF[%d][%d][%d](%f, %f)\n", i, j, m, OutTF[i][j][m].re, OutTF[i][j][m].im);
			}
		}
	}
	*/
	return(OK);
}

/*
	GTFファイルフォーマット
	0	: HARK
*/

//int	InitTFMatrix()
int	InitTFMatrix(char *tf_file_name)
{
#ifdef ENABLE_HARKIO3
    int f, s, m;
    float coord_tmp[3]; //if pos->sys is Polar
    LOGE("TF open");
    harkio_TransferFunction *tfp = harkio_TransferFunction_fromFile(tf_file_name, NULL);
    LOGE("TF opened");
    num_tf_pos   = tfp->poses->size;
    num_mic      = tfp->mics->size;
    int num_freq = tfp->cfg->nfft / 2 + 1;
    if(tfp->poses->pos[0]->sys == Cartesian){
        //LOGD("Source positions is Cartesian");
        for(s=0; s<num_tf_pos; s++){
            locaTFPos[s].ha_fX = tfp->poses->pos[s]->coord[0];
            locaTFPos[s].ha_fY = tfp->poses->pos[s]->coord[1];
            locaTFPos[s].ha_fZ = tfp->poses->pos[s]->coord[2];
            //LOGI("POS : sourceLocations[%d] = (%.6f, %.6f, %.6f) ", s, sourceLocations[s].x[0], sourceLocations[s].x[1], sourceLocations[s].x[2]);
        }
    }
    else{
        //LOGD("Source positions is Polar");
        for(s=0; s<num_tf_pos; s++){
            harkio_Position_Convert(tfp->poses->pos[s], coord_tmp, Cartesian);
            locaTFPos[s].ha_fX = coord_tmp[0];
            locaTFPos[s].ha_fY = coord_tmp[1];
            locaTFPos[s].ha_fZ = coord_tmp[2];
            //LOGI("POS : sourceLocations[%d] = (%.6f, %.6f, %.6f) ", s, sourceLocations[s].x[0], sourceLocations[s].x[1], sourceLocations[s].x[2]);
        }
    }
    if(tfp->mics->pos[0]->sys == Cartesian){
        //LOGD("Mic positions is Cartesian");
        for(m=0; m<num_mic; m++){
            locaMicPos[m].ha_fX = tfp->mics->pos[m]->coord[0];
            locaMicPos[m].ha_fY = tfp->mics->pos[m]->coord[1];
            locaMicPos[m].ha_fZ = tfp->mics->pos[m]->coord[2];
            //LOGI("MIC : micLocations[%d] = (%.6f, %.6f, %.6f) ", m, micLocations[m].x[0], micLocations[m].x[1], micLocations[m].x[2]);
        }
    }
    else{
        //LOGD("Mic positions is Polar");
        for(m=0; m<num_mic; m++){
            harkio_Position_Convert(tfp->mics->pos[m], coord_tmp, Cartesian);
            locaMicPos[m].ha_fX = coord_tmp[0];
            locaMicPos[m].ha_fY = coord_tmp[1];
            locaMicPos[m].ha_fZ = coord_tmp[2];
            //LOGI("MIC : micLocations[%d] = (%.6f, %.6f, %.6f) ", m, micLocations[m].x[0], micLocations[m].x[1], micLocations[m].x[2]);
        }
    }
    for(s=0; s<num_tf_pos; s++){
        //LOGD("get TF pos %d", s);
        if(tfp->septfs[s]->rows == num_mic && tfp->septfs[s]->cols == num_freq){
            for(m=0; m<num_mic; m++){
                for(f=0; f<num_freq; f++){
                    piaFreqLine[f][m][s].re = crealf(tfp->septfs[s]->data.complexdata[num_freq * m + f]);
                    piaFreqLine[f][m][s].im = cimagf(tfp->septfs[s]->data.complexdata[num_freq * m + f]);
                }
            }
        }
    }
    //int num_nbrs;
    //for(s=0; s<num_tf_pos; s++){
    //    harkio_Neighbors_getNeighbors(tfp->nbrs, s, neighborsInformations[s], &num_nbrs);
    //    neighborsInformations[s][num_nbrs] = -1; // terminate
    //}
    harkio_TransferFunction_delete(&tfp);
    //new_tf_format = 1;
#else // ENABLE_HARKIO3
	FILE	*fp;
	int i,j,k;
	float	fx,fy,fz;		// マイク座標
	float	re,im;

	char	s[256];
	int		d;
	short	major, minor;

	unsigned char	buf[256];

#ifdef NEVER

#if 1 // not L angle mic mode
	/* 下記は３話者用 */
#ifdef IS_APPLE_IOS
    extern char *getFilenameWithDocumentsPath(const char * const filename);

	if(NULL == (fp = fopen(getFilenameWithDocumentsPath("sep_tf.dat"),"rb"))){
		//printf("ERROR : TF file open.\n");
		LOGE("ERROR :SEP_TF file open.\n");
		return(ERROR);
	}
    
	LOGD("InitTFMatrix");
	LOGD("read sep_tf.dat");
    
    
#else // IS_APPLE_IOS

#ifdef ENABLE_ANDROID_PATH
	if(NULL == (fp = fopen("/mnt/sdcard/hark2/sep_tf.dat","rb"))){
		//printf("ERROR : TF file open.\n");
		LOGE("ERROR : SEP_TF file open.\n");
		return(ERROR);
	}

	LOGD("InitTFMatrix");
	LOGD("read /mnt/sdcard/hark2/sep_tf.dat");
#else // not ENABLE_ANDROID_PATH
	if(NULL == (fp = fopen("./hark-data/sep_tf.dat","rb"))){
		//printf("ERROR : TF file open.\n");
		LOGE("ERROR : SEP_TF file open.\n");
		return(ERROR);
	}

	LOGD("InitTFMatrix");
	LOGD("read /media/SD/hark2/sep_tf.dat");
#endif // end of ENABLE_ANDROID_PATH

#endif // IS_APPLE_IOS
    
#else // L angle mic mode

#ifdef IS_APPLE_IOS

	/* 下記はL字マイク用 */
    extern char *getFilenameWithDocumentsPath(const char * const filename);
    
	if(NULL == (fp = fopen(getFilenameWithDocumentsPath("sep_tf_l.dat"),"rb"))){
		//printf("ERROR : TF file open.\n");
		LOGE("ERROR :SEP_TF file open.\n");
		return(ERROR);
	}
    
	LOGD("InitTFMatrix");
	LOGD("read sep_tf_l.dat");
    
    
#else // IS_APPLE_IOS

	/* 下記はL字マイク用 */
#ifdef ENABLE_ANDROID_PATH
	if(NULL == (fp = fopen("/mnt/sdcard/hark2/sep_tf_l.dat","rb"))){
		//printf("ERROR : TF file open.\n");
		LOGE("ERROR : TF file open.\n");
		return(ERROR);
	}

	LOGD("InitTFMatrix");
	LOGD("read /mnt/sdcard/hark2/sep_tf_l.dat");
#else // not ENABLE_ANDROID_PATH
	if(NULL == (fp = fopen("/media/SD/hark2/sep_tf_l.dat","rb"))){
		//printf("ERROR : TF file open.\n");
		LOGE("ERROR : TF file open.\n");
		return(ERROR);
	}

	LOGD("InitTFMatrix");
	LOGD("read /media/SD/hark2/sep_tf_l.dat");
#endif // end of ENABLE_ANDROID_PATH

#endif // IS_APPLE_IOS

#endif // end of L angle mic mode

#else // NEVER

	/* 2013.08.12 K.Takagi ファイル名選択を上位へ */
	if(NULL == (fp = fopen(tf_file_name, "rb")))
	{
		LOGE("ERROR : SEP_TF file open.\n");
		return(ERROR);
	}

	LOGD("InitTFMatrix");
	LOGD("  read %s", tf_file_name);

#endif // NEVER

	/////////////////////////////////
	// データ読み出し

	// 識別子 HARK
	fread(s,4,1,fp); s[4] = 0; // s[0-4]="HARK\0"
	//LOGI("%s", s);

	// サイズフォームタイプ以降のサイズ
	fread(&d,4,1,fp);
	//LOGI("size=%d, 0x%08x", d, d);

	// フォームタイプ HGTF
	fread(s,4,1,fp); s[4] = 0; // s[0-4]="HGTF\0"
	//LOGI("%s", s);

	// フォーマットサブチャンク fmt
	fread(s,4,1,fp); // s[0-3]="fmt\0"
	//LOGI("%s", s);

	// チャンクサイズサイズ 24+12*Nmic
	fread(&d,4,1,fp);
	//LOGI("chank size=%d, 0x%08x", d, d);

	// fmtバージョン
	fread(&major,2,1,fp);
	fread(&minor,2,1,fp);
	//LOGI("major=%d, minor=%d", major, minor);

	// フォーマットID
	fread(&d,4,1,fp);
	//LOGI("fmt ID=%d", d);

	// マイクロホン数
	fread(&d,4,1,fp);
	//LOGI("microphone=%d", d);
	num_mic = d;

	// FFT長
	fread(&d,4,1,fp);
	//LOGI("FFT length=%d", d);

	// インパルスレスポンス長
	fread(&d,4,1,fp);
	//LOGI("Impulse length=%d", d);

	// サンプリング周波数
	fread(&d,4,1,fp);
	//LOGI("Sampling frequency=%d", d);

	//////////////////////////////////
	// マイク座標の読み出し

	fseek(fp,0x2c,0);		// マイク座標の先頭にポインタを移動する

	for(i=0; i<num_mic; i++){
		fread(&fx,4,1,fp);
		fread(&fy,4,1,fp);
		fread(&fz,4,1,fp);

		locaMicPos[i].ha_fX = fx;
		locaMicPos[i].ha_fY = fy;
		locaMicPos[i].ha_fZ = fz;

		//LOGI("MIC : fx = %f, fy= %f, fz= %f", locaMicPos[i].ha_fX, locaMicPos[i].ha_fY, locaMicPos[i].ha_fZ);
	}

	// リードバック
	//for(i=0; i<num_mic; i++){
	//	LOGI("MIC : fx = %f, fy= %f, fz= %f", locaMicPos[i].ha_fX, locaMicPos[i].ha_fY, locaMicPos[i].ha_fZ);
	//}

	//////////////////////////////////
	// 音源位置座標の読み出し

	// GTFサブチャンク GTF
	fread(s,4,1,fp); // s[0-3]="GTF\0"
	//LOGI("%s", s);

	// チャンクのサイズ
	fread(&d,4,1,fp);
	//LOGI("chank size=%d, 0x%08x", d, d);

	// GTFバージョン
	fread(&major,2,1,fp);
	fread(&minor,2,1,fp);
	//LOGI("major=%d, minor=%d", major, minor);

	// 音源位置数
	fread(&num_tf_pos,4,1,fp);
	//LOGI("Ns(pos num)=%d", num_tf_pos);
    if (NELEM(locaTFPos) < num_tf_pos) {
        LOGE("num_tf_pos = %d ? check your .dat file!!!", num_tf_pos);
        fclose(fp);
        return(ERROR);
    }

	for(i=0; i<num_tf_pos; i++){
		fread(&fx, 4,1,fp);
		fread(&fy, 4,1,fp);
		fread(&fz, 4,1,fp);

		locaTFPos[i].ha_fX = fx;
		locaTFPos[i].ha_fY = fy;
		locaTFPos[i].ha_fZ = fz;
		//LOGI("POS : fx = %f, fy= %f, fz= %f", locaTFPos[i].ha_fX, locaTFPos[i].ha_fY, locaTFPos[i].ha_fZ);
	}
	//for(i=0; i<num_tf_pos; i++){ // リードバック
	//	LOGI("POS : fx = %f, fy= %f, fz= %f\n", locaTFPos[i].ha_fX, locaTFPos[i].ha_fY, locaTFPos[i].ha_fZ);
	//}

	// 周波数ライン数
	fread(&d,4,1,fp);
	//LOGI("Frequency length=%d", d);

	// インデックスから周波数ビンへのマップ
	for(i=0; i<ARY_NUM_FFT; i++){
		fread(&d,4,1,fp);
		//LOGI("i=%d : Nf=%d", i, d);
	}

	//////////////////////////////////
	// 周波数ラインの読み込み

	//fseek(fp,0x804,0);		// 周波数ラインの先頭にポインタを移動する
	for(k=0; k<num_tf_pos; k++){
		for(j=0; j<num_mic; j++){
			for(i=0; i<ARY_NUM_FFT; i++){
				int re_d, im_d;

				re_d = fread(&re, 4,1,fp);
				im_d = fread(&im, 4,1,fp);

				piaFreqLine[i][j][k].re	= re;
				piaFreqLine[i][j][k].im	= im;

				//LOGI("[%d][%d][%d] %d %d : TF : re = %f, im = %f\n", i,j,k, re_d, im_d, piaFreqLine[i][j][k].re, piaFreqLine[i][j][k].im);
			}
		}
	}
	//LOGI("InitTFMatrix");
	//for(j=0; j<num_mic; j++){ // リードバック
	//	LOGI("TF : re = %f, im = %f\n", piaFreqLine[0][j][0].re, piaFreqLine[0][j][0].im);
	//}

	fclose(fp);
#endif // ENABLE_HARKIO3

	//////////////////////////////////
	// 一番近いTFを検索する
	GetNearestTFMatrixFromDB();

	return(OK);
}

///////////////////////////////////////////////////////////////
//	分離行列の初期化

// 伝達関数から分離行列の初期値を作成
int	MakeWMatGHDSS(int num_src)
{
	int	s, m, f;
	HA_Float tmp = 1.0f / num_mic;
#ifdef NEVER
	for(s=0; s<num_src; s++){
		for(m=0; m<num_mic; m++){
			for(f=0; f<ARY_NUM_FFT; f++){
				// KAMA
				//sepMat[s][f][m].re = OutTF[s][f][m].re / num_mic;
				//sepMat[s][f][m].im = OutTF[s][f][m].im / num_mic;
				if(stat_id[mat_id[s]] == 1){	// 音源検出の場合
					sepMat[mat_id[s]][f][m].re = OutTF[s][f][m].re / num_mic;
					sepMat[mat_id[s]][f][m].im = OutTF[s][f][m].im / num_mic;
				}
				//if(s==0 && m==0 && f==0){ printf("%f, %f\n", sepMat[s][f][m].re, sepMat[s][f][m].im);
			}
		}
	}
#endif
	// TAKIGAHIRA : change loop order, for more cache hit rate.
	for(s=0; s<num_src; s++){
		if(stat_id[mat_id[s]] == 1){	// 音源検出の場合
			//for(m=0; m<num_mic; m++){
				//for(f=0; f<ARY_NUM_FFT; f++){
			for(f=0; f<ARY_NUM_FFT; f++){
				for(m=0; m<num_mic; m++){
					sepMat[mat_id[s]][f][m].re = OutTF[s][f][m].re * tmp;
					sepMat[mat_id[s]][f][m].im = OutTF[s][f][m].im * tmp;
				}
			}
		}
	}
	/*
	LOGI("## MakeWMatGHDSS ##"); // ダンプ
	//for (f=0; f<ARY_NUM_FFT; f++)
	for(f=0; f<16; f++){
		for(m=0; m<num_mic; m++){
			for(s=0; s<num_src; s++){
				LOGI("m=%d, s=%d, f=%d : sepMat[s][f][m]%f, %f\n", m, s, f, sepMat[s][f][m].re, sepMat[s][f][m].im);
				}
			}
		}
	*/
	return(OK);
}

int	InitSepMatrix(int num_src)
{
	//分離行列の初期化
	// Calculation 計算で求める	<- とりあえずこっちだけ実装
	MakeWMatGHDSS(num_src);	//伝達関数から分離行列の初期値を作成

	return(OK);
}

///////////////////////////////////////////////////////////////
//	分離行列のアップデート

int	InitUpdateW()
{
	int ii ;
	int	s, f, m;

//	int iNLoc 	= 360 / __SAVED_LOC_THETA_PITCH+1 ;									<- 73
//	int iNmic 	= m_psSepMat->micary_smSeparation.ha_numInput ;						<- 8
//	int iNfreq 	= m_psSepMat->micary_smSeparation.micary_iaFreqLinex.ha_numValue ;	<- 257

//	UpdateSeparationMatAlloc(m_updateW,iNfreq,iNLoc,iNmic) ;


	//更新履歴の初期化
//	for(ii = 0 ; ii < m_updateW->micary_iaUpdate.ha_numValue; ii++){
//		m_updateW->micary_iaUpdate.ha_iValue[ii] = __INVALID_SRC_ID ;
//	}

	//マイク位置の代入
/*
	for(ii = 0 ; ii < iNmic ; ii++){
		m_updateW->micary_dbSeparation.micary_locaMic.micary_Location[ii].ha_fX =
					m_psSepMat->micary_tdTFDB.micary_locaMic.micary_Location[ii].ha_fX ;

		m_updateW->micary_dbSeparation.micary_locaMic.micary_Location[ii].ha_fY =
					m_psSepMat->micary_tdTFDB.micary_locaMic.micary_Location[ii].ha_fY ;

		m_updateW->micary_dbSeparation.micary_locaMic.micary_Location[ii].ha_fZ =
					m_psSepMat->micary_tdTFDB.micary_locaMic.micary_Location[ii].ha_fZ ;

		m_updateW->micary_dbSeparation.micary_locaMic.micary_Location[ii].ha_idPos =
		  			m_psSepMat->micary_tdTFDB.micary_locaMic.micary_Location[ii].ha_idPos; 

		m_updateW->micary_dbSeparation.micary_locaMic.ha_idLocation[ii] =
					m_psSepMat->micary_tdTFDB.micary_locaMic.ha_idLocation[ii] ;
	}
*/

/*
	// 周波数ラインの代入
	for(s=0; s<ARY_NUM_SRC; s++){
		for(f=0; f<ARY_NUM_FFT; f++){
			for(m=0; m<num_mic; m++){
				updateW[s][f][m].re = sepMat[s][f][m].re;
				updateW[s][f][m].im = sepMat[s][f][m].im;
				//LOGI("sepMat = %f, %f\n",sepMat[s][f][m].re, sepMat[s][f][m].im);
			}
		}
	}
*/

	//音源位置の作成
/*
	HA_Float fX,fY,fZ,fTheta,fPhi,pi;

	pi 		= acos(-1.0);
	fPhi 	= 16.7 *pi/180.0;

	for(ii=0; ii<iNLoc; ii++){
		fTheta = ii*__SAVED_LOC_THETA_PITCH*pi/180.0;
		fX = cos(fTheta)*cos(fPhi);
		fY = sin(fTheta)*cos(fPhi);
		fZ = sin(fPhi);

		m_updateW->micary_dbSeparation.micary_locaSource.micary_Location[ii].ha_fX = fX ;
		m_updateW->micary_dbSeparation.micary_locaSource.micary_Location[ii].ha_fY = fY ;
		m_updateW->micary_dbSeparation.micary_locaSource.micary_Location[ii].ha_fZ = fZ ;
	}

	//音源IDの初期化
	for(ii=0; ii<iNLoc; ii++){
		m_updateW->micary_dbSeparation.micary_locaSource.ha_idLocation[ii] = ii ;//__INVALID_SRC_ID ;
		m_updateW->micary_dbSeparation.micary_locaSource.micary_Location[ii].ha_idPos = ii ;
	}
*/
	return(OK);
}

///////////////////////////////////////////////////////////////
//	GHDSSの実行

// LCの計算
int	CalcLCStepSize_GHDSS(int num_src)
{
	//double fJlcp;
	float fJlcp;
	//double foptLCMyu;
	float foptLCMyu;
	int row, col;
	int	s,m,k;
	//double dTemp ;
	float dTemp ;

	HA_Complex	tmp, tmp2, tmp3;

	////HA_Complex	Atmp[ARY_NUM_MIC][ARY_NUM_SRC]; // TAKIGAHIRA
	////HA_Complex	Zsns[ARY_NUM_SRC][ARY_NUM_SRC]; // TAKIGAHIRA
	HA_Complex	E[ARY_NUM_SRC][ARY_NUM_SRC];
	////HA_Complex	Znsnm[ARY_NUM_SRC][ARY_NUM_MIC]; // TAKIGAHIRA
	////HA_Complex	Znsns[ARY_NUM_SRC][ARY_NUM_SRC]; // TAKIGAHIRA
	HA_Complex	Jlc[ARY_NUM_SRC][ARY_NUM_MIC];

	//////// TAKIGAHIRA : merge formula
	//// 複素共役の値は符号だけの違いであるため、Atmpを使用せず代入による式変形が可能
	//// この関数内でAとしてAtmpの値を使いまわす場所全てで単純置き換えが可能なのでAtmp配列を削減するために統合する
	//// Zsns配列は単位行列の保存のためだけに存在し、単位行列の減算のみで使用している
	//// そのため、 E = E - Znsns （プログラム内ではZnsns配列ではなくZsns配列）は単純化が可能なので統合する
	////
	////for(col=0; col<caA.size2(); col++){
	////	for(row=0; row<caA.size1(); row++){
	////		Atmp(row, col) = complex<double> (caA(row, col).real(), caA(row, col).imag() * (-1.0)) ;
	////	}
	////}
	//OLD-1//for(m=0; m<num_mic; m++){
	//OLD-1//	for(s=0; s<num_src; s++){
	//OLD-1//		Atmp[m][s].re = A[m][s].re;
	//OLD-1//		//Atmp[m][s].im = A[m][s].im * (-1.0) ;	// 複素共役
	//OLD-1//		Atmp[m][s].im = -A[m][s].im ;	// 複素共役
	//OLD-1//		//LOGI("m=%d, s=%d : Atmp[m][s](%f, %f)\n", Atmp[m][s].re, Atmp[m][s].im);
	//OLD-1//	}
	//OLD-1//}
	//// ■ Znsns = eye(Nsrc) ;	単位行列の作成
	////if(_EyeCompMat(&Znsns) == false){
	////	return 0;
	////}
	//OLD-1//for(s=0; s<num_src; s++){
	//OLD-1//	for(m=0; m<num_src; m++){
	//OLD-1//		if(s==m){ Zsns[s][m].re = 1.0; Zsns[s][m].im = 0.0; }
	//OLD-1//		else{     Zsns[s][m].re = 0.0; Zsns[s][m].im = 0.0; }
	//OLD-1//	}
	//OLD-1//}
	//OLD-2//for(s=0; s<num_src; s++){
	//OLD-2//	for(m=0; m<num_src; m++){
	//OLD-2//		Zsns[s][m].re = 0.0;
	//OLD-2//		Zsns[s][m].im = 0.0;
	//OLD-2//	}
	//OLD-2//	Zsns[s][s].re = 1.0;
	//OLD-2//}
	//// ■ E = W*A ;
	////E = prod(caW, Atmp);
	//OLD-1//for(s=0; s<num_src; s++){
	//OLD-1//	for(k=0; k<num_src; k++){
	//OLD-1//		HA_Complex	tmp;
	//OLD-1//		tmp.re	= 0.0;
	//OLD-1//		tmp.im	= 0.0;
	//OLD-1//		for(m=0; m<num_mic; m++){
	//OLD-1//			tmp.re	+= (W[s][m].re * Atmp[m][k].re) - (W[s][m].im * Atmp[m][k].im);
	//OLD-1//			tmp.im 	+= (W[s][m].re * Atmp[m][k].im) + (W[s][m].im * Atmp[m][k].re);
	//OLD-1//		}
	//OLD-1//		E[s][k].re = tmp.re;
	//OLD-1//		E[s][k].im = tmp.im;
	//OLD-1//	}
	//OLD-1//}
	//OLD-2//for(s=0; s<num_src; s++){
	//OLD-2//	for(k=0; k<num_src; k++){
	//OLD-2//		HA_Complex	tmp;
	//OLD-2//		tmp.re	= 0.0;
	//OLD-2//		tmp.im	= 0.0;
	//OLD-2//		for(m=0; m<num_mic; m++){
	//OLD-2//			tmp.re	+= (W[s][m].re * A[m][k].re) + (W[s][m].im * A[m][k].im);
	//OLD-2//			tmp.im 	+= (W[s][m].im * A[m][k].re) - (W[s][m].re * A[m][k].im);
	//OLD-2//		}
	//OLD-2//		E[s][k].re = tmp.re;
	//OLD-2//		E[s][k].im = tmp.im;
	//OLD-2//	}
	//OLD-2//}
	//for(s=0; s<num_src; s++){
	//	for(m=0; m<num_mic; m++){
	//		LOGI("s=%d, m=%d : W[s][m](%f, %f)\n", s, m, W[s][m].re, W[s][m].im);
	//	}
	//}
	//// ■ E = E -Znsns ;
	////E = E - Znsns;
	//OLD-1//for(s=0; s<num_src; s++){
	//OLD-1//	for(m=0; m<num_src; m++){
	//OLD-1//		E[s][m].re -= Zsns[s][m].re;
	//OLD-1//		E[s][m].im -= Zsns[s][m].im;
	//OLD-1//		LOGI("s=%d, m=%d : E[s][m](%f, %f)\n", s, m, E[s][m].re, E[s][m].im);
	//OLD-1//	}
	//OLD-1//}
	//OLD-2//for(s=0; s<num_src; s++){
	//OLD-2//	E[s][s].re -= Zsns[s][s].re;
	//OLD-2//	E[s][s].im -= Zsns[s][s].im;
	//OLD-2//}
	//OLD-3//for(s=0; s<num_src; s++){
	//OLD-3//	E[s][s].re -= 1.0f;
	//OLD-3//	E[s][s].im -= 0.0f;
	//OLD-3//}
	////-- merged formula --//// ■ E = W*A - eye(Nsrc);
	for(s=0; s<num_src; s++){
		for(k=0; k<num_src; k++){
			tmp.re = 0.0f;
			tmp.im = 0.0f;
			for(m=0; m<num_mic; m++){
				tmp2 = W[s][m];
				tmp3 = A[m][k];
				tmp.re	+= tmp2.re * tmp3.re;
				tmp.re	+= tmp2.im * tmp3.im;
				tmp.im 	+= tmp2.im * tmp3.re;
				tmp.im 	-= tmp2.re * tmp3.im;
			}
			E[s][k].re = tmp.re; 
			E[s][k].im = tmp.im; 
		}
		E[s][s].re -= 1.0f;
		//E[s][s].im -= 0.0f;
	}
	//for(s=0; s<num_src; s++){
	//	for(m=0; m<num_src; m++){
	//		//LOGI("s=%d, m=%d : E[s][m](%f, %f)\n", s, m, E[s][m].re, E[s][m].im);
	//	}
	//}

	// LC_Const = FULL は以上まで
	// LC_Const = DIAG
#ifdef ENABLE_SWITCHING_GHDSS_MODE
	//以下、FULLなのでとりあえずスキップ
	switch(){
	case LC_CONST_DIAG:
	{
		////if(iLCConst == _LC_CONST_DIAG){
		////	if(_DiagCompMat(&E, E) == false){	// Eを対角行列に。
		////		return 0;
		////	}
		////} //end LC_CONST = DIAG
		for(s=0; s<num_src; s++){ // diag(E)
			tmp.re = E[s][s].re; // 対角成分E[s][s]のバックアップ
			tmp.im = E[s][s].im;
			for(m=0; m<num_src; m++){
				E[s][m].re = 0.0f; // Eのクリア
				E[s][m].im = 0.0f;
			}
			E[s][s].re = tmp.re; // 対角成分E[s][s]のリストア
			E[s][s].im = tmp.im;
		}
	}
		break;
	case LC_CONST_FULL: // default is FULL
	default:
		break;
	}
#endif

	//////// TAKIGAHIRA : merge formula
	//// 複素共役転置の値は符号と配列のxy交換だけの違いであるため、Znsnmを使用せず代入による式変形が可能
	//// 既にAtmpの時点で複素共役をとっているので複素共役の複素共役となり行列に対する転置のみ行う
	//// この関数内でA'としてZnsnmの値を使いまわす事がなかったのでZnsnm配列を削減するためにJlcの算出ループと統合する
	////
	// ■ Znsnm = A' ;  共役転置複素数
	//cdMat Znsnm (iNsrc, iNmic);
	//Znsnm = trans(conj(Atmp));
	//OLD-1//for(s=0; s<num_src; s++){
	//OLD-1//	for(m=0; m<num_mic; m++){
	//OLD-1//		Znsnm[s][m].re =  Atmp[m][s].re;
	//OLD-1//		Znsnm[s][m].im = -Atmp[m][s].im;	// 複素共役
	//OLD-1//	}
	//OLD-1//}
	//OLD-2//for(s=0; s<num_src; s++){
	//OLD-2//	for(m=0; m<num_mic; m++){ // TAKIGAHIRA : [注]転置行列のため[m][s]を[s][m]へ代入
	//OLD-2//		Znsnm[s][m].re = A[m][s].re;
	//OLD-2//		Znsnm[s][m].im = A[m][s].im;
	//OLD-2//		//LOGI("s=%d, m=%d : Znsnm[s][m](%f, %f)\n", s, m, Znsnm[s][m].re, Znsnm[s][m].im);
	//OLD-2//	}
	//OLD-2//}
	//// ■ Jlc = E * Znsnm ;
	////cdMat Jlc (iNsrc, iNmic);
	////Jlc = prod(E, Znsnm);
	//OLD-1//for(s=0; s<num_src; s++){
	//OLD-1//	for(m=0; m<num_mic; m++){
	//OLD-1//		HA_Complex	tmp;
	//OLD-1//		tmp.re	= 0.0;
	//OLD-1//		tmp.im	= 0.0;
	//OLD-1//		for(k=0; k<num_src; k++){
	//OLD-1//			tmp.re += (E[s][k].re * Znsnm[k][m].re) - (E[s][k].im * Znsnm[k][m].im);
	//OLD-1//			tmp.im += (E[s][k].re * Znsnm[k][m].im) + (E[s][k].im * Znsnm[k][m].re);
	//OLD-1//		}
	//OLD-1//		Jlc[s][m].re = tmp.re;
	//OLD-1//		Jlc[s][m].im = tmp.im;
	//OLD-1//	}
	//OLD-1//}
	////-- merged formula --//// Jlc = E * A';
	for(s=0; s<num_src; s++){
		for(m=0; m<num_mic; m++){
			tmp.re = 0.0f;
			tmp.im = 0.0f;
			for(k=0; k<num_src; k++){
				tmp2 = E[s][k];
				tmp3 = A[m][k];
				tmp.re += tmp2.re * tmp3.re;
				tmp.re -= tmp2.im * tmp3.im;
				tmp.im += tmp2.re * tmp3.im;
				tmp.im += tmp2.im * tmp3.re;
			}
			Jlc[s][m].re = tmp.re;
			Jlc[s][m].im = tmp.im;
		}
	}
	//for(s=0; s<num_src; s++){
	//	for(m=0; m<num_mic; m++){
	//		LOGI("s=%d, m=%d : Jlc[s][m](%f, %f)\n", s, m, Jlc[s][m].re, Jlc[s][m].im);
	//	}
	//}

	// --- ステップサイズと更新量の決定 ---
#ifdef ENABLE_SWITCHING_GHDSS_MODE
	switch(iLCMethod){
	case LC_METHOD_FIX:
	{
		////for(row = 0 ; row < Jlc.size1() ; row++){		//rowでループ
		////	for(col = 0 ; col < Jlc.size2() ;col++){
		////		if(Jlc(row, col).real() * (double)fLCMyu > __MAX_FLOAT_VALUE
		////					&&  Jlc(row, col).imag() * (double)fLCMyu  > __MAX_FLOAT_VALUE){
		////			printf("Data is Inf.\n") ;
		////			return 0 ;
		////		}
		////		complex<double> caTemp((HA_Float)(Jlc(row, col).real() * (double)fLCMyu )
		////							, (HA_Float) (Jlc(row, col).imag() * (double)fLCMyu) );
		////		pcamyu_J_LC->insert_element(row, col, caTemp);
		////	}
		////}
		// need input fLCMyu. ex) fLCMyu = 0.001f;
		for(s=0; s<num_src; s++){
			for(m=0; m<num_mic; m++){
				tmp.re = Jlc[s][m].re * fLCMyu;
				tmp.im = Jlc[s][m].im * fLCMyu;
				if(tmp.re > _MAX_FLOAT_VALUE && tmp.im > _MAX_FLOAT_VALUE){
					LOGI("Data is Inf.\n") ;
					return 0;
				}
				J_LC[s][m].re = tmp.re;
				J_LC[s][m].im = tmp.im;
			}
		}
	}
		break;
	case LC_METHOD_ADAPTIVE: // default is ADAPTIVE
	default:
#endif
	{ // <- とりあえずこっち
		//////// TAKIGAHIRA : merge formula
		//// ABS計算で虚数部が0.0fとなり、またABS計算のルート後にfJlcpの計算で実数部を二乗する事が分かっているので無駄な計算を省く
		//// 更に、fJlcpのSum計算以外でZnsnm配列自体が不要となる事からメモリ削減のためSumのループと統合する、虚数部は計算しない
		////
		////if(_AbsCompMat(&Znsnm, Jlc) == false){
		////	return 0;
		////}
		//OLD-2//for(s=0; s<num_src; s++){
		//OLD-2//	for(m=0; m<num_mic; m++){
		//OLD-2//		//dTemp = pow((double)Jlc[s][m].re, 2.0) + pow((double)Jlc[s][m].im, 2.0);
		//OLD-2//		dTemp = (Jlc[s][m].re * Jlc[s][m].re) + (Jlc[s][m].im * Jlc[s][m].im);
		//OLD-2//		Znsnm[s][m].re = sqrtf(dTemp); // change function from sqrt() to sqrtf()
		//OLD-2//		Znsnm[s][m].im = 0.0;
		//OLD-2//	}
		//OLD-2//}
		////fJlcp = 0.0;
		////for(row=0; row<Znsnm.size1(); row++){
		////	for(col=0; col<Znsnm.size2(); col++){
		////		fJlcp = (double)(pow(Znsnm(row, col).real(), (double)2.0) + fJlcp);
		////	}
		////}
		//OLD-1//fJlcp = 0.0f;
		//OLD-1//for(s=0; s<num_src; s++){
		//OLD-1//	for(m=0; m<num_mic; m++){
		//OLD-1//		//fJlcp = (double)(pow(Znsnm[s][m].re, (double)2.0) + fJlcp);
		//OLD-1//		//fJlcp = ((Znsnm[s][m].re * Znsnm[s][m].re) + fJlcp);
		//OLD-1//		fJlcp += (Znsnm[s][m].re * Znsnm[s][m].re);
		//OLD-1//	}
		//OLD-1//}
		//OLD-2//fJlcp = 0.0f;
		//OLD-2//for(s=0; s<num_src; s++){
		//OLD-2//	for(m=0; m<num_mic; m++){
		//OLD-2//		//fJlcp = (double)(pow(Znsnm[s][m].re, (double)2.0) + fJlcp);
		//OLD-2//		//fJlcp = ((Znsnm[s][m].re * Znsnm[s][m].re) + fJlcp);
		//OLD-2//		fJlcp += (Znsnm[s][m].re * Znsnm[s][m].re);
		//OLD-2//	}
		//OLD-2//}
		////fJlcp = (double)(fJlcp + 0.0000000001);
		//OLD-1//fJlcp = (fJlcp + 0.0000000001);
		////-- merged formula --//// fJlcp = sum(abs(Jlc) .* abs(Jlc))  ==> fJlcp = ((fJlcp + avoid 0div value) * 2)
		fJlcp = 0.0f;
		for(s=0; s<num_src; s++){
			for(m=0; m<num_mic; m++){
				tmp2 = Jlc[s][m];
				tmp.re = tmp2.re * tmp2.re;
				tmp.im = tmp2.im * tmp2.im;
				fJlcp += (tmp.re + tmp.im);
			}
		}
		fJlcp += 0.0000000001f;
		if(fabsf(fJlcp) < _MINIMUM_ZERO_VALUE){
			fJlcp += _MINIMUM_ZERO_VALUE;
		}
		fJlcp *= 2;

		//////// TAKIGAHIRA : merge formula
		//// ABS計算で虚数部が0.0fとなり、またABS計算のルート後にfJlcpの計算で実数部を二乗する事が分かっているので無駄な計算を省く
		//// 更に、foptLCMyuのSum計算以外でZnsns配列自体が不要となる事からメモリ削減のためSumのループと統合する、虚数部は計算しない
		////
		////if(_AbsCompMat(&Znsns, E) == false){
		////	return 0;
		////}
		//OLD-1//for(s=0; s<num_src; s++){
		//OLD-1//	for(m=0; m<num_src; m++){
		//OLD-1//		//dTemp = pow((double)E[s][m].re, 2.0) + pow((double)E[s][m].im, 2.0);
		//OLD-1//		dTemp = (E[s][m].re * E[s][m].re) + (E[s][m].im * E[s][m].im);
		//OLD-1//		Znsns[s][m].re = sqrtf(dTemp); // change function from sqrt() to sqrtf()
		//OLD-1//		Znsns[s][m].im = 0.0;
		//OLD-1//		//LOGI("s=%d, m=%d : Znsns[s][m](%f, %f), E[s][m](%f, %f)\n", Znsns[s][m].re, Znsns[s][m].im, E[s][m].re, E[s][m].im);
		//OLD-1//	}
		//OLD-1//}
		////foptLCMyu = 0.0;
		////for(row=0; row<Znsns.size1(); row++){
		////	for(col=0; col<Znsns.size2(); col++){
		////		foptLCMyu = (double) (pow(Znsns(row, col).real(), (double)2.0) + foptLCMyu );
		////	}
		/////}
		//OLD-1//foptLCMyu = 0.0f;
		//OLD-1//for(s=0; s<num_src; s++){
		//OLD-1//	for(m=0; m<num_src; m++){
		//OLD-1//		//foptLCMyu = (double) (pow(Znsns[s][m].re, (double)2.0) + foptLCMyu );
		//OLD-1//		//foptLCMyu = ((Znsns[s][m].re * Znsns[s][m].re) + foptLCMyu );
		//OLD-1//		foptLCMyu += (Znsns[s][m].re * Znsns[s][m].re);
		//OLD-1//	}
		//OLD-1//}
		//// fJlcpに対する0除算防止値の加算と予め2倍にしておくことでfoptLCMyu計算の除算を減らせることから計算位置を移動
		//OLD-1//if(fabsf(fJlcp) < _MINIMUM_ZERO_VALUE){ // change function from fabs() to fabsf()
		//OLD-1//	foptLCMyu = foptLCMyu / (fJlcp+_MINIMUM_ZERO_VALUE) / 2 ;
		//OLD-1//}
		//OLD-1//else{
		//OLD-1//	foptLCMyu = foptLCMyu / fJlcp / 2 ;
		//OLD-1//}
		//OLD-2//if(fabsf(fJlcp) < _MINIMUM_ZERO_VALUE){
		//OLD-2//	fJlcp += _MINIMUM_ZERO_VALUE;
		//OLD-2//}
		//OLD-2//fJlcp *= 2;
		//OLD-2//foptLCMyu = foptLCMyu / fJlcp;
		////-- merged formula --//// foptLCMyu = sum(abs(E) .* abs(E)) / fJlcp  [ただし、fJlcp=((fJlcp+avoid_0div_value)*2)済み]
		foptLCMyu = 0.0f;
		for(s=0; s<num_src; s++){
			for(m=0; m<num_src; m++){
				tmp2 = E[s][m];
				tmp.re = tmp2.re * tmp2.re;
				tmp.im = tmp2.im * tmp2.im;
				foptLCMyu += (tmp.re + tmp.im);
			}
		}
		foptLCMyu = foptLCMyu / fJlcp;

		////for(row=0; row<Jlc.size1(); row++){
		////	for(col = 0 ; col <  Jlc.size2() ; col++ ){
		////		if(Jlc(row, col).real() * foptLCMyu > __MAX_FLOAT_VALUE && Jlc(row, col).imag() * foptLCMyu > __MAX_FLOAT_VALUE){
		////			printf("Data is Inf.\n") ;
		////			return 0;
		////		}
		////		complex<double> caTemp((HA_Float)( Jlc(row, col).real() * foptLCMyu ),(HA_Float) (Jlc(row, col).imag() * foptLCMyu) );
		////		pcamyu_J_LC->insert_element(row, col, caTemp);
		////	}
		////}
		for(s=0; s<num_src; s++){
			for(m=0; m<num_mic; m++){
				tmp.re = Jlc[s][m].re * foptLCMyu;
				tmp.im = Jlc[s][m].im * foptLCMyu;
				if(tmp.re > _MAX_FLOAT_VALUE && tmp.im > _MAX_FLOAT_VALUE){
					LOGI("Data is Inf.\n") ;
					return 0;
				}
				J_LC[s][m].re = tmp.re;
				J_LC[s][m].im = tmp.im;
			}
		}
	} // end LC_Method = Adaptive
#ifdef ENABLE_SWITCHING_GHDSS_MODE
		break;
	}
#endif
	//for(s=0; s<num_src; s++){
	//	for(m=0; m<num_mic; m++){
	//		LOGI("s=%d, m=%d : J_LC[s][m](%f, %f)\n", s, m, J_LC[s][m].re, J_LC[s][m].im);
	//	}
	//}
	return(OK);
}

// SSの計算
int	CalcSSStepSize_GHDSS(int num_src)
{
	int s, m;

	////cdMat Ryy,Zns1,E,Jss,Jpri,Znm1, Znsns,  Znsnm , Z11;

	////HA_Complex	Znm1,Z11; // TAKIGAHIRA

	////HA_Complex	Ryy[ARY_NUM_SRC][ARY_NUM_SRC]; // TAKIGAHIRA
	////HA_Complex	Zns1[ARY_NUM_SRC]; // TAKIGAHIRA
	////HA_Complex	Znsns[ARY_NUM_SRC][ARY_NUM_SRC]; // TAKIGAHIRA
	HA_Complex	E[ARY_NUM_SRC][ARY_NUM_SRC];

	HA_Complex	Jss[ARY_NUM_SRC][ARY_NUM_MIC];
	HA_Complex	Jpri[ARY_NUM_SRC][ARY_NUM_MIC];
	////HA_Complex	Znsnm[ARY_NUM_SRC][ARY_NUM_MIC]; // TAKIGAHIRA

    double fTmp,fYrms;
    double fTmp2 ;
	//double dTemp ;
    //float fTmp,fYrms;
    //float fTmp2 ;
	//float dTemp ;

	HA_Complex	tmp, tmp2, tmp3;

	// GetPQY	

	HA_Float 	fabsY, fabsYs, ftmp ;
	HA_Complex 	cmpExpY ;	// <- これはFloatで演算している

	for(s=0; s<num_src; s++){
		fabsY 	= sqrtf((Y[s].re * Y[s].re) + (Y[s].im * Y[s].im)) + _MINIMUM_ZERO_VALUE; // expand pow function, change function from sqrt() to sqrtf()
		//fabsYs 	= fabsY * 1.0;			// ha_fSSScal = 1.0
		fabsYs 	= fabsY;			// ha_fSSScal = 1.0

		cmpExpY.re = Y[s].re / fabsY ;
		cmpExpY.im = Y[s].im / fabsY ;
	    
		////complex<double> caTemp(tanh(fabsYs) * cmpExpY.re , tanh(fabsYs) * cmpExpY.im);
		////caPY->insert_element(row, col, caTemp);
		PY[s].re = tanhf(fabsYs) * cmpExpY.re; // change function from tanh() to tanhf()
		PY[s].im = tanhf(fabsYs) * cmpExpY.im; // change function from tanh() to tanhf()

		//ftmp = pow(cosh(fabsYs), (float)2.0) ;
		ftmp = coshf(fabsYs); // change function from cosh() to coshf()
		ftmp = ftmp * ftmp ;
		//ftmp = fabsYs / ftmp * 1.0;		// ha_fSSScal = 1.0
		ftmp = fabsYs / ftmp;		// ha_fSSScal = 1.0

		////complex<double>  caTemp2((tanh(fabsYs) + ftmp) * cmpExpY.re , (tanh(fabsYs) + ftmp) * cmpExpY.im);
		////caQY->insert_element(row, col, caTemp2);
		QY[s].re = (tanhf(fabsYs) + ftmp) * cmpExpY.re; // change function from tanh() to tanhf()
		QY[s].im = (tanhf(fabsYs) + ftmp) * cmpExpY.im; // change function from tanh() to tanhf()
	}
	//LOGI("Y[0](%f, %f) QY[0](%f, %f) PY[0](%f, %f)\n", Y[0].re, Y[0].im, QY[0].re, QY[0].im, PY[0].re, PY[0].im);

	//////// TAKIGAHIRA : re merge formula
	//// 以降のコードでRyyの依存関係が無い事を確認したのでEの計算はRyy配列を使用せず代入による式変形が可能
	//// Ryy配列を削減するために統合する
	////
	//////// TAKIGAHIRA : merge formula
	//// 複素共役の値は符号だけの違いであるため、Zns1を使用せず代入による式変形が可能
	//// この関数内でY'としてZns1の値を使いまわす事がなかったのでZns1配列を削減するために統合する
	////
	////  ■Ryy = y * y'
	////Zns1 = trans(conj(caY));
	////Ryy = prod(PY, Zns1);
	//OLD-1//for(s=0; s<num_src; s++){
	//OLD-1//	Zns1[s].re =  Y[s].re;
	//OLD-1//	Zns1[s].im = -Y[s].im;	// 複素共役
	//OLD-1//}
	//OLD-1//for(s=0; s<num_src; s++){
	//OLD-1//	for(m=0; m<num_src; m++){
	//OLD-1//		Ryy[s][m].re = (PY[s].re * Zns1[m].re) - (PY[s].im * Zns1[m].im);
	//OLD-1//		Ryy[s][m].im = (PY[s].re * Zns1[m].im) + (PY[s].im * Zns1[m].re);
	//OLD-1//		//LOGI("s=%d, m=%d : Ryy[s][m](%f, %f)\n",Ryy[s][m].re, Ryy[s][m].im);
	//OLD-1//	}
	//OLD-1//}
	//OLD-3//for(s=0; s<num_src; s++){
	//OLD-3//	for(m=0; m<num_src; m++){
	//OLD-3//		Ryy[s][m].re = (PY[s].re * Y[m].re) + (PY[s].im * Y[m].im);
	//OLD-3//		Ryy[s][m].im = (PY[s].im * Y[m].re) - (PY[s].re * Y[m].im);
	//OLD-3//		//LOGI("s=%d, m=%d : Ryy[s][m](%f, %f)\n",Ryy[s][m].re, Ryy[s][m].im);
	//OLD-3//	}
	//OLD-3//}
	//////// TAKIGAHIRA : merge formula
	//// E はRyyからRyyの対角行列を差し引くので、Ryyをコピーして対角成分のみ0.0f上書きで良い
	////
	////　■E = Ryy - diag(Ryy)
	////if(_DiagCompMat(&Znsns, Ryy) == false){
	////	return 0;
	////}
	////else{
	////	E = Ryy - Znsns;
	////}
	//// Znsns = diag(Ryy)
	//OLD-1//for(s=0; s<num_src; s++){
	//OLD-1//	for(m=0; m<num_src; m++){
	//OLD-1//		if(s == m){
	//OLD-1//			Znsns[s][m].re = Ryy[s][m].re;
	//OLD-1//			Znsns[s][m].im = Ryy[s][m].im;	// 対角だけ代入
	//OLD-1//		}
	//OLD-1//		else{
	//OLD-1//			Znsns[s][m].re = 0.0;
	//OLD-1//			Znsns[s][m].im = 0.0; 			// 対角以外はゼロ
	//OLD-1//		}
	//OLD-1//	}
	//OLD-1//}
	//OLD-2//for(s=0; s<num_src; s++){
	//OLD-2//	for(m=0; m<num_src; m++){ // 対角を含めゼロで初期化
	//OLD-2//		Znsns[s][m].re = 0.0;
	//OLD-2//		Znsns[s][m].im = 0.0;
	//OLD-2//	}
	//OLD-2//	Znsns[s][s].re = Ryy[s][s].re;
	//OLD-2//	Znsns[s][s].im = Ryy[s][s].im;	// 対角だけ上書き代入
	//OLD-2//}
	//OLD-2//for(s=0; s<num_src; s++){
	//OLD-2//	for(m=0; m<num_src; m++){
	//OLD-2//		//LOGI("s=%d, m=%d : Znsns[s][m](%f, %f)\n", s, m, Znsns[s][m].re, Znsns[s][m].im);
	//OLD-2//	}
	//OLD-2//}
	//// E = Ryy - Znsns
	//OLD-2//for(s=0; s<num_src; s++){
	//OLD-2//	for(m=0; m<num_src; m++){
	//OLD-2//		E[s][m].re = Ryy[s][m].re - Znsns[s][m].re;
	//OLD-2//		E[s][m].im = Ryy[s][m].im - Znsns[s][m].im;
	//OLD-2//		//LOGI("s=%d, m=%d : E[s][m](%f, %f)\n", s, m, E[s][m].re, E[s][m].im);
	//OLD-2//	}
	//OLD-2//}
	//OLD-3//for(s=0; s<num_src; s++){
	//OLD-3//	for(m=0; m<num_src; m++){ // 対角を含めRyyを代入
	//OLD-3//		E[s][m].re = Ryy[s][m].re;
	//OLD-3//		E[s][m].im = Ryy[s][m].im;
	//OLD-3//	}
	//OLD-3//	E[s][s].re = 0.0f;
	//OLD-3//	E[s][s].im = 0.0f; // 対角だけゼロで上書き
	//OLD-3//}
	////-- merged formula --//// E = (y*y') - diag(y*y')
	for(s=0; s<num_src; s++){
		tmp2 = PY[s];
		for(m=0; m<num_src; m++){ // 対角を含めRyyつまり(y*y')を代入
			tmp3 = Y[m];
			tmp.re  = tmp2.re * tmp3.re;
			tmp.re += tmp2.im * tmp3.im;
			E[s][m].re = tmp.re;
			tmp.im  = tmp2.im * tmp3.re;
			tmp.im -= tmp2.re * tmp3.im;
			E[s][m].im = tmp.im;
		}
		E[s][s].re = 0.0f;
		E[s][s].im = 0.0f; // 対角だけゼロで上書き
	}
	//for(s=0; s<num_src; s++){
	//	for(m=0; m<num_src; m++){
	//		LOGI("s=%d, m=%d : E[s][m](%f, %f)\n", s, m, E[s][m].re, E[s][m].im);
	//	}
	//}

// 高域にノイズが乗るバージョン
#ifdef NEVER
	//　■Zns1 = E * QY
	//Zns1 = prod(E,  QY);
	for(s=0; s<num_src; s++){
		HA_ComplexDouble	tmp;
		tmp.re = 0.0;
		tmp.im = 0.0;

		for(m=0; m<num_src; m++){
			tmp.re += (E[s][m].re * QY[m].re) - (E[s][m].im * QY[m].im);
			tmp.im += (E[s][m].re * QY[m].im) + (E[s][m].im * QY[m].re);
		}
		Zns1[s].re = tmp.re;
		Zns1[s].im = tmp.im;
		//LOGI("s=%d : Zns[s](%f, %f)\n", s, Zns1[s].re, Zns1[s].im);
	}

	//　■X = X'
	//caX = trans(caX);

	//　■Jss = Zns1 * X
	//Jss = prod(Zns1 , caX);
	for(s=0; s<num_src; s++){
		for(m=0; m<num_mic; m++){
			Jss[s][m].re = (Zns1[s].re * X[m].re) - (Zns1[s].im * X[m].im);
			Jss[s][m].im = (Zns1[s].re * X[m].im) + (Zns1[s].im * X[m].re);
			//LOGI("s=%d, m=%d : Jss[s][m](%f, %f)\n", s, m, Jss[s][m].re, Jss[s][m].im);
		}
	}
#endif
// ノイズのないバージョン
// V1.1

	//////// TAKIGAHIRA : remove
	//// Ryyを更新していないのにRyyの計算が冗長に書かれているので不要と思われ、以降のコードでもRyyを使用した形跡がない
	////
	////  ■Ryy = y * y'
	////Zns1 = trans(conj(caY));
	////　■GHDSS
	////Ryy = prod(PY, Zns1);
	//OLD-1//for(s=0; s<num_src; s++){
	//OLD-1//	Zns1[s].re =  Y[s].re;
	//OLD-1//	Zns1[s].im = -Y[s].im;	// 複素共役
	//OLD-1//}
	//OLD-1//for(s=0; s<num_src; s++){
	//OLD-1//	for(m=0; m<num_src; m++){
	//OLD-1//		Ryy[s][m].re = (PY[s].re * Zns1[m].re) - (PY[s].im * Zns1[m].im);
	//OLD-1//		Ryy[s][m].im = (PY[s].re * Zns1[m].im) + (PY[s].im * Zns1[m].re);
	//OLD-1//	}
	//OLD-1//}

	//////// TAKIGAHIRA : merge formula
	//// 複素共役の値は符号だけの違いであるため、本来は代入による式変形が可能であるが
	//// 自分自身のX配列にX'を代入していてローカル変数ではないのでX'生成ループのマージは保留
	//// Zns1配列を使用せず計算するため処理順を交換し、以下の順で処理を行うように変更した
	//// 1. X=X'の計算
	//// 2. Zns1 = prod(E,QY) と Jss = Zns1 * X の計算（ループは統合）
	////
	////　■Zns1 = E * QY
	////Zns1 = prod(E,QY);
	//OLD-1//for(s=0; s<num_src; s++){
	//OLD-1//	HA_Complex	tmp;
	//OLD-1//	tmp.re = 0.0;
	//OLD-1//	tmp.im = 0.0;
	//OLD-1//	for(m=0; m<num_src; m++){
	//OLD-1//		tmp.re += (E[s][m].re * QY[m].re) - (E[s][m].im * QY[m].im);
	//OLD-1//		tmp.im += (E[s][m].re * QY[m].im) + (E[s][m].im * QY[m].re);
	//OLD-1//	}
	//OLD-1//	Zns1[s].re = tmp.re;
	//OLD-1//	Zns1[s].im = tmp.im;
	//OLD-1//}
	////　■X = X'
	////caX = trans(conj(caX));
	//OLD-1//for(m=0; m<num_mic; m++){
	//OLD-1//	//X[m].re =  X[m].re;
	//OLD-1//	X[m].im = -X[m].im;	// 複素共役
	//OLD-1//}
	////　■Jss = Zns1 * X
	////Jss = prod(Zns1 , caX);
	//OLD-1//for(s=0; s<num_src; s++){
	//OLD-1//	for(m=0; m<num_mic; m++){
	//OLD-1//		Jss[s][m].re = (Zns1[s].re * X[m].re) - (Zns1[s].im * X[m].im);
	//OLD-1//		Jss[s][m].im = (Zns1[s].re * X[m].im) + (Zns1[s].im * X[m].re);
	//OLD-1//	}
	//OLD-1//}
	////-- merged formula --//// Jss = (E * QY) * X'
	for(m=0; m<num_mic; m++){
		//X[m].re =  X[m].re;
		X[m].im = -X[m].im;	// 複素共役
	}
	for(s=0; s<num_src; s++){ // tmp は Zns1[s] に相当
		tmp.re = 0.0f;
		tmp.im = 0.0f;
		for(m=0; m<num_src; m++){
			tmp2 = E[s][m];
			tmp3 = QY[m];
			tmp.re += tmp2.re * tmp3.re;
			tmp.re -= tmp2.im * tmp3.im;
			tmp.im += tmp2.re * tmp3.im;
			tmp.im += tmp2.im * tmp3.re;
		}
		for(m=0; m<num_mic; m++){
			tmp2 = X[m];
			Jss[s][m].re = (tmp.re * tmp2.re) - (tmp.im * tmp2.im);
			Jss[s][m].im = (tmp.re * tmp2.im) + (tmp.im * tmp2.re);
		}
	}

// V1.1
	////　■Jpri = conj(Jss)
	////Jpri = conj(Jss);
	for(s=0; s<num_src; s++){
		for(m=0; m<num_mic; m++){
			Jpri[s][m].re = Jss[s][m].re;
			Jpri[s][m].im = -Jss[s][m].im;
		}
	}

#ifdef ENABLE_SWITCHING_GHDSS_MODE
	//--- 実処理開始 ---
	switch(iSSMethod){
	case SS_METHOD_FIX: // myu_J_SS : fix
	{
		//myu_J_SS = 2.0 * JSS
		////for(row = 0; row < Jss.size1(); row++){
		////	for(col = 0; col < Jss.size2(); col++){
		////		if(Jss(row, col).real() *  (double)fSSMyu > __MAX_FLOAT_VALUE &&
		////		   Jss(row, col).imag() *  (double)fSSMyu > __MAX_FLOAT_VALUE ){
		////		   printf("Data is Inf.\n");
		////		   return 0;
		////		}
		////		complex<double> caTemp((HA_Float)(Jss(row, col).real() * (double)fSSMyu) , (HA_Float)(Jss(row, col).imag() * (double)fSSMyu));
		////		pcamyu_J_SS->insert_element(row, col, caTemp);
		////	}
		////}
		// need input fSSMyu. ex) fSSMyu = 0.001f;
		for(s=0; s<num_src; s++){
			for(m=0; m<num_mic; m++){
				tmp.re = Jss[s][m].re * fSSMyu;
				tmp.im = Jss[s][m].im * fSSMyu;
				if(tmp.re > _MAX_FLOAT_VALUE && tmp.im > _MAX_FLOAT_VALUE){
					LOGI("Data is Inf. = %e (%e) * %e .\n", Jss[s][m].re, Jss[s][m].im, fSSMyu);
					return 0;
				}
				J_SS[s][m].re = tmp.re;
				J_SS[s][m].im = tmp.im;
				//LOGI("s=%d, m=%d : J_SS[s][m](%f, %f)\n", s, m, J_SS[s][m].re, J_SS[s][m].im);
			}
		}
	} // end iSSMethod = (0 == SS_METHOD_FIX)
		break;
	case SS_METHOD_LC_MYU: // myu_J_SS : same as myu_LC(=fSSMyu)
	{
		////Znm1 = trans(conj(caX));
		////Z11 = prod(Znm1, caX);
		//dummy1//for(m=0; m<num_mic; m++){
		//dummy1//	//Znm1[m].re =  X[m].re;
		//dummy1//	Znm1[m].im = -X[m].im;	// 複素共役
		//dummy1//}
		//dummy1//for(s=0; s<num_mic; s++){
		//dummy1//	for(m=0; m<num_mic; m++){
		//dummy1//		Z11[s][m].re = (Znm1[s].re * X[m].re) - (Znm1[s].im * X[m].im);
		//dummy1//		Z11[s][m].im = (Znm1[s].re * X[m].im) + (Znm1[s].im * X[m].re);
		//dummy1//	}
		//dummy1//}
		//dummy2//for(s=0; s<num_mic; s++){
		//dummy2//	for(m=0; m<num_mic; m++){
		//dummy2//		Z11[s][m].re = (X[s].re * X[m].re) + (X[s].im * X[m].im);
		//dummy2//		Z11[s][m].im = (X[s].re * X[m].im) - (X[s].im * X[m].re);
		//dummy2//	}
		//dummy2//}
		//dummy3//Z11[0][0].re = (X[0].re * X[0].re) + (X[0].im * X[0].im);
		//dummy3//Z11[0][0].im = (X[0].re * X[0].im) - (X[0].im * X[0].re);
		//dummy4//Z11 = (X[0].re * X[0].re) + (X[0].im * X[0].im);
		////if(fabs(pow(Z11(0,0).real(),2.0)) < _MINIMUM_ZERO_VALUE){
		////	fTmp = 1.0 / _MINIMUM_ZERO_VALUE;
		////}
		////else{
		////	//　■myu_J_SS = LC_myu(fSSMyu) * Rxx^-2 * Jss
		////	fTmp = (double)(1.0 / (pow(Z11(0,0).real(), 2.0)));
		////}
		////fTmp = fTmp  * (double)fSSMyu;
		//dummy1//if(fabsf(Z11[0][0].re * Z11[0][0].re) < _MINIMUM_ZERO_VALUE){
		//dummy1//	fTmp = 1.0f / _MINIMUM_ZERO_VALUE;
		//dummy1//}
		//dummy1//else{
		//dummy1//	fTmp = (1.0f / (Z11[0][0].re * Z11[0][0].re));
		//dummy1//}
		//dummy1//fTmp *= fSSMyu;
		//dummy4//fTmp = fSSMyu;
		//dummy4//if(fabsf(Z11 * Z11) < _MINIMUM_ZERO_VALUE){
		//dummy4//	fTmp /= _MINIMUM_ZERO_VALUE;
		//dummy4//}
		//dummy4//else{
		//dummy4//	fTmp /= (Z11 * Z11);
		//dummy4//}
		fTmp = fSSMyu;
		fTmp2= (X[0].re * X[0].re) + (X[0].im * X[0].im);
		if(fabsf(fTmp2) < _MINIMUM_ZERO_VALUE){
			fTmp /= _MINIMUM_ZERO_VALUE;
		}
		else{
			fTmp /= fTmp2;
		}

		////for(row=0; row<Jss.size1(); row++){
		////	for(col=0; col<Jss.size2(); col++){
		////		if(Jss(row, col).real() *  fTmp > __MAX_FLOAT_VALUE &&
		////		   Jss(row, col).imag() *  fTmp > __MAX_FLOAT_VALUE ){
		////		   printf("Data is Inf.\n");
		////		   return 0;
		////		}
		////		complex<double> caTemp(Jss(row, col).real() * fTmp , Jss(row, col).imag() * fTmp );
		////		pcamyu_J_SS->insert_element(row, col, caTemp);
		////	}
		////}
		for(s=0; s<num_src; s++){
			for(m=0; m<num_mic; m++){
				tmp.re = Jss[s][m].re * fTmp;
				tmp.im = Jss[s][m].im * fTmp;
				if(tmp.re > _MAX_FLOAT_VALUE && tmp.im > _MAX_FLOAT_VALUE){
					LOGI("Data is Inf. = %e (%e) * %e .\n", Jss[s][m].re, Jss[s][m].im, fTmp);
					return 0;
				}
				J_SS[s][m].re = tmp.re;
				J_SS[s][m].im = tmp.im;
				//LOGI("s=%d, m=%d : J_SS[s][m](%f, %f)\n", s, m, J_SS[s][m].re, J_SS[s][m].im);
			}
		}
	} // end iSSMethod = (1 == SS_METHOD_LC_MYU)
		break;
	case SS_METHOD_ADAPTIVE: // myu_J_SS : adaptive // default is ADAPTIVE
	default:
#endif
	{ // <- とりあえず2なのでこれを先に移植
		//////// TAKIGAHIRA : merge formula
		//// ABS計算で虚数部が0.0fとなり、またABS計算のルート後にDotProductで二乗する事が分かっているので無駄な計算を省く
		//// 更に、Sum計算以外でZnsns配列自体が不要となる事からメモリ削減のためSumのループと統合する、虚数部は計算しない
		//// Znsns = abs(E) .* abs(E)
		//// Znsns[s][m].re = (Znsns[s][m].re * Znsns[s][m].re) - (Znsns[s][m].im * Znsns[s][m].im)
		////                = (Znsns[s][m].re * Znsns[s][m].re) - (0.0f * 0.0f)
		////                = (Znsns[s][m].re * Znsns[s][m].re)
		////                = sqrtf((E[s][m].re * E[s][m].re) + (E[s][m].im * E[s][m].im))
		////                * sqrtf((E[s][m].re * E[s][m].re) + (E[s][m].im * E[s][m].im))
		////                = ((E[s][m].re * E[s][m].re) + (E[s][m].im * E[s][m].im))
		//// Znsns[s][m].im = (Znsns[s][m].re * Znsns[s][m].im) + (Znsns[s][m].im * Znsns[s][m].re)
		////                = (Znsns[s][m].re * 0.0f) + (0.0f * Znsns[s][m].re)
		////                = 0.0f
		////
		////　■Znsns = abs(E)
		////if(_AbsCompMat(&Znsns, E) == false){
		////	return 0;
		////}
		//for(s=0; s<num_src; s++){
		//	for(m=0; m<num_src; m++){
		//		//dTemp = pow((double)E[s][m].re, 2.0) + pow((double)E[s][m].im, 2.0);
		//		dTemp = (E[s][m].re * E[s][m].re) + (E[s][m].im * E[s][m].im);
		//		Znsns[s][m].re = sqrtf(dTemp); // change function from sqrt() to sqrtf()
		//		Znsns[s][m].im = 0.0;
		//		//LOGI("s=%d, m=%d : Znsns[s][m](%f, %f)\n", s, m, Znsns[s][m].re, Znsns[s][m].im);
		//	}
		//}
		////　■Znsns = Znsns .* Znsns
		////Znsns = element_prod(Znsns, Znsns);		// <- 要素ごとに掛け算
		//for(s=0; s<num_src; s++){
		//	HA_Complex	tmp;
		//	tmp.re = 0.0;
		//	tmp.im = 0.0;
		//	for(m=0; m<num_src; m++){
		//		tmp.re = (Znsns[s][m].re * Znsns[s][m].re) - (Znsns[s][m].im * Znsns[s][m].im);
		//		tmp.im = (Znsns[s][m].re * Znsns[s][m].im) + (Znsns[s][m].im * Znsns[s][m].re);
		//		Znsns[s][m].re = tmp.re;
		//		Znsns[s][m].im = tmp.im;
		//		//LOGI("s=%d, m=%d : Znsns[s][m](%f, %f)\n", s, m, Znsns[s][m].re, Znsns[s][m].im);
		//	}
		//}
		////　■fTmp = sum(Znsns);
		////fTmp = 0.0;
		////for(row=0; row<Znsns.size1(); row++){
		////	for(col=0; col<Znsns.size2(); col++){
		////		fTmp = fTmp + Znsns(row, col).real();
		////	}
		////}
		//fTmp = 0.0f;
		//for(s=0; s<num_src; s++){
		//	for(m=0; m<num_src; m++){
		//		//fTmp = fTmp + Znsns[s][m].re;
		//		fTmp += Znsns[s][m].re;
		//	}
		//}
		////-- merged formula --//// fTmp = sum(abs(E) .* abs(E))
		fTmp = 0.0f;
		for(s=0; s<num_src; s++){
			for(m=0; m<num_src; m++){
				tmp = E[s][m];
				fTmp += tmp.re * tmp.re;
				fTmp += tmp.im * tmp.im;
			}
		}

		//////// TAKIGAHIRA : merge formula
		//// ABS計算で虚数部が0.0fとなり、同時にDotProductに含まれる項が打ち消されて処理量が削減されると分かっているので無駄な計算を省く
		//// 更に、Sum計算以外でZnsnm配列自体が不要となる事からメモリ削減のためSumのループと統合する、虚数部は計算しない
		//// dTemp = (Jss[s][m].re * Jss[s][m].re * Jpri[s][m].re * Jpri[s][m].re)
		////       + (Jss[s][m].re * Jss[s][m].re * Jpri[s][m].im * Jpri[s][m].im)
		////       + (Jss[s][m].im * Jss[s][m].im * Jpri[s][m].re * Jpri[s][m].re)
		////       + (Jss[s][m].im * Jss[s][m].im * Jpri[s][m].im * Jpri[s][m].im)
		////       - 2 * (Jss[s][m].re * Jss[s][m].im * Jpri[s][m].re * Jpri[s][m].im)
		////       + 2 * (Jss[s][m].re * Jss[s][m].im * Jpri[s][m].re * Jpri[s][m].im)
		////       = (Jss[s][m].re * Jss[s][m].re + Jss[s][m].im * Jss[s][m].im)
		////       * (Jpri[s][m].re * Jpri[s][m].re + Jpri[s][m].im * Jpri[s][m].im)
		////
		////　■Znsnm = Jss .* Jpri
		////Znsnm = element_prod(Jss, Jpri);
		//for(s=0; s<num_src; s++){
		//	for(m=0; m<num_mic; m++){
		//		Znsnm[s][m].re = (Jss[s][m].re * Jpri[s][m].re) - (Jss[s][m].im * Jpri[s][m].im);
		//		Znsnm[s][m].im = (Jss[s][m].re * Jpri[s][m].im) + (Jss[s][m].im * Jpri[s][m].re);
		//	}
		//}
		////　■Znsnm = abs(Znsnm)
		////if(_AbsCompMat(&Znsnm, Znsnm) == false){
		////	return 0;
		////}
		//for(s=0; s<num_src; s++){
		//	for(m=0; m<num_mic; m++){
		//		//dTemp = pow((double)Znsnm[s][m].re, 2.0) + pow((double)Znsnm[s][m].im, 2.0);
		//		dTemp = (Znsnm[s][m].re * Znsnm[s][m].re) + (Znsnm[s][m].im * Znsnm[s][m].im);
		//		//Znsnm[s][m].re = sqrt(dTemp);
		//		Znsnm[s][m].re = sqrtf(dTemp);
		//		Znsnm[s][m].im = 0.0;
		//	}
		//}
		////　■fTmp = sum(Znsns)
		////fTmp2 = 0.0;
		////for(row=0; row<Znsnm.size1(); row++){
		////	for(col=0; col<Znsnm.size2(); col++){
		////		fTmp2 = fTmp2 + Znsnm(row, col).real();
		////	}
		////}
		//fTmp2 = 0.0f;
		//for(s=0; s<num_src; s++){
		//	for(m=0; m<num_mic; m++){
		//		//fTmp2 = fTmp2 + Znsnm[s][m].re;
		//		fTmp2 += Znsnm[s][m].re;
		//		//LOGI("fTmp2=%e\n", fTmp2);
		//	}
		//}
		////-- merged formula --//// fTmp2 = sum(abs(Jss .* Jpri))
#if 0
		fTmp2 = 0.0f;
		for(s=0; s<num_src; s++){
			for(m=0; m<num_mic; m++){
				//Znsnm[s][m].re = sqrtf((Jss[s][m].re * Jss[s][m].re + Jss[s][m].im * Jss[s][m].im) * (Jpri[s][m].re * Jpri[s][m].re + Jpri[s][m].im * Jpri[s][m].im));
				//Znsnm[s][m].im = 0.0f;
				//LOGI("s=%d, m=%d : Znsnm(%f, %f)\n", s, m, Znsnm[s][m].re, Znsnm[s][m].im);
				tmp2 = Jss[s][m];
				tmp.re  = tmp2.re * tmp2.re;
				tmp.re += tmp2.im * tmp2.im;
				tmp2 = Jpri[s][m];
				tmp.im  = tmp2.re * tmp2.re;
				tmp.im += tmp2.im * tmp2.im;
				fTmp2 += sqrtf(tmp.re * tmp.im);
			}
		}
#else
        /* 2014.12.12 ktakagi@sif
        **
        ** 音源IDが異なり＆音源方向が同じ＆発話区間が重複した場合に
        ** 計算のオーバーフローが生じ、分離音が破綻した
        ** 計算をdoubleで実行するように修正
        ** 
        */
        fTmp2 = 0.0;
        {
            double tmp_re;
            double tmp_im;
	    	for(s=0; s<num_src; s++){
	    		for(m=0; m<num_mic; m++){
	    			//Znsnm[s][m].re = sqrtf((Jss[s][m].re * Jss[s][m].re + Jss[s][m].im * Jss[s][m].im) * (Jpri[s][m].re * Jpri[s][m].re + Jpri[s][m].im * Jpri[s][m].im));
	    			//Znsnm[s][m].im = 0.0f;
	    			//LOGI("s=%d, m=%d : Znsnm(%f, %f)\n", s, m, Znsnm[s][m].re, Znsnm[s][m].im);
	    			tmp2 = Jss[s][m];
	    			tmp_re  = tmp2.re * tmp2.re;
	    			tmp_re += tmp2.im * tmp2.im;
	    			tmp2 = Jpri[s][m];
	    			tmp_im  = tmp2.re * tmp2.re;
	    			tmp_im += tmp2.im * tmp2.im;
	    			fTmp2 += sqrt(tmp_re * tmp_im);
	    		}
	    	}
		}
#endif
		if(fabsf(fTmp2) < _MINIMUM_ZERO_VALUE){ // change function from fabs() to fabsf()
			//fTmp2 = fTmp2 + _MINIMUM_ZERO_VALUE;
			fTmp2 += _MINIMUM_ZERO_VALUE;
		}
		//fTmp = (fTmp / fTmp2 / (double)2.0);			// <- ゼロ割注意！！
		//fTmp = (fTmp / fTmp2 / 2.0f);			// <- ゼロ割注意！！
		fTmp2 *= 2.0f;
		fTmp /= fTmp2;			// <- ゼロ割注意！！
		//LOGI("fTmp=%f\n", fTmp);

		////　■myu_J_SS = fTmp * Js
		////for(row = 0; row < Jss.size1(); row++){
		////	for(col = 0; col < Jss.size2(); col++){
		////		if(Jss(row, col).real() * fTmp > 3.4028E038 &&
		////		   Jss(row, col).imag() * fTmp > 3.4028E038	){
		////			printf("Data is Inf. = %e (%e) * %e .\n", Jss(row, col).real(), Jss(row, col).imag(), fTmp);
		////			return 0;
		////		}
		////		complex<double> caTemp(Jss(row, col).real() * fTmp , Jss(row, col).imag() * fTmp );
		////		pcamyu_J_SS->insert_element(row, col, caTemp);
		////	}
		////}
		for(s=0; s<num_src; s++){
			for(m=0; m<num_mic; m++){
				tmp.re = Jss[s][m].re * fTmp;
				tmp.im = Jss[s][m].im * fTmp;
				//if(tmp.re * fTmp > _MAX_FLOAT_VALUE && tmp.im * fTmp > _MAX_FLOAT_VALUE){ // TAKIGAHIRA ::memo:: tmpに既にfTmpが乗じてあるのでこの条件はバグではないだろうか？
				if(tmp.re > _MAX_FLOAT_VALUE && tmp.im > _MAX_FLOAT_VALUE){
					LOGI("Data is Inf. = %e (%e) * %e .\n", Jss[s][m].re, Jss[s][m].im, fTmp);
					return 0;
				}
				J_SS[s][m].re = tmp.re;
				J_SS[s][m].im = tmp.im;
				//LOGI("s=%d, m=%d : J_SS[s][m](%f, %f)\n", s, m, J_SS[s][m].re, J_SS[s][m].im);
			}
		}
	} // end iSSMethod = (2 == SS_METHOD_ADAPTIVE)
#ifdef ENABLE_SWITCHING_GHDSS_MODE
		break;
	}
#endif
	//////// TAKIGAHIRA : merge formula
	//// ABS計算で虚数部が0.0fとなり、またABS計算のルート後に二乗する事が分かっているので無駄な計算を省く
	//// 更に、Sum計算以外でZns1配列自体が不要となる事からメモリ削減のためSumのループと統合する、虚数部は計算しない
	////
	////if(_AbsCompMat(&Zns1, caY) == false){
	////	return 0;
	////}
	//for(s=0; s<num_src; s++){
	//	//dTemp = pow((double)Y[s].re, 2.0) + pow((double)Y[s].im, 2.0);
	//	dTemp = (Y[s].re * Y[s].re) + (Y[s].im * Y[s].im); // expand pow function
	//	Zns1[s].re = sqrtf(dTemp); // change function from sqrt() to sqrtf()
	//	Zns1[s].im = 0.0;
	//}
	//// ■fYrms
	////fYrms = 0.0;
	////for(row = 0; row < Zns1.size1(); row++){
	////	for(col = 0; col < Zns1.size2(); col++){
	////		fYrms = (double)pow(Zns1(row, col).real(), 2.0) + fYrms;
	////	}
	////}
	//fYrms = 0.0;
	//for(s=0; s<num_src; s++){
	//	//fYrms += (double)pow(Zns1[s].re, 2.0);
	//	fYrms += (Zns1[s].re * Zns1[s].re); // expand pow function
	//}
	fYrms = 0.0f;
	for(s=0; s<num_src; s++){
		tmp = Y[s];
		fYrms += tmp.re * tmp.re;
		fYrms += tmp.im * tmp.im;
	}

	//fYrms =  fYrms / (Zns1.size1() * Zns1.size2());
	//fYrms =  fYrms / num_src;
	fYrms /= num_src;
	fYrms = sqrtf(fYrms); // change function from sqrt() to sqrtf()
	//LOGI("fYrms=%f\n",fYrms);

	//if(fYrms < fNoiseFloor)
	if(fYrms < 0.0f){		// <- 後でパラメータ化すること
		////_InitCompMat(pcamyu_J_SS);		//NoiseFloorより小さかったら，更新値をなかったことにする？ ゼロ埋め
		for(s=0; s<num_src; s++){
			for(m=0; m<num_mic; m++){
				J_SS[s][m].re = 0.0f;
				J_SS[s][m].im = 0.0f;
			}
		}
		LOGI("jss_init\n");
	}
    return(OK);
}

int	dUpdateSeparationMatGHDSS(
	int	num_src,
	HA_Complex inputSpec[ARY_NUM_MIC][ARY_NUM_FFT]
	)
{
//    int 		Nsrc, Nfreq, Nmic, ifreq, ind;
    int 		ifreq, ind;
	HA_Float 	Threshold_val, Max_val, fTmp;
	HA_Complex tmp, tmp2, tmp3;

	int		m,f,s;	
	int 	iUp = 0;

	//Treshold_val

	Max_val = 32768.0f;
	Max_val = 10 * log10(Max_val);
	fTmp 	= (Max_val - THRESHOLD) / 10.0f;
	//TAKIGAHIRA
	//Threshold_val = pow((float)10.0 , fTmp) ;
	{
		union {
			double d_val;
			int i_val[2];
		} u;
		u.i_val[1] = (int)(fTmp*3468673+1072632447);
		u.i_val[0] = 0;
		Threshold_val = (float) u.d_val;
	}

	//■　初期化＆チェック
	ifreq 	= 0; 		//開始周波数インデックス
	//Nmic 	= ARY_NUM_MIC;
	//Nfreq 	= ARY_NUM_FFT;
	//Nsrc 	= ARY_NUM_SRC;

	/////////////////////////////
	// メインループ
	while(1){	// frequency loop
		//printf("--------- ifreq: %d --------\n", ifreq);

		if(ifreq == 0){	// D.Cはスキップ
			ifreq ++ ;
			continue ;
		}

		//if(ifreq > 256){	// とりあえず定数 (UpperFreq)
		if(ifreq > 255){	// とりあえず定数 (UpperFreq)	// 1.#QNAN対策（ゼロ割）
			break ;
		}
		if(ifreq < 0){		// とりあえず定数 (LowerFreq)
			ifreq ++ ;
			continue ;
		}

		// 範囲チェック。とりあえずパス。

		// ■ カレントの周波数帯のデータのみを切り出して，Matrix型に変換
		//cdMat A (Nmic, Nsrc);	// 8 x 3
		//cdMat X (Nmic, 1);	// 8 x 1
		//cdMat W (Nsrc, Nmic);	// 3 x 8

		// psSavedSeparation->micary_tdTFDB を変換
		// _Convert_ComplexSpec() 相当
		for(m=0; m<num_mic; m++){
			for(s=0; s<num_src; s++){
				A[m][s].re = OutTF[s][ifreq][m].re;
				A[m][s].im = OutTF[s][ifreq][m].im;
				//LOGI("m=%d, s=%d : A[m][s](%15.8f, %15.8f)\n", A[m][s].re, A[m][s].im);
				//LOGI("m=%d, s=%d : A[m][s](%f, %f)\n", A[m][s].re, A[m][s].im);
			}
		}
		//LOGI("A[0][0](%f, %f)\n", A[0][0].re, A[0][0].im);

		// csInputSpecを変換
		// _Convert_Complex_InputSpec()相当
		for(m=0; m<num_mic; m++){
			X[m].re = inputSpec[m][ifreq].re;
			X[m].im = inputSpec[m][ifreq].im;
		}
		//LOGI("X[0](%f, %f)\n", X[0].re, X[0].im);

		// psSavedSeparation->micary_smSeparation を変換
		// _Convert_ComplexSpec()相当
		for(s=0; s<num_src; s++){
			for(m=0; m<num_mic; m++){
				// KAMA
				//W[s][m].re = sepMat[s][ifreq][m].re;
				//W[s][m].im = sepMat[s][ifreq][m].im;
				W[s][m].re = sepMat[mat_id[s]][ifreq][m].re;
				W[s][m].im = sepMat[mat_id[s]][ifreq][m].im;
				//LOGI("s=%d, m=%d : W[s][m](%f, %f)\n", s, m, W[s][m].re, W[s][m].im);
			}
		}

		// 2013.02.14
		/*
		if(ifreq == 128){
			LOGI("ifreq = %d", ifreq);
			for (s = 0; s<num_src; s++){
				for (m = 0; m<num_mic; m++){
					LOGI("W[%d][%d] = %f, %f\n", s,m, W[s][m].re, W[s][m].im);
				}
			}
		}
		*/
	
		// ------------------------------------------//
		// ---------- Execute GHDSS --------------- //
		//	Y = prod(W, X); // B = prod(A) は、配列の次元ごとに積を返します
		//
		//	(A+jB)(C+jD)
		// = (AC-BD)+j(AD+BC)
		for(s=0; s<num_src; s++){
			tmp.re = 0.0f;
			tmp.im = 0.0f;
			for(m=0; m<num_mic; m++){
				//float	aa = W[s][m].re;
				//float	bb = W[s][m].im;
				//float	cc = X[m].re;
				//float	dd = X[m].im;

				//Y[s].re += (aa*cc - bb*dd);
				//Y[s].im += (aa*dd + bb*cc);
				tmp2 = W[s][m];
				tmp3 = X[m];
				tmp.re += tmp2.re * tmp3.re;
				tmp.re -= tmp2.im * tmp3.im;
				tmp.im += tmp2.re * tmp3.im;
				tmp.im += tmp2.im * tmp3.re;
				Y[s] = tmp;
				//if(ifreq == 256){ LOGI("%d : %f, %f\n", ifreq, X[m].re, X[m].im); }
				//if(ifreq == 256){ LOGI("%d : %f, %f\n", ifreq, W[s][m].re, W[s][m].im); }
			}
		}
		//LOGI("%d : Y[0](%f, %f), Y[1](%f, %f), Y[2](%f, %f)\n", ifreq, Y[0].re, Y[0].im, Y[1].re, Y[1].im, Y[2].re, Y[2].im);

	    // --- Copy : Y -> Separated spectrum(src->freqの順) --- //
		//csSeparationSpecをYで更新（出力用）

		for(s=0; s<num_src; s++){
			csaOutputSpec[s][ifreq].re = Y[s].re;
			csaOutputSpec[s][ifreq].im = Y[s].im;
		}
		//LOGI("%d : csaOutputSpec = %f, %f\n", ifreq,csaOutputSpec[1][ifreq].re, csaOutputSpec[1][ifreq].im);

		// --------------------------------------- //
		// ------ Update separated matrix --------- //
		for(m=0; m<num_mic; m++){
			//fTmp = pow(X[m].re , (double)2.0) + pow(X[m].im , (double)2.0) ;
			fTmp  = (X[m].re * X[m].re); // expand pow function
			fTmp += (X[m].im * X[m].im); // expand pow function
			fTmp = sqrtf(fTmp); // change function from sqrt() to sqrtf()

			if(fTmp < Threshold_val){
				iUp = 1 ;
				break ;
			}
		}
		//	printf("iUp = %d\n", iUp);
		if(iUp == 0){
			/////////////////////
			// ■　SS
//		    if(sPrmSeparation.ha_iSSMethod == _SS_METHOD_LCMYU){ //LCMyuと共通化			<- とりあえずLCMYUではない
//				sPrmSeparation.ha_fSSMyu = sPrmSeparation.ha_fLCMyu ;
//		    }
//		    if(_dCalcSSStepSize_GHDSS(W,A,Y,X,
//					      sPrmSeparation.ha_iSSMethod,
//					      sPrmSeparation.ha_fSSMyu,
//					      sPrmSeparation.ha_fSSScal,
//					      sPrmSeparation.ha_fNoiseFloor, & J_SS) != 1 ){
//				return 0 ;
//		    }
			CalcSSStepSize_GHDSS(num_src);
			//if(ifreq == 256){ LOGI("ifreq=%d : J_SS[0][0](%f, %f)\n", ifreq, J_SS[0][0].re, J_SS[0][0].im); }
			if(ha_iUpdate == 0){	//段階的
				// Update W
//				W = W - J_SS;
				for(s=0; s<num_src; s++){
					for(m=0; m<num_mic; m++){
						W[s][m].re	-= J_SS[s][m].re;
						W[s][m].im	-= J_SS[s][m].im;
						//LOGI("s=%d, m=%d : W[s][m](%f, %f), J_SS[s][m](%f, %f)\n", s, m, W[s][m].re, W[s][m].im, J_SS[s][m].re, J_SS[s][m].im);
					}
				}
			}
			//if(ifreq == 256){ LOGI("ifreq=%d : W[0][0](%f, %f)\n", ifreq, W[0][0].re, W[0][0].im); }

			/////////////////////
			// ■　LC
			CalcLCStepSize_GHDSS(num_src);
		    if(ha_iUpdate == 0){	// 段階的
				// Update W
//				W = W - J_LC;
				for(s=0; s<num_src; s++){
					for(m=0; m<num_mic; m++){
						W[s][m].re	-= J_LC[s][m].re;
						W[s][m].im	-= J_LC[s][m].im;
						W[s][m].re	*= (1.0 - ha_fWmyu);
						W[s][m].im	*= (1.0 - ha_fWmyu);
					}
				}
				//if(ifreq == 256){ LOGI("ifreq=%d : W[0][0](%f, %f)\n", ifreq, W[0][0].re, W[0][0].im);
				// 2010/4/8
				//for(col=0; col<W.size2(); col++){
				//	for(row=0; row<W.size1(); row++){
				//		W(row, col) = complex<double> (W(row, col).real() * (1.0 - ha_fWmyu) , W(row, col).imag() * (1.0 - ha_fWmyu));
				//	}
				//}
		    }
		    else{
				// Wmyuで発散防止
				//for(col = 0; col < W.size2(); col++){
				//	for(row = 0; row < W.size1(); row++){
				//		W(row, col) = complex<double> (W(row, col).real() * (1.0 - ha_fWmyu) , W(row, col).imag() * (1.0 - ha_fWmyu));
				//	}
				//}
				//W = W - J_SS;
				//W = W - J_LC;
				for(s=0; s<num_src; s++){
					for(m=0; m<num_mic; m++){
						W[s][m].re	*= (1.0 - ha_fWmyu);
						W[s][m].im	*= (1.0 - ha_fWmyu);
						W[s][m].re	-= J_LC[s][m].re;
						W[s][m].im	-= J_LC[s][m].im;
					}
				}
			}
		    //for(s=0; s<num_src; s++){
		    //	for(m=0; m<num_mic; m++){
			//		LOGI("s=%d, m=%d : W[s][m](%f, %f), J_LC[s][m](%f, %f)\n", W[s][m].re, W[s][m].im, J_LC[s][m].re, J_LC[s][m].im);
		    //	}
		    //}
		}
		//for(s=0; s<ARY_NUM_SRC; s++){
		//	for(m=0; m<ARY_NUM_MIC; m++){
		//		LOGI("s=%d, m=%d : W[s][m](%f, %f)\n", W[s][m].re, W[s][m].im);
		//	}
		//}

		//--- Update Spec array ---//  
		// --- 2010.9.1 修正 ---
		// ■ psSavedSeparation->micary_smSeparation.micary_cmpaSeparation をWで更新
		//_Update_ComplexSpec(&(psSavedSeparation->micary_smSeparation.micary_cmpaSeparation), W, Nsrc, Nmic, ifreq);
		for(s=0; s<num_src; s++){
			for(m=0; m<num_mic; m++){
				// KAMA
				//sepMat[s][ifreq][m].re = W[s][m].re;
				//sepMat[s][ifreq][m].im = W[s][m].im;
				sepMat[mat_id[s]][ifreq][m].re = W[s][m].re;
				sepMat[mat_id[s]][ifreq][m].im = W[s][m].im;
			}
		}
		//if (ifreq == 256) printf("%d : %f, %f\n", ifreq, W[0][0].re, W[0][0].im);
		// ------------------------------------------//
		ifreq++ ;
	}	//end while
	return(OK);
}

int	ExecuteGHDSS(
	int	num_src,
	HA_Complex		inputSpec[ARY_NUM_MIC][ARY_NUM_FFT]
	)
{
	// GHDSSの実行と分離行列の更新
	dUpdateSeparationMatGHDSS(num_src, inputSpec);
	return(OK);
}

///////////////////////////////////////////////////////////////
//	Wの更新

// SetUpdateW
int SetUpdateW()
{
	int ii,jj,iPos,Nmic,Npos_cur,Npos_all,iLower_f,iUpper_f,Nfreq;
	int	m,f;

//	Nmic = m_psSepMat->micary_smSeparation.ha_numInput ;
//	Npos_cur = m_psSepMat->micary_tdTFDB.micary_locaSource.ha_numLocation ;
//	Npos_all = m_updateW->micary_dbSeparation.micary_locaSource.ha_numLocation ;
//	iLower_f = m_psSepMat->micary_smSeparation.micary_iaFreqLinex.ha_iValue[0] ;
//	iUpper_f = m_psSepMat->micary_smSeparation.micary_iaFreqLinex.ha_numValue + iLower_f -1 ;
//	Nfreq = m_psSepMat->micary_smSeparation.micary_iaFreqLinex.ha_numValue ;

//	if(m_iUpdateMethodWex->ha_numValue == 0){
//	  	IntArrayFree(m_iUpdateMethodWex) ;
//		IntArrayAlloc(m_iUpdateMethodWex,Npos_cur) ;
//
//		for(ii=0; ii<Npos_cur; ii++){
//			m_iUpdateMethodWex->ha_iValue[ii] = m_iUpdateMethodW ;
//		}
//	}

//	for(ii=0; ii<Npos_cur; ii++){
	for(ii=0; ii<ARY_NUM_SRC; ii++){
#ifdef NEVER
		switch (m_iUpdateMethodWex->ha_iValue[ii]){
		case __UPDATE_METHOD_POS :
			iPos = GetNearestPos(m_psSepMat->micary_tdTFDB.micary_locaSource.micary_Location[ii],
				&(m_updateW->micary_dbSeparation.micary_locaSource)) ;
			if(iPos == __INVALID_SRC_ID){
				for(jj=0; jj<Npos_all; jj++){
					if(m_updateW->micary_iaUpdate.ha_iValue[jj] == __INVALID_SRC_ID){
						iPos = jj;
						break;
					}
				}
			}	  
			for(k=0; k<Nfreq; k++){
					for(m=0; m<Nmic; m++){
						m_updateW->micary_dbSeparation.micary_smSeparation.micary_cmpaSeparation.ha_cmpValue[iPos+m*Npos_all+k*Npos_all*Nmic].re=
							m_psSepMat->micary_smSeparation.micary_cmpaSeparation.ha_cmpValue[ii+m*Npos_cur+k*Npos_cur*Nmic].re ;
						m_updateW->micary_dbSeparation.micary_smSeparation.micary_cmpaSeparation.ha_cmpValue[iPos+m*Npos_all+k*Npos_all*Nmic].im = 
							m_psSepMat->micary_smSeparation.micary_cmpaSeparation.ha_cmpValue[ii+m*Npos_cur+k*Npos_cur*Nmic].im  ;
					}
				}
				//音源情報の更新
				m_updateW->micary_dbSeparation.micary_locaSource.micary_Location[iPos].ha_fX = m_psSepMat->micary_tdTFDB.micary_locaSource.micary_Location[ii].ha_fX ;
				m_updateW->micary_dbSeparation.micary_locaSource.micary_Location[iPos].ha_fY = m_psSepMat->micary_tdTFDB.micary_locaSource.micary_Location[ii].ha_fY ;
				m_updateW->micary_dbSeparation.micary_locaSource.micary_Location[iPos].ha_fZ = m_psSepMat->micary_tdTFDB.micary_locaSource.micary_Location[ii].ha_fZ ;
				m_updateW->micary_dbSeparation.micary_locaSource.micary_Location[iPos].ha_idPos = m_psSepMat->micary_tdTFDB.micary_locaSource.micary_Location[ii].ha_idPos ;

				//音源IDも更新
				m_updateW->micary_dbSeparation.micary_locaSource.ha_idLocation[iPos]= m_psSepMat->micary_tdTFDB.micary_locaSource.ha_idLocation[ii] ;
				//更新履歴の更新
				m_updateW->micary_iaUpdate.ha_iValue[iPos] = __SRCID_FRONT_EXIST ;

		break ;

#endif
		// とりあえずこっち	UpdateMethod = 2
//		case __UPDATE_METHOD_ID :
//		case __UPDATE_METHOD_ID_POS :
//			m_iUpdateMethodWex->ha_iValue[ii] = __UPDATE_METHOD_ID;

//			iPos = Npos_all ;

/* 音源の更新のチェック
			for(jj=0; jj<Npos_all; jj++){
				if(m_psSepMat->micary_tdTFDB.micary_locaSource.ha_idLocation[ii] ==
					m_updateW->micary_dbSeparation.micary_locaSource.ha_idLocation[jj]){
					iPos = jj ;
					break ;
				}
			}

			if(iPos >= Npos_all){
				for(jj=0; jj<Npos_all; jj++){
					if(m_updateW->micary_iaUpdate.ha_iValue[jj] == __INVALID_SRC_ID){
						iPos = jj ;
						break ;
					}
				}
			}
*/

/*
			for(f=0; f<ARY_NUM_FFT; f++){
				for(m=0; m<num_mic; m++){
					updateW[ii][f][m].re	= sepMat[ii][f][m].re;
					updateW[ii][f][m].im	= sepMat[ii][f][m].im;
					//printf("%d UpdateW = %f, %f\n", ii,updateW[ii][f][m].re, updateW[ii][f][m].im);
				}
				//printf("\n");
			}
*/
					
			//音源情報の更新
/*
			m_updateW->micary_dbSeparation.micary_locaSource.micary_Location[iPos].ha_fX 
								= m_psSepMat->micary_tdTFDB.micary_locaSource.micary_Location[ii].ha_fX ;

			m_updateW->micary_dbSeparation.micary_locaSource.micary_Location[iPos].ha_fY 
								= m_psSepMat->micary_tdTFDB.micary_locaSource.micary_Location[ii].ha_fY ;

			m_updateW->micary_dbSeparation.micary_locaSource.micary_Location[iPos].ha_fZ 
								= m_psSepMat->micary_tdTFDB.micary_locaSource.micary_Location[ii].ha_fZ ;

			//音源IDも更新
			m_updateW->micary_dbSeparation.micary_locaSource.ha_idLocation[iPos] 
								= m_psSepMat->micary_tdTFDB.micary_locaSource.ha_idLocation[ii] ;

			m_updateW->micary_dbSeparation.micary_locaSource.micary_Location[iPos].ha_idPos 
								= m_psSepMat->micary_tdTFDB.micary_locaSource.micary_Location[ii].ha_idPos ;

			//更新履歴の更新
			m_updateW->micary_iaUpdate.ha_iValue[iPos] = __SRCID_FRONT_EXIST ;
*/
//		break ;
//		default :	break ;
//		}
	}
//	_SetRemoveSrc() ;
	return(OK) ;
}


// AddUpdateW
int AddUpdateW()
{
	int ii ,jj ,Npos,Nmic,Nfreq,k,m,Npos_all,idtmp;

//	bool bUpdate ;
//	bool bRtn ;

//	Npos_all = m_updateW->micary_dbSeparation.micary_locaSource.ha_numLocation;
//	Nmic = m_updateW->micary_dbSeparation.micary_locaMic.ha_numLocation ;
//	Nfreq = m_updateW->micary_dbSeparation.micary_smSeparation.micary_iaFreqLinex.ha_numValue ;

//	for(ii=0; ii<Npos_all; ii++){
	for(ii=0; ii<num_tf_pos; ii++){
#ifdef NEVER
		if(m_updateW->micary_iaUpdate.ha_iValue[ii] == __SRCID_FRONT_REMOVE && 
			m_updateW->micary_dbSeparation.micary_locaSource.micary_Location[ii].ha_idPos != __INVALID_SRC_ID){
			if(!bExpW){
		    	//フラグの更新 <- こっち
/*
		    	if (m_iUpdateMethodW == __UPDATE_METHOD_ID || m_iUpdateMethodW == __UPDATE_METHOD_ID_POS){
			       	m_updateW->micary_iaUpdate.ha_iValue[ii]=__INVALID_SRC_ID;

			       	for(k = 0 ; k < Nfreq ; k++){
					 	for(m = 0 ; m < Nmic ; m++){
				    		m_updateW->micary_dbSeparation.micary_smSeparation.micary_cmpaSeparation.ha_cmpValue[ii+m*Npos_all+k*Nmic*Npos_all].re = 0.0;
				    		m_updateW->micary_dbSeparation.micary_smSeparation.micary_cmpaSeparation.ha_cmpValue[ii+m*Npos_all+k*Nmic*Npos_all].im = 0.0;
		   	    		}
			  		}
				}
*/
		 	}
		 	else{
				// とりあえずエクスポートしないほう
				// 2010.8.11
			   	cout << "Export file : " << cFilename <<" src = " << m_updateW->micary_dbSeparation.micary_locaSource.micary_Location[ii].ha_idPos << endl ;

				MICARY_SMDatabase *pstmpW ;
				// ファイルから読込み
				MICARY_TFDBFileHeader * psH ;	//データベースヘッダ
				psH = (MICARY_TFDBFileHeader *)calloc(1,sizeof(MICARY_TFDBFileHeader)) ;
	
				HA_String file ; // ファイル名
				file.s = (HA_Char *)calloc(strlen(cFilename)+1,sizeof(char)) ;
				strcpy(file.s,cFilename) ;
				file.slen = strlen(cFilename) ;
		
				if(m_iFormat_ExportW == __FILE_FORMAT_HARK){
					if(!cHark.ReadHeader(file.s,psH)){ //ファイルのヘッダ情報を取得
						cout << "Can not read export file."<< endl ;
						if(psH){
							free(psH) ;
							psH = NULL ;
						}

						if(file.s){
							free(file.s) ;
							file.s = NULL ;
						}
						return false ;
					}

					pstmpW = (MICARY_SMDatabase *)calloc(1,sizeof(MICARY_SMDatabase)) ;	//分離行列テンポラリ

					SMDatabaseAlloc(pstmpW,0,0,0) ;
					SMDatabaseAlloc(pstmpW,(int)psH->lNFreq,(int)psH->lNSrc,(int)psH->lNMic) ;
			
					// Read Header
					if(!cHark.ReadInfo(file.s,psH ,&pstmpW->micary_locaSource,
							   &pstmpW->micary_locaMic,&pstmpW->micary_smSeparation.micary_iaFreqLinex,false)){
						cout << "Can not read export file."<< endl ;
						if(psH){
							free(psH) ;
							psH = NULL ;
						}
						if(file.s){
							free(file.s) ;
							file.s = NULL ;
						}
	
						SMDatabaseFree(pstmpW) ;
						free(pstmpW) ;
						pstmpW = NULL ;
	
						return false ;
					}
	
					Npos = pstmpW->micary_locaSource.ha_numLocation ;
					Nmic = pstmpW->micary_locaMic.ha_numLocation ;
					Nfreq = pstmpW->micary_smSeparation.micary_iaFreqLinex.ha_numValue ;
	
					if(!cHark.ReadData(file.s,&pstmpW->micary_smSeparation.micary_cmpaSeparation)){
						std ::cout << "Fail to read export file." << std::endl ;
	
						if(psH){
							free(psH) ;
							psH = NULL ;
						}
						if(file.s){
							free(file.s) ;
							file.s = NULL ;
						}
	
						SMDatabaseFree(pstmpW) ;
						free(pstmpW) ;
						pstmpW = NULL ;
	
						return false ;
					}
				}

				// 同じIDがあれば、更新
				bUpdate = false ;
				idtmp = GetNearestPos(m_updateW->micary_dbSeparation.micary_locaSource.micary_Location[ii],&pstmpW->micary_locaSource) ;

				if(idtmp != __INVALID_SRC_ID){
					bool btmp = _IsThreshPos(m_updateW->micary_dbSeparation.micary_locaSource.micary_Location[ii],
								pstmpW->micary_locaSource.micary_Location[idtmp]) ;
					if(btmp){
						//分離行列の引継ぎ
				  		for(k = 0 ; k < Nfreq ; k++){
			    			for(m = 0 ; m < Nmic ; m++){
			      				pstmpW->micary_smSeparation.micary_cmpaSeparation.ha_cmpValue[idtmp+m*Npos+k*Nmic*Npos].re 
									= m_updateW->micary_dbSeparation.micary_smSeparation.micary_cmpaSeparation.ha_cmpValue[ii+m*Npos_all+k*Nmic*Npos_all].re ;

			   	      			pstmpW->micary_smSeparation.micary_cmpaSeparation.ha_cmpValue[idtmp+m*Npos+k*Nmic*Npos].im 
									= m_updateW->micary_dbSeparation.micary_smSeparation.micary_cmpaSeparation.ha_cmpValue[ii+m*Npos_all+k*Nmic*Npos_all].im ;
		   	    			}
			  			}

				  		//SrcPosも更新
				  		pstmpW->micary_locaSource.micary_Location[idtmp].ha_fX = m_updateW->micary_dbSeparation.micary_locaSource.micary_Location[ii].ha_fX ;
				  		pstmpW->micary_locaSource.micary_Location[idtmp].ha_fY = m_updateW->micary_dbSeparation.micary_locaSource.micary_Location[ii].ha_fY ;
				  		pstmpW->micary_locaSource.micary_Location[idtmp].ha_fZ = m_updateW->micary_dbSeparation.micary_locaSource.micary_Location[ii].ha_fZ ;
				  		bUpdate = true ;
					}
				}
		
				if(bUpdate){
					if(m_iFormat_ExportW == __FILE_FORMAT_HARK){
						psH->lFs = (int)psPrmFrame->ha_fFs ;
				  		psH->lNFFT = psPrmFrame->ha_numNFFT ;

				 		// 2010.8.11
				  		psH->lNSrc = pstmpW->micary_locaSource.ha_numLocation ;
				  		psH->lNMic =  pstmpW->micary_locaMic.ha_numLocation ;
				  		psH->lNFreq = pstmpW->micary_smSeparation.micary_iaFreqLinex.ha_numValue ;
				  		psH->iVersion = 1 ;
				  		psH->iFileType = FORMAT_TYPE_W ;
			
						if(!cHark.WriteData(file.s,psH,
							pstmpW->micary_smSeparation.micary_cmpaSeparation,
							pstmpW->micary_smSeparation.micary_iaFreqLinex,
							pstmpW->micary_locaSource,
							pstmpW->micary_locaMic,
							"", "", "", "", "", "GHDSS_EXPORT")){

							if(psH){
								free(psH) ;
								psH = NULL ;
							}
							if(file.s){
								free(file.s) ;
								file.s = NULL ;
							}

							SMDatabaseFree(pstmpW) ;
							free(pstmpW) ;
							pstmpW = NULL ;

							return false ;
						}
					}
				}

				else{ //更新する音源がなければ追加
					MICARY_SMDatabase *pstmpW2 ;
					pstmpW2 = (MICARY_SMDatabase *)calloc(1,sizeof(MICARY_SMDatabase)) ;	//分離行列テンポラリ
					SMDatabaseAlloc(pstmpW2,0,0,0) ;
					SMDatabaseAlloc(pstmpW2,Nfreq,Npos+1,Nmic) ;

					for(jj=0; jj<Nmic; jj++){ //マイク座標
						pstmpW2->micary_locaMic.ha_idLocation[jj] 			= pstmpW->micary_locaMic.ha_idLocation[jj] ;
						pstmpW2->micary_locaMic.micary_Location[jj].ha_fX 	= pstmpW->micary_locaMic.micary_Location[jj].ha_fX ;
						pstmpW2->micary_locaMic.micary_Location[jj].ha_fY 	= pstmpW->micary_locaMic.micary_Location[jj].ha_fY ;
						pstmpW2->micary_locaMic.micary_Location[jj].ha_fZ 	= pstmpW->micary_locaMic.micary_Location[jj].ha_fZ ;
						pstmpW2->micary_locaMic.micary_Location[jj].ha_idPos= pstmpW->micary_locaMic.micary_Location[jj].ha_idPos ;
					}
					for(jj=0; jj<Nfreq; jj++){ //周波数ライン
						pstmpW2->micary_smSeparation.micary_iaFreqLinex.ha_iValue[jj] = pstmpW->micary_smSeparation.micary_iaFreqLinex.ha_iValue[jj] ;
					}
					for(jj=0; jj<Npos; jj++){ //音源座標
						pstmpW2->micary_locaSource.ha_idLocation[jj] 			= pstmpW->micary_locaSource.ha_idLocation[jj] ;
						pstmpW2->micary_locaSource.micary_Location[jj].ha_fX 	= pstmpW->micary_locaSource.micary_Location[jj].ha_fX ;
						pstmpW2->micary_locaSource.micary_Location[jj].ha_fY 	= pstmpW->micary_locaSource.micary_Location[jj].ha_fY ;
						pstmpW2->micary_locaSource.micary_Location[jj].ha_fZ 	= pstmpW->micary_locaSource.micary_Location[jj].ha_fZ ;
						pstmpW2->micary_locaSource.micary_Location[jj].ha_idPos = pstmpW->micary_locaSource.micary_Location[jj].ha_idPos ;
					}
	
					pstmpW2->micary_locaSource.ha_idLocation[Npos] 			= m_updateW->micary_dbSeparation.micary_locaSource.ha_idLocation[ii] ;
					pstmpW2->micary_locaSource.micary_Location[Npos].ha_fX 	= m_updateW->micary_dbSeparation.micary_locaSource.micary_Location[ii].ha_fX ;
					pstmpW2->micary_locaSource.micary_Location[Npos].ha_fY 	= m_updateW->micary_dbSeparation.micary_locaSource.micary_Location[ii].ha_fY ;
					pstmpW2->micary_locaSource.micary_Location[Npos].ha_fZ 	= m_updateW->micary_dbSeparation.micary_locaSource.micary_Location[ii].ha_fZ ;
					pstmpW2->micary_locaSource.micary_Location[Npos].ha_idPos = m_updateW->micary_dbSeparation.micary_locaSource.micary_Location[ii].ha_idPos ;
	
					//ファイルデータを読み込み(2009/8/5)
					for(jj = 0 ; jj < Npos +1 ; jj++){
						for(k = 0 ; k < Nfreq ; k++){
							for(m = 0 ; m < Nmic ; m++){
								if(jj < Npos){
									pstmpW2->micary_smSeparation.micary_cmpaSeparation.ha_cmpValue[jj+m*(Npos+1)+k*Nmic*(Npos+1)].re 
										= pstmpW->micary_smSeparation.micary_cmpaSeparation.ha_cmpValue[jj+m*Npos+k*Nmic*Npos].re ;

		   							pstmpW2->micary_smSeparation.micary_cmpaSeparation.ha_cmpValue[jj+m*(Npos+1)+k*Nmic*(Npos+1)].im 
										= pstmpW->micary_smSeparation.micary_cmpaSeparation.ha_cmpValue[jj+m*Npos+k*Nmic*Npos].im ;
							
								}
								else{
									pstmpW2->micary_smSeparation.micary_cmpaSeparation.ha_cmpValue[jj+m*(Npos+1)+k*Nmic*(Npos+1)].re 
										= m_updateW->micary_dbSeparation.micary_smSeparation.micary_cmpaSeparation.ha_cmpValue[ii+m*Npos_all+k*Nmic*Npos_all].re ;

		   							pstmpW2->micary_smSeparation.micary_cmpaSeparation.ha_cmpValue[jj+m*(Npos+1)+k*Nmic*(Npos+1)].im 
										= m_updateW->micary_dbSeparation.micary_smSeparation.micary_cmpaSeparation.ha_cmpValue[ii+m*Npos_all+k*Nmic*Npos_all].im ;
								}
							}
						}
					}

					// Export File 
					if(m_iFormat_ExportW == __FILE_FORMAT_HARK){
				  		psH->lFs = (int)psPrmFrame->ha_fFs;
				  		psH->lNFFT = psPrmFrame->ha_numNFFT;

				 		// 2010.8.11
				  		psH->lNSrc = pstmpW2->micary_locaSource.ha_numLocation;
				  		psH->lNMic =  pstmpW2->micary_locaMic.ha_numLocation;
				  		psH->lNFreq = pstmpW2->micary_smSeparation.micary_iaFreqLinex.ha_numValue;
				  		psH->iVersion = 1;
				  		psH->iFileType = FORMAT_TYPE_W;
				  
				  		if(!cHark.WriteData(file.s,psH,
							pstmpW2->micary_smSeparation.micary_cmpaSeparation,
							pstmpW2->micary_smSeparation.micary_iaFreqLinex,
							pstmpW2->micary_locaSource,
							pstmpW2->micary_locaMic,
							"", "", "", "", "", "GHDSS_EXPORT")){

							if(psH){
						  		free(psH) ;
						  		psH = NULL ;
							}
							if(file.s){
						  		free(file.s) ;
						  		file.s = NULL ;
							}

							SMDatabaseFree(pstmpW) ;
							free(pstmpW) ;
							pstmpW = NULL ;
						
					        SMDatabaseFree(pstmpW2) ;
							free(pstmpW2) ;
							pstmpW2 = NULL ;
							cout << "Fail to Export file as HARK2 format." << endl ;
							return false ;
						}
			     	}

					SMDatabaseFree(pstmpW2) ;
					free(pstmpW2) ;
					pstmpW2 = NULL ;
				}

				//フラグの更新
				if(m_iUpdateMethodW == __UPDATE_METHOD_ID){
					m_updateW->micary_iaUpdate.ha_iValue[ii]=__INVALID_SRC_ID;
				}

				if(psH){
					free(psH) ;
					psH = NULL ;
				}
				if(file.s){
					free(file.s) ;
					file.s = NULL ;
				}

				SMDatabaseFree(pstmpW) ;
				free(pstmpW) ;
				pstmpW = NULL ;
		  	}
		}
#endif
	}
	return(OK);
}

///////////////////////////////////////////////////////////////
//	GHDSSメイン
int GHDSS_core
	(
	int	num_src,
	int	num_src_pre,
	HA_Complex		inputSpec[ARY_NUM_MIC][ARY_NUM_FFT],
	MICARY_Location	localSrcPos[ARY_NUM_SRC],
	HA_Complex		outputSpec[ARY_NUM_SRC][ARY_NUM_FFT]
	)
{
	FILE 	*fp;
	int		f,s,i;
	int		iFlagChange;

	if(num_src != 0){ //音源がないときは行わない
		// 2013.02.14 引数渡しの音源情報を広域変数にコピー
		for(s=0; s<num_src; s++){
			locaSrcPos[s] = localSrcPos[s];
		}
		for(s=0; s<num_src; s++){
			mat_id[s] = locaSrcPos[s].ha_idPos % 10;		// 音源IDとnum_srcの関連づけ
		}

		// 音源の検出処理
		for(i=0; i<10; i++){
			int	hit = 0;
			for(s=0; s<num_src; s++){
				if(mat_id[s] == i){ // ID発見
					hit = 1;
					switch(stat_id[i]){
					case SRC_NOT_EXIST: // 音源なし=>音源検出(W初期化)
						stat_id[i] = SRC_DETECTED; // ID変更
						break;
					case SRC_DETECTED: // 音源検出=>音源継続
						stat_id[i] = SRC_CONTINUE; // ID変更
						break;
					case SRC_CONTINUE: // 音源継続=>音源継続
						break;
					}
					break; // 検出済のため次のiへ
				}
			}
			if(hit == 0){ // 音源消滅
				stat_id[i] = SRC_NOT_EXIST;
			}
		}
		//for(s=0; s<num_src; s++){
		//	LOGI("s=%d : mat_id[s]=%d\n", s, mat_id[s]);
		//}
		//for(i=0; i<10; i++){
		//	LOGI("i=%d : stat_id[i]=%d\n", i, stat_id[i]);
		//}

		if(m_bFlgIni == TRUE){	// 最初の一回だけ
			////////////////////////////////////////////////////////////
			// 作業メモリ初期化
			// 作業メモリの初期化など。後で。

			// 2013.02.22 時間がかかるのでStartで実行
			//InitTFMatrix();		// 音源に近い伝達関数を求める
			InitSepMatrix(num_src);	// 伝達関数から分離行列の初期値を求める
			InitUpdateW();
			m_bFlgIni = FALSE ;
		}
		else{
		    // TF_CONJの更新・引継
		    //iFlagChange = ChangeSrcPos_TF_CONJ(locaSrcPos,m_psPrmFrame) ;
		    iFlagChange = ChangeSrcPos_TF_CONJ();

		    // Wの更新・引継
		    //iFlagChange = m_cGHDSSExec.ChangeSrcPos_W(locaSrcPos,m_psPrmFrame) ;
		    iFlagChange = ChangeSrcPos_W(num_src);
#ifdef NEVER
		    if(iFlagChange != 0){	//音源位置または数の変更
				m_cGHDSSExec.Initialize_GHDSS(iNRowCh,iNVecSrc,0,iNColFreq-1) ;	 //Rxx,Ryyの初期化
			}
#endif
		}

		// GHDSSの実行
		ExecuteGHDSS(num_src, inputSpec);

		//LOGI("%f\n", csaOutputSpec[0][256].re);
	
		// Set UpdateW matrix
		SetUpdateW();
	
		// export W
		AddUpdateW();	// <-  不要かも

		for(s=0; s<num_src; s++){
		    for(f=0; f<ARY_NUM_FFT; f ++){
				outputSpec[s][f].re = csaOutputSpec[s][f].re;
				outputSpec[s][f].im = csaOutputSpec[s][f].im;
				//if(f<10){
				//	LOGI("s=%d, f=%d : sep[s][f](%f, %f)\n", s, f, outputSpec[s][f].re, outputSpec[s][f].im);
				//}
		    }
			//LOGI("\n");
		}

		/*
		LOGI("GHDSS_out");
		for(s=0; s<num_src; s++){
			LOGI("Src No = %d", s);
			for(f=0; f<32; f++){
				LOGD("  [%d][%d] = %f %f", s,i, outputSpec[s][f].re, outputSpec[s][f].im);
			}
		}
		*/
	}
	return(OK);
}
#endif // BUILD_MODULE_GHDSS

// EOF
