//#include "BF.h"
//#include <stdio.h>
//#include <map>

/************************************************************
** BF.c
**
**  Private :
**
**  History :
**     2013.12.17 M.Takigahira 新規作成
**
**  Description
**  -----------
**  ビームフォーミング（共通）
**  入力1 ：マイク収録データ
**  出力1 ：分離データ
**
**      処理の内容//dummy
**
**      1) pha_fS		vector float[257]を３個。IDごとにコピー
**      2) pha_fS_sum	vector float[257]を１個分。pha_fSを周波数ごとに加算。
**      3) pha_fS_leak	vector float[257]を３個分。	pha_fS_sum - pha_fS
**      4) α、βの計算
**          beta = -alp_leak / (1 - alp_leak^2 + alp_leak*(1 - alp_leak)*(M - 2) );
**          alpha = 1 - (M - 1) * alp_leak * beta;
**      5) Zの計算
**          Z = alpha * S + beta * S_leak; <- Z = alpha * pha_fS + beta * pha_fS_leak
**          Z(Z < 1) = 1; % Clipping
**
*/

/* == source from pos2tf.m

function H = pos2tf(Micpos, Srcpos, f, c)
% H = pos2tf(Micpos, Srcpos, f[, c])
% Micpos: Mic position [m], array (3[x; y; z], NMic)
% Srcpos: Source position [m], array (3[x; y; z], NSource)
% f: Frequency vector [Hz], vector (NFreq, 1)
% c: Sound speed [m/s], scalar (default: 340)
% H: Transfer function (TF) matrix, 3D-array (NMic, NSource, NFreq)

if nargin < 4, c = 340; end

NMic = size(Micpos, 2);
NSrc = size(Srcpos, 2);
NFreq = size(f, 1);

Dist = zeros(NMic, NSrc);
for ns = 1:NSrc
    rpos = Micpos - repmat(Srcpos(:, ns), 1, NMic);
    Dist(:, ns) = sqrt(sum(rpos.^2)); % Distance [m]
end
Del = Dist/c; % Delay time [s]

H = zeros(NMic, NSrc, NFreq);
for nf = 1:NFreq
    H(:, :, nf) = 1./Dist.*exp(-i*2*pi*f(nf)*Del);
end

*/


///////////////////////////////////////////////////////////////
//  Include Files
//#include <string>
//#include <iostream>
//#include <cstdlib>
//#include <complex>
//#include <cmath>
//#include "ArrayInit.h"
//#include "MICARY_struct.h"
#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

////#include "BF_common.h"
#include "BF_extern.h"

// BF_common.h
#ifndef _HARK__BEAMFORMING__BF_H__INCLUDED_
#define _HARK__BEAMFORMING__BF_H__INCLUDED_ 1

//int getBfAlgorithmType();
//void updateSources(const std::vector<MicLocation> &micPositions, const std::vector<SourceLocation> &sourcePositions);
//void executeBeamForming(const Matrix &inputSpectrum, Matrix &outputSpectrum);
//void adaptSeparationMatrices();
//void calculateTransformFunctions(const std::vector<MicLocation> &micPositions, const std::vector<SourceLocation> &sourcePositions, std::vector<Matrix> &transformFunctions);
//void setTransformFunctionDatabase(const TransformFunctionDatabase &transformFunctionDatabase);

#endif //_HARK__BEAMFORMING__BF_H__INCLUDED_





//#include "BF_Matrix.h"
//<BF_Matrix.h> Location
/*
typedef struct{
    float x[3];
} BF_MicLocation;

typedef struct{
    float x[3];
    int   source_id;
    int   is_signal;
} BF_SourceLocation;
*/
void (*updateSources)(int num_src, BF_SourceLocation *);
void (*adaptSeparationMatrices)();



///////////////////////////////////////////////////////////////
//  Define Macros

#if !defined BUILD_MODULE_BF
///////////////////////////////////////////////////////////////
//  Dummy Functions for build empty methods.
void ClearBF(void){ }
void HAInitBF(void){ }
int HASetParamBF(Param_BF_t *param){ return 0; }
int BF(
    int num_src,
    int num_fft,
    HA_Float inputSpec[ARY_NUM_SRC][ARY_NUM_FFT],
    HA_Float outputSpec[ARY_NUM_SRC][ARY_NUM_FFT]
    ){ return 0; }
#else // #if defined BUILD_MODULE_BF
///////////////////////////////////////////////////////////////
//  Parameter
static Param_BF_t bf_param = {
    SEP_LCMV,               // int   bf_method;
    ARY_NUM_WAVE,           // int   length;
    _ADVANCE_VAL_,                // int   advance;
    DEFAULT_SAMPLING_RATE,  // int   sampling_rate;
    "/mnt/sdcard/hark/20130918_SHT_SmartRoom_norm.zip",              // char  tf_conj_filename[256];
    NLFUNC_TANH,            // int   nlfunc;
    SS_STEP_ADAPTIVE,       // int   ss_method;
    1.0f,                   // float ss_scal;
    0.001f,                 // float ss_myu;
    LC_STEP_ADAPTIVE,       // int   lc_method;
    0.001f,                 // float lc_myu;
    GEVD,                   // int   decomposition_algorithm; //GEVD(default), GSVD
    0.99f,                  // float alpha;
    0.0001f                 // int   reg_factor;
};

static const float BF_EPS = 1e-10;

int   length           = 512;     //周波数解析窓長 :: The frame length of each channel (in samples) [default: 512].
int   sampling_rate    = 16000;   //サンプリング周波数 :: Sampling rate (Hz) [default: 16000].
//float sound_speed      = 343.0f;  //音速値 :: Speed of sound(m/s) [default: 343.0].

//GSS GICA GHDSSのみ
int   nl_func         = 0;       //ICA, HDSS で用いる非線形関数の種類
float ss_scale        = 1.0f;    //高次相関行列計算におけるスケールファクタ :: Scaling factor of the nonlinear function for SS step size. [default: 1.0]
int   ss_myu_adaptive = 1;       //高次相関行列 ADAPTIVE? :: The calculation method for SS step size parameter corresponding to the blind separation part. "FIX" uses a fixed step size,"LC_MYU" uses the same value as LC_MYU, and "ADAPTIVE" adaptively estimates an optimal step size. [default: ADAPTIVE]
float ss_myu          = 0.001f;  //高次相関行列による分離行列更新時のステップサイズ :: SS step size value if LC_METHOD=FIX. SS adaptive step size scaler if SS_METHOD=ADAPTIVE. [default 0.001]

//LCMV GJ GSS GICA GHDSSのみ
int   lc_myu_adaptive = 1;       //幾何制約 ADAPTIVE? :: The calculation method for LC step size corresponding to geometric constraints. "FIX" uses a fixed value, and "Adaptive" adaptively estimates an optimal step size. [default: ADAPTIVE]
float lc_myu          = 0.001f;  //幾何制約による分離行列更新時のステップサイズ :: LC step size value if LC_METHOD=FIX. LC adaptive step size scaler if LC_METHOD=ADAPTIVE. [default 0.001]

//MSNRのみ
float alpha           = 0.99f;   //MSNR で用いる alpha 値 :: [NEW] ALPHA parameter used in MNSR as step size parameter.

//MLのみ
//int   period          = 50;      //ML で用いる period 値 :: The period in which the source localization is processed if BF_METHOD=ML.
float reg_factor      = 0.0001f; //ML で用いる RegFactor 値 :: Reg Factor value if BF_METHOD=ML. [default 1.0e-4]

int   enable_debug    = 0;       //デバッグ出力用フラグ :: enable debug print

//int   use_init_w      = 0;       //分離行列初期値使用有無
//char  init_w_filename[257];      //分離行列初期値ファイル :: Filename of an initial separation matrix. If specified, a matrix in INITW_FILENAME is used as an initial separation matrix. Otherwise, initial separation matrix is estimated from the geometrical relationship or pre-measured TF according to TF_CONJ.
//int   use_export_w    = 0;       //分離行列をファイルへ書き込むか？ :: Separation matrix W is exported if true. [default: false]
//char  export_w_filename[257];    //分離行列をファイルへ書き込む場合はそのファイル名 :: The filename to export W.



///////////////////////////////////////////////////////////////
//  Local Buffer
/*== コンストラクタで初期化するのみ ==*/
//TransformFunctionDatabase  *transformFunctionDatabase;
//<BF_Matrix.h> TransformFunctionDatabase クラス :: 伝達関数ファイル用領域
BF_SourceLocation  sourceLocationsDB[ARY_NUM_TF_POS];
BF_MicLocation     micLocationsDB[ARY_NUM_MIC];
HA_Complex         transformFunctionsDB[ARY_NUM_FFT][ARY_NUM_TF_POS][ARY_NUM_MIC]; /* size_is(numFreq), elemnent_is(Matrix(numMic, numSrc)) */ //順序交換済
int                neighborsInformations[ARY_NUM_TF_POS][ARY_NUM_TF_POS+1]; // neighborsInformations[ids][neighbors] : -1で終端

int num_tf_pos;    // TransferFunctionDB :: number of source positions
int num_mic_pos;   // TransferFunctionDB :: number of microphone positions
int num_freq;      // TransferFunctionDB :: number of fft length
int new_tf_format; // TransferFunctionDB :: libharkio3 format is included neighbors informations, if true, you can use new neighbors search algorithm

/*== コンストラクタで初期化するのみ ==*/
//int   sampling_rate;
//float sound_speed;

/*== 動的に変動 ==*/
/* updateSources で更新 */
BF_SourceLocation  sourcePositions[ARY_NUM_SRC];
BF_MicLocation     micPositions[ARY_NUM_MIC];
HA_Complex         transformFunctions[ARY_NUM_FFT][ARY_NUM_SRC][ARY_NUM_MIC]; /* size_is(numFreq), element_is(Matrix(numMic, numSrc)) */
int                srcMap[ARY_NUM_SRC];
int                num_pre_src;

/* executeBeamForming で更新 */
HA_Complex         covarianceMatrices[ARY_NUM_FFT][ARY_NUM_MIC][ARY_NUM_MIC];  /* size_is(numFreq), element_is(Matrix(numMic, numMic)) */

/* updateSources, adaptSeparationMatrices で更新 */
HA_Complex         separationMatrices[ARY_NUM_FFT][ARY_NUM_SRC][ARY_NUM_MIC]; /* size_is(numFreq), element_is(Matrix(numSrc, numMic)) */

/* executeBeamForming で更新 */
//HA_Complex         inputSpectrum[ARY_NUM_MIC][ARY_NUM_FFT];      /* size_is(numMic, numFreq) */
//HA_Complex         outputSpectrum[ARY_NUM_SRC][ARY_NUM_FFT];     /* size_is(numSrc, numFreq) */

// Fixed (DS, WDS, Null, ILSE)
// Fixed (DS, WDS, Null, ILSE)

// GSS (GHDSS, GICA)
//int nlFuncType;
//float mu, mu_ss, scale;
//int muAdp, mu_ssAdp; //bool
// GSS (GHDSS, GICA)

// GJ
HA_Complex Wc[ARY_NUM_FFT][ARY_NUM_SRC][ARY_NUM_MIC]; /* sizs_is(numFreq), element_is(Matrix(numSrc, numMic)) */
HA_Complex Ws[ARY_NUM_FFT][ARY_NUM_SRC][ARY_NUM_MIC-1][ARY_NUM_MIC]; /* sizs_is(numSrc * numFreq), element_is(Matrix(numMic-1, numMic)) */
HA_Complex Al[ARY_NUM_FFT][ARY_NUM_SRC][ARY_NUM_MIC-1]; /* sizs_is(numFreq), element_is(Matrix(numSrc, numMic-1)) */
//float mu;
//int muAdp; //bool
// GJ

// LCMV
HA_Complex F[ARY_NUM_FFT][ARY_NUM_SRC][ARY_NUM_MIC]; /* sizs_is(numFreq), element_is(Matrix(numSrc, numMic)) */
HA_Complex P[ARY_NUM_FFT][ARY_NUM_SRC][ARY_NUM_MIC][ARY_NUM_MIC]; /* sizs_is(numSrc * numFreq), element_is(Matrix(numMic, numMic)) */
//float mu;
//int muAdp; //bool
// LCMV

// ML
//float regFactor;
// ML

// MSNR
HA_Complex Rss[ARY_NUM_FFT][ARY_NUM_SRC][ARY_NUM_MIC][ARY_NUM_MIC]; /* sizs_is(numSrc * numFreq), element_is(Matrix(numMic, numMic)) */
HA_Complex Rnn[ARY_NUM_FFT][ARY_NUM_SRC][ARY_NUM_MIC][ARY_NUM_MIC]; /* sizs_is(numSrc * numFreq), element_is(Matrix(numMic, numMic)) */
//float alpha;
// MSNR

void calculateTransformFunctions(int num_src);

#define BUILD_MODULE_LCMV
#undef BUILD_MODULE_GJ
#undef BUILD_MODULE_MSNR
#undef BUILD_MODULE_GSS
#undef BUILD_MODULE_GICA
#undef BUILD_MODULE_GHDSS
#undef BUILD_MODULE_DS
#undef BUILD_MODULE_WDS
#undef BUILD_MODULE_NULL
#undef BUILD_MODULE_ILSE
#undef BUILD_MODULE_ML

#ifdef BUILD_MODULE_LCMV
#include "BF_LCMV.c"
#else
void LCMVupdateSources(int num_src, BF_SourceLocation currentSourcePositions[ARY_NUM_SRC]){  }
void LCMVadaptSeparationMatrices(int num_src){  }
#endif
#ifdef BUILD_MODULE_GJ
#include "BF_GJ.c"
#else
void GJupdateSources(int num_src, BF_SourceLocation currentSourcePositions[ARY_NUM_SRC]){  }
void GJadaptSeparationMatrices(int num_src){  }
#endif
#ifdef BUILD_MODULE_MSNR
#include "BF_MSNR.c"
#else
void MSNRupdateSources(int num_src, BF_SourceLocation currentSourcePositions[ARY_NUM_SRC]){  }
void MSNRadaptSeparationMatrices(int num_src){  }
#endif
#ifdef BUILD_MODULE_GSS
#include "BF_GSS.c"
#else
void GSSupdateSources(int num_src, BF_SourceLocation currentSourcePositions[ARY_NUM_SRC]){  }
void GSSadaptSeparationMatrices(int num_src){  }
#endif
#ifdef BUILD_MODULE_GICA
#include "BF_GICA.c"
#else
void GICAupdateSources(int num_src, BF_SourceLocation currentSourcePositions[ARY_NUM_SRC]){  }
void GICAadaptSeparationMatrices(int num_src){  }
#endif
#ifdef BUILD_MODULE_GHDSS
#include "BF_GHDSS.c"
#else
void GHDSSupdateSources(int num_src, BF_SourceLocation currentSourcePositions[ARY_NUM_SRC]){  }
void GHDSSadaptSeparationMatrices(int num_src){  }
#endif
#ifdef BUILD_MODULE_DS
#include "BF_DS.c"
#else
void DSupdateSources(int num_src, BF_SourceLocation currentSourcePositions[ARY_NUM_SRC]){  }
void DSadaptSeparationMatrices(int num_src){  }
#endif
#ifdef BUILD_MODULE_WDS
#include "BF_WDS.c"
#else
void WDSupdateSources(int num_src, BF_SourceLocation currentSourcePositions[ARY_NUM_SRC]){  }
void WDSadaptSeparationMatrices(int num_src){  }
#endif
#ifdef BUILD_MODULE_NULL
#include "BF_NULL.c"
#else
void NULLupdateSources(int num_src, BF_SourceLocation currentSourcePositions[ARY_NUM_SRC]){  }
void NULLadaptSeparationMatrices(int num_src){  }
#endif
#ifdef BUILD_MODULE_ILSE
#include "BF_ILSE.c"
#else
void ILSEupdateSources(int num_src, BF_SourceLocation currentSourcePositions[ARY_NUM_SRC]){  }
void ILSEadaptSeparationMatrices(int num_src){  }
#endif
#ifdef BUILD_MODULE_ML
#include "BF_ML.c"
#else
void MLupdateSources(int num_src, BF_SourceLocation currentSourcePositions[ARY_NUM_SRC]){  }
void MLadaptSeparationMatrices(int num_src){  }
#endif


///////////////////////////////////////////////////////////////
//  Clear
/******************************************************************************
**  History :
**    2013.12.17 M.Takigahira 新規作成
*/
// Public : バッファクリア
void ClearBF(void)
{
    //common
    bzero(sourceLocationsDB, sizeof(sourceLocationsDB));       // 伝達関数の音源配置
    bzero(micLocationsDB, sizeof(micLocationsDB));             // 伝達関数のマイク配置
    bzero(transformFunctionsDB, sizeof(transformFunctionsDB)); // 伝達関数
    bzero(sourcePositions, sizeof(sourcePositions));           // 直近フレームの音源位置バックアップ
    bzero(micPositions, sizeof(micPositions));                 // 直近フレームのマイク位置バックアップ（使っていない）
    bzero(transformFunctions, sizeof(transformFunctions));
    bzero(covarianceMatrices, sizeof(covarianceMatrices));
    bzero(separationMatrices, sizeof(separationMatrices));
    //GJ
    bzero(Wc, sizeof(Wc));
    bzero(Ws, sizeof(Ws));
    bzero(Al, sizeof(Al));
    //LCMV
    bzero(F, sizeof(F));
    bzero(P, sizeof(P));
    //MSNR
    bzero(Rss, sizeof(Rss));
    bzero(Rnn, sizeof(Rnn));
    //
    int i;
    for(i=0; i<ARY_NUM_SRC; i++){ sourcePositions[i].source_id = -1; } // ID==0時updateSourcesでID変化無し誤判別対策
}

///////////////////////////////////////////////////////////////
//  Initialize
/******************************************************************************
**  History :
**    2013.12.17 M.Takigahira 新規作成
*/
// Public : 初期化
void setTransformFunctionDatabase(char *tf_filepath, int undo_conj)
{

    int ct, f, m;

    LOGD("setTransformFunctionDatabase(\"%s\") <InitTFMatrix>", tf_filepath);
#ifdef ENABLE_HARKIO3
    LOGD("INFO : libharkio3 enabled");
    int s;
    float coord_tmp[3]; //if pos->sys is Polar
    harkio_TransferFunction *tfp = harkio_TransferFunction_fromFile(tf_filepath, NULL);
    num_tf_pos  = tfp->poses->size;
    num_mic_pos = tfp->mics->size;
    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++){
            sourceLocationsDB[s].x[0] = tfp->poses->pos[s]->coord[0];
            sourceLocationsDB[s].x[1] = tfp->poses->pos[s]->coord[1];
            sourceLocationsDB[s].x[2] = 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);
            sourceLocationsDB[s].x[0] = coord_tmp[0];
            sourceLocationsDB[s].x[1] = coord_tmp[1];
            sourceLocationsDB[s].x[2] = 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_pos; m++){
            micLocationsDB[m].x[0] = tfp->mics->pos[m]->coord[0];
            micLocationsDB[m].x[1] = tfp->mics->pos[m]->coord[1];
            micLocationsDB[m].x[2] = 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_pos; m++){
            harkio_Position_Convert(tfp->mics->pos[m], coord_tmp, Cartesian);
            micLocationsDB[m].x[0] = coord_tmp[0];
            micLocationsDB[m].x[1] = coord_tmp[1];
            micLocationsDB[m].x[2] = coord_tmp[2];
            //LOGI("MIC : micLocations[%d] = (%.6f, %.6f, %.6f) ", m, micLocations[m].x[0], micLocations[m].x[1], micLocations[m].x[2]);
        }
    }
    ct=0;
    if(undo_conj){
        for(s=0; s<num_tf_pos; s++){
            if(tfp->septfs[s]->rows == num_mic_pos && tfp->septfs[s]->cols == num_freq){
                for(m=0; m<num_mic_pos; m++){
                    for(f=0; f<num_freq; f++){
                        transformFunctionsDB[f][s][m].re =  crealf(tfp->septfs[s]->data.complexdata[num_freq * m + f]);
                        transformFunctionsDB[f][s][m].im = -cimagf(tfp->septfs[s]->data.complexdata[num_freq * m + f]);
                    }
                }
            }
        }
    }
    else{
        for(s=0; s<num_tf_pos; s++){
            if(tfp->septfs[s]->rows == num_mic_pos && tfp->septfs[s]->cols == num_freq){
                for(m=0; m<num_mic_pos; m++){
                    for(f=0; f<num_freq; f++){
                        transformFunctionsDB[f][s][m].re = crealf(tfp->septfs[s]->data.complexdata[num_freq * m + f]);
                        transformFunctionsDB[f][s][m].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
    static const int true = 1;
    LOGD("INFO : libharkio3 disabled");
    FILE  *fp;
    int   d, i, j, k;
    float fx, fy, fz;    // MicCoordinates
    float re, im;
    char  s[8]; //SPECチャンクは読まないので最大4 Byteだが、printf用の\0を書きたいので8 Byte（アライメント対策を含む）とする
    int ss;
    short major, minor;

    if(NULL == (fp = fopen(tf_filepath, "rb"))){ LOGE("ERROR : SEP_TF file open. %s\n", tf_filepath); return; }
    /////////////////////////////////
    // データ読み出し

    // 識別子 HARK
    fread(s,4,1,fp); //s[4] = 0; LOGI("%s", s); // s[0-4]="HARK\0"
    // サイズフォームタイプ以降のサイズ
    fread(&d,4,1,fp); //LOGI("size=%d, 0x%08x", d, d);
    // フォームタイプ HGTF
    fread(s,4,1,fp); //s[4] = 0; LOGI("%s", s); // s[0-4]="HGTF\0"

    // フォーマットサブチャンク fmt
    fread(s,4,1,fp); //LOGI("%s", s); // s[0-3]="fmt\0"
    // チャンクサイズサイズ 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(&num_mic_pos,4,1,fp); //LOGI("microphone=%d", num_mic);
    // 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(m=0; m<num_mic_pos; m++){
        fread(&fx,4,1,fp);
        fread(&fy,4,1,fp);
        fread(&fz,4,1,fp);
        micLocationsDB[m].x[0] = fx;
        micLocationsDB[m].x[1] = fy;
        micLocationsDB[m].x[2] = fz;
        //LOGI("MIC : micLocations[%d] = (%.6f, %.6f, %.6f) ", m, micLocations[m].x[0], micLocations[m].x[1], micLocations[m].x[2]);
    }

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

    // GTFサブチャンク GTF
    fread(s,4,1,fp); //LOGI("%s", s); // s[0-3]="GTF\0"
    // チャンクのサイズ
    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(sourceLocationsDB) < num_tf_pos){ LOGE("num_tf_pos = %d ? check your .dat file!!!", num_tf_pos); fclose(fp); return; }
    for(ss=0; ss<num_tf_pos; ss++){
        fread(&fx, 4,1,fp);
        fread(&fy, 4,1,fp);
        fread(&fz, 4,1,fp);
        sourceLocationsDB[ss].x[0]      = fx;
        sourceLocationsDB[ss].x[1]      = fy;
        sourceLocationsDB[ss].x[2]      = fz;
        sourceLocationsDB[ss].source_id = 0;
        sourceLocationsDB[ss].is_signal = true;
        //LOGI("POS : sourceLocations[%d] = (%.6f, %.6f, %.6f) ", s, sourceLocations[s].x[0], sourceLocations[s].x[1], sourceLocations[s].x[2]);
    }
    // 周波数ライン数
    fread(&num_freq,4,1,fp); //LOGI("Frequency length=%d", num_freq);
    // インデックスから周波数ビンへのマップ
    for(f=0; f<num_freq; f++){
        fread(&d,4,1,fp); //LOGI("f=%d : Nf=%d", f, d);
    }

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

    //fseek(fp,0x804,0); // 周波数ラインの先頭にポインタを移動する（固定長ではないので誤りのためコメントアウトをはずさない事）
    int re_d, im_d;
    if(undo_conj){
        for(ss=0; ss<num_tf_pos; ss++){
            for(m=0; m<num_mic_pos; m++){
                for(f=0; f<num_freq; f++){
                    re_d = fread(&re, 4,1,fp);
                    im_d = fread(&im, 4,1,fp);
                    transformFunctionsDB[f][ss][m].re =  re; //注意：GHDSSでは piaFreqLine[f][m][s].re = re; で順序が異なる（計算時の高速化のために変更）
                    transformFunctionsDB[f][ss][m].im = -im; //注意：GHDSSでは piaFreqLine[f][m][s].im = im; で順序が異なる（計算時の高速化のために変更）
                    //LOGI("[%d][%d][%d] %d %d : TF : (%.6f, %.6f)\n", f, s, m, re_d, im_d, transformFunctions[f][s][m].re, transformFunctions[f][s][m].im);
                }
            }
        }
    }
    else{
        for(ss=0; ss<num_tf_pos; ss++){
            for(m=0; m<num_mic_pos; m++){
                for(f=0; f<num_freq; f++){
                    re_d = fread(&re, 4,1,fp);
                    im_d = fread(&im, 4,1,fp);
                    transformFunctionsDB[f][ss][m].re = re; //注意：GHDSSでは piaFreqLine[f][m][s].re = re; で順序が異なる（計算時の高速化のために変更）
                    transformFunctionsDB[f][ss][m].im = im; //注意：GHDSSでは piaFreqLine[f][m][s].im = im; で順序が異なる（計算時の高速化のために変更）
                    //LOGI("[%d][%d][%d] %d %d : TF : (%.6f, %.6f)\n", f, s, m, re_d, im_d, transformFunctions[f][s][m].re, transformFunctions[f][s][m].im);
                }
            }
        }
    }

    fclose(fp);
    new_tf_format = 0;
#endif // ENABLE_HARKIO3
}

void HAInitBF(void)
{
    /*== パラメータの取得と検証 ==*/
    char *tf_file_name; // 伝達関数をファイルから読み込んで使用する場合のファイル名 :: Filename of a pre-measured transfer function for separation.
    length        = bf_param.length;
    num_freq      = bf_param.length / 2 + 1;   // 周波数解析窓長パラメータ値の初期化（実際には読み込まれた伝達関数の値で上書きされる）
    sampling_rate = bf_param.sampling_rate;    // サンプリング周波数パラメータ
    tf_file_name  = bf_param.tf_conj_filename; // 伝達関数の定義ファイル名
    //sound_speed   = bf_param.speed_of_sound;   // 音速値の取得 (obsolete)

    // ビームフォーミング手法の選択
    switch(bf_param.bf_method){
    case SEP_LCMV:  updateSources = LCMVupdateSources;  adaptSeparationMatrices = LCMVadaptSeparationMatrices;  /*BF::BfLCMV; */ break;
    case SEP_GJ:    updateSources = GJupdateSources;    adaptSeparationMatrices = GJadaptSeparationMatrices;    /*BF::BfGJ;   */ break;
    case SEP_MSNR:  updateSources = MSNRupdateSources;  adaptSeparationMatrices = MSNRadaptSeparationMatrices;  /*BF::BfMSNR; */ break;
    case SEP_GSS:   updateSources = GSSupdateSources;   adaptSeparationMatrices = GSSadaptSeparationMatrices;   /*BF::BfGSS;  */ break;
    case SEP_GICA:  updateSources = GICAupdateSources;  adaptSeparationMatrices = GICAadaptSeparationMatrices;  /*BF::BfGICA; */ break;
    case SEP_GHDSS: updateSources = GHDSSupdateSources; adaptSeparationMatrices = GHDSSadaptSeparationMatrices; /*BF::BfGHDSS;*/ break;
    case SEP_DS:    updateSources = DSupdateSources;    adaptSeparationMatrices = DSadaptSeparationMatrices;    /*BF::BfDS;   */ break;
    case SEP_WDS:   updateSources = WDSupdateSources;   adaptSeparationMatrices = WDSadaptSeparationMatrices;   /*BF::BfWDS;  */ break;
    case SEP_NULL:  updateSources = NULLupdateSources;  adaptSeparationMatrices = NULLadaptSeparationMatrices;  /*BF::BfNull; */ break;
    case SEP_ILSE:  updateSources = ILSEupdateSources;  adaptSeparationMatrices = ILSEadaptSeparationMatrices;  /*BF::BfILSE; */ break;
    case SEP_ML:    updateSources = MLupdateSources;    adaptSeparationMatrices = MLadaptSeparationMatrices;    /*BF::BfML;   */ break;
    default: LOGE("Unexpected bf_method of BeamForming is set."); break;
    }

    switch(bf_param.bf_method){
    case SEP_LCMV:
    case SEP_GJ:
        lc_myu = bf_param.lc_myu; // 幾何制約による分離行列更新時のステップサイズ
        switch(bf_param.lc_method){
        case LC_STEP_ADAPTIVE: lc_myu_adaptive = 1; break;
        case LC_STEP_FIX:      lc_myu_adaptive = 0; break;
        default:                                    break;
        }
        break;
    case SEP_MSNR:
        alpha = bf_param.alpha;
        break;
    case SEP_GSS:
    case SEP_GICA:
    case SEP_GHDSS:
        lc_myu = bf_param.lc_myu; // 幾何制約による分離行列更新時のステップサイズ
        switch(bf_param.lc_method){
        case LC_STEP_ADAPTIVE: lc_myu_adaptive = 1; break;
        case LC_STEP_FIX:      lc_myu_adaptive = 0; break;
        default:                                    break;
        }
        ss_myu = bf_param.ss_myu; // 高次相関行列による分離行列更新時のステップサイズ
        switch(bf_param.ss_method){
        case SS_STEP_ADAPTIVE: ss_myu_adaptive = 1;                  break;
        case SS_STEP_FIX:      ss_myu_adaptive = 0;                  break;
        case SS_STEP_LC_MYU:   ss_myu_adaptive = 0; ss_myu = lc_myu; break;
        default:                                                     break;
        }
        ss_scale   = bf_param.ss_scal; // 高次相関行列計算におけるスケールファクタ
        nl_func    = bf_param.nl_func;  // ICA, HDSS で用いる非線形関数の種類
        break;
    case SEP_DS:
    case SEP_WDS:
    case SEP_NULL:
    case SEP_ILSE:
        break;
    case SEP_ML:
        //period     = bf_param.period;     // period 値 (obsolete)
        reg_factor = bf_param.reg_factor; // RegFactor 値
        break;
    default:
        LOGE("Unexpected bf_method of BeamForming is set.");
        break;
    }

    /* 伝達関数データベース構築 */ // transformFunctionDB 配列が相当
    // HARK 形式のデータベース読み込み データベース形式を変換
    setTransformFunctionDatabase(tf_file_name, 1); // GHDSSのInitTFMatrixに相当 , 第二引数が1はTFの共役を戻して読む設定
    //以下の対応は第二引数を1とすることで処理済
    // 2012/05/24 added by N.Tanaka H=conj(TFCONJ)
    //tf.setElementAt(j, k, v.re, v.im);   ===>   tf.setElementAt(j, k, v.re, -v.im);

    int m;
    for(m=0; m<num_mic_pos; m++){ micPositions[m] = micLocationsDB[m]; } // CALCモードが無いので伝達関数定義ファイルからの単なるコピー

    // 分離行列初期値（指定されなかった場合はTF_CONJと同じ値となる）
    //ex)
    //use_init_w = 1; init_w_filename = bf_param.init_w_filename; //INITW_FILENAME
    //use_init_w = 0; init_w_filename = "";

    //if(use_init_w == 0){ importSeparationMatrices(init_w_filename); } // 分離行列初期値の初期化

    //use_export_w = false; // = true; export_w_filename = "export.w"; // 分離行列のエクスポート機能
    //enable_debug = false; // = true; // デバッグ出力用フラグ
}

///////////////////////////////////////////////////////////////
//  SetParam
/******************************************************************************
**  History :
**    2013.12.17 M.Takigahira 新規作成
*/
// Public : パラメータ設定 初期化の前に実行すること
int HASetParamBF(Param_BF_t *param)
{
    int ret_code = 0;
    switch(param->bf_method){
    case SEP_LCMV:
    case SEP_GJ:
    case SEP_MSNR:
    case SEP_GSS:
    case SEP_GICA:
    case SEP_DS:
    case SEP_WDS:
    case SEP_NULL:
    case SEP_ILSE:
    case SEP_ML:
        break;
    case SEP_NONE:
    case SEP_GHDSS:
    default:
        LOGE("Param_BF_t param->bf_method is invalid value. Unknown beamforming method or none.");
        ret_code = -1;
        break;
    }
    if((param->length <= 0) || (param->length > ARY_NUM_WAVE)){
        LOGE("Param_BF_t param->length is invalid value.");
        ret_code = -1;
    }
    if(param->sampling_rate <= 0){
        LOGE("Param_BF_t param->sampling_rate is invalid value.");
        ret_code = -1;
    }
    switch(param->nl_func){
    case NLFUNC_TANH:
        break;
    case NLFUNC_DUMMY:
    case NLFUNC_CUBE:
    default:
        LOGE("Param_BF_t param->nl_func is invalid value. Unkown nl_func, only support tanh now.");
        ret_code = -1;
        break;
    }
    switch(param->ss_method){
    case SS_STEP_ADAPTIVE:
    case SS_STEP_FIX:
    case SS_STEP_LC_MYU:
        break;
    default:
        LOGE("Param_BF_t param->ss_method is invalid value. Only support ADAPTIVE/FIX/LC_MYU.");
        ret_code = -1;
        break;
    }
    switch(param->lc_method){
    case LC_STEP_ADAPTIVE:
    case LC_STEP_FIX:
        break;
    default:
        LOGE("Param_BF_t param->lc_method is invalid value. Only support ADAPTIVE/FIX.");
        ret_code = -1;
        break;
    }
    switch(param->decomposition_algorithm){
    case GEVD:
    case GSVD:
        break;
    case SEVD:
    default:
        LOGE("Param_BF_t param->decomposition_algorithm is invalid value. Only support GEVD/GSVD.");
        ret_code = -1;
        break;
    }
//    if(ret_code == 0){ bf_param = *param; }
    { bf_param = *param; }
    return ret_code;
}

int HAGetParamBF(Param_BF_t *param)
{
    *param = bf_param;
    return 0;
}




///////////////////////////////////////////////////////////////
//  MAIN

// [INFO]
//int num_tf_pos;    // 伝達関数の音源数
//int num_mic_pos;   // 伝達関数のマイク数
//int num_freq;      // 伝達関数の周波数ライン数（FFT長/2+1）
//int num_src;       // 検出音源数（入力）
//int num_mic;       // 収録マイク数（伝達関数と一致しているはずなのでnum_mic_posを使う）
//int num_fft;       // 入力データのFFT長（重ね合わせ分は除外しているのでnum_freqを使う）
//マイク位置は伝達関数と同じ（動的に変わらない）つまり実際にはNumMicが欲しいだけ、音源位置も伝達関数もGlobal変数なので引数はいらない
void calculateTransformFunctions(int num_src)
{
    int f, s, m, sd; // f:freq, s:source, m:mic, sd:source_of_DB
    float mind, d;
    //伝達関数が2個以上あれば入力音源が伝達関数のどの音源方向に対応するか対応付ける、1個以下は常に最初の伝達関数を参照する
    if(num_tf_pos > 1){
        for(s=0; s<num_src; s++){
            srcMap[s] = 0;
            mind = (sourceLocationsDB[0].x[0] - sourcePositions[s].x[0]) * (sourceLocationsDB[0].x[0] - sourcePositions[s].x[0])
                 + (sourceLocationsDB[0].x[1] - sourcePositions[s].x[1]) * (sourceLocationsDB[0].x[1] - sourcePositions[s].x[1])
                 + (sourceLocationsDB[0].x[2] - sourcePositions[s].x[2]) * (sourceLocationsDB[0].x[2] - sourcePositions[s].x[2]);
            for(sd=1; sd<num_tf_pos; sd++){
                d = (sourceLocationsDB[sd].x[0] - sourcePositions[s].x[0]) * (sourceLocationsDB[sd].x[0] - sourcePositions[s].x[0])
                  + (sourceLocationsDB[sd].x[1] - sourcePositions[s].x[1]) * (sourceLocationsDB[sd].x[1] - sourcePositions[s].x[1])
                  + (sourceLocationsDB[sd].x[2] - sourcePositions[s].x[2]) * (sourceLocationsDB[sd].x[2] - sourcePositions[s].x[2]);
                if(d<mind){
                    mind = d; // 近傍度合い（距離計算のsqrtfを外しただけ）の最小値
                    srcMap[s] = sd; // sd : 最近傍の伝達関数インデックス
                }
            }
        }
    }
    else{
        for(s=0; s<num_src; s++){
            srcMap[s] = 0;
        }
    }
    // 演算用伝達関数の準備（メモリ領域を連続化し、高速化するためだけに行う：実際にはsrcMapだけあれば良い）
    for(f=0; f<num_freq; f++){
        for(s=0; s<num_src; s++){
            sd = srcMap[s]; // srcMap[s] : 音源sに対応する伝達関数インデックス
            for(m=0; m<num_mic_pos; m++){
                transformFunctions[f][s][m].re = transformFunctionsDB[f][sd][m].re;
                transformFunctions[f][s][m].im = transformFunctionsDB[f][sd][m].im;
            }
        }
    }
}

//GHDSS_core の場合 :: Line:1982-2013 に相当
void executeBeamForming(int num_src, HA_Complex inputSpectrum[ARY_NUM_MIC][ARY_NUM_FFT], HA_Complex outputSpectrum[ARY_NUM_SRC][ARY_NUM_FFT])
{
    int f, s, m;
    for(f=0; f<num_freq; f++){
        for(s=0; s<num_src; s++){
            outputSpectrum[s][f].re = 0.0f;
            outputSpectrum[s][f].im = 0.0f;
            for(m=0; m<num_mic_pos; m++){
                outputSpectrum[s][f].re += separationMatrices[f][s][m].re * inputSpectrum[m][f].re - separationMatrices[f][s][m].im * inputSpectrum[m][f].im;
                outputSpectrum[s][f].im += separationMatrices[f][s][m].re * inputSpectrum[m][f].im + separationMatrices[f][s][m].im * inputSpectrum[m][f].re;
            }
        }
    }
    //LOGD("inputSpectrum[m][f] : "); for(m=0; m<num_mic; m++){ for(f=0; f<num_freq; f++){ LOGD("(%.6f, %.6f) ", inputSpectrum[m][f].re, inputSpectrum[m][f].im); } }
    //LOGD("separationMatrices[f][s][m] : "); for(f=0; f<num_freq; f++){ for(s=0; s<num_src; s++){ for(m=0; m<num_mic_pos; m++){ LOGD("(%.6f, %.6f) ", separationMatrices[f][s][m].re, separationMatrices[f][s][m].im); } } }
    //LOGD("outputSpectrum[s][f] : "); for(s=0; s<num_src; s++){ for(f=0; f<num_freq; f++){ LOGD("(%.6f, %.6f) ", outputSpectrum[s][f].re, outputSpectrum[s][f].im); } }
}

//////////////////////////////////////// from Beamforming.cc ////////////////////////////////////////

// ExportWは実装しない
/*
void exportSeparationMatrices(const char *w_filepath, int num_src)
{
#ifdef ENABLE_HARKIO3
    int f, s, m;
    float coord[3];
    harkio_Position *pos;
    harkio_Positions *mics = harkio_Positions_new("microphone", 0, 0, NULL);
    harkio_Positions *sources = harkio_Positions_new("soundsource", 0, 0, NULL);
    harkio_Matrix *sm = harkio_Matrix_new("COMPLEX", );
    for(m = 0; m < num_mic_pos; m++){
        coord[0] = micPositions[m].x[0];
        coord[1] = micPositions[m].x[1];
        coord[2] = micPositions[m].x[2];
        pos = harkio_Position_new(m, Cartesian, coord, "sep_w");
        harkio_Positions_append(mics, pos);
        harkio_Position_delete(&pos);
    }
    for(s = 0; s < num_src; s++){
        coord[0] = sourcePositions[i].x[0];
        coord[1] = sourcePositions[i].x[1];
        coord[2] = sourcePositions[i].x[2];
        pos = harkio_Position_new(sourcePositions[i].source_id, Cartesian, coord, "sep_w");
        harkio_Positions_append(sources, pos);
        harkio_Position_delete(&pos);
    }
    for(f = 0 ; f < num_freq; f++){
        smDatabase.micary_smSeparation.micary_iaFreqLinex.ha_iValue[f] = (float)samplingRate * (f * 2 + 1) / 4 / num_freq;
    }
    int c = 0;
    for(f = 0 ; f < num_freq; f++){
        for(s = 0 ; s < num_src; s++){
            for(m = 0 ; m < num_mic; m++){
                smDatabase.micary_smSeparation.micary_cmpaSeparation.ha_cmpValue[c].re = separationMatrices[f][s][m].re;
                smDatabase.micary_smSeparation.micary_cmpaSeparation.ha_cmpValue[c].im = separationMatrices[f][s][m].im;
                c++;
            }
        }
    }
    harkio_Positions_delete(&sources);
    harkio_Positions_delete(&mics);
#else // ENABLE_HARKIO3
#endif // ENABLE_HARKIO3
    
    MICARY_SMDatabase smDatabase = {0};

    SMDatabaseAlloc(&smDatabase, 0, 0, 0);
    SMDatabaseAlloc(&smDatabase, numFreq, numSrc, numMic);

    for(int i = 0; i < num_mic; i++){
        const BF::MicLocation &ml = micPositions[i];
        smDatabase.micary_locaMic.ha_idLocation[i] = i;
        smDatabase.micary_locaMic.micary_Location[i].ha_fX = micPositions[i].x[0];
        smDatabase.micary_locaMic.micary_Location[i].ha_fY = micPositions[i].x[1];
        smDatabase.micary_locaMic.micary_Location[i].ha_fZ = micPositions[i].x[2];
        smDatabase.micary_locaMic.micary_Location[i].ha_idPos = i;
    }

    for(int i = 0; i < num_src; i++){
        const BF::SourceLocation &sl = sourcePositions[i];
        smDatabase.micary_locaSource.ha_idLocation[i] = sl.sourceID;
        smDatabase.micary_locaSource.micary_Location[i].ha_fX = sourcePositions[i].x[0];
        smDatabase.micary_locaSource.micary_Location[i].ha_fY = sourcePositions[i].x[1];
        smDatabase.micary_locaSource.micary_Location[i].ha_fZ = sourcePositions[i].x[2];
        smDatabase.micary_locaSource.micary_Location[i].ha_idPos = sl.sourceID;
    }

    for(int f = 0 ; f < num_freq; f++){
        smDatabase.micary_smSeparation.micary_iaFreqLinex.ha_iValue[f] = (float)samplingRate * (f * 2 + 1) / 4 / num_freq;
    }

    int c = 0;
    for(int f = 0 ; f < num_freq; f++){
        for(int s = 0 ; s < num_src; s++){
            for(int m = 0 ; m < num_mic; m++){
                smDatabase.micary_smSeparation.micary_cmpaSeparation.ha_cmpValue[c].re = separationMatrices[f][s][m].re;
                smDatabase.micary_smSeparation.micary_cmpaSeparation.ha_cmpValue[c].im = separationMatrices[f][s][m].im;
                c++;
            }
        }
    }

    MICARY_TFDBFileHeader tfdbfh;
    tfdbfh.lFs       = samplingRate;
    tfdbfh.lNFFT     = numFreq * 2;
    tfdbfh.lNMic     = numMic;
    tfdbfh.lNSrc     = numSrc;
    tfdbfh.lNFreq    = numFreq;
    tfdbfh.iVersion  = 1;
    tfdbfh.iFileType = FORMAT_TYPE_W;

    CHarkFileIO cHark;
    if(!cHark.WriteData(filename.c_str(), &tfdbfh,
            smDatabase.micary_smSeparation.micary_cmpaSeparation,
            smDatabase.micary_smSeparation.micary_iaFreqLinex,
            smDatabase.micary_locaSource,
            smDatabase.micary_locaMic,
            "",
            "",
            "",
            "",
            "",
            "GHDSS_EXPORT")){
        SMDatabaseFree(&smDatabase);
        throw new NodeException(this, "Fail to Export file as HARK format.", __FILE__, __LINE__);
    }
    SMDatabaseFree(&smDatabase);
}
*/

int BF_execute(
    int num_src,
    HA_Complex inputSpectrum[ARY_NUM_MIC][ARY_NUM_FFT],               // 入力スペクトル
    BF_SourceLocation currentSourcePositions[num_src],                                           // 検出音源位置
//    SOURCE_DATA_ARY_t ary,                                           // 検出音源位置
    //int noiseUpdated,                                                 // 既知雑音の相関行列が更新された事を示すフラグ（オリジナルHARKの動作は、先頭フレームのみ0、その他は1で同等となる）
    //HA_Complex noiseMatrices[ARY_NUM_FFT][ARY_NUM_MIC][ARY_NUM_MIC],  // 既知雑音の相関行列入力（ML専用）CMMakeFromFFTの出力相当
    HA_Complex outputSpectrum[ARY_NUM_SRC][ARY_NUM_FFT]               // 出力スペクトル
    )
{
    int f, s, m, pm;
    // Android HARK標準のSource構造体配列 SOURCE_DATA_ARY_t からBeamform専用のSource構造体配列 BF_SourceLocation[] へ変換
//    BF_SourceLocation currentSourcePositions[num_src];
//    for(s=0; s<num_src; s++){
//        currentSourcePositions[s].x[0]      = ary.data[s].x[0];
//        currentSourcePositions[s].x[1]      = ary.data[s].x[1];
//        currentSourcePositions[s].x[2]      = ary.data[s].x[2];
//        currentSourcePositions[s].source_id = ary.data[s].id;
//        currentSourcePositions[s].is_signal = ((ary.data[s].mask & Mask_Use_Separation) ? (ary.data[s].mask & Mask_Use_Output) : 0); //SeparationするがOutputしない方向はノイズ
//    }

    //ML専用（既知雑音の相関行列が更新されていない場合は前回値を使用し、初回フレームはClearBF()で0.0f初期化が行われているものとする）
    //if(bf_param.bf_method == SEP_ML && noiseUpdated){ // ML実装前なのでコメントアウト
    //    for(f=0; f<num_freq; f++){
    //        for(m=0; m<num_mic; m++){
    //            for(pm=0; pm<num_mic; pm++){
    //                covarianceMatrices[f][m][pm] = noiseMatrices[f][m][pm];
    //            }
    //        }
    //    }
    //}

    if(num_src > 0){
        //updateSources(micPositions, sourcePositions);         // 伝達関数計算（更新または継承）および分離行列初期化
        updateSources(num_src, currentSourcePositions);                                      // 伝達関数計算（更新または継承）および分離行列初期化（マイク位置が動的に変わる事は無く、音源位置はGlobal変数なので引数不要）
        executeBeamForming(num_src, inputSpectrum, outputSpectrum);    // BeamForming 実行
        adaptSeparationMatrices(num_src);                            // 分離行列適応処理
        //if(use_export_w){ exportSeparationMatrices(export_w_filename, num_src); } // 分離行列のエクスポート（オリジナルも実装無し）
        //if(enable_debug){ // デバッグ用NAN,INFチェック
        //    float check_val;
        //    for(s=0; s<num_src; s++){
        //        for(f=0; f<num_fft; f++){
        //            check_val = outputSpectrum[s][f].re;
        //            switch(fpclassify(check_val)){
        //            case FP_NAN:      LOGD("BeamForming: outputSpectrum[%d][%d].re is NAN. Please check the parameters.", s, f); break;
        //            case FP_INFINITE: LOGD("BeamForming: outputSpectrum[%d][%d].re is INF. Please check the parameters.", s, f); break;
        //            default: break;
        //            }
        //            check_val = outputSpectrum[s][f].im;
        //            switch(fpclassify(check_val)){
        //            case FP_NAN:      LOGD("BeamForming: outputSpectrum[%d][%d].im is NAN. Please check the parameters.", s, f); break;
        //            case FP_INFINITE: LOGD("BeamForming: outputSpectrum[%d][%d].im is INF. Please check the parameters.", s, f); break;
        //            default: break;
        //            }
        //        }
        //    }
        //}
    }
}

#endif // BUILD_MODULE_BF

// EOF

