/*
 * HA_ControlObject.cpp
 *
 */
#include <pthread.h>
#include <unistd.h>
#include <algorithm>
#include <memory>
#include <iostream>
#include <sstream>
#include <string>

#include <sys/stat.h>
#include <sys/select.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netdb.h>

#include "HA_config.h"
#ifdef ENABLE_JNI_FOR_ANDROID
#include "HA_java.h"
#endif
#include "header.h"
#include "build_modules.h"
#include "HA_server.h"
#include "HA_port.h"
#include "HA_log.h"
#include "HA_misc.h"
#include "HA_ControlObject.h"
#include "socketutil.h"

#include "AudioStreamFromMic.h"
#include "AudioStreamFromWave.h"
#include "MatrixMemoryAllocate.h"
#include "LocalizeMUSIC.h"
#include "ConstantLocalization.h"
#include "ConstantLocalizationFilter.h"
#include "SourceTracker.h"
#include "HABuffer.h"
#include "LowpassFilter.h"
#include "ZeroCross_s.h"

#include "GHDSS.h"
#ifdef BUILD_MODULE_BF
#include "BF_extern.h"
#endif // BUILD_MODULE_BF
#include "HA_params.h"

#undef SEND_C_FILTERED
#undef SSL_ONLY_FRONT_SIDE

#ifdef IS_APPLE_IOS
extern "C" char *getFilenameWithDocumentsPath(const char * const filename);

#define WAV_FILE_NAME (getFilenameWithDocumentsPath("MultiSpeech.wav"))
#define LOCATION_FILE_NAME (getFilenameWithDocumentsPath("location.txt"))
#define OUT_FILE_PATH (getFilenameWithDocumentsPath(""))
#define OUT_FILE_NAME (getFilenameWithDocumentsPath("output"))
#define OUT_FILE_NAME_TMP (getFilenameWithDocumentsPath("_output"))
#define SPT_FILE_NAME (getFilenameWithDocumentsPath("spect.raw"))

#else // IS_APPLE_IOS

#ifdef ENABLE_ANDROID_PATH
/*
//#define WAV_FILE_NAME "/mnt/sdcard/hark/MultiSpeech.wav"
#define WAV_FILE_NAME "/mnt/sdcard/hark2/3sp_multi.wav"
//#define WAV_FILE_NAME "/mnt/sdcard/hark2/input.wav"
//#define WAV_FILE_NAME "/mnt/sdcard/hark2/TSP_D_H_D330.wav"
//#define WAV_FILE_NAME "/mnt/sdcard/hark2/subT_60km_BT_16k_40s.wav"
#define LOCATION_FILE_NAME "/mnt/sdcard/hark2/location.txt"
#define OUT_FILE_PATH  "/mnt/sdcard/hark2"
//#define OUT_FILE_NAME  "/mnt/sdcard/hark2/output.raw"
#define OUT_FILE_NAME "/mnt/sdcard/hark2/output"
#define OUT_FILE_NAME_TMP "/mnt/sdcard/hark2/_output"
//#define SPT_FILE_NAME "/mnt/sdcard/hark2/spect.raw"
#define SPT_FILE_NAME "/mnt/sdcard/hark2/spect.raw"
*/
//#define WAV_FILE_NAME      (getFilenameWithHarkPath("MultiSpeech.wav"))
#define WAV_FILE_NAME      (getFilenameWithHarkPath("3sp_multi.wav"))
#define LOCATION_FILE_NAME (getFilenameWithHarkPath("location.txt"))
#define OUT_FILE_PATH      (getFilenameWithHarkPath(""))
#define OUT_FILE_NAME      (getFilenameWithHarkPath("output"))
#define OUT_FILE_NAME_TMP  (getFilenameWithHarkPath("_output"))
#define SPT_FILE_NAME      (getFilenameWithHarkPath("spect.raw"))

#else
/*
#define WAV_FILE_NAME "/media/SD/hark/MultiSpeech.wav"
//#define WAV_FILE_NAME "/media/SD/hark2/3sp_multi.wav"
//#define WAV_FILE_NAME "/media/SD/hark2/input.wav"
//#define WAV_FILE_NAME "/media/SD/hark2/TSP_D_H_D330.wav"
//#define WAV_FILE_NAME "/media/SD/hark2/subT_60km_BT_16k_40s.wav"
#define LOCATION_FILE_NAME "/media/SD/hark2/location.txt"
#define OUT_FILE_PATH  "/media/SD/hark2"
//#define OUT_FILE_NAME  "/media/SD/hark2/output.raw"
#define OUT_FILE_NAME "/media/SD/hark2/output"
#define OUT_FILE_NAME_TMP "/media/SD/hark2/_output"
//#define SPT_FILE_NAME "/media/SD/hark2/spect.raw"
#define SPT_FILE_NAME "/media/SD/hark2/spect.raw"
*/

#define WAV_FILE_NAME "./hark-data/MultiSpeech.wav"
//#define WAV_FILE_NAME "/media/SD/hark2/3sp_multi.wav"
//#define WAV_FILE_NAME "/media/SD/hark2/input.wav"
//#define WAV_FILE_NAME "/media/SD/hark2/TSP_D_H_D330.wav"
//#define WAV_FILE_NAME "/media/SD/hark2/subT_60km_BT_16k_40s.wav"
#define MIC_IN_FILE_NAME "./hark-data/input"
#define LOCATION_FILE_NAME "./hark-data/location.txt"
#define OUT_FILE_PATH  "./hark-data"
//#define OUT_FILE_NAME  "/media/SD/hark2/output.raw"
#define OUT_FILE_NAME "./hark-data/output"
#define OUT_FILE_NAME_TMP "./hark-data/_output"
//#define SPT_FILE_NAME "/media/SD/hark2/spect.raw"
#define SPT_FILE_NAME "./hark-data/spect.raw"

#endif

#endif // IS_APPLE_IOS

#define OUT_FILE_EXTENSION "raw" // flt
#undef TIME_MEASURE_MODE

/* 2013.03.18 HA_lib/HarkData.hに移動 */
/*
#define ADVANCE (160)
*/

// floatx8
//#define BUFFER_OBJ_SIZE (1024 *    16)     // 512K
//#define BUFFER_OBJ_SIZE (1024 *    32)     // 1M
//#define BUFFER_OBJ_SIZE (1024 *    64)     // 2M
//#define BUFFER_OBJ_SIZE (1024 *   128)     // 4M
//#define BUFFER_OBJ_SIZE (1024 *   256)     // 8M
//#define BUFFER_OBJ_SIZE (1024 *   512)     // 16M
//#define BUFFER_OBJ_SIZE (1024 *  1024)     // 32M
//#define BUFFER_OBJ_SIZE (1024 *  2048)     // 64M
#define BUFFER_OBJ_SIZE (1024 *  4096)     // 128M
//#define BUFFER_OBJ_SIZE (1024 *  8192)     // 256M
//#define BUFFER_OBJ_SIZE (1024 * 16384)     // 512M

//#define FFT_GAIN    6.0
#define FFT_GAIN    1.0

namespace HARKAndroid {

//const ::Param_AudioStreamFromMic_t ControlObject::audio_info = {
::Param_AudioStreamFromMic_t ControlObject::audio_info = {
#if defined(__clang__) && defined(__llvm__)
    .length                 = ARY_NUM_WAVE, // 512
    .advance                = _ADVANCE_VAL_,
    .channel_count          = _DEV_CH_VAL_,
    .logical_channel_count  = _CH_VAL_,
    .channel_offset         = _CH_OFFSET_VAL_,
    .sampling_rate          = 16000,
    .nbits                  = _BIT_VAL_,
#else
    ARY_NUM_WAVE, // 512
    _ADVANCE_VAL_,
    _DEV_CH_VAL_,
    _CH_VAL_,
    _CH_OFFSET_VAL_,
    16000,
    _BIT_VAL_,
#endif
};

ControlObject::ControlObject() : valid(false),
                                 Started(false),
                                 BeingStopped(false),
                                 DeviceAvailable(false),
                                 FftCount(0),
                                 LmCount(0),
                                 GHDSSCount(0),
                                 OutECount(0),
                                 ls(0),
                                 // If AndroidCompatible is true,
                                 // will read the same file again and again as File had never terminated
                                 // if when it detects the end of file.
                                 AndroidCompatible(0), // 1 : loop / 0 : 1 time
                                 TerminateInputFile(0), // please don't touch this variable.
                                 UseReadWavFile(1),
                                 SendPort(SEND_DUMMY
                                        | SEND_PORT_A
                                        | SEND_PORT_B
                                        | SEND_PORT_C
                                        | SEND_PORT_D
                                        | SEND_PORT_E
                                        | SEND_PORT_F
                                        | SEND_JULIUS
                                        | SEND_PORT_A_FLAC
                                        | SEND_PORT_F_FLAC
                                        ),
                                 UseTimeStamp(TIMESTAMP_DUMMY
                                         // | TIMESTAMP_USE_PORT_A
                                         // | TIMESTAMP_USE_PORT_B
                                         // | TIMESTAMP_USE_PORT_C
                                         // | TIMESTAMP_USE_PORT_D
                                         // | TIMESTAMP_USE_PORT_E
                                         // | TIMESTAMP_USE_PORT_F
                                         // | TIMESTAMP_USE_JULIUS
                                         // | TIMESTAMP_USE
                                         ),
                                 LocalizeAlgorithm(
                                         //LOC_NONE
                                         //LOC_CONSTANT
                                         LOC_MUSIC
                                         //LOC_MUSIC_FILTER
                                         //LOC_NMUSIC
                                         //LOC_NMUSIC_FILTER
                                         ),
                                 UseSeparation(
                                         //SEP_NONE
                                         SEP_GHDSS
                                         //SEP_LCMV
                                         ),
                                 UseFilter(
                                         //FILTER_NONE
                                         FILTER_HRLE
                                         ),
                                 UseSynthesize(0), //if you used PortF, flag set to automatically.
                                 UseSourceFilter(SRC_FILTER_DUMMY
                                            //  | SRC_FILTER_USE_PORT_C
                                            //  | SRC_FILTER_USE_PORT_D
                                            //  | SRC_FILTER_USE_PORT_E
                                            //  | SRC_FILTER_USE_PORT_F
                                            //  | SRC_FILTER_USE_JULIUS
                                            //  | SRC_FILTER_USE
                                                ),
                                 UseCalcFeature(0), //if you used PortE or send to Julius, flag set to automatically.
                                 UseZeroCross(0),
                                 SaveMicSpec(0),
                                 SaveMicRaw(
                                         PCM_NONE
                                         //PCM_RAW_SINT16
                                         //PCM_RAW_SINT24
                                         //PCM_WAV_SINT16
                                         //PCM_WAV_SINT24
                                         ),
                                 SaveLocPowSpec(0),
                                 SaveSepSpec(0),
                                 SaveSepRaw(
                                         //PCM_NONE
                                         PCM_RAW_SINT16
                                         //PCM_RAW_SINT24 //unsupported yet
                                         //PCM_RAW_FLOAT32
                                         //PCM_WAV_SINT16
                                         //PCM_WAV_SINT24 //unsupported yet
                                         //PCM_WAV_FLOAT32
                                         ),
                                 SaveSepFeature(
                                         FEATURE_SAVE_NONE
                                         //FEATURE_SAVE_NOSMN
                                         //FEATURE_SAVE_SMN
                                         ),
                                 SaveFeatureType(
                                    //    FEATURE_NOHEADER  //MSLS format supported only
                                    //    FEATURE_MFCC
                                          FEATURE_USER      //MSLS format supported only
                                    //  | FEATURE_USE_E
                                    //  | FEATURE_USE_N
                                    //  | FEATURE_USE_D
                                    //  | FEATURE_USE_A
                                    //  | FEATURE_USE_C
                                    //  | FEATURE_USE_Z
                                    //  | FEATURE_USE_K
                                    //  | FEATURE_USE_0
                                    //  | FEATURE_USE_V
                                    //  | FEATURE_USE_T
                                         ),
                                 SaveSource(0),
                                 SocketMicConnected(false),
                                 SocketMicHostname("192.168.1.1"),
                                 //Legacy//RaspZXConnect(false),
                                 //Legacy//RaspZXhostname("192.168.1.1"),
                                 juliusMFThostname("127.0.0.1"),
                                 advanceBuffer(_ADVANCE_VAL_),
                                 audio_pre_data(NULL),
                                 bufferObj(BUFFER_OBJ_SIZE),
                                 //wavFileObj(WAV_FILE_NAME),
#ifdef ENABLE_BLUETOOTH
                                 BluetoothTransfer(true),
                                 BluetoothMinRad(-M_PI),
                                 BluetoothMaxRad(M_PI),
                                 bt_current_id(-1),
#endif	// ENABLE_BLUETOOTH
                                 selectedDeviceObj(0),
// FLAC
                                 flac_blocksize(0),
                                 flac_mic_channel(0),
                                 flac_mic_port_use(0),
                                 flac_mic_max_channel(HA_PORT_A_FLAC_DATA_NUM * 8),
                                 flac_sep_host("127.0.0.1"),
                                 flac_sep_sock_fd(-1),
                                 flac_mic_max_lpc_order(0),
                                 flac_mic_rice_partition_order(0),
                                 flac_sep_max_lpc_order(0),
                                 flac_sep_rice_partition_order(0),
// FLAC end
                                 dummy_end(0)
{
    init();
    
    /*
     * _CH_VAL_ = 8ch 分確保するが実際の処理では必要なチャネル数分のみ使用
     */
    //audio_pre_data = (float **)::MemoryAllocate2D(audio_info.logical_channel_count, audio_info.length, sizeof(float));
    audio_pre_data = (float **)::MemoryAllocate2D(_CH_VAL_, audio_info.length, sizeof(float));
    
    UserParamConfigInput_pcm_file_name[0] = '\0';
    
    UserParamConfigSave_input_pcm_file_name[0] = '\0';
    UserParamConfigSave_output_pow_spec_file_name[0] = '\0';
    UserParamConfigSave_output_feature_file_name[0] = '\0';
    UserParamConfigSave_output_pcm_file_name[0] = '\0';
    UserParamConfigSave_output_pcm_tmp_file_name[0] = '\0';
    UserParamConfigSave_output_source_file_name[0] = '\0';
    
    UserParamMicChannelOffset = 0;
    UserParamBypassOutE = 0;
}

ControlObject::~ControlObject()
{

    ::free(audio_pre_data[0]);
    ::free(audio_pre_data);

    ::pthread_mutex_destroy(&Started_mutex);
    ::pthread_mutex_destroy(&Being_Stopped_mutex);
    ::pthread_mutex_destroy(&Started_mutex);
    ::pthread_mutex_destroy(&PortASockets_mutex);
    ::pthread_mutex_destroy(&PortBSockets_mutex);
    ::pthread_mutex_destroy(&PortCSockets_mutex);
    ::pthread_mutex_destroy(&PortDSockets_mutex);
    ::pthread_mutex_destroy(&PortESockets_mutex);
    ::pthread_mutex_destroy(&PortFSockets_mutex);
    //::pthread_mutex_destroy(&CommandPortSockets_mutex);
    //::pthread_mutex_destroy(&ImportParamPortSockets_mutex);
    //::pthread_mutex_destroy(&ExportParamPortSockets_mutex);

    ::pthread_mutex_destroy(&PortA_FLAC_Sockets_mutex);
    ::pthread_mutex_destroy(&PortA_FLAC_DATA_Sockets_mutex);
}

int ControlObject::init()
{
    int ret;

    for(int i = 0; i < WorkerThreadNum; i++){
#ifdef IS_APPLE_IOS
        thread_id[i] = reinterpret_cast<pthread_t>(-1);
#else
        thread_id[i] = -1;
#endif
    }
    ret = ::pthread_mutex_init(&RaspLc_Stop_mutex, NULL);
    if(ret != 0){ return(ret); }
    ret = ::pthread_mutex_init(&Started_mutex, NULL);
    if(ret != 0){ return(ret); }
    ret = ::pthread_mutex_init(&Being_Stopped_mutex, NULL);
    if(ret != 0){ return(ret); }
    ret = ::pthread_mutex_init(&Start_Stop_mutex, NULL);
    if(ret != 0){ return(ret); }
    ret = ::pthread_mutex_init(&PortASockets_mutex, NULL);
    if(ret != 0){ return(ret); }
    ret = ::pthread_mutex_init(&PortBSockets_mutex, NULL);
    if(ret != 0){ return(ret); }
    ret = ::pthread_mutex_init(&PortCSockets_mutex, NULL);
    if(ret != 0){ return(ret); }
    ret = ::pthread_mutex_init(&PortDSockets_mutex, NULL);
    if(ret != 0){ return(ret); }
    ret = ::pthread_mutex_init(&PortESockets_mutex, NULL);
    if(ret != 0){ return(ret); }
    ret = ::pthread_mutex_init(&PortFSockets_mutex, NULL);
    if(ret != 0){ return(ret); }
    //ret = ::pthread_mutex_init(&CommandPortSockets_mutex, NULL);
    //if(ret != 0){ return(ret); }
    //ret = ::pthread_mutex_init(&ImportParamPortSockets_mutex, NULL);
    //if(ret != 0){ return(ret); }
    //ret = ::pthread_mutex_init(&ExportParamPortSockets_mutex, NULL);
    //if(ret != 0){ return(ret); }

    ret = ::pthread_mutex_init(&PortA_FLAC_Sockets_mutex, NULL);
    if(ret != 0){ return(ret); }

    ret = ::pthread_mutex_init(&PortA_FLAC_DATA_Sockets_mutex, NULL);
    if(ret != 0){ return(ret); }

#ifdef ENABLE_BLUETOOTH
    ret = ::sem_init(&bt_max_sem, 0, 1);
    if(ret != 0){ return(ret); }
#endif

    valid = true;
    return(0);
}

#ifdef ENABLE_JNI_FOR_ANDROID
int ControlObject::Create(JNIEnv *env, jobject thiz)
#else
int ControlObject::Create()
#endif // ENABLE_JNI_FOR_ANDROID
{
    // init servers
    int ret;
#ifdef ENABLE_JNI_FOR_ANDROID
    ret = ::_server_start(env, thiz);
#else
    ret = ::_server_start();
#endif // ENABLE_JNI_FOR_ANDROID
    return(ret);
}

//int ControlObject::Raw(const int thread_no, const bool debug, float **data, char* ts)
int ControlObject::Raw(const int thread_no, float **data, char* ts)
{
    //::Param_AudioStreamFromMic_t param;
    //::HAGetParamAudioStreamFromMic(&param);
    const ::Param_AudioStreamFromMic_t &param(audio_info);

    //LOGD("wait for raw %d", thread_no);

    WaitRaw(thread_no);


#if 1
    {
      static unsigned int cnt = 0;
      static double last;
      if (cnt == 0) {
	last = current_ms();
      }

      if ((++cnt % 100) == 0) {

	char outstr[200];
#if 0
	time_t t;
	struct tm *tmp;

	t = time(NULL);
	tmp = localtime(&t);

	if (strftime(outstr, sizeof(outstr), "%x %T", tmp) == 0) {
	  fprintf(stderr, "strftime returned 0");
	}
	printf("%s\n", outstr);
#else


	double cur = current_ms();
	printf("%f [ms] dt %f [ms]\n", cur, cur - last);
	last = cur;

#endif

      }
    }
#endif

    //LOGD(" WaitRaw pass[%d] : %d", RawCount, thread_no);

    ::HD_Header hdr;
    hdr.type = PACKET_MIC_WAVE;
    hdr.advance = param.advance;
    hdr.count = RawCount++;

    ::HDH_MicData mic;
    mic.nch = param.logical_channel_count;
    mic.length = param.length;
    mic.data_bytes = mic.nch * mic.length * sizeof(float);

    int stat = mic.data_bytes;

    //float buf[512 * 8];
    //float *buf = data[0];   // 実は一次元らしい
    const float * const buf = data[0];  // 実は一次元らしい

    if (isBeingStopped()) {
        //LOGD("stop trapped %d", thread_no);
        //LOGD("stop trapped @1 %d", thread_no);
        GoNextRaw(thread_no);
        return(-1);
    } else {
        //LOGD("NON stop %d", thread_no);
    }

    //
    // タイムスタンプ
    //
    if(UseTimeStamp){
        struct timeval tv;
        gettimeofday(&tv, NULL);
        unsigned long long millisecondsSinceEpoch =
        (unsigned long long)(tv.tv_sec) * 1000 +
        (unsigned long long)(tv.tv_usec) / 1000;
        sprintf(ts, "%llu", millisecondsSinceEpoch);
        /*
         // tv.tv_usec=[0-999999]への正規化 while内は本来通らないはず
         while(tv.tv_usec<0){ tv.tv_sec--; tv.tv_usec += 1000000; } // tv_usecの負値対策
         while(tv.tv_usec>999999){ tv.tv_sec++; tv.tv_usec -= 1000000; } // tv_usecのsec値超過対策
         if(tv.tv_sec<0){ tv.tv_sec = 0; tv.tv_usec = 0; } // LANAさん実装に合わせtimevalの負値は0で処理する
         sprintf(ts, "%lu%06lu", tv.tv_sec, tv.tv_usec); // 符号+10桁+6桁+\0でtsは最低限18Byte必要
         */
    }
    
    const int length  = param.length;
    const int advance = param.advance;
    const int target_channels = param.logical_channel_count;
    const int overrap_len = length - advance;
    const int num_mic = param.logical_channel_count;

#ifdef NEVER
    // get datas
    if(debug){
        if(UseReadWavFile){
            if (::ReadWaveData(hdr.count, data) == -1) {
                ::CloseWaveFile();
                LOGI("**** END OF WAVEFILE ****\n");
#ifndef IS_ANDROID
                if(AndroidCompatible == 0){ TerminateInputFile = 1; }
#endif
#ifdef TIME_MEASURE_MODE
                struct timeval tv;
                gettimeofday(&tv, NULL);
                LOGI("%lu.%6lu\n", tv.tv_sec, tv.tv_usec);
#endif
                // reopen
                ::OpenWaveFile(WAV_FILE_NAME);
                ::ReadWaveData(hdr.count, data);
            }
        }
        else{
            const float PI (3.14159265);
            const int b = 1000000;
            int ct = 0;

            for(int i = 0; i < 512; i++){ *(buf + ct++) = sin((2 * PI /  30/*360*/) * (i + ls)) * b; }
            for(int i = 0; i < 512; i++){ *(buf + ct++) = sin((2 * PI / 180) * (i + ls)) * b; }
            for(int i = 0; i < 512; i++){ *(buf + ct++) = sin((2 * PI / 120) * (i + ls)) * b; }
            for(int i = 0; i < 512; i++){ *(buf + ct++) = sin((2 * PI /  60) * (i + ls)) * b; }
            for(int i = 0; i < 512; i++){ *(buf + ct++) = cos((2 * PI / 360) * (i + ls)) * b; }
            for(int i = 0; i < 512; i++){ *(buf + ct++) = cos((2 * PI / 180) * (i + ls)) * b; }
            for(int i = 0; i < 512; i++){ *(buf + ct++) = cos((2 * PI / 120) * (i + ls)) * b; }
            for(int i = 0; i < 512; i++){ *(buf + ct++) = cos((2 * PI /  60) * (i + ls)) * b; }
            //LOGD("send float %f", buf[0]);
            ls += 512;
            //::usleep(1000000 ); // 1sec;
            //::usleep(500000); // 0.5sec;
            ::usleep(32000); // 32msec;
        }
    }
    else{
        //const double start = current_ms();

        stat = RaspLc_ReadData(hdr.count, data, ts, UseTimeStamp);
        /*
        int ct = 0;
        float mg_coef = 0.03125f; // 1.0/256.0*8.0
        if(MicInMultiGain){
            for(int ch = 0; ch < ARY_NUM_MIC; ch++){
                for(int i = 0; i < 512; i++){
                    buf[ct++] = data[ch][i] * mg_coef;
                }
            }
        }
        else{
            for(int ch = 0; ch < ARY_NUM_MIC; ch++) {
                for(int i = 0; i < 512; i++){
                    buf[ct++] = data[ch][i];
                }
            }
        }
        */
        //const double end = current_ms();
        //LOGI("RaspLc_ReadData time elapsed = %f ms", end - start);
    }
#endif // NEVER

    //
    // MARK: advance 分を読む
    //
retry:
    int ret = bufferObj.readWithTimeout(advanceBuffer, 250);  // 250ms
    if(isBeingStopped()){
        //LOGD("stop trapped @2 %d", thread_no);
        GoNextRaw(thread_no);
        return(-1);
    }
    if(ret == 0){
        // OK
    }else if(ret == ETIMEDOUT){
        //LOGI("raw() read retry %d (%d/%d)", hdr.count, i, advance);
        goto retry;
    }else{
        LOGE("advance read error %d", ret);
        return(-1);
    }

    /* 前フレームのオーバーラップ部分をコピー */
    for(int ch = 0; ch < target_channels; ch++){
        std::copy(&audio_pre_data[ch][0], &audio_pre_data[ch][overrap_len], &data[ch][0]);
    }
    //
    // MARK: advance分インターリーブ解除
    //
    //const double from = current_ms();
#ifdef ENABLE_NEON
    const unsigned int channel_num(param.logical_channel_count);
    const unsigned int channel_offset(param.channel_offset);
    
    std::vector<const float *> src(channel_num);
    std::vector<float *> dest(channel_num);
    deinterleave deinterleave;
    
    for(int index = overrap_len; index < overrap_len + advance; index += channel_num){
        for (int i = 0; i < channel_num; i++) {
            src[i] = advanceBuffer[index - overrap_len + i].getDatAddr(channel_offset);
        }
        for (int i = 0; i < channel_num; i++) {
            dest[i] = &data[i][index];
        }
        deinterleave(&dest[0], &src[0], channel_num, channel_num);
    }
    // あまり
    const int mod = advance % channel_num;
    if (mod) {
        const int start_offset = (advance / channel_num) * channel_num;
        for (int i = 0; i < mod; i++) {
            src[i] = advanceBuffer[start_offset + i].getDatAddr(channel_offset);
        }
        for (int i = 0; i < channel_num; i++) {
            dest[i] = &data[i][overrap_len + start_offset];
        }
        deinterleave(&dest[0], &src[0], channel_num, mod);
    }
    
#else   // ENABLE_NEON

    for(int ch = 0; ch < target_channels; ch++){
        for(int index = overrap_len; index < overrap_len + advance; index++){
            advanceBuffer[index - overrap_len].get(&data[ch][index], param.channel_offset + ch, 1);
        }
    }

#endif  // ENABLE_NEON
    //const double to = current_ms();
    //if (thread_no == 0) {
    //    LOGI("deinterleave %f", to - from);
    //}
    
    /* オーバーラップ部分を保持 */
    for(int ch = 0; ch < target_channels; ch++){
        std::copy(&data[ch][advance], &data[ch][advance + overrap_len], &audio_pre_data[ch][0]);
    }

    //
    // 読み込み終了
    //
    //LOGD("raw() read end %d", thread_no);

    if(SaveMicRaw){
        FILE *fp = input_raw_fp;
#if 0 // Legacy code /* 2013.02.18 Rawデータ保存 */
        FILE *fp = NULL;
        char ifname[ARY_PATH_LENGTH];
        sprintf(ifname, "%s/input.raw", OUT_FILE_PATH);
        if ((fp = fopen(ifname, "ab")) == NULL) {
            LOGE("file open error");
        }
#endif
        if(fp != NULL){
            const int device_bits = audio_info.nbits; // selectedDeviceObj->GetBits(); //test
            union multibit {
                int           buf_si[ARY_NUM_WAVE*ARY_NUM_MIC];
                short int     buf_ss[ARY_NUM_WAVE*ARY_NUM_MIC*2];
                unsigned char buf_uc[ARY_NUM_WAVE*ARY_NUM_MIC*4];
            } buftmp_multibit ;
            //char buftmp_24[ARY_NUM_WAVE*ARY_NUM_MIC*3];    // buftmp_24 ==> buftmp_multibit.buf_uc
            //short int buftmp_16[ARY_NUM_WAVE*ARY_NUM_MIC]; // buftmp_16 ==> buftmp_multibit.buf_ss
            if(hdr.count == 1){
                int i, j, k;
                switch(SaveMicRaw){
                case PCM_WAV_SINT32:
                    break;
                case PCM_WAV_SINT24:
                    switch(device_bits){
                    case 16:
                        for(i=0; i<ARY_NUM_WAVE; i++){
                            for(j=0, k=0; j<num_mic; j++, k+=3){
                                buftmp_multibit.buf_uc[i*num_mic*3+k  ] = 0x00;
                                buftmp_multibit.buf_uc[i*num_mic*3+k+1] = (((int) buf[j*ARY_NUM_WAVE+i])      ) & 0xFF;
                                buftmp_multibit.buf_uc[i*num_mic*3+k+2] = (((int) buf[j*ARY_NUM_WAVE+i]) >>  8) & 0xFF;
                            }
                        }
                        break;
                    case 24:
                        for(i=0; i<ARY_NUM_WAVE; i++){
                            for(j=0, k=0; j<num_mic; j++, k+=3){
                                buftmp_multibit.buf_uc[i*num_mic*3+k  ] = (((int) buf[j*ARY_NUM_WAVE+i])      ) & 0xFF;
                                buftmp_multibit.buf_uc[i*num_mic*3+k+1] = (((int) buf[j*ARY_NUM_WAVE+i]) >>  8) & 0xFF;
                                buftmp_multibit.buf_uc[i*num_mic*3+k+2] = (((int) buf[j*ARY_NUM_WAVE+i]) >> 16) & 0xFF;
                            }
                        }
                        break;
                    case 32:
                        for(i=0; i<ARY_NUM_WAVE; i++){
                            for(j=0, k=0; j<num_mic; j++, k+=3){
                                buftmp_multibit.buf_uc[i*num_mic*3+k  ] = (((int) buf[j*ARY_NUM_WAVE+i]) >>  8) & 0xFF;
                                buftmp_multibit.buf_uc[i*num_mic*3+k+1] = (((int) buf[j*ARY_NUM_WAVE+i]) >> 16) & 0xFF;
                                buftmp_multibit.buf_uc[i*num_mic*3+k+2] = (((int) buf[j*ARY_NUM_WAVE+i]) >> 24) & 0xFF;
                            }
                        }
                        break;
                    case 0: // if use no bit convert option
                    default:
                        for(i=0; i<ARY_NUM_WAVE; i++){
                            for(j=0, k=0; j<num_mic; j++, k+=3){
                                buftmp_multibit.buf_uc[i*num_mic*3+k  ] = (((int) buf[j*ARY_NUM_WAVE+i])      ) & 0xFF;
                                buftmp_multibit.buf_uc[i*num_mic*3+k+1] = (((int) buf[j*ARY_NUM_WAVE+i]) >>  8) & 0xFF;
                                buftmp_multibit.buf_uc[i*num_mic*3+k+2] = (((int) buf[j*ARY_NUM_WAVE+i]) >> 16) & 0xFF;
                            }
                        }
                        break;
                    }
                    fwrite(buftmp_multibit.buf_uc, sizeof(char) * 3 * ARY_NUM_WAVE * num_mic, 1, fp);
                    break;
                case PCM_WAV_SINT16:
                    switch(device_bits){
                    case 16:
                        for(i=0; i<ARY_NUM_WAVE; i++){
                            for(j=0; j<num_mic; j++){
                                buftmp_multibit.buf_ss[i*num_mic+j] = (short int)buf[j*ARY_NUM_WAVE+i];
                            }
                        }
                        break;
                    case 24:
                        for(i=0; i<ARY_NUM_WAVE; i++){
                            for(j=0; j<num_mic; j++){
                                buftmp_multibit.buf_ss[i*num_mic+j] = (short int)(((int)buf[j*ARY_NUM_WAVE+i]) >> 8);
                            }
                        }
                        break;
                    case 32:
                        for(i=0; i<ARY_NUM_WAVE; i++){
                            for(j=0; j<num_mic; j++){
                                buftmp_multibit.buf_ss[i*num_mic+j] = (short int)(((int)buf[j*ARY_NUM_WAVE+i]) >> 16);
                            }
                        }
                        break;
                    case 0: // if use no bit convert option
                    default:
                        for(i=0; i<ARY_NUM_WAVE; i++){
                            for(j=0; j<num_mic; j++){
                                buftmp_multibit.buf_ss[i*num_mic+j] = (short int)buf[j*ARY_NUM_WAVE+i];
                            }
                        }
                        break;
                    }
                    fwrite(buftmp_multibit.buf_ss, sizeof(short int) * ARY_NUM_WAVE * num_mic, 1, fp);
                    break;
                case PCM_RAW_SINT32:
                    break;
                case PCM_RAW_SINT24:
                    switch(device_bits){
                    case 16:
                        for(i=0; i<ARY_NUM_WAVE; i++){
                            for(j=0, k=0; j<num_mic; j++, k+=3){
                                buftmp_multibit.buf_uc[i*num_mic*3+k  ] = 0x00;
                                buftmp_multibit.buf_uc[i*num_mic*3+k+1] = (((int) buf[j*ARY_NUM_WAVE+i])      ) & 0xFF;
                                buftmp_multibit.buf_uc[i*num_mic*3+k+2] = (((int) buf[j*ARY_NUM_WAVE+i]) >>  8) & 0xFF;
                            }
                        }
                        break;
                    case 24:
                        for(i=0; i<ARY_NUM_WAVE; i++){
                            for(j=0, k=0; j<num_mic; j++, k+=3){
                                buftmp_multibit.buf_uc[i*num_mic*3+k  ] = (((int) buf[j*ARY_NUM_WAVE+i])      ) & 0xFF;
                                buftmp_multibit.buf_uc[i*num_mic*3+k+1] = (((int) buf[j*ARY_NUM_WAVE+i]) >>  8) & 0xFF;
                                buftmp_multibit.buf_uc[i*num_mic*3+k+2] = (((int) buf[j*ARY_NUM_WAVE+i]) >> 16) & 0xFF;
                            }
                        }
                        break;
                    case 32:
                        for(i=0; i<ARY_NUM_WAVE; i++){
                            for(j=0, k=0; j<num_mic; j++, k+=3){
                                buftmp_multibit.buf_uc[i*num_mic*3+k  ] = (((int) buf[j*ARY_NUM_WAVE+i]) >>  8) & 0xFF;
                                buftmp_multibit.buf_uc[i*num_mic*3+k+1] = (((int) buf[j*ARY_NUM_WAVE+i]) >> 16) & 0xFF;
                                buftmp_multibit.buf_uc[i*num_mic*3+k+2] = (((int) buf[j*ARY_NUM_WAVE+i]) >> 24) & 0xFF;
                            }
                        }
                        break;
                    case 0: // if use no bit convert option
                    default:
                        for(i=0; i<ARY_NUM_WAVE; i++){
                            for(j=0, k=0; j<num_mic; j++, k+=3){
                                buftmp_multibit.buf_uc[i*num_mic*3+k  ] = (((int) buf[j*ARY_NUM_WAVE+i])      ) & 0xFF;
                                buftmp_multibit.buf_uc[i*num_mic*3+k+1] = (((int) buf[j*ARY_NUM_WAVE+i]) >>  8) & 0xFF;
                                buftmp_multibit.buf_uc[i*num_mic*3+k+2] = (((int) buf[j*ARY_NUM_WAVE+i]) >> 16) & 0xFF;
                            }
                        }
                        break;
                    }
                    fwrite(buftmp_multibit.buf_uc, sizeof(char) * 3 * ARY_NUM_WAVE * num_mic, 1, fp);
                    break;
                case PCM_RAW_SINT16:
                    switch(device_bits){
                    case 16:
                        for(i=0; i<ARY_NUM_WAVE; i++){
                            for(j=0; j<num_mic; j++){
                                buftmp_multibit.buf_ss[i*num_mic+j] = (short int)buf[j*ARY_NUM_WAVE+i];
                            }
                        }
                        break;
                    case 24:
                        for(i=0; i<ARY_NUM_WAVE; i++){
                            for(j=0; j<num_mic; j++){
                                buftmp_multibit.buf_ss[i*num_mic+j] = (short int)(((int)buf[j*ARY_NUM_WAVE+i]) >> 8);
                            }
                        }
                        break;
                    case 32:
                        for(i=0; i<ARY_NUM_WAVE; i++){
                            for(j=0; j<num_mic; j++){
                                buftmp_multibit.buf_ss[i*num_mic+j] = (short int)(((int)buf[j*ARY_NUM_WAVE+i]) >> 16);
                            }
                        }
                        break;
                    case 0: // if use no bit convert option
                    default:
                        for(i=0; i<ARY_NUM_WAVE; i++){
                            for(j=0; j<num_mic; j++){
                                //buftmp[i*num_mic+j] = (short int)data[j][i]; // <-- OK
                                buftmp_multibit.buf_ss[i*num_mic+j] = (short int)buf[j*ARY_NUM_WAVE+i];
                            }
                        }
                        break;
                    }
                    fwrite(buftmp_multibit.buf_ss, sizeof(short int) * ARY_NUM_WAVE * num_mic, 1, fp);
                    break;
                case PCM_NONE:
                default:
                    break;
                }
            }
            else{
                int i, j, k;
                switch(SaveMicRaw){
                case PCM_WAV_SINT24:
                case PCM_RAW_SINT24:
                    switch(device_bits){
                    case 16:
                        for(i=0; i<advance; i++){
                            for(j=0, k=0; j<num_mic; j++, k+=3){
                                buftmp_multibit.buf_uc[i*num_mic*3+k  ] = 0x00;
                                buftmp_multibit.buf_uc[i*num_mic*3+k+1] = (((int) buf[(j+1)*ARY_NUM_WAVE-advance+i])      ) & 0xFF; // <-- OK
                                buftmp_multibit.buf_uc[i*num_mic*3+k+2] = (((int) buf[(j+1)*ARY_NUM_WAVE-advance+i]) >>  8) & 0xFF; // <-- OK
                            }
                        }
                        break;
                    case 24:
                        for(i=0; i<advance; i++){
                            for(j=0, k=0; j<num_mic; j++, k+=3){
                                buftmp_multibit.buf_uc[i*num_mic*3+k  ] = (((int) buf[(j+1)*ARY_NUM_WAVE-advance+i])      ) & 0xFF; // <-- OK
                                buftmp_multibit.buf_uc[i*num_mic*3+k+1] = (((int) buf[(j+1)*ARY_NUM_WAVE-advance+i]) >>  8) & 0xFF; // <-- OK
                                buftmp_multibit.buf_uc[i*num_mic*3+k+2] = (((int) buf[(j+1)*ARY_NUM_WAVE-advance+i]) >> 16) & 0xFF; // <-- OK
                            }
                        }
                        break;
                    case 32:
                        for(i=0; i<advance; i++){
                            for(j=0, k=0; j<num_mic; j++, k+=3){
                                buftmp_multibit.buf_uc[i*num_mic*3+k  ] = (((int) buf[(j+1)*ARY_NUM_WAVE-advance+i]) >>  8) & 0xFF; // <-- OK
                                buftmp_multibit.buf_uc[i*num_mic*3+k+1] = (((int) buf[(j+1)*ARY_NUM_WAVE-advance+i]) >> 16) & 0xFF; // <-- OK
                                buftmp_multibit.buf_uc[i*num_mic*3+k+2] = (((int) buf[(j+1)*ARY_NUM_WAVE-advance+i]) >> 24) & 0xFF; // <-- OK
                            }
                        }
                        break;
                    case 0: // if use no bit convert option
                    default:
                        for(i=0; i<advance; i++){
                            for(j=0, k=0; j<num_mic; j++, k+=3){
                                buftmp_multibit.buf_uc[i*num_mic*3+k  ] = (((int) buf[(j+1)*ARY_NUM_WAVE-advance+i])      ) & 0xFF; // <-- OK
                                buftmp_multibit.buf_uc[i*num_mic*3+k+1] = (((int) buf[(j+1)*ARY_NUM_WAVE-advance+i]) >>  8) & 0xFF; // <-- OK
                                buftmp_multibit.buf_uc[i*num_mic*3+k+2] = (((int) buf[(j+1)*ARY_NUM_WAVE-advance+i]) >> 16) & 0xFF; // <-- OK
                            }
                        }
                        break;
                    }
                    fwrite(buftmp_multibit.buf_uc, sizeof(char) * 3 * advance * num_mic, 1, fp);
                    break;
                case PCM_WAV_SINT16:
                case PCM_RAW_SINT16:
                    switch(device_bits){
                    case 16:
                        for(i=0; i<advance; i++){
                            for(j=0; j<num_mic; j++){
                                buftmp_multibit.buf_ss[i*num_mic+j] = (short int)buf[(j+1)*ARY_NUM_WAVE-advance+i]; // <-- OK
                            }
                        }
                        break;
                    case 24:
                        for(i=0; i<advance; i++){
                            for(j=0; j<num_mic; j++){
                                buftmp_multibit.buf_ss[i*num_mic+j] = (short int)(((int)buf[(j+1)*ARY_NUM_WAVE-advance+i]) >> 8); // <-- OK
                            }
                        }
                        break;
                    case 32:
                        for(i=0; i<advance; i++){
                            for(j=0; j<num_mic; j++){
                                buftmp_multibit.buf_ss[i*num_mic+j] = (short int)(((int)buf[(j+1)*ARY_NUM_WAVE-advance+i]) >> 16); // <-- OK
                            }
                        }
                        break;
                    case 0: // if use no bit convert option
                    default:
                        for(i=0; i<advance; i++){
                            for(j=0; j<num_mic; j++){
                                ////buftmp[i*num_mic+j] = (short int)buf[j*ARY_NUM_WAVE+(ARY_NUM_WAVE-advance+i)];
                                //buftmp[i*num_mic+j] = (short int)buf[j*(ARY_NUM_WAVE-advance)+i]; // <-- バッファアクセスミス
                                //buftmp[i*num_mic+j] = (short int)data[j][(ARY_NUM_WAVE-advance)+i]; // <-- OK
                                buftmp_multibit.buf_ss[i*num_mic+j] = (short int)buf[(j+1)*ARY_NUM_WAVE-advance+i]; // <-- OK
                            }
                        }
                        break;
                    }
                    fwrite(buftmp_multibit.buf_ss, sizeof(short int) * advance * num_mic, 1, fp);
                    break;
                case PCM_NONE:
                default:
                    break;
                }
            }
        }
#if 0 // Legacy code
        fclose(fp);
#endif
    }
    //LOGD(" GoNextRaw[%d] : %d", hdr.count, thread_no);
    GoNextRaw(thread_no);
    //LOGD("wait for raw send %d", thread_no);
    WaitSendRaw(thread_no);
    //LOGD(" WaitSendRaw pass[%d] : %d", hdr.count, thread_no);

    // send portA
    //SendPortA(&hdr, sizeof(hdr));
    //SendPortA(&mic, sizeof(mic));
    //SendPortA(&buf, sizeof(buf));
    //LOGD("raw() send port %d", thread_no);

    if(SendPort & SEND_PORT_A){
        SendPortA(&hdr, &mic, buf);
    }

    //LOGD("SendPort %08x\n", SendPort);
    if(SendPort & SEND_PORT_A_FLAC){
      //LOGD("send_port_a_flac");
      SendPortA_flac(&hdr, &mic, buf);
    }

    //LOGD(" GoNextSendRaw[%d] : %d", hdr.count, thread_no);
    GoNextSendRaw(thread_no);

    ////LOGD(" GoNextRaw[%d] : %d", hdr.count, thread_no);
    //GoNextRaw(thread_no);
    //LOGD("raw() end %d", thread_no);
    
    return(stat);
}

MULTI_FFT_INFO_t *ControlObject::init_fft(const int thread_no) {

    /* 窓係数の指定を追加
     *   FFTの窓係数を指定すると入力信号へのMulitGain相当の処理が可能
     */
    ::SetFFTWindowGain(1.0);
//  ::SetFFTWindowGain(FFT_GAIN);    
    //::SetFFTWindowGain(0.05);
    //::SetFFTWindowGain(0.00005); //for bluetooth rec data

//    MULTI_FFT_INFO_t *fft_info = ::InitMultiFFT("HANNING", 512);
//    MULTI_FFT_INFO_t *fft_info = ::InitMultiFFT("HAMMING", 512);
//    MULTI_FFT_INFO_t *fft_info = ::InitMultiFFT("CONJ", 512);
    MULTI_FFT_INFO_t *fft_info = ::InitMultiFFT("CONJ", ARY_NUM_WAVE);

    return(fft_info);
}

int ControlObject::Fft(const int thread_no, MULTI_FFT_INFO_t *fft_info, float **data, COMPLEX_FLOAT **fft_data, char* ts)
{
    //::Param_AudioStreamFromMic_t param;
    //::HAGetParamAudioStreamFromMic(&param);
    const ::Param_AudioStreamFromMic_t &param(audio_info);

    //LOGD("wait for fft %d", thread_no);
    WaitFft(thread_no);
    //LOGD("  WaitFft pass[%d] : %d", FftCount, thread_no);

    ::HD_Header hdr;
    hdr.type = PACKET_MIC_FFT;
    hdr.advance = param.advance;
    hdr.count = FftCount++;

    //LOGD("  GoNextFft[%d] : %d", hdr.count, thread_no);
    //GoNextFft(thread_no); // 20160225 remove 実行後にGoNext

    ::HDH_MicData mic;
    mic.nch = param.logical_channel_count;
    mic.length = param.length;
    mic.data_bytes = mic.nch * ((mic.length / 2) + 1) * sizeof(COMPLEX_FLOAT);

    const int channels = param.logical_channel_count;
    const int num_mic = param.logical_channel_count;
    /* FFT演算 */
    //{
    //const double start = current_ms();

    ::MultiFFT(fft_info, fft_data, data, channels);

    //const double end = current_ms();
    //LOGD("MultiFFT time elapsed = %f ms", end - start);
    //}
    //LOGD("  GoNextFft[%d] : %d", hdr.count, thread_no);
    GoNextFft(thread_no); // 20160225 fixed 実行後にGoNext

    // re-order
    //const int datnum = ((512 / 2) + 1);
    const int datnum = ((mic.length / 2) + 1);
    float re_order[datnum * num_mic * 2];
    if(SendPort & SEND_PORT_B){
        for(int ch = 0; ch < num_mic; ch++) {
            for(int i = 0; i < datnum; i++) {
                re_order[ch * datnum * 2 + i] = fft_data[ch][i].real;
                re_order[ch * datnum * 2 + datnum + i] = fft_data[ch][i].imag;
            }
        }
        //LOGD("send %d %f %f %f %f", mic.data_bytes, fft_data[0][0].real, fft_data[0][0].imag, re_order[0], re_order[257]);
    }

    //LOGD("wait for send fft %d", thread_no);
    WaitSendFft(thread_no);
    //LOGD("  WaitSendFft pass[%d] : %d", hdr.count, thread_no);

    if(SendPort & SEND_PORT_B){
        SendPortB(&hdr, &mic, re_order);
    }
    //LOGD("  GoNextSendFft[%d] : %d", hdr.count, thread_no);
    GoNextSendFft(thread_no);

    return(0);
}

int ControlObject::SetLocalizeMusic(int cmd_param_id, int i_value, float f_value, char* file_path)
{
    FILE *fp = NULL; // for TF file exist check.
    int ret = 0;
    int sr = UserParamConfigLocalizeMusic.sampling_rate;
    /* LocalizeMUSICのパラメータ設定 */
    switch(cmd_param_id){
    case PARAM_LM_MUSIC_ALGORITHM:
        switch(i_value){
        case VALUE_LM_MUSIC_ALGORITHM_SEVD:
            UserParamConfigLocalizeMusic.music_algorithm = SEVD;
            break;
        case VALUE_LM_MUSIC_ALGORITHM_GEVD:
            UserParamConfigLocalizeMusic.music_algorithm = GEVD;
            break;
        case VALUE_LM_MUSIC_ALGORITHM_GSVD:
            UserParamConfigLocalizeMusic.music_algorithm = GSVD;
            break;
        default: // unsupported type found. default is GSVD.
            UserParamConfigLocalizeMusic.music_algorithm = GSVD;
            ret = -1;
            break;
        }
        break;
    case PARAM_LM_LENGTH:
        if(i_value<3){ // invalid value found, reset to 512.
            UserParamConfigLocalizeMusic.length = ARY_NUM_WAVE; // 512
            ret = -1;
        }
        else{
            UserParamConfigLocalizeMusic.length = i_value;
        }
        break;
    case PARAM_LM_SAMPLING_RATE:
        switch(i_value){
        case VALUE_LM_SAMPLING_RATE_8000:
            UserParamConfigLocalizeMusic.sampling_rate = 8000;
            break;
        case VALUE_LM_SAMPLING_RATE_11025:
            UserParamConfigLocalizeMusic.sampling_rate = 11025;
            break;
        case VALUE_LM_SAMPLING_RATE_16000:
            UserParamConfigLocalizeMusic.sampling_rate = 16000;
            break;
        case VALUE_LM_SAMPLING_RATE_22050:
            UserParamConfigLocalizeMusic.sampling_rate = 22050;
            break;
        case VALUE_LM_SAMPLING_RATE_32000:
            UserParamConfigLocalizeMusic.sampling_rate = 32000;
            break;
        case VALUE_LM_SAMPLING_RATE_44100:
            UserParamConfigLocalizeMusic.sampling_rate = 44100;
            break;
        case VALUE_LM_SAMPLING_RATE_48000:
            UserParamConfigLocalizeMusic.sampling_rate = 48000;
            break;
        case VALUE_LM_SAMPLING_RATE_96000:
            UserParamConfigLocalizeMusic.sampling_rate = 96000;
            break;
        case VALUE_LM_SAMPLING_RATE_192000:
            UserParamConfigLocalizeMusic.sampling_rate = 192000;
            break;
        default: // unsupported rate found. default is 16000.
            UserParamConfigLocalizeMusic.sampling_rate = DEFAULT_SAMPLING_RATE; // 16000
            ret = -1;
            break;
        }
        break;
    case PARAM_LM_WINDOW:
        if(i_value<1){ // invalid value found, reset to 50.
            UserParamConfigLocalizeMusic.window = 50; // 20;
            ret = -1;
        }
        else{
            UserParamConfigLocalizeMusic.window = i_value;
        }
        break;
    case PARAM_LM_PERIOD:
        if(i_value<1){ // invalid value found, reset to 25.
            UserParamConfigLocalizeMusic.period = 25; // 50; // 1;
            ret = -1;
        }
        else{
            UserParamConfigLocalizeMusic.period = i_value;
        }
        break;
    case PARAM_LM_ELEVATION:
        if((f_value<-360.0f)||(f_value>360.0f)){ // invalid angle found, reset to 15.0.
            UserParamConfigLocalizeMusic.elevation = 15.0f; // サンプルネットワーク
            ret = -1;
        }
        else{
            UserParamConfigLocalizeMusic.elevation = f_value;
        }
        break;
    case PARAM_LM_NUM_SOURCE:
        if((i_value<1)||(i_value>ARY_NUM_MIC-1)){ // invalid value found, reset to 25.
            UserParamConfigLocalizeMusic.num_source = 1; // 2; // 3;
            ret = -1;
        }
        else{
            UserParamConfigLocalizeMusic.num_source = i_value;
        }
        break;
    case PARAM_LM_EXPORT_NUM_SOURCE: // PowerPeakの検出数：出力する最大Source数（マイクch数が少ない場合対策）
        if((i_value<-1)||(i_value>ARY_NUM_MIC-1)){ // invalid value found, reset to -1(same as num_source).
            UserParamConfigLocalizeMusic.export_num_source = -1; // 3;
            ret = -1;
        }
        else{
            UserParamConfigLocalizeMusic.export_num_source = i_value;
        }
        break;
    case PARAM_LM_SPECTRUM_WEGHT_TYPE:
        switch(i_value){
        case VALUE_LM_SPECTRUM_WEGHT_TYPE_UNIFORM:
            UserParamConfigLocalizeMusic.spectrum_weight_type = Uniform;
            break;
        case VALUE_LM_SPECTRUM_WEGHT_TYPE_A_CHARACTERISTIC:
            UserParamConfigLocalizeMusic.spectrum_weight_type = A_Characteristic;
            break;
        case VALUE_LM_SPECTRUM_WEGHT_TYPE_MANUAL_SPLINE:
            UserParamConfigLocalizeMusic.spectrum_weight_type = Manual_Spline;
            break;
        case VALUE_LM_SPECTRUM_WEGHT_TYPE_MANUAL_SQUARE:
            UserParamConfigLocalizeMusic.spectrum_weight_type = Manual_Square;
            break;
        default: // unsupported type found. default is Uniform.
            UserParamConfigLocalizeMusic.spectrum_weight_type = Uniform;
            ret = -1;
            break;
        }
        break;
    case PARAM_LM_LOW_BOUND_FREQUENCY:
        if((i_value<0)||(i_value>sr)){ // invalid value found, reset to 500.
            UserParamConfigLocalizeMusic.low_bound_frequency = 500;
            ret = -1;
        }
        else{
            UserParamConfigLocalizeMusic.low_bound_frequency = i_value;
        }
        break;
    case PARAM_LM_UPPER_BOUND_FREQUENCY:
        if((i_value<0)||(i_value>sr)){ // invalid value found, reset to 2800.
            UserParamConfigLocalizeMusic.upper_bound_frequency = 2800; // 2000;
            ret = -1;
        }
        else{
            UserParamConfigLocalizeMusic.upper_bound_frequency = i_value;
        }
        break;
    case PARAM_LM_MIN_DEG:
        if((i_value<-360)||(i_value>360)){ // invalid angle found, reset to -180.
            UserParamConfigLocalizeMusic.min_deg = -180;
            ret = -1;
        }
        else{
            UserParamConfigLocalizeMusic.min_deg = i_value;
        }
        break;
    case PARAM_LM_MAX_DEG:
        if((i_value<-360)||(i_value>360)){ // invalid angle found, reset to 180.
            UserParamConfigLocalizeMusic.max_deg = 180;
            ret = -1;
        }
        else{
            UserParamConfigLocalizeMusic.max_deg = i_value;
        }
        break;
    case PARAM_LM_A_CHAR_SCALING:
        if(f_value<=0.0f){ // zero or minus value found, reset to 1.0.
            UserParamConfigLocalizeMusic.a_char_scaling = 1.0f;
            ret = -1;
        }
        else{
            UserParamConfigLocalizeMusic.a_char_scaling = f_value;
        }
        break;
    case PARAM_LM_ENABLE_EIGENVALUE_WEIGHT:
        if(i_value>0){ // i_value: plus=>1, zero_or_minus=>0.
            UserParamConfigLocalizeMusic.enable_eigenvalue_weight = 1;
        }
        else{
            UserParamConfigLocalizeMusic.enable_eigenvalue_weight = 0;
        }
        break;
    case PARAM_LM_SPLINE_NUM:
        if(i_value<0){ // invalid value found, reset to 0.
            UserParamConfigLocalizeMusic.spline_num = 0;
            ret = -1;
        }
        else{
            UserParamConfigLocalizeMusic.spline_num = i_value;
        }
        break;
    case PARAM_LM_SQUARE_NUM:
        if(i_value<0){ // invalid value found, reset to 0.
            UserParamConfigLocalizeMusic.square_num = 0;
            ret = -1;
        }
        else{
            UserParamConfigLocalizeMusic.square_num = i_value;
        }
        break;
    case PARAM_LM_TF_CHANNEL_NUM:
        UserParamConfigLocalizeMusic.tf_channel_num = ARY_NUM_MIC;
        break;
    case PARAM_LM_TF_CHANNEL_SELECTION:
        for(int index=0; index< ARY_NUM_MIC ; index++)
        {
            UserParamConfigLocalizeMusic.tf_channel_selection[index] = index;
        }
        break;
    case PARAM_LM_A_MATRIX:
        if((fp=fopen(file_path, "r"))!=NULL){
            ::strcpy(UserParamConfigLocalizeMusic.a_matrix, file_path);
            fclose(fp);
        }
        else{ // TF file not found, reset to "/mnt/sdcard/hark/mic-ary.dat".
#ifdef IS_ANDROID
            ::strcpy(UserParamConfigLocalizeMusic.a_matrix, "/mnt/sdcard/hark/mic-ary.dat");
#else // IS_ANDROID
#ifdef IS_APPLE_IOS
            ::strcpy(UserParamConfigLocalizeMusic.a_matrix, ::getFilenameWithDocumentsPath("mic-ary.dat"));
#else // IS_APPLE_IOS
            ::strcpy(UserParamConfigLocalizeMusic.a_matrix, "/media/SD/hark/mic-ary.dat");
#endif // IS_APPLE_IOS
#endif // IS_ANDROID
            ret = -2;
        }
        break;
    default:
        ret = -256;
        break;
    }
    // min_deg > max_deg found, swap min_deg and max_deg.
    if(UserParamConfigLocalizeMusic.min_deg>UserParamConfigLocalizeMusic.max_deg){
        int tmp = UserParamConfigLocalizeMusic.min_deg;
        UserParamConfigLocalizeMusic.min_deg = UserParamConfigLocalizeMusic.max_deg;
        UserParamConfigLocalizeMusic.max_deg = tmp;
        ret = -3;
    }
    // low_bound_frequency > upper_bound_frequency found, swap low_bound_frequency and upper_bound_frequency.
    if(UserParamConfigLocalizeMusic.low_bound_frequency>UserParamConfigLocalizeMusic.upper_bound_frequency){
        int tmp = UserParamConfigLocalizeMusic.low_bound_frequency;
        UserParamConfigLocalizeMusic.low_bound_frequency = UserParamConfigLocalizeMusic.upper_bound_frequency;
        UserParamConfigLocalizeMusic.upper_bound_frequency = tmp;
        ret = -3;
    }
    return(ret);
}

// K.Takagi
int ControlObject::SetLocalizeMusicParamNumSource(int num_source)
{
    if((num_source<1)||(num_source>ARY_NUM_MIC-1))
    {
        UserParamConfigLocalizeMusic.num_source = 1;
        return -1;
    }
    UserParamConfigLocalizeMusic.num_source = num_source;

    return 0;
}

int ControlObject::SetLocalizeMusicParamPeriod(int period)
{
    if(period<1)
    {
        UserParamConfigLocalizeMusic.period = 50;
        return -1;
    }
    UserParamConfigLocalizeMusic.period = period;

    return 0;
}

int ControlObject::SetLocalizeMusicParamFrequency(int low_bound_freq, int upper_bound_freq)
{
    int ret;

    ret = 0;

    if(low_bound_freq >= upper_bound_freq)
    {
        return -1;
    }

    if((low_bound_freq<0)||(low_bound_freq>8000))
    {
        UserParamConfigLocalizeMusic.low_bound_frequency = 500;
        ret = -1;
    }
    else
    {
        UserParamConfigLocalizeMusic.low_bound_frequency = low_bound_freq;
    }

    if((upper_bound_freq<0)||(upper_bound_freq>8000))
    {
        UserParamConfigLocalizeMusic.upper_bound_frequency = 2800;
        ret = -1;
    }
    else
    {
        UserParamConfigLocalizeMusic.upper_bound_frequency = upper_bound_freq;
    }

    return ret;
}

int ControlObject::SetLocalizeMusicParamDeg(int min_deg, int max_deg)
{
    int ret;

    if(min_deg >= max_deg)
    {
        return -1;
    }

    if((min_deg<-360)||(min_deg>360))
    {
        UserParamConfigLocalizeMusic.min_deg = -180;
        ret = -1;
    }
    else
    {
        UserParamConfigLocalizeMusic.min_deg = min_deg;
    }

    if((max_deg<-360)||(max_deg>360))
    {
        UserParamConfigLocalizeMusic.max_deg = 180;
        ret = -1;
    }
    else
    {
        UserParamConfigLocalizeMusic.max_deg = max_deg;
    }

    return ret;
}

int ControlObject::SetLocalizeMusicParamFilePath(const char *file_name)
{
    ::strcpy(UserParamConfigLocalizeMusic.a_matrix, file_name);
    return 0;
}

int ControlObject::SetSourceTrackerParamThresh(float thresh)
{
    if(thresh < 0.0f){
        UserParamConfigSourceTracker.thresh = _THRESH_VAL_;
        return -1;
    }
    UserParamConfigSourceTracker.thresh = thresh;
    return 0;
}

int ControlObject::SetSourceTrackerParamPauseLength(float pause_length)
{
    if(pause_length < 0.0f){
        UserParamConfigSourceTracker.pause_length = 800.0f;
        return -1;
    }
    UserParamConfigSourceTracker.pause_length = pause_length;
    return 0;
}

int ControlObject::SetSourceTrackerParamMinSrcInterval(float min_src_interval)
{
    if(min_src_interval < 0.0f){
        UserParamConfigSourceTracker.min_src_interval = 20.0f;
        return -1;
    }
    UserParamConfigSourceTracker.min_src_interval = min_src_interval;
    return 0;
}

int ControlObject::SetSourceIntervalExtenderParam(int preroll_length)
{
    if(preroll_length < 0){
        UserParamConfigSourceIntervalExtender.preroll_length = 50;
        return -1;
    }
    UserParamConfigSourceIntervalExtender.preroll_length = preroll_length;
    return 0;
}

int ControlObject::SetInputParamPCMFilePath(const char *file_name)
{
    ::strcpy(UserParamConfigInput_pcm_file_name, file_name);
    return 0;
}
int ControlObject::SetOutputParamMicPCMFilePath(const char *file_name)
{
    ::strcpy(UserParamConfigSave_input_pcm_file_name, file_name);
    return 0;
}
int ControlObject::SetOutputParamPowSpecFilePath(const char *file_name)
{
    ::strcpy(UserParamConfigSave_output_pow_spec_file_name, file_name);
    return 0;
}
int ControlObject::SetOutputParamSepPCMFilePath(const char *file_name)
{
    ::strcpy(UserParamConfigSave_output_pcm_file_name, file_name);
    return 0;
}
int ControlObject::SetOutputParamSepPCMTMPFilePath(const char *file_name)
{
    ::strcpy(UserParamConfigSave_output_pcm_tmp_file_name, file_name);
    return 0;
}
int ControlObject::SetOutputParamSepFeatureFilePath(const char *file_name)
{
    ::strcpy(UserParamConfigSave_output_feature_file_name, file_name);
    return 0;
}
int ControlObject::SetOutputParamSourceFilePath(const char *file_name)
{
    ::strcpy(UserParamConfigSave_output_source_file_name, file_name);
    return 0;
}

int ControlObject::SetGhdssParamFilePath(const char *file_name)
{
    ::strcpy(UserParamConfigGhdss_sep_tf_file_name, file_name);
    return 0;
}

int ControlObject::SetEstimateLeakParamFactor(float factor)
{
    UserParamConfigEstimateLeak.leak_factor = factor;
    return 0;
}

int ControlObject::SetHrleParamLx(float lx)
{
    UserParamConfigHrle.lx = lx;
    return 0;
}

int ControlObject::SetHrleParamTr(float tr)
{
    UserParamConfigHrle.tr = tr;
    return 0;
}

int ControlObject::SetHrleParamMinLv(float min_lv)
{
    UserParamConfigHrle.min_lv = min_lv;
    return 0;
}

int ControlObject::SetHrleParamStepLv(float step_lv)
{
    UserParamConfigHrle.step_lv = step_lv;
    return 0;
}

int ControlObject::SetHrleParamNumBin(int num_bin)
{
    UserParamConfigHrle.num_bin = num_bin;
    return 0;
}

int ControlObject::SetWhiteNoiseAdderParamLevel(float wn_level)
{
    UserParamConfigWhiteNoiseAdder.wn_level = wn_level;
    return 0;
}

int ControlObject::SetPreEmphasisParamCutoff(int cut_off)
{
    UserParamConfigPreEmphasis.cutoff = cut_off;
    return 0;
}

int ControlObject::SetPreEmphasisParamCoef(float coef)
{
    UserParamConfigPreEmphasis.preem_coef = coef;
    return 0;
}

int ControlObject::SetMelFilterParamCutoff(int cut_off)
{
    UserParamConfigMelFilterBank.cutoff = cut_off;
    return 0;
}

int ControlObject::SetMelFilterParamFreq(int min_freq, int max_freq)
{
    UserParamConfigMelFilterBank.min_frequency = min_freq;
    UserParamConfigMelFilterBank.max_frequency = max_freq;
    return 0;
}


int ControlObject::SetExtendedSourceTrackerParamThresh(float thresh)
{
    UserParamConfigExtendedSourceTracker.thresh = thresh;
    return 0;
}
int ControlObject::SetExtendedSourceTrackerParamPauseLength(int pause_length)
{
    UserParamConfigExtendedSourceTracker.pause_length = pause_length;
    return 0;
}
int ControlObject::SetExtendedSourceTrackerParamRemoveLength(int remove_length)
{
    UserParamConfigExtendedSourceTracker.remove_length = remove_length;
    return 0;
}
int ControlObject::SetExtendedSourceTrackerParamRemoveCheckLength(int remove_check_length)
{
    UserParamConfigExtendedSourceTracker.remove_check_length = remove_check_length;
    return 0;
}
int ControlObject::SetExtendedSourceTrackerParamCompareMode(int compare_mode)
{
    UserParamConfigExtendedSourceTracker.compare_mode = compare_mode;
    return 0;
}
int ControlObject::SetExtendedSourceTrackerParamMinSrcInterval(float min_src_interval)
{
    UserParamConfigExtendedSourceTracker.min_src_interval = min_src_interval;
    return 0;
}
int ControlObject::SetExtendedSourceTrackerParamMinTFIndexInterval(int min_tfindex_interval)
{
    UserParamConfigExtendedSourceTracker.min_tfindex_interval = min_tfindex_interval;
    return 0;
}
int ControlObject::SetExtendedSourceTrackerParamMaxNumSource(int max_num_source)
{
    UserParamConfigExtendedSourceTracker.max_num_source = max_num_source;
    return 0;
}
int ControlObject::SetExtendedSourceTrackerParamPrerollLength(int preroll_length)
{
    UserParamConfigExtendedSourceTracker.preroll_length = preroll_length;
    return 0;
}
int ControlObject::SetExtendedSourceTrackerParamRemovedSourceAlgorithm(int removed_source_algorithm)
{
    UserParamConfigExtendedSourceTracker.removed_source_algorithm = removed_source_algorithm;
    return 0;
}
int ControlObject::SetExtendedSourceTrackerParamMinID(int min_id)
{
    UserParamConfigExtendedSourceTracker.min_id = min_id;
    return 0;
}
int ControlObject::SetNormalizeMusicParamInitialThreshold(float initial_threshold)
{
    UserParamConfigNormalizeMusic.initial_threshold = initial_threshold;
    return 0;
}
int ControlObject::SetNormalizeMusicParamActiveProp(float active_prop)
{
    UserParamConfigNormalizeMusic.active_prop = active_prop;
    return 0;
}
int ControlObject::SetNormalizeMusicParamUpdateInterval(int update_interval)
{
    UserParamConfigNormalizeMusic.update_interval = update_interval;
    return 0;
}
int ControlObject::SetNormalizeMusicParamPriorWeight(float prior_weight)
{
    UserParamConfigNormalizeMusic.prior_weight = prior_weight;
    return 0;
}
int ControlObject::SetNormalizeMusicParamMaxSourceNum(int max_source_num)
{
    UserParamConfigNormalizeMusic.max_source_num = max_source_num;
    return 0;
}
int ControlObject::SetNormalizeMusicParamParticleNum(int particle_num)
{
    UserParamConfigNormalizeMusic.particle_num = particle_num;
    return 0;
}
int ControlObject::SetNormalizeMusicParamLocalPeakMargin(float local_peak_margin)
{
    UserParamConfigNormalizeMusic.local_peak_margin = local_peak_margin;
    return 0;
}
int ControlObject::SetBeamformingParamBFMethod(int bf_method)
{
    UserParamConfigBeamforming.bf_method = bf_method;
    return 0;
}
int ControlObject::SetBeamformingParamTFConjFilePath(const char *file_name)
{
    ::strcpy(UserParamConfigBeamforming_sep_tf_file_name, file_name);
    return 0;
}
int ControlObject::SetBeamformingParamLCMethod(int lc_method)
{
    UserParamConfigBeamforming.lc_method = lc_method;
    return 0;
}
int ControlObject::SetBeamformingParamLCMyu(float lc_myu)
{
    UserParamConfigBeamforming.lc_myu = lc_myu;
    return 0;
}
int ControlObject::SetBeamformingParamSSMethod(int ss_method)
{
    UserParamConfigBeamforming.ss_method = ss_method;
    return 0;
}
int ControlObject::SetBeamformingParamSSMyu(float ss_myu)
{
    UserParamConfigBeamforming.ss_myu = ss_myu;
    return 0;
}
int ControlObject::SetBeamformingParamSSScale(float ss_scal)
{
    UserParamConfigBeamforming.ss_scal = ss_scal;
    return 0;
}
int ControlObject::SetBeamformingParamDecompositionAlgorithm(int decomposition_algorithm)
{
    UserParamConfigBeamforming.decomposition_algorithm = decomposition_algorithm;
    return 0;
}
int ControlObject::SetBeamformingParamNlFunc(int nl_func)
{
    UserParamConfigBeamforming.nl_func = nl_func;
    return 0;
}
int ControlObject::SetBeamformingParamAlpha(float alpha)
{
    UserParamConfigBeamforming.alpha = alpha;
    return 0;
}
int ControlObject::SetBeamformingParamRegFactor(float reg_factor)
{
    UserParamConfigBeamforming.reg_factor = reg_factor;
    return 0;
}


int ControlObject::SetConstantLocalization(int cmd_param_id, int i_value, float* f_ar_value)
{
    int ret = 0;

    switch(cmd_param_id){
    case PARAM_LM_CONSTANT:
        if((i_value<0)||(i_value>16)){
            UserParamConstantLocalization.source_num = 0;
            ret = -1;
        }
        else{
            UserParamConstantLocalization.source_num = i_value;
            for(int i=0, j=0; i<i_value; i++, j+=2){
                UserParamConstantLocalization.angle[i]      = *(f_ar_value+j);
                UserParamConstantLocalization.elevations[i] = *(f_ar_value+j+1);
            }
        }
        break;
    default:
        ret = -256;
        break;
    }
    return(ret);
}

int ControlObject::SetConstantLocalizationFilter(int cmd_param_id, int i_value, float* f_ar_value)
{
    int ret = 0;

    switch(cmd_param_id){
    case PARAM_LM_CONSTANT_FILTER:
        if((i_value<0)||(i_value>16)){
//            UserParamConstantLocalizationFilter.source_num = -1;
            ret = -1;
        }
        else{
//            UserParamConstantLocalizationFilter.source_num = i_value;
            for(int i=0, j=0; i<i_value; i++, j+=2){
//                UserParamConstantLocalizationFilter.angle[i]      = *(f_ar_value+j);
//                UserParamConstantLocalizationFilter.elevations[i] = *(f_ar_value+j+1);
            }
        }
        break;
    default:
        ret = -256;
        break;
    }
    return(ret);
}

int ControlObject::init_lm(const bool hw_avail)
{
    /* LocalizeMUSICのパラメータ設定 */
    ::Param_LocalizeMUSIC_t music_param;
    //music_param.music_algorithm = SEVD;
    music_param.music_algorithm = GSVD;
    music_param.length = ARY_NUM_WAVE; // 512
    music_param.sampling_rate = DEFAULT_SAMPLING_RATE; // 16000
    music_param.window = 50;
    //music_param.window = 20;
    //music_param.period = 50; // original HARK default
    //music_param.period = 1;
    music_param.period = 25;
    music_param.elevation = 15; // サンプルネットワーク
    music_param.num_source = 1;
    //music_param.num_source = 2;
    //music_param.num_source = 3;
    music_param.export_num_source = 3; // PowerPeakの検出数：出力する最大Source数（マイクch数が少ない場合対策）
    music_param.spectrum_weight_type = Uniform;
    music_param.low_bound_frequency   = 500;
    music_param.upper_bound_frequency = 2800;
    //music_param.upper_bound_frequency = 2000;
#ifdef SSL_ONLY_FRONT_SIDE
    //music_param.min_deg = -150;
    //music_param.max_deg = -30;
    music_param.min_deg = -60;
    music_param.max_deg = 60;
#else // Not SSL_ONLY_FRONT_SIDE
    music_param.min_deg = -180;
    music_param.max_deg = 180;
    //music_param.min_deg = -150;
    //music_param.max_deg = 150;
#endif // End of SSL_ONLY_FRONT_SIDE
    music_param.a_char_scaling = 1.0;
    music_param.enable_eigenvalue_weight = 1;
    music_param.spline_num = 0;
    music_param.square_num = 0;

    /*
    music_param.tf_channel_num = ARY_NUM_MIC;
    for(int index=0; index< ARY_NUM_MIC ; index++){
        music_param.tf_channel_selection[index] = index;
    }
    */
    music_param.tf_channel_num = audio_info.logical_channel_count;
    for(int index=0; index< music_param.tf_channel_num; index++){
        music_param.tf_channel_selection[index] = index;
    }
    //LOGD("audio_info.logical_channel_count = %d (%d)", audio_info.logical_channel_count, ARY_NUM_MIC);

#ifdef NEVER
#ifdef IS_APPLE_IOS
    if(hw_avail){
        ::strcpy(music_param.a_matrix, ::getFilenameWithDocumentsPath("mic-ary.dat"));
        //::strcpy(music_param.a_matrix, ::getFilenameWithDocumentsPath("mic-ary_l.dat")); // L字マイク
    }else{
        ::strcpy(music_param.a_matrix, ::getFilenameWithDocumentsPath("loc_tf.dat"));
    }
    LOGD("reading %s", music_param.a_matrix);
#else // IS_APPLE_IOS
#ifdef ENABLE_ANDROID_PATH
    if(hw_avail){
        ::strcpy(music_param.a_matrix, "/mnt/sdcard/hark/mic-ary.dat");
        //::strcpy(music_param.a_matrix, "/mnt/sdcard/hark/mic-ary_l.dat"); // L字マイク
    }else{
        ::strcpy(music_param.a_matrix, "/mnt/sdcard/hark2/loc_tf.dat");
    }
    LOGD("reading %s", music_param.a_matrix);
#else // ENABLE_ANDROID_PATH
    if(hw_avail){
        ::strcpy(music_param.a_matrix, "/media/SD/hark/mic-ary.dat");
        //::strcpy(music_param.a_matrix, "/media/SD/hark/mic-ary_l.dat"); // L字マイク
    }else{
        ::strcpy(music_param.a_matrix, "/media/SD/hark2/loc_tf.dat");
    }
    LOGD("reading %s", music_param.a_matrix);
#endif // ENABLE_ANDROID_PATH
#endif // IS_APPLE_IOS
#endif // NEVER

    LOGI("LM User Param");
    LOGD(" num_source = %d", UserParamConfigLocalizeMusic.num_source);
    LOGD(" period     = %d", UserParamConfigLocalizeMusic.period);
    LOGD(" freq       = %d , %d", UserParamConfigLocalizeMusic.low_bound_frequency, UserParamConfigLocalizeMusic.upper_bound_frequency);
    LOGD(" deg        = %d , %d", UserParamConfigLocalizeMusic.min_deg, UserParamConfigLocalizeMusic.max_deg);
    LOGD(" loc_tf     = %s", UserParamConfigLocalizeMusic.a_matrix);

    LOGI("ST User Param");
    LOGD(" thresh           = %f", UserParamConfigSourceTracker.thresh);
    LOGD(" pause_length     = %f", UserParamConfigSourceTracker.pause_length);
    LOGD(" min_src_interval = %f", UserParamConfigSourceTracker.min_src_interval);

    LOGI("SI User Param");
    LOGD(" preroll_length   = %d", UserParamConfigSourceIntervalExtender.preroll_length);

    /* 平滑化のためのスペクトル加算は負荷分散のため各フレームで処理するのでwindow=period */
    music_param.num_source = UserParamConfigLocalizeMusic.num_source;
    music_param.window = UserParamConfigLocalizeMusic.period;
    music_param.period = UserParamConfigLocalizeMusic.period;
    music_param.low_bound_frequency   = UserParamConfigLocalizeMusic.low_bound_frequency;
    music_param.upper_bound_frequency = UserParamConfigLocalizeMusic.upper_bound_frequency;
    music_param.min_deg = UserParamConfigLocalizeMusic.min_deg;
    music_param.max_deg = UserParamConfigLocalizeMusic.max_deg;

    setFullPath(music_param.a_matrix, UserParamConfigLocalizeMusic.a_matrix);
#ifdef NEVER // ファイル入力に対しても伝達関数を変更したいのでユーザ設定を使う
    /* デバイスがある場合 a_matrix のファイルパスもここで設定する */
    if(hw_avail){
        LOGD("reading %s", UserParamConfigLocalizeMusic.a_matrix);
#ifdef IS_APPLE_IOS
        ::strcpy(music_param.a_matrix, ::getFilenameWithDocumentsPath(UserParamConfigLocalizeMusic.a_matrix));
#else // IS_APPLE_IOS
        ::strcpy(music_param.a_matrix, UserParamConfigLocalizeMusic.a_matrix);
#endif // IS_APPLE_IOS
    }
#endif

    ::HASetParamLocalizeMUSIC(&music_param);

    /* 固定位置音源のパラメータ設定 */
    ::Param_ConstantLocalization_t const_location_param;
    //const_location_param.source_num = 3;
    //const_location_param.angle[0] = 0.0;
    //const_location_param.angle[1] = 30.0;
    //const_location_param.angle[2] = 90.0;
    //const_location_param.elevations[0] = 0.0;
    //const_location_param.elevations[1] = 0.0;
    //const_location_param.elevations[2] = 0.0;
    //Front side and L/R 30 deg
    const_location_param.source_num = 3;
    const_location_param.angle[0] = -60.0;
    const_location_param.angle[1] = 0.0;
    const_location_param.angle[2] = 60.0;
    const_location_param.elevations[0] = 0.0;
    const_location_param.elevations[1] = 0.0;
    const_location_param.elevations[2] = 0.0;
    const_location_param.mask[0] = Mask_Use_Localize | Mask_Use_Separation;
    const_location_param.mask[1] = Mask_Use_Localize | Mask_Use_Separation | Mask_Use_Output;
    const_location_param.mask[2] = Mask_Use_Localize | Mask_Use_Separation;
    //Only front side
    //const_location_param.source_num = 1;
    //const_location_param.angle[0] = 0.0;
    //const_location_param.elevations[0] = 0.0;

    int stat = HASetParamConstantLocalization(&const_location_param);
    ::HAInitConstantLocalization();

    ///* 出力フィルタ用の固定位置音源のパラメータ設定 */
    //::Param_ConstantLocalization_t filter_location_param;
    //filter_location_param.source_num = 1;
    //filter_location_param.angle[0] = 0.0;
    //filter_location_param.elevations[0] = 0.0;

    //stat = HASetParamConstantLocalizationFilter(&filter_location_param);
    //::HAInitConstantLocalizationFilter();

    /* SourceTrackerのパラメータ設定 */
    ::Param_SourceTracker_t source_tracker_param;
    if (!hw_avail) {
        //source_tracker_param.thresh           = 29.5; // for order demo
        //source_tracker_param.thresh           = 24.0;
        source_tracker_param.thresh = UserParamConfigSourceTracker.thresh;
    } else {
        //source_tracker_param.thresh           = 27.0; // 2src best
        //source_tracker_param.thresh           = 28.0; // 1src best
        //source_tracker_param.thresh           = 38.0; // L字マイク用（MultiGain処理なし）
        //source_tracker_param.thresh           = 31.0; // PS-EYE 1src best
        //source_tracker_param.thresh           = _THRESH_VAL_;
        source_tracker_param.thresh = UserParamConfigSourceTracker.thresh;
    }

    // TAKIGAHIRA
    //source_tracker_param.pause_length     = 2000; // for AudioVisualiser
    //source_tracker_param.pause_length     = 800; // original HARK default
    //source_tracker_param.pause_length     = 400;
    source_tracker_param.pause_length     = UserParamConfigSourceTracker.pause_length;
    // NAKAMURA
    //source_tracker_param.min_src_interval = 180; // for AudioVisualiser
    //source_tracker_param.min_src_interval = 50;
    //source_tracker_param.min_src_interval = 20;
    source_tracker_param.min_src_interval = UserParamConfigSourceTracker.min_src_interval;
    source_tracker_param.min_id           = 0;

    ::HASetParamSourceTracker(&source_tracker_param);
    ::HAInitSourceTracker();

    ::Param_SourceIntervalExtender_t source_interval_extender_param;
    //source_interval_extender_param.preroll_length = 50;
    source_interval_extender_param.preroll_length = UserParamConfigSourceIntervalExtender.preroll_length;

    ::HASetParamSourceIntervalExtender(&source_interval_extender_param);

    /* データ中継用のバッファ初期化 */
    //::HABufferSetParam(ARY_NUM_MIC, (512/2 + 1));
    //::HABufferSetParam(audio_info.logical_channel_count, (512/2 + 1));
    ::HABufferSetParam(audio_info.logical_channel_count, ARY_NUM_FFT);


    stat = ::HABufferInit();
    if(stat != 0){ LOGE("HABuffer Allocate Error.\n"); return -1; }
    ::HABufferClear();

    // LocalizeMUSICの初期化
    stat = ::HAInitLocalizeMUSIC();
    if(stat != 0){ LOGE("HAInitLocalizeMUSIC Error.\n"); return -1; }

    return(0);
}

int ControlObject::Lm(const int thread_no, COMPLEX_FLOAT **fftdata, SOURCE_DATA_ARY_t &ary, SOURCE_DATA_ARY_t &filter_ary, bool &valid_source, char* ts)
{
    //valid_source = false;

    //::Param_AudioStreamFromMic_t param;
    //::HAGetParamAudioStreamFromMic(&param);
    ::Param_AudioStreamFromMic_t param = audio_info;

    //LOGD("wait for lm %d", thread_no);

    WaitLm(thread_no);

    //LOGD(" WaitLm pass[%d] : %d", LmCount, thread_no);

    ::FFT_DATA_ARY_t fft_data_ary;
    fft_data_ary.data = fftdata;

    int stat = ::HABufferSetFFTData(LmCount, &fft_data_ary);
    //LOGI("[%d] HABufferSetFFTData", LmCount);

    //if(UseSourceFilter){
    //    stat = ::HAGetConstantLocalizationFilter(LmCount, &filter_ary);
    //}

    /* 音源定位 */
    if(LocalizeAlgorithm == LOC_CONSTANT){
        stat = ::HAGetConstantLocalization(LmCount, &ary);
    }
    else if(LocalizeAlgorithm == LOC_MUSIC_FILTER){
        // MUSIC Speech Interval Detection mode
        // 発話区間の検出にLocalizeMUSICを使用したいが、ConstantLocalizationのように定位方向を限定したい場合
        // LocalizeMUSICの定位結果をConstantLocalizationに指定した方向でフィルタ出来るようにするためのモード
        // 仕様について：
        //   ConstantLocalizationで指定された方向に近い方向のみ出力し、その他はpowerを0.0でOverwriteする

        SOURCE_DATA_ARY_t target_direc;
        // LocalizeMUSICでTrackする対象音源をConstantLocalozationから取得する
        stat = ::HAGetConstantLocalization(LmCount, &target_direc);
        if(stat >= 0){
            //{
            //const double start = current_ms();
            ::LocalizeMUSIC(LmCount, &ary);
            //const double end = current_ms();
            //LOGD("LcalizeMUSIC LmCount %d", LmCount);
            //LOGI("LcalizeMUSIC time elapsed = %f ms", end - start);
            //LOGD("LcalizeMUSIC LmCount %d power = %f remaining %f", LmCount, ary->data[0].power, ary->data[0].remaining);
            //LOGD("t %d source_num1 %d", thread_no, ary->source_num);
            //}

            /*
            LOGI("LocalizeMUSIC LmCount %d", LmCount);
            LOGD("  source_num %d", ary.source_num);
            for(int i=0; i<ary.source_num; i++)
            {
                LOGD("[%d] : power = %f", i, ary.data[i].power);
            }
             */

            /* 音源追跡 */
            ::SourceTrackerWithFilter(LmCount, &ary, &target_direc);
            //LOGI("SourceTracker Src Num = %d", ary.source_num );

            /* 検出音源の出力タイミングを調整
             ** 現在のフレーム位置と指定数前のフレーム位置に音源情報をキューイング
             ** 指定数前のフレーム位置の音源情報によりGHDSS以降の処理が可能
             ** 引数aryは指定数前の音源情報に置き換えられる
             */
            stat = ::SourceIntervalExtender(LmCount, &ary);
            //LOGD("C  source_num %d", target_direc.source_num);
            //for(int i=0; i<target_direc.source_num; i++){
            //  LOGD("C [%d] : power = %f", i, target_direc.data[i].power);
            //}
            //LOGD("M  source_num %d", ary.source_num);
            //for(int i=0; i<ary.source_num; i++){
            //  LOGD("M [%d] : power = %f", i, ary.data[i].power);
            //}
        }
    }
    else{ // default is LOC_MUSIC
        //{
        //const double start = current_ms();
        ::LocalizeMUSIC(LmCount, &ary);
        //const double end = current_ms();
        //LOGD("LcalizeMUSIC LmCount %d", LmCount);
        //LOGI("LcalizeMUSIC time elapsed = %f ms", end - start);
        //LOGD("LcalizeMUSIC LmCount %d power = %f remaining %f", LmCount, ary->data[0].power, ary->data[0].remaining);
        //LOGD("t %d source_num1 %d", thread_no, ary->source_num);
        //}

        /*
        LOGI("LocalizeMUSIC LmCount %d", LmCount);
        LOGD("  source_num %d", ary.source_num);
	 */
        /*
        if(ary.source_num > 0)
        {
        LOGI("LocalizeMUSIC LmCount %d", LmCount);
            for(int i=0; i<ary.source_num; i++)
            {
                LOGD("[%d] : power = %f", i, ary.data[i].power);
            }
        }
        */

        /* 音源追跡 */
        ::SourceTracker(LmCount, &ary);
        //LOGI("SourceTracker Src Num = %d", ary.source_num );

        /* 検出音源の出力タイミングを調整
        ** 現在のフレーム位置と指定数前のフレーム位置に音源情報をキューイング
        ** 指定数前のフレーム位置の音源情報によりGHDSS以降の処理が可能
        ** 引数aryは指定数前の音源情報に置き換えられる
        */
        stat = ::SourceIntervalExtender(LmCount, &ary);
    }
    if(stat < 0){
        valid_source = false;
    }
    else{
        valid_source = true;
        /*
        LOGD("SourceIntervalExtender LmCount %d ary.count = %d", LmCount, ary.count);
        LOGD("t %d source_num2 %d", thread_no, ary.source_num);
        if(ary.source_num == 1) LOGD("IDs = %d", ary.data[0].id);
        else if(ary.source_num == 2) LOGD("IDs = %d , %d", ary.data[0].id, ary.data[1].id);
        else if(ary.source_num == 3) LOGD("IDs = %d , %d , %d", ary.data[0].id, ary.data[1].id, ary.data[2].id);
        */
    }
    //LOGI("[%d] SourceIntervalExtender (%d)", LmCount, ary.count );

    //LOGD("SourceIntervalExtender LmCount %d power = %f", LmCount, ary->data[0].power);
    //LOGD("t %d source_num2 %d remainig %f", thread_no, ary->source_num, ary->data[0].remaining);
    /*
    LOGD("source_num %d", ary.source_num);
    for(int k=0; k<ary.source_num; k++)
    {
        LOGI("  %f, %f", ary.data[k].x[0], ary.data[k].x[1]);
    }
    */

    ::HD_Header hdr;
    hdr.type = PACKET_SRC_INFO;
    hdr.advance = param.advance;
    //hdr.count = LmCount++;
    hdr.count = ary.count; /* 2013.02.06 K.Takagi 送信する音源のフレーム番号を送る */
    LmCount++;

    //LOGD(" GoNextLm[%d] : %d", LmCount-1, thread_no);

    GoNextLm(thread_no);

    ::HDH_SrcInfo srcinfo[ARY_NUM_SRC];
    const int num_src = std::min(ary.source_num, static_cast<int>(NELEM(srcinfo)));
    int new_i = 0;
    if(SendPort & SEND_PORT_C){
        if(valid_source){
            if(UseSourceFilter & SRC_FILTER_USE_PORT_C){
                // TAKIGAHIRA : modified code for use mask
                //for(int i = 0; i < num_src; i++) {
                //    for(int j = 0; j < filter_ary.source_num; j++) {
                //        //LOGD("org %d %f %f %f ************************************************", i, ary.data[i].x[0], ary.data[i].x[1], ary.data[i].x[2]);
                //        //LOGD("flt %d %f %f %f ************************************************", i, filter_ary.data[j].x[0], filter_ary.data[j].x[1], filter_ary.data[j].x[2]);
                //        if((filter_ary.data[j].x[0] == ary.data[i].x[0])
                //        && (filter_ary.data[j].x[1] == ary.data[i].x[1])
                //        && (filter_ary.data[j].x[2] == ary.data[i].x[2])) {
                //            srcinfo[new_i].src_id = ary.data[i].id;
                //            srcinfo[new_i].x[0] = ary.data[i].x[0];
                //            srcinfo[new_i].x[1] = ary.data[i].x[1];
                //            srcinfo[new_i].x[2] = ary.data[i].x[2];
                //            srcinfo[new_i].power = ary.data[i].power;
                //            //LOGD("sending count %d %f %f %f ************************************************", new_i, srcinfo[new_i].x[0], srcinfo[new_i].x[1], srcinfo[new_i].x[2]);
                //            new_i++;
                //            j = filter_ary.source_num;
                //        }
                //    }
                //}
                for(int i = 0; i < num_src; i++){
                    if(ary.data[i].mask & Mask_Use_Localize){
                        srcinfo[new_i].src_id = ary.data[i].id;
                        srcinfo[new_i].x[0] = ary.data[i].x[0];
                        srcinfo[new_i].x[1] = ary.data[i].x[1];
                        srcinfo[new_i].x[2] = ary.data[i].x[2];
                        srcinfo[new_i].power = ary.data[i].power;
                        //LOGD("sending count %d %f %f %f ************************************************", i, srcinfo[i].x[0], srcinfo[i].x[1], srcinfo[i].x[2]);
                        new_i++;
                    }
                }
            }
            else{
                for(int i = 0; i < num_src; i++){
                    srcinfo[i].src_id = ary.data[i].id;
                    srcinfo[i].x[0] = ary.data[i].x[0];
                    srcinfo[i].x[1] = ary.data[i].x[1];
                    srcinfo[i].x[2] = ary.data[i].x[2];
                    srcinfo[i].power = ary.data[i].power;
                    //LOGD("sending count %d %f %f %f ************************************************", i, srcinfo[i].x[0], srcinfo[i].x[1], srcinfo[i].x[2]);
                }
                new_i = num_src;
            }
        }
    }
    //LOGD("wait for lm send %d", thread_no);
    WaitSendLm(thread_no);
    //LOGD(" WaitSendLm pass[%d] : %d", LmCount-1, thread_no);

    if(SendPort & SEND_PORT_C){
        // 2013.02.06 K.Takagi 音源が有効になってから送信する
        if(valid_source){
            //LOGD("sending count %d %d", hdr.count, ary->source_num);
            if(UseTimeStamp & TIMESTAMP_USE_PORT_C){
                SendPortCwithTS(&hdr, new_i, srcinfo, ts);
            }
            else{
                SendPortC(&hdr, new_i, srcinfo);
            }
        }
    }
    //LOGD(" GoNextSendLm[%d] : %d", LmCount-1, thread_no);
    GoNextSendLm(thread_no);
    return(0);
}

int ControlObject::checkid(SOURCE_DATA_ARY_t *pre_src, int num, int id)
{
    int flag = NEW_ID;
    for(int i=0; i<num; i++){
        if(i<pre_src->source_num){ // 2014.11.20 K.Takagi
            if(pre_src->data[i].id == id){ flag = EXISTING_ID; break; } // TAKIGAHIRA : break追加
        }
    }
    return(flag);
}

int ControlObject::checkterminate(int pre_id, int src_num, const SOURCE_DATA_ARY_t &ary)
{
    int flag = TERMINATED_ID;
    for(int i=0; i<src_num; i++){
        if(ary.data[i].id == pre_id){ flag = EXISTING_ID; break; } // TAKIGAHIRA : break追加
    }
    return(flag);
}

int ControlObject::writerawdata(HA_Float write_data[ARY_NUM_SRC][ARY_NUM_WAVE], int index, int id, int flag)
{
    char fname[ARY_PATH_LENGTH];
    FILE *fp = NULL;
    //short int write_data_sint[_ADVANCE_VAL_]; // write_data_sint  ==> write_data_multibit.buf_ss
    //HA_Float write_data_float[_ADVANCE_VAL_]; // write_data_float ==> write_data_multibit.buf_hf

    // 後できれいに書き換える
    const int num_wave  = ARY_NUM_WAVE;
    const int advance   = audio_info.advance;
    const int remaining = num_wave - advance;
    const int device_bits = audio_info.nbits; // selectedDeviceObj->GetBits(); //test
    union multibit {
        HA_Float      buf_hf[_ADVANCE_VAL_];
        int           buf_si[_ADVANCE_VAL_];
        short int     buf_ss[_ADVANCE_VAL_*2];
        unsigned char buf_uc[_ADVANCE_VAL_*4];
    } write_data_multibit ;
    int i, j, k;

    switch(flag){
    case NEW_ID:
        //LOGE("NEW_ID -s-: %d", id);
        switch(SaveSepRaw){
        case PCM_WAV_SINT16:
            switch(device_bits){
            case 16:
                for(j = 0; j < advance; j++){ write_data_multibit.buf_ss[j] = (short int)(write_data[index][j]); }
                break;
            case 24:
                for(j = 0; j < advance; j++){ write_data_multibit.buf_ss[j] = (short int)(((int)(write_data[index][j])) >> 8); }
                break;
            case 32:
                for(j = 0; j < advance; j++){ write_data_multibit.buf_ss[j] = (short int)(((int)(write_data[index][j])) >> 16); }
                break;
            case 0: // if use no bit convert option
            default:
                for(j = 0; j < advance; j++){ write_data_multibit.buf_ss[j] = (short int)(write_data[index][j]); }
                break;
            }
            sprintf(fname, "%s%03d.%s", UserParamConfigSave_output_pcm_tmp_file_name, id, "wav");
            if((fp = fopen(fname, "wb")) == NULL){
                fprintf(stderr, "file open error!!\n");
                LOGE("file open error, case of SaveSepRaw->NEW_ID->PCM_WAV_SINT16");
            }
            else{
                fwrite(SepWavFileHeader, sizeof(int) * 11, 1, fp);
                fwrite(write_data_multibit.buf_ss, sizeof(short int) * advance, 1, fp);
                fclose(fp);
            }
            break;
        case PCM_WAV_SINT24:
            switch(device_bits){
            case 16:
                for(j=0, k=0; j<advance; j++, k+=3){
                    write_data_multibit.buf_uc[k  ] = 0x00;
                    write_data_multibit.buf_uc[k+1] = (((int) write_data[index][j])      ) & 0xFF;
                    write_data_multibit.buf_uc[k+2] = (((int) write_data[index][j]) >>  8) & 0xFF;
                }
                break;
            case 24:
                for(j=0, k=0; j<advance; j++, k+=3){
                    write_data_multibit.buf_uc[k  ] = (((int) write_data[index][j])      ) & 0xFF;
                    write_data_multibit.buf_uc[k+1] = (((int) write_data[index][j]) >>  8) & 0xFF;
                    write_data_multibit.buf_uc[k+2] = (((int) write_data[index][j]) >> 16) & 0xFF;
                }
                break;
            case 32:
                for(j=0, k=0; j<advance; j++, k+=3){
                    write_data_multibit.buf_uc[k  ] = (((int) write_data[index][j]) >>  8) & 0xFF;
                    write_data_multibit.buf_uc[k+1] = (((int) write_data[index][j]) >> 16) & 0xFF;
                    write_data_multibit.buf_uc[k+2] = (((int) write_data[index][j]) >> 24) & 0xFF;
                }
                break;
            case 0: // if use no bit convert option
            default:
                for(j=0, k=0; j<advance; j++, k+=3){
                    write_data_multibit.buf_uc[k  ] = (((int) write_data[index][j])      ) & 0xFF;
                    write_data_multibit.buf_uc[k+1] = (((int) write_data[index][j]) >>  8) & 0xFF;
                    write_data_multibit.buf_uc[k+2] = (((int) write_data[index][j]) >> 16) & 0xFF;
                }
                break;
            }
            sprintf(fname, "%s%03d.%s", UserParamConfigSave_output_pcm_tmp_file_name, id, "wav");
            if((fp = fopen(fname, "wb")) == NULL){
                fprintf(stderr, "file open error!!\n");
                LOGE("file open error, case of SaveSepRaw->NEW_ID->PCM_WAV_SINT24");
            }
            else{
                fwrite(SepWavFileHeader, sizeof(int) * 11, 1, fp);
                fwrite(write_data_multibit.buf_uc, sizeof(char) * 3 * advance, 1, fp);
                fclose(fp);
            }
            break;
        case PCM_WAV_FLOAT32:
            switch(device_bits){
            case 16:
                for(j = 0; j < advance; j++){ write_data_multibit.buf_hf[j] = (HA_Float)(write_data[index][j] * 0.000030517578125f); }
                break;
            case 24:
                for(j = 0; j < advance; j++){ write_data_multibit.buf_hf[j] = (HA_Float)(write_data[index][j] * 0.00000011920928955078125f); }
                break;
            case 32:
                for(j = 0; j < advance; j++){ write_data_multibit.buf_hf[j] = (HA_Float)(write_data[index][j] * 0.0000000004656612873077392578125f); }
                break;
            case 0: // if use no bit convert option
            default:
                for(j = 0; j < advance; j++){ write_data_multibit.buf_hf[j] = (HA_Float)(write_data[index][j] * 0.0000000004656612873077392578125f); }
                break;
            }
            sprintf(fname, "%s%03d.%s", UserParamConfigSave_output_pcm_tmp_file_name, id, "wav");
            if((fp = fopen(fname, "wb")) == NULL){
                fprintf(stderr, "file open error!!\n");
                LOGE("file open error, case of SaveSepRaw->NEW_ID->PCM_WAV_FLOAT32");
            }
            else{
                fwrite(SepWavFileHeader, sizeof(int) * 11, 1, fp);
                fwrite(write_data_multibit.buf_hf, sizeof(HA_Float) * advance, 1, fp);
                fclose(fp);
            }
            break;
        case PCM_RAW_SINT16:
            switch(device_bits){
            case 16:
                for(j = 0; j < advance; j++){ write_data_multibit.buf_ss[j] = (short int)(write_data[index][j]); }
                break;
            case 24:
                for(j = 0; j < advance; j++){ write_data_multibit.buf_ss[j] = (short int)(((int)(write_data[index][j])) >> 8); }
                break;
            case 32:
                for(j = 0; j < advance; j++){ write_data_multibit.buf_ss[j] = (short int)(((int)(write_data[index][j])) >> 16); }
                break;
            case 0: // if use no bit convert option
            default:
                for(j = 0; j < advance; j++){ write_data_multibit.buf_ss[j] = (short int)(write_data[index][j]); }
                break;
            }
            sprintf(fname, "%s%03d.%s", UserParamConfigSave_output_pcm_tmp_file_name, id, "raw");
            if((fp = fopen(fname, "wb")) == NULL){
                fprintf(stderr, "file open error!!\n");
                LOGE("file open error, case of SaveSepRaw->NEW_ID->PCM_RAW_SINT16");
            }
            else{
                fwrite(write_data_multibit.buf_ss, sizeof(short int) * advance, 1, fp);
                fclose(fp);
            }
            break;
        case PCM_RAW_SINT24:
            switch(device_bits){
            case 16:
                for(j=0, k=0; j<advance; j++, k+=3){
                    write_data_multibit.buf_uc[k  ] = 0x00;
                    write_data_multibit.buf_uc[k+1] = (((int) write_data[index][j])      ) & 0xFF;
                    write_data_multibit.buf_uc[k+2] = (((int) write_data[index][j]) >>  8) & 0xFF;
                }
                break;
            case 24:
                for(j=0, k=0; j<advance; j++, k+=3){
                    write_data_multibit.buf_uc[k  ] = (((int) write_data[index][j])      ) & 0xFF;
                    write_data_multibit.buf_uc[k+1] = (((int) write_data[index][j]) >>  8) & 0xFF;
                    write_data_multibit.buf_uc[k+2] = (((int) write_data[index][j]) >> 16) & 0xFF;
                }
                break;
            case 32:
                for(j=0, k=0; j<advance; j++, k+=3){
                    write_data_multibit.buf_uc[k  ] = (((int) write_data[index][j]) >>  8) & 0xFF;
                    write_data_multibit.buf_uc[k+1] = (((int) write_data[index][j]) >> 16) & 0xFF;
                    write_data_multibit.buf_uc[k+2] = (((int) write_data[index][j]) >> 24) & 0xFF;
                }
                break;
            case 0: // if use no bit convert option
            default:
                for(j=0, k=0; j<advance; j++, k+=3){
                    write_data_multibit.buf_uc[k  ] = (((int) write_data[index][j])      ) & 0xFF;
                    write_data_multibit.buf_uc[k+1] = (((int) write_data[index][j]) >>  8) & 0xFF;
                    write_data_multibit.buf_uc[k+2] = (((int) write_data[index][j]) >> 16) & 0xFF;
                }
                break;
            }
            sprintf(fname, "%s%03d.%s", UserParamConfigSave_output_pcm_tmp_file_name, id, "raw");
            if((fp = fopen(fname, "wb")) == NULL){
                fprintf(stderr, "file open error!!\n");
                LOGE("file open error, case of SaveSepRaw->NEW_ID->PCM_RAW_SINT24");
            }
            else{
                fwrite(write_data_multibit.buf_uc, sizeof(char) * 3 * advance, 1, fp);
                fclose(fp);
            }
            break;
        case PCM_RAW_FLOAT32:
            switch(device_bits){
            case 16:
                for(j = 0; j < advance; j++){ write_data_multibit.buf_hf[j] = (HA_Float)(write_data[index][j] * 0.000030517578125f); }
                break;
            case 24:
                for(j = 0; j < advance; j++){ write_data_multibit.buf_hf[j] = (HA_Float)(write_data[index][j] * 0.00000011920928955078125f); }
                break;
            case 32:
                for(j = 0; j < advance; j++){ write_data_multibit.buf_hf[j] = (HA_Float)(write_data[index][j] * 0.0000000004656612873077392578125f); }
                break;
            case 0: // if use no bit convert option
            default:
                for(j = 0; j < advance; j++){ write_data_multibit.buf_hf[j] = (HA_Float)(write_data[index][j] * 0.0000000004656612873077392578125f); }
                break;
            }
            sprintf(fname, "%s%03d.%s", UserParamConfigSave_output_pcm_tmp_file_name, id, "raw");
            if((fp = fopen(fname, "wb")) == NULL){
                fprintf(stderr, "file open error!!\n");
                LOGE("file open error, case of SaveSepRaw->NEW_ID->PCM_RAW_FLOAT32");
            }
            else{
                fwrite(write_data_multibit.buf_hf, sizeof(HA_Float) * advance, 1, fp);
                fclose(fp);
            }
            break;
        case PCM_RAW_RAWFLOAT:
            sprintf(fname, "%s%03d.%s", UserParamConfigSave_output_pcm_tmp_file_name, id, "raw");
            if((fp = fopen(fname, "wb")) == NULL){
                fprintf(stderr, "file open error!!\n");
                LOGE("file open error, case of SaveSepRaw->NEW_ID->PCM_RAW_RAWFLOAT");
            }
            else{
                fwrite(write_data[index], sizeof(HA_Float) * advance, 1, fp);
                fclose(fp);
            }
            break;
        case PCM_NONE:
        default:
            break;
        }
        for(i = 0; i < advance; i++){
            tcp_data[index][i] = write_data[index][i];
        }
        // data for buffer
        for(j = 0; j < remaining; j++){
            wavedata[index][j] = write_data[index][j+advance];
        }
        // zero padding
        memset(&(wavedata[index][remaining]), 0, sizeof(HA_Float) * advance);
        //LOGE("NEW_ID -e-: %d", id);
        break;
    case EXISTING_ID:
        //LOGE("EXISTING_ID -s-: %d", id);
        // overlap-add
        for(j = 0; j < num_wave; j++){
            wavedata[index][j] += write_data[index][j];
        }
        // data for append
        switch(SaveSepRaw){
        case PCM_WAV_SINT16:
            switch(device_bits){
            case 16:
                for(j = 0; j < advance; j++){ write_data_multibit.buf_ss[j] = (short int)(wavedata[index][j]); }
                break;
            case 24:
                for(j = 0; j < advance; j++){ write_data_multibit.buf_ss[j] = (short int)(((int)(wavedata[index][j])) >> 8); }
                break;
            case 32:
                for(j = 0; j < advance; j++){ write_data_multibit.buf_ss[j] = (short int)(((int)(wavedata[index][j])) >> 16); }
                break;
            case 0: // if use no bit convert option
            default:
                for(j = 0; j < advance; j++){ write_data_multibit.buf_ss[j] = (short int)(wavedata[index][j]); }
                break;
            }
            sprintf(fname, "%s%03d.%s", UserParamConfigSave_output_pcm_tmp_file_name, id, "wav");
            if((fp = fopen(fname, "a")) == NULL){
                fprintf(stderr, "file open error!!\n");
                LOGE("file open error, case of SaveSepRaw->EXISTING_ID->PCM_WAV_SINT16");
            }
            else{
                fwrite(write_data_multibit.buf_ss, sizeof(short int) * advance, 1, fp);
                fclose(fp);
            }
            break;
        case PCM_WAV_SINT24:
            switch(device_bits){
            case 16:
                for(j=0, k=0; j<advance; j++, k+=3){
                    write_data_multibit.buf_uc[k  ] = 0x00;
                    write_data_multibit.buf_uc[k+1] = (((int) wavedata[index][j])      ) & 0xFF;
                    write_data_multibit.buf_uc[k+2] = (((int) wavedata[index][j]) >>  8) & 0xFF;
                }
                break;
            case 24:
                for(j=0, k=0; j<advance; j++, k+=3){
                    write_data_multibit.buf_uc[k  ] = (((int) wavedata[index][j])      ) & 0xFF;
                    write_data_multibit.buf_uc[k+1] = (((int) wavedata[index][j]) >>  8) & 0xFF;
                    write_data_multibit.buf_uc[k+2] = (((int) wavedata[index][j]) >> 16) & 0xFF;
                }
                break;
            case 32:
                for(j=0, k=0; j<advance; j++, k+=3){
                    write_data_multibit.buf_uc[k  ] = (((int) wavedata[index][j]) >>  8) & 0xFF;
                    write_data_multibit.buf_uc[k+1] = (((int) wavedata[index][j]) >> 16) & 0xFF;
                    write_data_multibit.buf_uc[k+2] = (((int) wavedata[index][j]) >> 24) & 0xFF;
                }
                break;
            case 0: // if use no bit convert option
            default:
                for(j=0, k=0; j<advance; j++, k+=3){
                    write_data_multibit.buf_uc[k  ] = (((int) wavedata[index][j])      ) & 0xFF;
                    write_data_multibit.buf_uc[k+1] = (((int) wavedata[index][j]) >>  8) & 0xFF;
                    write_data_multibit.buf_uc[k+2] = (((int) wavedata[index][j]) >> 16) & 0xFF;
                }
                break;
            }
            sprintf(fname, "%s%03d.%s", UserParamConfigSave_output_pcm_tmp_file_name, id, "wav");
            if((fp = fopen(fname, "a")) == NULL){
                fprintf(stderr, "file open error!!\n");
                LOGE("file open error, case of SaveSepRaw->EXISTING_ID->PCM_WAV_SINT24");
            }
            else{
                fwrite(write_data_multibit.buf_uc, sizeof(char) * 3 * advance, 1, fp);
                fclose(fp);
            }
            break;
        case PCM_WAV_FLOAT32:
            switch(device_bits){
            case 16:
                for(j = 0; j < advance; j++){ write_data_multibit.buf_hf[j] = (HA_Float)(wavedata[index][j] * 0.000030517578125f); }
                break;
            case 24:
                for(j = 0; j < advance; j++){ write_data_multibit.buf_hf[j] = (HA_Float)(wavedata[index][j] * 0.00000011920928955078125f); }
                break;
            case 32:
                for(j = 0; j < advance; j++){ write_data_multibit.buf_hf[j] = (HA_Float)(wavedata[index][j] * 0.0000000004656612873077392578125f); }
                break;
            case 0: // if use no bit convert option
            default:
                for(j = 0; j < advance; j++){ write_data_multibit.buf_hf[j] = (HA_Float)(wavedata[index][j] * 0.0000000004656612873077392578125f); }
                break;
            }
            sprintf(fname, "%s%03d.%s", UserParamConfigSave_output_pcm_tmp_file_name, id, "wav");
            if((fp = fopen(fname, "a")) == NULL){
                fprintf(stderr, "file open error!!\n");
                LOGE("file open error, case of SaveSepRaw->EXISTING_ID->PCM_WAV_FLOAT32");
            }
            else{
                fwrite(write_data_multibit.buf_hf, sizeof(HA_Float) * advance, 1, fp);
                fclose(fp);
            }
            break;
        case PCM_RAW_SINT16:
            switch(device_bits){
            case 16:
                for(j = 0; j < advance; j++){ write_data_multibit.buf_ss[j] = (short int)(wavedata[index][j]); }
                break;
            case 24:
                for(j = 0; j < advance; j++){ write_data_multibit.buf_ss[j] = (short int)(((int)(wavedata[index][j])) >> 8); }
                break;
            case 32:
                for(j = 0; j < advance; j++){ write_data_multibit.buf_ss[j] = (short int)(((int)(wavedata[index][j])) >> 16); }
                break;
            case 0: // if use no bit convert option
            default:
                for(j = 0; j < advance; j++){ write_data_multibit.buf_ss[j] = (short int)(wavedata[index][j]); }
                break;
            }
            sprintf(fname, "%s%03d.%s", UserParamConfigSave_output_pcm_tmp_file_name, id, "raw");
            if((fp = fopen(fname, "a")) == NULL){
                fprintf(stderr, "file open error!!\n");
                LOGE("file open error, case of SaveSepRaw->EXISTING_ID->PCM_RAW_SINT16");
            }
            else{
                fwrite(write_data_multibit.buf_ss, sizeof(short int) * advance, 1, fp);
                fclose(fp);
            }
            break;
        case PCM_RAW_SINT24:
            switch(device_bits){
            case 16:
                for(j=0, k=0; j<advance; j++, k+=3){
                    write_data_multibit.buf_uc[k  ] = 0x00;
                    write_data_multibit.buf_uc[k+1] = (((int) wavedata[index][j])      ) & 0xFF;
                    write_data_multibit.buf_uc[k+2] = (((int) wavedata[index][j]) >>  8) & 0xFF;
                }
                break;
            case 24:
                for(j=0, k=0; j<advance; j++, k+=3){
                    write_data_multibit.buf_uc[k  ] = (((int) wavedata[index][j])      ) & 0xFF;
                    write_data_multibit.buf_uc[k+1] = (((int) wavedata[index][j]) >>  8) & 0xFF;
                    write_data_multibit.buf_uc[k+2] = (((int) wavedata[index][j]) >> 16) & 0xFF;
                }
                break;
            case 32:
                for(j=0, k=0; j<advance; j++, k+=3){
                    write_data_multibit.buf_uc[k  ] = (((int) wavedata[index][j]) >>  8) & 0xFF;
                    write_data_multibit.buf_uc[k+1] = (((int) wavedata[index][j]) >> 16) & 0xFF;
                    write_data_multibit.buf_uc[k+2] = (((int) wavedata[index][j]) >> 24) & 0xFF;
                }
                break;
            case 0: // if use no bit convert option
            default:
                for(j=0, k=0; j<advance; j++, k+=3){
                    write_data_multibit.buf_uc[k  ] = (((int) wavedata[index][j])      ) & 0xFF;
                    write_data_multibit.buf_uc[k+1] = (((int) wavedata[index][j]) >>  8) & 0xFF;
                    write_data_multibit.buf_uc[k+2] = (((int) wavedata[index][j]) >> 16) & 0xFF;
                }
                break;
            }
            sprintf(fname, "%s%03d.%s", UserParamConfigSave_output_pcm_tmp_file_name, id, "raw");
            if((fp = fopen(fname, "a")) == NULL){
                fprintf(stderr, "file open error!!\n");
                LOGE("file open error, case of SaveSepRaw->EXISTING_ID->PCM_RAW_SINT24");
            }
            else{
                fwrite(write_data_multibit.buf_uc, sizeof(char) * 3 * advance, 1, fp);
                fclose(fp);
            }
            break;
        case PCM_RAW_FLOAT32:
            switch(device_bits){
            case 16:
                for(j = 0; j < advance; j++){ write_data_multibit.buf_hf[j] = (HA_Float)(wavedata[index][j] * 0.000030517578125f); }
                break;
            case 24:
                for(j = 0; j < advance; j++){ write_data_multibit.buf_hf[j] = (HA_Float)(wavedata[index][j] * 0.00000011920928955078125f); }
                break;
            case 32:
                for(j = 0; j < advance; j++){ write_data_multibit.buf_hf[j] = (HA_Float)(wavedata[index][j] * 0.0000000004656612873077392578125f); }
                break;
            case 0: // if use no bit convert option
            default:
                for(j = 0; j < advance; j++){ write_data_multibit.buf_hf[j] = (HA_Float)(wavedata[index][j] * 0.0000000004656612873077392578125f); }
                break;
            }
            sprintf(fname, "%s%03d.%s", UserParamConfigSave_output_pcm_tmp_file_name, id, "raw");
            if((fp = fopen(fname, "a")) == NULL){
                fprintf(stderr, "file open error!!\n");
                LOGE("file open error, case of SaveSepRaw->EXISTING_ID->PCM_RAW_FLOAT32");
            }
            else{
                fwrite(write_data_multibit.buf_hf, sizeof(HA_Float) * advance, 1, fp);
                fclose(fp);
            }
            break;
        case PCM_RAW_RAWFLOAT:
            sprintf(fname, "%s%03d.%s", UserParamConfigSave_output_pcm_tmp_file_name, id, "raw");
            if((fp = fopen(fname, "a")) == NULL){
                fprintf(stderr, "file open error!!\n");
                LOGE("file open error, case of SaveSepRaw->EXISTING_ID->PCM_RAW_RAWFLOAT");
            }
            else{
                fwrite(wavedata[index], sizeof(HA_Float) * advance, 1, fp);
                fclose(fp);
            }
            break;
        case PCM_NONE:
        default:
            break;
        }
        for(i = 0; i < advance; i++){
            tcp_data[index][i] = wavedata[index][i];
        }
        // buffer shift for next
        for(j = 0; j < remaining; j++){
            wavedata[index][j] = wavedata[index][j+advance];
        }
        // zero padding
        memset(&(wavedata[index][remaining]), 0, sizeof(HA_Float) * advance);
        //LOGE("EXSITING_ID -e-: %d", id);
        break;
    default:
        fprintf(stderr, "error flag\n");
        LOGE("ERROR_ID --");
        break;
    }

    return 1;
}


int ControlObject::finalizerawdata(int index, int id)
{
    char fname[ARY_PATH_LENGTH], fnamef[ARY_PATH_LENGTH];
    //short int write_data_sint[ARY_NUM_WAVE-_ADVANCE_VAL_];
    //HA_Float write_data_float[ARY_NUM_WAVE-_ADVANCE_VAL_];
    //short int write_data_sint[ARY_NUM_WAVE]; // write_data_sint  ==> write_data_multibit.buf_ss
    //HA_Float write_data_float[ARY_NUM_WAVE]; // write_data_float ==> write_data_multibit.buf_hf
    int riff_size, data_size;
    struct stat file_stat;

    int fd = -1;
    FILE *fp = NULL;

    // 後できれいに書き換える
    const int num_wave  = ARY_NUM_WAVE;
    const int advance   = audio_info.advance;
    const int remaining = num_wave - advance;
    const int device_bits = audio_info.nbits; // selectedDeviceObj->GetBits(); //test
    union multibit {
        HA_Float      buf_hf[ARY_NUM_WAVE];
        int           buf_si[ARY_NUM_WAVE];
        short int     buf_ss[ARY_NUM_WAVE*2];
        unsigned char buf_uc[ARY_NUM_WAVE*4];
    } write_data_multibit ;
    int i, j, k;

//  LOGE("FINALIZE_ID -s-: %d", id);

    // data to write
    switch(SaveSepRaw){
    case PCM_WAV_SINT16:
        switch(device_bits){
        case 0: // if use no bit convert option
            for(j = 0; j < remaining; j++){ write_data_multibit.buf_ss[j] = (short int)(wavedata[index][j]); }
            break;
        case 16:
            for(j = 0; j < remaining; j++){ write_data_multibit.buf_ss[j] = (short int)(wavedata[index][j]); }
            break;
        case 24:
            for(j = 0; j < remaining; j++){ write_data_multibit.buf_ss[j] = (short int)(((int)(wavedata[index][j])) >> 8); }
            break;
        case 32:
            for(j = 0; j < remaining; j++){ write_data_multibit.buf_ss[j] = (short int)(((int)(wavedata[index][j])) >> 16); }
            break;
        }
        sprintf(fname, "%s%03d.%s", UserParamConfigSave_output_pcm_tmp_file_name, id, "wav");
        if((fp = fopen(fname, "a")) == NULL){
            fprintf(stderr, "file open error!!\n");
            LOGE("file open error, case of SaveSepRaw->FINALIZE_ID->PCM_WAV_SINT16");
        }
        else{
            fwrite(write_data_multibit.buf_ss, sizeof(short int) * remaining, 1, fp);
            fclose(fp);
        }
        if((fd = open(fname, O_RDWR)) < 0){
            fprintf(stderr, "file descriptor open error!!\n");
            LOGE("file descriptor open error, case of SaveSepRaw->FINALIZE_ID->PCM_WAV_SINT16->HeaderWrite");
        }
        else{
            if(fstat(fd, &file_stat) < 0){ fprintf(stderr, "file stat error!!\n"); break; }
            if((fp = fdopen(fd, "wb")) == NULL){
                fprintf(stderr, "file open error!!\n");
                LOGE("file open error, case of SaveSepRaw->FINALIZE_ID->PCM_WAV_SINT16->HeaderWrite");
            }
            else{
                riff_size = (int) (file_stat.st_size < 0xFFFFFFFF ? file_stat.st_size : 0xFFFFFFFF) - 8;
                data_size = riff_size - 36;
                fseek(fp, 4, SEEK_SET);
                fwrite(&riff_size, sizeof(int), 1, fp);
                fseek(fp, 32, SEEK_CUR);
                fwrite(&data_size, sizeof(int), 1, fp);
                fclose(fp);
            }
            close(fd);
        }
        sprintf(fnamef, "%s%03d.%s", UserParamConfigSave_output_pcm_file_name, id, "wav");
        rename(fname, fnamef);
        break;
    case PCM_WAV_SINT24:
        switch(device_bits){
        case 0: // if use no bit convert option
            for(j=0, k=0; j<remaining; j++, k+=3){
                write_data_multibit.buf_uc[k  ] = (((int) wavedata[index][j])      ) & 0xFF;
                write_data_multibit.buf_uc[k+1] = (((int) wavedata[index][j]) >>  8) & 0xFF;
                write_data_multibit.buf_uc[k+2] = (((int) wavedata[index][j]) >> 16) & 0xFF;
            }
            break;
        case 16:
            for(j=0, k=0; j<remaining; j++, k+=3){
                write_data_multibit.buf_uc[k  ] = 0x00;
                write_data_multibit.buf_uc[k+1] = (((int) wavedata[index][j])      ) & 0xFF;
                write_data_multibit.buf_uc[k+2] = (((int) wavedata[index][j]) >>  8) & 0xFF;
            }
            break;
        case 24:
            for(j=0, k=0; j<remaining; j++, k+=3){
                write_data_multibit.buf_uc[k  ] = (((int) wavedata[index][j])      ) & 0xFF;
                write_data_multibit.buf_uc[k+1] = (((int) wavedata[index][j]) >>  8) & 0xFF;
                write_data_multibit.buf_uc[k+2] = (((int) wavedata[index][j]) >> 16) & 0xFF;
            }
            break;
        case 32:
            for(j=0, k=0; j<remaining; j++, k+=3){
                write_data_multibit.buf_uc[k  ] = (((int) wavedata[index][j]) >>  8) & 0xFF;
                write_data_multibit.buf_uc[k+1] = (((int) wavedata[index][j]) >> 16) & 0xFF;
                write_data_multibit.buf_uc[k+2] = (((int) wavedata[index][j]) >> 24) & 0xFF;
            }
            break;
        }
        sprintf(fname, "%s%03d.%s", UserParamConfigSave_output_pcm_tmp_file_name, id, "wav");
        if((fp = fopen(fname, "a")) == NULL){
            fprintf(stderr, "file open error!!\n");
            LOGE("file open error, case of SaveSepRaw->FINALIZE_ID->PCM_WAV_SINT24");
        }
        else{
            fwrite(write_data_multibit.buf_uc, sizeof(char) * 3 * remaining, 1, fp);
            fclose(fp);
        }
        if((fd = open(fname, O_RDWR)) < 0){
            fprintf(stderr, "file descriptor open error!!\n");
            LOGE("file descriptor open error, case of SaveSepRaw->FINALIZE_ID->PCM_WAV_SINT24->HeaderWrite");
        }
        else{
            if(fstat(fd, &file_stat) < 0){ fprintf(stderr, "file stat error!!\n"); break; }
            if((fp = fdopen(fd, "wb")) == NULL){
                fprintf(stderr, "file open error!!\n");
                LOGE("file open error, case of SaveSepRaw->FINALIZE_ID->PCM_WAV_SINT24->HeaderWrite");
            }
            else{
                riff_size = (int) (file_stat.st_size < 0xFFFFFFFF ? file_stat.st_size : 0xFFFFFFFF) - 8;
                data_size = riff_size - 36;
                fseek(fp, 4, SEEK_SET);
                fwrite(&riff_size, sizeof(int), 1, fp);
                fseek(fp, 32, SEEK_CUR);
                fwrite(&data_size, sizeof(int), 1, fp);
                fclose(fp);
            }
            close(fd);
        }
        sprintf(fnamef, "%s%03d.%s", UserParamConfigSave_output_pcm_file_name, id, "wav");
        rename(fname, fnamef);
        break;
    case PCM_WAV_FLOAT32:
        switch(device_bits){
        case 0: // if use no bit convert option
            for(j = 0; j < remaining; j++){ write_data_multibit.buf_hf[j] = (HA_Float)(wavedata[index][j] * 0.0000000004656612873077392578125f); }
            break;
        case 16:
            for(j = 0; j < remaining; j++){ write_data_multibit.buf_hf[j] = (HA_Float)(wavedata[index][j] * 0.000030517578125f); }
            break;
        case 24:
            for(j = 0; j < remaining; j++){ write_data_multibit.buf_hf[j] = (HA_Float)(wavedata[index][j] * 0.00000011920928955078125f); }
            break;
        case 32:
            for(j = 0; j < remaining; j++){ write_data_multibit.buf_hf[j] = (HA_Float)(wavedata[index][j] * 0.0000000004656612873077392578125f); }
            break;
        }
        sprintf(fname, "%s%03d.%s", UserParamConfigSave_output_pcm_tmp_file_name, id, "wav");
        if((fp = fopen(fname, "a")) == NULL){
            fprintf(stderr, "file open error!!\n");
            LOGE("file open error, case of SaveSepRaw->FINALIZE_ID->PCM_WAV_FLOAT32");
        }
        else{
            //fwrite(write_data_float, sizeof(HA_Float) * remaining, 1, fp);
            fwrite(write_data_multibit.buf_hf, sizeof(HA_Float) * remaining, 1, fp);
            fclose(fp);
        }
        if((fd = open(fname, O_RDWR)) < 0){
            fprintf(stderr, "file descriptor open error!!\n");
            LOGE("file descriptor open error, case of SaveSepRaw->FINALIZE_ID->PCM_WAV_FLOAT32->HeaderWrite");
        }
        else{
            if(fstat(fd, &file_stat) < 0){ fprintf(stderr, "file stat error!!\n"); break; }
            if((fp = fdopen(fd, "wb")) == NULL){
                fprintf(stderr, "file open error!!\n");
                LOGE("file open error, case of SaveSepRaw->FINALIZE_ID->PCM_WAV_FLOAT32->HeaderWrite");
            }
            else{
                riff_size = (int) (file_stat.st_size < 0xFFFFFFFF ? file_stat.st_size : 0xFFFFFFFF) - 8;
                data_size = riff_size - 36;
                fseek(fp, 4, SEEK_SET);
                fwrite(&riff_size, sizeof(int), 1, fp);
                fseek(fp, 32, SEEK_CUR);
                fwrite(&data_size, sizeof(int), 1, fp);
                fclose(fp);
            }
            close(fd);
        }
        sprintf(fnamef, "%s%03d.%s", UserParamConfigSave_output_pcm_file_name, id, "wav");
        rename(fname, fnamef);
        break;
    case PCM_RAW_SINT16:
        switch(device_bits){
        case 0: // if use no bit convert option
            for(j = 0; j < remaining; j++){ write_data_multibit.buf_ss[j] = (short int)(wavedata[index][j]); }
            break;
        case 16:
            for(j = 0; j < remaining; j++){ write_data_multibit.buf_ss[j] = (short int)(wavedata[index][j]); }
            break;
        case 24:
            for(j = 0; j < remaining; j++){ write_data_multibit.buf_ss[j] = (short int)((int)(wavedata[index][j]) >> 8); }
            break;
        case 32:
            for(j = 0; j < remaining; j++){ write_data_multibit.buf_ss[j] = (short int)((int)(wavedata[index][j]) >> 16); }
            break;
        }
        sprintf(fname, "%s%03d.%s", UserParamConfigSave_output_pcm_tmp_file_name, id, "raw");
        if((fp = fopen(fname, "a")) == NULL){
            fprintf(stderr, "file open error!!\n");
            LOGE("file open error, case of SaveSepRaw->FINALIZE_ID->PCM_RAW_SINT16");
        }
        else{
            //fwrite(write_data_sint, sizeof(short int) * remaining, 1, fp);
            fwrite(write_data_multibit.buf_ss, sizeof(short int) * remaining, 1, fp);
            fclose(fp);
        }
        sprintf(fnamef, "%s%03d.%s", UserParamConfigSave_output_pcm_file_name, id, "raw");
        rename(fname, fnamef);
        break;
    case PCM_RAW_SINT24:
        switch(device_bits){
        case 0: // if use no bit convert option
            for(j=0, k=0; j<remaining; j++, k+=3){
                write_data_multibit.buf_uc[k  ] = (((int) wavedata[index][j])      ) & 0xFF;
                write_data_multibit.buf_uc[k+1] = (((int) wavedata[index][j]) >>  8) & 0xFF;
                write_data_multibit.buf_uc[k+2] = (((int) wavedata[index][j]) >> 16) & 0xFF;
            }
            break;
        case 16:
            for(j=0, k=0; j<remaining; j++, k+=3){
                write_data_multibit.buf_uc[k  ] = 0x00;
                write_data_multibit.buf_uc[k+1] = (((int) wavedata[index][j])      ) & 0xFF;
                write_data_multibit.buf_uc[k+2] = (((int) wavedata[index][j]) >>  8) & 0xFF;
            }
            break;
        case 24:
            for(j=0, k=0; j<remaining; j++, k+=3){
                write_data_multibit.buf_uc[k  ] = (((int) wavedata[index][j])      ) & 0xFF;
                write_data_multibit.buf_uc[k+1] = (((int) wavedata[index][j]) >>  8) & 0xFF;
                write_data_multibit.buf_uc[k+2] = (((int) wavedata[index][j]) >> 16) & 0xFF;
            }
            break;
        case 32:
            for(j=0, k=0; j<remaining; j++, k+=3){
                write_data_multibit.buf_uc[k  ] = (((int) wavedata[index][j]) >>  8) & 0xFF;
                write_data_multibit.buf_uc[k+1] = (((int) wavedata[index][j]) >> 16) & 0xFF;
                write_data_multibit.buf_uc[k+2] = (((int) wavedata[index][j]) >> 24) & 0xFF;
            }
            break;
        }
        sprintf(fname, "%s%03d.%s", UserParamConfigSave_output_pcm_tmp_file_name, id, "raw");
        if((fp = fopen(fname, "a")) == NULL){
            fprintf(stderr, "file open error!!\n");
            LOGE("file open error, case of SaveSepRaw->FINALIZE_ID->PCM_WAV_SINT24");
        }
        else{
            fwrite(write_data_multibit.buf_uc, sizeof(char) * 3 * remaining, 1, fp);
            fclose(fp);
        }
        sprintf(fnamef, "%s%03d.%s", UserParamConfigSave_output_pcm_file_name, id, "raw");
        rename(fname, fnamef);
        break;
    case PCM_RAW_FLOAT32:
        switch(device_bits){
        case 0: // if use no bit convert option
            for(j = 0; j < remaining; j++){ write_data_multibit.buf_hf[j] = (HA_Float)(wavedata[index][j] * 0.0000000004656612873077392578125f); }
            break;
        case 16:
            for(j = 0; j < remaining; j++){ write_data_multibit.buf_hf[j] = (HA_Float)(wavedata[index][j] * 0.000030517578125f); }
            break;
        case 24:
            for(j = 0; j < remaining; j++){ write_data_multibit.buf_hf[j] = (HA_Float)(wavedata[index][j] * 0.00000011920928955078125f); }
            break;
        case 32:
            for(j = 0; j < remaining; j++){ write_data_multibit.buf_hf[j] = (HA_Float)(wavedata[index][j] * 0.0000000004656612873077392578125f); }
            break;
        }
        sprintf(fname, "%s%03d.%s", UserParamConfigSave_output_pcm_tmp_file_name, id, "raw");
        if((fp = fopen(fname, "a")) == NULL){
            fprintf(stderr, "file open error!!\n");
            LOGE("file open error, case of SaveSepRaw->FINALIZE_ID->PCM_RAW_FLOAT32");
        }
        else{
            fwrite(write_data_multibit.buf_hf, sizeof(HA_Float) * remaining, 1, fp);
            fclose(fp);
        }
        sprintf(fnamef, "%s%03d.%s", UserParamConfigSave_output_pcm_file_name, id, "raw");
        rename(fname, fnamef);
        break;
    case PCM_RAW_RAWFLOAT:
        sprintf(fname, "%s%03d.%s", UserParamConfigSave_output_pcm_tmp_file_name, id, "raw");
        if((fp = fopen(fname, "a")) == NULL){
            fprintf(stderr, "file open error!!\n");
            LOGE("file open error, case of SaveSepRaw->FINALIZE_ID->PCM_RAW_RAWFLOAT");
        }
        else{
            fwrite(wavedata[index], sizeof(HA_Float) * remaining, 1, fp);
            fclose(fp);
        }
        sprintf(fnamef, "%s%03d.%s", UserParamConfigSave_output_pcm_file_name, id, "raw");
        rename(fname, fnamef);
        break;
    case PCM_NONE:
    default:
        break;
    }

    for(i = 0; i < remaining; i++){
        tcp_data[index][i] = wavedata[index][i];
    }

    // zero padding
    memset(wavedata[index], 0, sizeof(HA_Float) * ARY_NUM_WAVE);

    //LOGE("FINALIZE_ID -e-");

    return(rename(fname, fnamef) == 0);
}

#ifdef ENABLE_BLUETOOTH
//
//
//
int ControlObject::init_bluetooth() {
      
  for (std::map<int, int>::iterator iter = bt_sockets.begin(); iter != bt_sockets.end(); iter++) {
    ::close(iter->second);
  }
  
  bt_sockets.clear();
  bt_set_id(-1);

  if (BluetoothMaxRad < BluetoothMinRad) {
    std::swap(BluetoothMinRad, BluetoothMaxRad);
  }

  return(0);
}

int ControlObject::connect_bt_service(const int id)
{

    struct sockaddr_in server;
    struct sockaddr_in dstAddr;
    
    memset(&server, 0, sizeof(server));
    
    //server.sin_addr.s_addr = inet_addr("192.168.33.137");
    server.sin_addr.s_addr = inet_addr("127.0.0.1");
    server.sin_family = AF_INET;

    // TODO: 貯め込まない版
    //server.sin_port = htons(37564);
    server.sin_port = htons(42731);
    
    int sock = socket(AF_INET, SOCK_STREAM, 0);
    if (sock == -1) {
      printf("Could not create socket");
      return(-1);
    }
    
    if (connect(sock , (struct sockaddr *)&server , sizeof(server)) < 0) {
      perror("connect failed. Error");
      close(sock);
      return(-1);
    }

    bt_sockets[id] = sock;

    return(0);

}

int ControlObject::write_bt_service(const int id, void *abuf, const ssize_t wsize)
{

    int fd = bt_sockets[id];
    char *buf = reinterpret_cast<char *>(abuf);

    ssize_t remain = wsize;
    ssize_t write_success = 0;
    while(remain > 0) {

	ssize_t wrote = write(fd, &buf[write_success], remain);
	if (wrote == -1) {
		return(-1);
	}
	remain -= wrote;
	write_success += wrote;
	
    }

    return(write_success);

}

int ControlObject::disconnect_bt_service(const int id)
{
  ::close(bt_sockets[id]);
  bt_sockets.erase(id);
  return(0);
}

int ControlObject::bt_writerawdata(const HA_Float write_data[ARY_NUM_SRC][ARY_NUM_WAVE], const int index, const int id, const float x, const float y, const int flag)
{

    if (flag == NEW_ID) {
      //
      // 新規ID
      //
      if (bt_check_range(x, y)) {
	// 角度が範囲内
	if (::sem_trywait(&bt_max_sem) == 0) {
	  // とれれば誰もやっていない
	  bt_set_id(id);
	} else {
	  // 既に処理中
	  return(1);
	}
      } else {
	// 角度が範囲外
	return(1);
      }
      
    } else {
      //
      // 継続ID
      //
      if (!bt_check_id(id)) {
	// 処理中のIDではない
	return(1);
      }
    }
    
    int  btSaveSepRaw;
    //char fname[ARY_PATH_LENGTH];
    //FILE *fp = NULL;
    //short int write_data_sint[_ADVANCE_VAL_]; // write_data_sint  ==> write_data_multibit.buf_ss
    //HA_Float write_data_float[_ADVANCE_VAL_]; // write_data_float ==> write_data_multibit.buf_hf

    // 後できれいに書き換える
    const int num_wave  = ARY_NUM_WAVE;
    const int advance   = audio_info.advance;
    const int remaining = num_wave - advance;
    const int device_bits = audio_info.nbits; // selectedDeviceObj->GetBits(); //test
    union multibit {
        HA_Float      buf_hf[_ADVANCE_VAL_];
        int           buf_si[_ADVANCE_VAL_];
        short int     buf_ss[_ADVANCE_VAL_*2];
        unsigned char buf_uc[_ADVANCE_VAL_*4];
    } write_data_multibit ;
    int i, j, k;

    btSaveSepRaw = PCM_RAW_SINT16;
    
    switch(flag){
    case NEW_ID:
        //LOGE("NEW_ID -s-: %d", id);
        switch(btSaveSepRaw){
        case PCM_WAV_SINT16:
            switch(device_bits){
            case 16:
                for(j = 0; j < advance; j++){ write_data_multibit.buf_ss[j] = (short int)(write_data[index][j]); }
                break;
            case 24:
                for(j = 0; j < advance; j++){ write_data_multibit.buf_ss[j] = (short int)(((int)(write_data[index][j])) >> 8); }
                break;
            case 32:
                for(j = 0; j < advance; j++){ write_data_multibit.buf_ss[j] = (short int)(((int)(write_data[index][j])) >> 16); }
                break;
            case 0: // if use no bit convert option
            default:
                for(j = 0; j < advance; j++){ write_data_multibit.buf_ss[j] = (short int)(write_data[index][j]); }
                break;
            }
            if(connect_bt_service(id) == -1){
                fprintf(stderr, "bt connect  error!!\n");
                LOGE("bt connect error, case of SaveSepRaw->NEW_ID->PCM_WAV_SINT16");
            }
            else{
                write_bt_service(id, write_data_multibit.buf_ss, sizeof(short int) * advance);
            }
            break;
#if 0
        case PCM_WAV_SINT24:
            switch(device_bits){
            case 16:
                for(j=0, k=0; j<advance; j++, k+=3){
                    write_data_multibit.buf_uc[k  ] = 0x00;
                    write_data_multibit.buf_uc[k+1] = (((int) write_data[index][j])      ) & 0xFF;
                    write_data_multibit.buf_uc[k+2] = (((int) write_data[index][j]) >>  8) & 0xFF;
                }
                break;
            case 24:
                for(j=0, k=0; j<advance; j++, k+=3){
                    write_data_multibit.buf_uc[k  ] = (((int) write_data[index][j])      ) & 0xFF;
                    write_data_multibit.buf_uc[k+1] = (((int) write_data[index][j]) >>  8) & 0xFF;
                    write_data_multibit.buf_uc[k+2] = (((int) write_data[index][j]) >> 16) & 0xFF;
                }
                break;
            case 32:
                for(j=0, k=0; j<advance; j++, k+=3){
                    write_data_multibit.buf_uc[k  ] = (((int) write_data[index][j]) >>  8) & 0xFF;
                    write_data_multibit.buf_uc[k+1] = (((int) write_data[index][j]) >> 16) & 0xFF;
                    write_data_multibit.buf_uc[k+2] = (((int) write_data[index][j]) >> 24) & 0xFF;
                }
                break;
            case 0: // if use no bit convert option
            default:
                for(j=0, k=0; j<advance; j++, k+=3){
                    write_data_multibit.buf_uc[k  ] = (((int) write_data[index][j])      ) & 0xFF;
                    write_data_multibit.buf_uc[k+1] = (((int) write_data[index][j]) >>  8) & 0xFF;
                    write_data_multibit.buf_uc[k+2] = (((int) write_data[index][j]) >> 16) & 0xFF;
                }
                break;
            }
            if(connect_bt_service(id) == -1){
	        fprintf(stderr, "bt connect error!!\n");
                LOGE("bt connect error, case of SaveSepRaw->NEW_ID->PCM_WAV_SINT24");
            }
            else{
                write_bt_service(id, write_data_multibit.buf_uc, sizeof(char) * 3 * advance);
            }
            break;
        case PCM_WAV_FLOAT32:
            switch(device_bits){
            case 16:
                for(j = 0; j < advance; j++){ write_data_multibit.buf_hf[j] = (HA_Float)(write_data[index][j] * 0.000030517578125f); }
                break;
            case 24:
                for(j = 0; j < advance; j++){ write_data_multibit.buf_hf[j] = (HA_Float)(write_data[index][j] * 0.00000011920928955078125f); }
                break;
            case 32:
                for(j = 0; j < advance; j++){ write_data_multibit.buf_hf[j] = (HA_Float)(write_data[index][j] * 0.0000000004656612873077392578125f); }
                break;
            case 0: // if use no bit convert option
            default:
                for(j = 0; j < advance; j++){ write_data_multibit.buf_hf[j] = (HA_Float)(write_data[index][j] * 0.0000000004656612873077392578125f); }
                break;
            }
            if(connect_bt_service(id) == -1){
                fprintf(stderr, "bt connect error!!\n");
                LOGE("bt connect error, case of SaveSepRaw->NEW_ID->PCM_WAV_FLOAT32");
            }
            else{
	      write_bt_service(id, write_data_multibit.buf_hf, sizeof(HA_Float) * advance);
            }
            break;
#endif	// 0

        case PCM_RAW_SINT16:
            switch(device_bits){
            case 16:
                for(j = 0; j < advance; j++){ write_data_multibit.buf_ss[j] = (short int)(write_data[index][j]); }
                break;
            case 24:
                for(j = 0; j < advance; j++){ write_data_multibit.buf_ss[j] = (short int)(((int)(write_data[index][j])) >> 8); }
                break;
            case 32:
                for(j = 0; j < advance; j++){ write_data_multibit.buf_ss[j] = (short int)(((int)(write_data[index][j])) >> 16); }
                break;
            case 0: // if use no bit convert option
            default:
                for(j = 0; j < advance; j++){ write_data_multibit.buf_ss[j] = (short int)(write_data[index][j]); }
                break;
            }
            if(connect_bt_service(id) == -1){
                fprintf(stderr, "bt connect error!!\n");
                LOGE("bt connect error, case of SaveSepRaw->NEW_ID->PCM_RAW_SINT16");
            }
            else{
	        write_bt_service(id, write_data_multibit.buf_ss, sizeof(short int) * advance);
            }
            break;
#if 0
        case PCM_RAW_SINT24:
            switch(device_bits){
            case 16:
                for(j=0, k=0; j<advance; j++, k+=3){
                    write_data_multibit.buf_uc[k  ] = 0x00;
                    write_data_multibit.buf_uc[k+1] = (((int) write_data[index][j])      ) & 0xFF;
                    write_data_multibit.buf_uc[k+2] = (((int) write_data[index][j]) >>  8) & 0xFF;
                }
                break;
            case 24:
                for(j=0, k=0; j<advance; j++, k+=3){
                    write_data_multibit.buf_uc[k  ] = (((int) write_data[index][j])      ) & 0xFF;
                    write_data_multibit.buf_uc[k+1] = (((int) write_data[index][j]) >>  8) & 0xFF;
                    write_data_multibit.buf_uc[k+2] = (((int) write_data[index][j]) >> 16) & 0xFF;
                }
                break;
            case 32:
                for(j=0, k=0; j<advance; j++, k+=3){
                    write_data_multibit.buf_uc[k  ] = (((int) write_data[index][j]) >>  8) & 0xFF;
                    write_data_multibit.buf_uc[k+1] = (((int) write_data[index][j]) >> 16) & 0xFF;
                    write_data_multibit.buf_uc[k+2] = (((int) write_data[index][j]) >> 24) & 0xFF;
                }
                break;
            case 0: // if use no bit convert option
            default:
                for(j=0, k=0; j<advance; j++, k+=3){
                    write_data_multibit.buf_uc[k  ] = (((int) write_data[index][j])      ) & 0xFF;
                    write_data_multibit.buf_uc[k+1] = (((int) write_data[index][j]) >>  8) & 0xFF;
                    write_data_multibit.buf_uc[k+2] = (((int) write_data[index][j]) >> 16) & 0xFF;
                }
                break;
            }
            if(connect_bt_service(id) == -1){
                fprintf(stderr, "bt connect error!!\n");
                LOGE("bt connect error, case of SaveSepRaw->NEW_ID->PCM_RAW_SINT24");
            }
            else{
	        write_bt_service(id,write_data_multibit.buf_uc, sizeof(char) * 3 * advance);
            }
            break;
        case PCM_RAW_FLOAT32:
            switch(device_bits){
            case 16:
                for(j = 0; j < advance; j++){ write_data_multibit.buf_hf[j] = (HA_Float)(write_data[index][j] * 0.000030517578125f); }
                break;
            case 24:
                for(j = 0; j < advance; j++){ write_data_multibit.buf_hf[j] = (HA_Float)(write_data[index][j] * 0.00000011920928955078125f); }
                break;
            case 32:
                for(j = 0; j < advance; j++){ write_data_multibit.buf_hf[j] = (HA_Float)(write_data[index][j] * 0.0000000004656612873077392578125f); }
                break;
            case 0: // if use no bit convert option
            default:
                for(j = 0; j < advance; j++){ write_data_multibit.buf_hf[j] = (HA_Float)(write_data[index][j] * 0.0000000004656612873077392578125f); }
                break;
            }
            if(connect_bt_service(id) == -1){
                fprintf(stderr, "bt connect error!!\n");
                LOGE("bt connect error, case of SaveSepRaw->NEW_ID->PCM_RAW_FLOAT32");
            }
            else{
	        write_bt_service(id, write_data_multibit.buf_hf, sizeof(HA_Float) * advance);
            }
            break;
        case PCM_RAW_RAWFLOAT:
            if(connect_bt_service(id) == -1){
                fprintf(stderr, "bt connect error!!\n");
                LOGE("bt connect error, case of SaveSepRaw->NEW_ID->PCM_RAW_RAWFLOAT");
            }
            else{
  	        write_bt_service(id, write_data[index], sizeof(HA_Float) * advance);
            }
            break;
        case PCM_NONE:
        default:
            break;
#endif	// 0
        }
#if 0
	// tcp_dataは必要ない模様
        for(i = 0; i < advance; i++){
            tcp_data[index][i] = write_data[index][i];
        }
#endif
        // data for buffer
        for(j = 0; j < remaining; j++){
            bt_wavedata[index][j] = write_data[index][j+advance];
        }
        // zero padding
        memset(&(bt_wavedata[index][remaining]), 0, sizeof(HA_Float) * advance);
        //LOGE("NEW_ID -e-: %d", id);
        break;
    case EXISTING_ID:
        //LOGE("EXISTING_ID -s-: %d", id);
        // overlap-add
        for(j = 0; j < num_wave; j++){
            bt_wavedata[index][j] += write_data[index][j];
        }
        // data for append
        switch(btSaveSepRaw){

        case PCM_WAV_SINT16:
            switch(device_bits){
            case 16:
                for(j = 0; j < advance; j++){ write_data_multibit.buf_ss[j] = (short int)(bt_wavedata[index][j]); }
                break;
            case 24:
                for(j = 0; j < advance; j++){ write_data_multibit.buf_ss[j] = (short int)(((int)(bt_wavedata[index][j])) >> 8); }
                break;
            case 32:
                for(j = 0; j < advance; j++){ write_data_multibit.buf_ss[j] = (short int)(((int)(bt_wavedata[index][j])) >> 16); }
                break;
            case 0: // if use no bit convert option
            default:
                for(j = 0; j < advance; j++){ write_data_multibit.buf_ss[j] = (short int)(bt_wavedata[index][j]); }
                break;
            }
	    write_bt_service(id, write_data_multibit.buf_ss, sizeof(short int) * advance);
            break;
#if 0
        case PCM_WAV_SINT24:
            switch(device_bits){
            case 16:
                for(j=0, k=0; j<advance; j++, k+=3){
                    write_data_multibit.buf_uc[k  ] = 0x00;
                    write_data_multibit.buf_uc[k+1] = (((int) bt_wavedata[index][j])      ) & 0xFF;
                    write_data_multibit.buf_uc[k+2] = (((int) bt_wavedata[index][j]) >>  8) & 0xFF;
                }
                break;
            case 24:
                for(j=0, k=0; j<advance; j++, k+=3){
                    write_data_multibit.buf_uc[k  ] = (((int) bt_wavedata[index][j])      ) & 0xFF;
                    write_data_multibit.buf_uc[k+1] = (((int) bt_wavedata[index][j]) >>  8) & 0xFF;
                    write_data_multibit.buf_uc[k+2] = (((int) bt_wavedata[index][j]) >> 16) & 0xFF;
                }
                break;
            case 32:
                for(j=0, k=0; j<advance; j++, k+=3){
                    write_data_multibit.buf_uc[k  ] = (((int) bt_wavedata[index][j]) >>  8) & 0xFF;
                    write_data_multibit.buf_uc[k+1] = (((int) bt_wavedata[index][j]) >> 16) & 0xFF;
                    write_data_multibit.buf_uc[k+2] = (((int) bt_wavedata[index][j]) >> 24) & 0xFF;
                }
                break;
            case 0: // if use no bit convert option
            default:
                for(j=0, k=0; j<advance; j++, k+=3){
                    write_data_multibit.buf_uc[k  ] = (((int) bt_wavedata[index][j])      ) & 0xFF;
                    write_data_multibit.buf_uc[k+1] = (((int) bt_wavedata[index][j]) >>  8) & 0xFF;
                    write_data_multibit.buf_uc[k+2] = (((int) bt_wavedata[index][j]) >> 16) & 0xFF;
                }
                break;
            }

	    write_bt_service(id, write_data_multibit.buf_uc, sizeof(char) * 3 * advance);

            break;
        case PCM_WAV_FLOAT32:
            switch(device_bits){
            case 16:
                for(j = 0; j < advance; j++){ write_data_multibit.buf_hf[j] = (HA_Float)(bt_wavedata[index][j] * 0.000030517578125f); }
                break;
            case 24:
                for(j = 0; j < advance; j++){ write_data_multibit.buf_hf[j] = (HA_Float)(bt_wavedata[index][j] * 0.00000011920928955078125f); }
                break;
            case 32:
                for(j = 0; j < advance; j++){ write_data_multibit.buf_hf[j] = (HA_Float)(bt_wavedata[index][j] * 0.0000000004656612873077392578125f); }
                break;
            case 0: // if use no bit convert option
            default:
                for(j = 0; j < advance; j++){ write_data_multibit.buf_hf[j] = (HA_Float)(bt_wavedata[index][j] * 0.0000000004656612873077392578125f); }
                break;
            }
	    write_bt_service(id, write_data_multibit.buf_hf, sizeof(HA_Float) * advance);

            break;
#endif	// 0

	// PCM_RAW_SINT16のみ
        case PCM_RAW_SINT16:
            switch(device_bits){
            case 16:
                for(j = 0; j < advance; j++){ write_data_multibit.buf_ss[j] = (short int)(bt_wavedata[index][j]); }
                break;
            case 24:
                for(j = 0; j < advance; j++){ write_data_multibit.buf_ss[j] = (short int)(((int)(bt_wavedata[index][j])) >> 8); }
                break;
            case 32:
                for(j = 0; j < advance; j++){ write_data_multibit.buf_ss[j] = (short int)(((int)(bt_wavedata[index][j])) >> 16); }
                break;
            case 0: // if use no bit convert option
            default:
                for(j = 0; j < advance; j++){ write_data_multibit.buf_ss[j] = (short int)(bt_wavedata[index][j]); }
                break;
            }

	    write_bt_service(id, write_data_multibit.buf_ss, sizeof(short int) * advance);

            break;
#if 0
        case PCM_RAW_SINT24:
            switch(device_bits){
            case 16:
                for(j=0, k=0; j<advance; j++, k+=3){
                    write_data_multibit.buf_uc[k  ] = 0x00;
                    write_data_multibit.buf_uc[k+1] = (((int) bt_wavedata[index][j])      ) & 0xFF;
                    write_data_multibit.buf_uc[k+2] = (((int) bt_wavedata[index][j]) >>  8) & 0xFF;
                }
                break;
            case 24:
                for(j=0, k=0; j<advance; j++, k+=3){
                    write_data_multibit.buf_uc[k  ] = (((int) bt_wavedata[index][j])      ) & 0xFF;
                    write_data_multibit.buf_uc[k+1] = (((int) bt_wavedata[index][j]) >>  8) & 0xFF;
                    write_data_multibit.buf_uc[k+2] = (((int) bt_wavedata[index][j]) >> 16) & 0xFF;
                }
                break;
            case 32:
                for(j=0, k=0; j<advance; j++, k+=3){
                    write_data_multibit.buf_uc[k  ] = (((int) bt_wavedata[index][j]) >>  8) & 0xFF;
                    write_data_multibit.buf_uc[k+1] = (((int) bt_wavedata[index][j]) >> 16) & 0xFF;
                    write_data_multibit.buf_uc[k+2] = (((int) bt_wavedata[index][j]) >> 24) & 0xFF;
                }
                break;
            case 0: // if use no bit convert option
            default:
                for(j=0, k=0; j<advance; j++, k+=3){
                    write_data_multibit.buf_uc[k  ] = (((int) bt_wavedata[index][j])      ) & 0xFF;
                    write_data_multibit.buf_uc[k+1] = (((int) bt_wavedata[index][j]) >>  8) & 0xFF;
                    write_data_multibit.buf_uc[k+2] = (((int) bt_wavedata[index][j]) >> 16) & 0xFF;
                }
                break;
            }

	    write_bt_service(id, write_data_multibit.buf_uc, sizeof(char) * 3 * advance);

            break;
        case PCM_RAW_FLOAT32:
            switch(device_bits){
            case 16:
                for(j = 0; j < advance; j++){ write_data_multibit.buf_hf[j] = (HA_Float)(bt_wavedata[index][j] * 0.000030517578125f); }
                break;
            case 24:
                for(j = 0; j < advance; j++){ write_data_multibit.buf_hf[j] = (HA_Float)(bt_wavedata[index][j] * 0.00000011920928955078125f); }
                break;
            case 32:
                for(j = 0; j < advance; j++){ write_data_multibit.buf_hf[j] = (HA_Float)(bt_wavedata[index][j] * 0.0000000004656612873077392578125f); }
                break;
            case 0: // if use no bit convert option
            default:
                for(j = 0; j < advance; j++){ write_data_multibit.buf_hf[j] = (HA_Float)(bt_wavedata[index][j] * 0.0000000004656612873077392578125f); }
                break;
            }
	    write_bt_service(id, write_data_multibit.buf_hf, sizeof(HA_Float) * advance);
            break;
        case PCM_RAW_RAWFLOAT:
	    write_bt_service(id, bt_wavedata[index], sizeof(HA_Float) * advance);
            break;
        case PCM_NONE:
        default:
            break;
#endif	// 0

        }

#if 0
	// tcp_dataは必要ない模様
        for(i = 0; i < advance; i++){
            tcp_data[index][i] = bt_wavedata[index][i];
        }
#endif
        // buffer shift for next
        for(j = 0; j < remaining; j++){
            bt_wavedata[index][j] = bt_wavedata[index][j+advance];
        }
        // zero padding
        memset(&(bt_wavedata[index][remaining]), 0, sizeof(HA_Float) * advance);
        //LOGE("EXSITING_ID -e-: %d", id);
        break;
    default:
        fprintf(stderr, "error flag\n");
        LOGE("ERROR_ID --");
        break;
    }

    return(0);
}


int ControlObject::bt_finalizerawdata(const int index, const int id)
{

    if (!bt_check_id(id)) {
      return(1);
    }

    //printf("end id %d", id);

    int btSaveSepRaw;
    //char fname[ARY_PATH_LENGTH], fnamef[ARY_PATH_LENGTH];
    //short int write_data_sint[ARY_NUM_WAVE-_ADVANCE_VAL_];
    //HA_Float write_data_float[ARY_NUM_WAVE-_ADVANCE_VAL_];
    //short int write_data_sint[ARY_NUM_WAVE]; // write_data_sint  ==> write_data_multibit.buf_ss
    //HA_Float write_data_float[ARY_NUM_WAVE]; // write_data_float ==> write_data_multibit.buf_hf
    int riff_size, data_size;
    struct stat file_stat;

    //int fd = -1;
    //FILE *fp = NULL;

    // 後できれいに書き換える
    const int num_wave  = ARY_NUM_WAVE;
    const int advance   = audio_info.advance;
    const int remaining = num_wave - advance;
    const int device_bits = audio_info.nbits; // selectedDeviceObj->GetBits(); //test
    union multibit {
        HA_Float      buf_hf[ARY_NUM_WAVE];
        int           buf_si[ARY_NUM_WAVE];
        short int     buf_ss[ARY_NUM_WAVE*2];
        unsigned char buf_uc[ARY_NUM_WAVE*4];
    } write_data_multibit ;
    int i, j, k;

//  LOGE("FINALIZE_ID -s-: %d", id);

    btSaveSepRaw = PCM_RAW_SINT16;
    
    // data to write
    switch(btSaveSepRaw){
    case PCM_WAV_SINT16:
        switch(device_bits){
        case 0: // if use no bit convert option
            for(j = 0; j < remaining; j++){ write_data_multibit.buf_ss[j] = (short int)(bt_wavedata[index][j]); }
            break;
        case 16:
            for(j = 0; j < remaining; j++){ write_data_multibit.buf_ss[j] = (short int)(bt_wavedata[index][j]); }
            break;
        case 24:
            for(j = 0; j < remaining; j++){ write_data_multibit.buf_ss[j] = (short int)(((int)(bt_wavedata[index][j])) >> 8); }
            break;
        case 32:
            for(j = 0; j < remaining; j++){ write_data_multibit.buf_ss[j] = (short int)(((int)(bt_wavedata[index][j])) >> 16); }
            break;
        }
	write_bt_service(id, write_data_multibit.buf_ss, sizeof(short int) * remaining);
	disconnect_bt_service(id);
        break;
    case PCM_WAV_SINT24:
        switch(device_bits){
        case 0: // if use no bit convert option
            for(j=0, k=0; j<remaining; j++, k+=3){
                write_data_multibit.buf_uc[k  ] = (((int) bt_wavedata[index][j])      ) & 0xFF;
                write_data_multibit.buf_uc[k+1] = (((int) bt_wavedata[index][j]) >>  8) & 0xFF;
                write_data_multibit.buf_uc[k+2] = (((int) bt_wavedata[index][j]) >> 16) & 0xFF;
            }
            break;
        case 16:
            for(j=0, k=0; j<remaining; j++, k+=3){
                write_data_multibit.buf_uc[k  ] = 0x00;
                write_data_multibit.buf_uc[k+1] = (((int) bt_wavedata[index][j])      ) & 0xFF;
                write_data_multibit.buf_uc[k+2] = (((int) bt_wavedata[index][j]) >>  8) & 0xFF;
            }
            break;
        case 24:
            for(j=0, k=0; j<remaining; j++, k+=3){
                write_data_multibit.buf_uc[k  ] = (((int) bt_wavedata[index][j])      ) & 0xFF;
                write_data_multibit.buf_uc[k+1] = (((int) bt_wavedata[index][j]) >>  8) & 0xFF;
                write_data_multibit.buf_uc[k+2] = (((int) bt_wavedata[index][j]) >> 16) & 0xFF;
            }
            break;
        case 32:
            for(j=0, k=0; j<remaining; j++, k+=3){
                write_data_multibit.buf_uc[k  ] = (((int) bt_wavedata[index][j]) >>  8) & 0xFF;
                write_data_multibit.buf_uc[k+1] = (((int) bt_wavedata[index][j]) >> 16) & 0xFF;
                write_data_multibit.buf_uc[k+2] = (((int) bt_wavedata[index][j]) >> 24) & 0xFF;
            }
            break;
        }
	write_bt_service(id, write_data_multibit.buf_uc, sizeof(char) * 3 * remaining);
	disconnect_bt_service(id);
        break;
    case PCM_WAV_FLOAT32:
        switch(device_bits){
        case 0: // if use no bit convert option
            for(j = 0; j < remaining; j++){ write_data_multibit.buf_hf[j] = (HA_Float)(bt_wavedata[index][j] * 0.0000000004656612873077392578125f); }
            break;
        case 16:
            for(j = 0; j < remaining; j++){ write_data_multibit.buf_hf[j] = (HA_Float)(bt_wavedata[index][j] * 0.000030517578125f); }
            break;
        case 24:
            for(j = 0; j < remaining; j++){ write_data_multibit.buf_hf[j] = (HA_Float)(bt_wavedata[index][j] * 0.00000011920928955078125f); }
            break;
        case 32:
            for(j = 0; j < remaining; j++){ write_data_multibit.buf_hf[j] = (HA_Float)(bt_wavedata[index][j] * 0.0000000004656612873077392578125f); }
            break;
        }

	write_bt_service(id, write_data_multibit.buf_hf, sizeof(HA_Float) * remaining);
	disconnect_bt_service(id);
        break;
    case PCM_RAW_SINT16:
        switch(device_bits){
        case 0: // if use no bit convert option
            for(j = 0; j < remaining; j++){ write_data_multibit.buf_ss[j] = (short int)(bt_wavedata[index][j]); }
            break;
        case 16:
            for(j = 0; j < remaining; j++){ write_data_multibit.buf_ss[j] = (short int)(bt_wavedata[index][j]); }
            break;
        case 24:
            for(j = 0; j < remaining; j++){ write_data_multibit.buf_ss[j] = (short int)((int)(bt_wavedata[index][j]) >> 8); }
            break;
        case 32:
            for(j = 0; j < remaining; j++){ write_data_multibit.buf_ss[j] = (short int)((int)(bt_wavedata[index][j]) >> 16); }
            break;
        }
	write_bt_service(id, write_data_multibit.buf_ss, sizeof(short int) * remaining);
	disconnect_bt_service(id);
        break;
    case PCM_RAW_SINT24:
        switch(device_bits){
        case 0: // if use no bit convert option
            for(j=0, k=0; j<remaining; j++, k+=3){
                write_data_multibit.buf_uc[k  ] = (((int) bt_wavedata[index][j])      ) & 0xFF;
                write_data_multibit.buf_uc[k+1] = (((int) bt_wavedata[index][j]) >>  8) & 0xFF;
                write_data_multibit.buf_uc[k+2] = (((int) bt_wavedata[index][j]) >> 16) & 0xFF;
            }
            break;
        case 16:
            for(j=0, k=0; j<remaining; j++, k+=3){
                write_data_multibit.buf_uc[k  ] = 0x00;
                write_data_multibit.buf_uc[k+1] = (((int) bt_wavedata[index][j])      ) & 0xFF;
                write_data_multibit.buf_uc[k+2] = (((int) bt_wavedata[index][j]) >>  8) & 0xFF;
            }
            break;
        case 24:
            for(j=0, k=0; j<remaining; j++, k+=3){
                write_data_multibit.buf_uc[k  ] = (((int) bt_wavedata[index][j])      ) & 0xFF;
                write_data_multibit.buf_uc[k+1] = (((int) bt_wavedata[index][j]) >>  8) & 0xFF;
                write_data_multibit.buf_uc[k+2] = (((int) bt_wavedata[index][j]) >> 16) & 0xFF;
            }
            break;
        case 32:
            for(j=0, k=0; j<remaining; j++, k+=3){
                write_data_multibit.buf_uc[k  ] = (((int) bt_wavedata[index][j]) >>  8) & 0xFF;
                write_data_multibit.buf_uc[k+1] = (((int) bt_wavedata[index][j]) >> 16) & 0xFF;
                write_data_multibit.buf_uc[k+2] = (((int) bt_wavedata[index][j]) >> 24) & 0xFF;
            }
            break;
        }
	write_bt_service(id, write_data_multibit.buf_uc, sizeof(char) * 3 * remaining);
	disconnect_bt_service(id);
        break;
    case PCM_RAW_FLOAT32:
        switch(device_bits){
        case 0: // if use no bit convert option
            for(j = 0; j < remaining; j++){ write_data_multibit.buf_hf[j] = (HA_Float)(bt_wavedata[index][j] * 0.0000000004656612873077392578125f); }
            break;
        case 16:
            for(j = 0; j < remaining; j++){ write_data_multibit.buf_hf[j] = (HA_Float)(bt_wavedata[index][j] * 0.000030517578125f); }
            break;
        case 24:
            for(j = 0; j < remaining; j++){ write_data_multibit.buf_hf[j] = (HA_Float)(bt_wavedata[index][j] * 0.00000011920928955078125f); }
            break;
        case 32:
            for(j = 0; j < remaining; j++){ write_data_multibit.buf_hf[j] = (HA_Float)(bt_wavedata[index][j] * 0.0000000004656612873077392578125f); }
            break;
        }
	write_bt_service(id, write_data_multibit.buf_hf, sizeof(HA_Float) * remaining);
	disconnect_bt_service(id);
        break;
    case PCM_RAW_RAWFLOAT:
        write_bt_service(id, bt_wavedata[index], sizeof(HA_Float) * remaining);
	disconnect_bt_service(id);
        break;
    case PCM_NONE:
    default:
        break;
    }

#if 0
    // tcp_dataは必要ない模様
    for(i = 0; i < remaining; i++){
        tcp_data[index][i] = bt_wavedata[index][i];
    }
#endif

    // zero padding
    memset(bt_wavedata[index], 0, sizeof(HA_Float) * ARY_NUM_WAVE);

    //LOGE("FINALIZE_ID -e-");

    //return(rename(fname, fnamef) == 0);

    ::sem_post(&bt_max_sem);

    return(0);
}
//
//
//
#endif	// ENABLE_BLUETOOTH


//int ControlObject::init_GHDSS()
int ControlObject::init_GHDSS(const bool hw_avail)
{
    ClearGHDSS();         /* 2013.02.15 GHDSS_coreで使用しているフラグとバッファのクリア */
    
#ifdef BUILD_MODULE_BF
    ClearBF();            /* 2013.11.25 BF_executeで使用しているフラグとバッファのクリア */
    Param_BF_t beamforming_param;
    HAGetParamBF(&beamforming_param);
    beamforming_param.bf_method               = UserParamConfigBeamforming.bf_method;
    //beamforming_param.length                  = UserParamConfigBeamforming.length;
    //beamforming_param.advance                 = UserParamConfigBeamforming.advance;
    //beamforming_param.sampling_rate           = UserParamConfigBeamforming.sampling_rate;
    //beamforming_param.tf_conj_filename        = UserParamConfigBeamforming.;
    setFullPath(beamforming_param.tf_conj_filename, UserParamConfigGhdss_sep_tf_file_name);
    beamforming_param.nl_func                 = UserParamConfigBeamforming.nl_func;
    beamforming_param.ss_method               = UserParamConfigBeamforming.ss_method;
    beamforming_param.ss_scal                 = UserParamConfigBeamforming.ss_scal;
    beamforming_param.ss_myu                  = UserParamConfigBeamforming.ss_myu;
    beamforming_param.lc_method               = UserParamConfigBeamforming.lc_method;
    beamforming_param.lc_myu                  = UserParamConfigBeamforming.lc_myu;
    beamforming_param.decomposition_algorithm = UserParamConfigBeamforming.decomposition_algorithm;
    beamforming_param.alpha                   = UserParamConfigBeamforming.alpha;
    beamforming_param.reg_factor              = UserParamConfigBeamforming.reg_factor;
    HASetParamBF(&beamforming_param);
    HAInitBF();
#endif // BUILD_MODULE_BF
    
#if 0 // K.Takagi 旧動作
    //ClearHRLE();          /* 2013.02.15 HRLEで使用しているフラグとバッファのクリア */
#endif

//  SetFFTWindowGain(1.0);
    SetFFTWindowGain(FFT_GAIN);    
    //SetFFTWindowGain(0.05);
    makeConjWindow();     /* Synthesize用の窓係数の算出 */

    ClearDelta();         /* 2013.02.22 Deltaで使用しているバッファのクリア */
    //HASetParamDelta(13); //use default value
    //HAInitDelta(); //use default value

    ::Param_EstimateLeak_t estimate_leak_param = {
        ARY_NUM_FFT,
        0.25f
    }; // 暫定
    ClearEstimateLeak();  /* 2013.02.22 EstimateLeakで使用しているバッファのクリア */
#if 1 // K.Takagi UserParam使用
    estimate_leak_param.leak_factor = UserParamConfigEstimateLeak.leak_factor;
#endif
    HASetParamEstimateLeak(&estimate_leak_param);
    HAInitEstimateLeak();

    ::Param_MelFilterBank_t melfilter_bank_param = {
        ARY_NUM_FBANK,
        ARY_NUM_WAVE,
        ARY_NUM_FFT,
        DEFAULT_SAMPLING_RATE,
        8000,
        63,
        8000
    }; // 暫定
    ClearMelFilterBank(); /* 2013.02.22 MelFilterBankで使用しているバッファのクリア */
#if 1 // K.Takagi UserParam使用
    melfilter_bank_param.cutoff = UserParamConfigMelFilterBank.cutoff;
    melfilter_bank_param.min_frequency = UserParamConfigMelFilterBank.min_frequency;
    melfilter_bank_param.max_frequency = UserParamConfigMelFilterBank.max_frequency;
#endif
    HASetParamMelFilterBank(&melfilter_bank_param);
    HAInitMelFilterBank();

    ::Param_PreEmphasis_t preemphasis_param = {
        ARY_NUM_WAVE,
        ARY_NUM_FFT,
        DEFAULT_SAMPLING_RATE,
        7900,
        0.97f
    }; // 暫定
    ClearPreEmphasis();   /* 2013.02.22 PreEmphasisで使用しているバッファのクリア */
#if 1 // K.Takagi UserParam使用
    preemphasis_param.cutoff = UserParamConfigPreEmphasis.cutoff;
    preemphasis_param.preem_coef = UserParamConfigPreEmphasis.preem_coef;
#endif
    HASetParamPreEmphasis(&preemphasis_param);
    HAInitPreEmphasis();

    ClearLowpassFilter();
    ClearZeroCross_s();

    /*
     * HRLE.cでパラメータの初期値が設定されている
     * 一度取得して、更新して再設定
     */
    Param_HRLE_t hrle_prm;
    HAGetParamHRLE(&hrle_prm);
    hrle_prm.lx = UserParamConfigHrle.lx;
    hrle_prm.tr = UserParamConfigHrle.tr;
    hrle_prm.min_lv = UserParamConfigHrle.min_lv;
    hrle_prm.step_lv = UserParamConfigHrle.step_lv;
    hrle_prm.num_bin = UserParamConfigHrle.num_bin;
    HASetParamHRLE(&hrle_prm);
    ClearHRLE();

    /*
     * WhiteNoiseAdder.cでパラメータの初期値が設定されている
     * 一度取得して、wn_levelのみを更新して再設定
     */
	Param_WhiteNoiseAdder_t whitenoise_prm;
	HAGetParamWhiteNoiseAdder(&whitenoise_prm);
	whitenoise_prm.wn_level = UserParamConfigWhiteNoiseAdder.wn_level;
	HASetParamWhiteNoiseAdder(&whitenoise_prm);

    // debug
    {
        LOGI("GHDSS User Param");
        LOGD(" sep_tf = %s", UserParamConfigGhdss_sep_tf_file_name);

        LOGI("EL User Param");
        LOGD(" factor = %f", UserParamConfigEstimateLeak.leak_factor);

        LOGI("HRLE User Param");
        LOGD(" lx      = %f", UserParamConfigHrle.lx);
        LOGD(" tr      = %f", UserParamConfigHrle.tr);
        LOGD(" min_lv  = %f", UserParamConfigHrle.min_lv);
        LOGD(" step_lv = %f", UserParamConfigHrle.step_lv);
        LOGD(" num_bin = %d", UserParamConfigHrle.num_bin);

        LOGI("WN User Param");
        LOGD(" wn_level = %f", UserParamConfigWhiteNoiseAdder.wn_level);

        LOGI("PE User Param");
        LOGD(" cut_off = %d", UserParamConfigPreEmphasis.cutoff);
        LOGD(" coef    = %f", UserParamConfigPreEmphasis.preem_coef);

        LOGI("MF User Param");
        LOGD(" cut_off = %d", UserParamConfigMelFilterBank.cutoff);
        LOGD(" min_freq = %d, max_freq = %d", UserParamConfigMelFilterBank.min_frequency, UserParamConfigMelFilterBank.max_frequency);

    }
    //

#ifdef NEVER

    const int ret = InitTFMatrix();       /* 2013.02.22 時間がかかるので先にファイルから読み込みを実行 */
    if(ret != 0){ return(-1); }

#else // NEVER

    char tf_file_name[ARY_PATH_LENGTH];
    setFullPath(tf_file_name, UserParamConfigGhdss_sep_tf_file_name);
#ifdef NEVER // ファイル入力に対しても伝達関数を変更したいのでユーザ設定を使う
    if(hw_avail){
#ifdef IS_APPLE_IOS
        ::strcpy(tf_file_name, ::getFilenameWithDocumentsPath(UserParamConfigGhdss_sep_tf_file_name));
#else // IS_APPLE_IOS
        ::strcpy(tf_file_name, UserParamConfigGhdss_sep_tf_file_name);
#endif // IS_APPLE_IOS
    }
    else{
#ifdef IS_APPLE_IOS
        ::strcpy(tf_file_name, ::getFilenameWithDocumentsPath("sep_tf.dat"));
#else // IS_APPLE_IOS
#ifdef ENABLE_ANDROID_PATH
        ::strcpy(tf_file_name, "/mnt/sdcard/hark2/sep_tf.dat");
#else // ENABLE_ANDROID_PATH
        ::strcpy(tf_file_name, "/media/SD/hark2/sep_tf.dat");
#endif // ENABLE_ANDROID_PATH
#endif // IS_APPLE_IOS
    }
#endif // NEVER
    const int ret = InitTFMatrix(tf_file_name);       /* 2013.02.22 時間がかかるので先にファイルから読み込みを実行 */
    if(ret != 0){ return(-1); }

#endif // NEVER

    for(int i = 0; i < WorkerThreadNum; i++){ num_src_pre[i] = 0; }

    return(0);
}

int ControlObject::GHDSS(const int thread_no, /*const*/ SOURCE_DATA_ARY_t &ary, const SOURCE_DATA_ARY_t &filter_ary, const bool valid_source, ::HA_Complex SpectralGainFilter_outputSpec[][ARY_NUM_FFT], char* ts)
{
    //::Param_AudioStreamFromMic_t param;
    //::HAGetParamAudioStreamFromMic(&param);
    const ::Param_AudioStreamFromMic_t &param(audio_info);
    const int advance = audio_info.advance;
    const int num_mic = audio_info.logical_channel_count;

    WaitGHDSS(thread_no);
    //LOGD("  WaitGHDSS pass[%d] : %d", ary.count, thread_no);

    const int num_src = std::min(ary.source_num, ARY_NUM_SRC);
    //if(num_src > ARY_NUM_SRC){ LOGI("**** num_src %d", num_src); }
    
    //num_src_pre[GetNextGo(thread_no)] = num_src;  // 次の人   // 2013.03.01 代入位置を後ろに移動
    
    if(valid_source){
        int new_i = 0;
        int src_mask[num_src+1]; // num_src is already known // Must larger than all source [+1]
        if(UseSourceFilter){
            for(int i=0; i<num_src+1; i++){ src_mask[i] = -1; }
            //for(int i=0; i<num_src; i++) {
            //  for(int j=0; j<filter_ary.source_num; j++) {
            //      //LOGD("org %d %f %f %f ************************************************", i, ary.data[i].x[0], ary.data[i].x[1], ary.data[i].x[2]);
            //      //LOGD("flt %d %f %f %f ************************************************", i, filter_ary.data[j].x[0], filter_ary.data[j].x[1], filter_ary.data[j].x[2]);
            //      if((filter_ary.data[j].x[0] == ary.data[i].x[0])
            //      && (filter_ary.data[j].x[1] == ary.data[i].x[1])
            //      && (filter_ary.data[j].x[2] == ary.data[i].x[2])){ src_mask[i] = ary.data[i].id; new_i++; }
            //      //LOGD("mask %d %d %d ************************************************", i, ary.data[i].id, src_mask[i]);
            //  }
            //}
            for(int i=0; i<num_src; i++) {
                //LOGD("org %d %f %f %f ************************************************", i, ary.data[i].x[0], ary.data[i].x[1], ary.data[i].x[2]);
                if(ary.data[i].mask & Mask_Use_Output){ src_mask[i] = ary.data[i].id; new_i++; }
                //LOGD("mask %d %d %d ************************************************", i, ary.data[i].id, src_mask[i]);
            }
        }
        else{
            new_i = num_src;
        }
        const int filtered_num_src = new_i;

        // allocate variables for separate calculation.
        ::HA_Complex GHDSS_outputSpec[ARY_NUM_SRC][ARY_NUM_FFT];    // outputSpec
        GHDSSCount = ary.count; // 2013.02.06 K.Takagi 音源情報のフレーム番号と一致させる
        ::FFT_DATA_ARY_t *iS = ::HABufferGetFFTData(GHDSSCount);
        ::HA_Complex inputSpec[ARY_NUM_MIC][ARY_NUM_FFT];   // inputSpec
        ::MICARY_Location localSrcPos[ARY_NUM_SRC]; // inputLocation
        //const double start = current_ms();
        switch(UseSeparation){
        case SEP_GHDSS: // GHDSSフローの実行
            if(num_src > 0){
                //LOGI("[%d] GHDSS (%d) num_src = %d", GHDSSCount, ary.count, ary.source_num);
                if(iS != NULL){
                    for(int ch = 0; ch < num_mic; ch++){
                        for(int i = 0; i < ARY_NUM_FFT; i++){
                            inputSpec[ch][i].re = iS->data[ch][i].real;
                            inputSpec[ch][i].im = iS->data[ch][i].imag;
                        }
                    }
                }
                else{
                    //LOGI("HABufferGetFFTData --> NULL");
                    ::memset(&inputSpec, 0, sizeof(inputSpec));
                }
                /*
                //LOGD("num_src %d num_src_pre %d real %f imag %f", num_src, num_src_pre[thread_no], iS->data[0][0].real, iS->data[0][0].imag);
                LOGD("num_src %d num_src_pre %d", num_src, num_src_pre[thread_no]);
                LOGD("in[0][0] = (%f  %f) ", iS->data[0][0].real, iS->data[0][0].imag);
                LOGD("in[0][1] = (%f  %f) ", iS->data[0][1].real, iS->data[0][1].imag);
                LOGD("in[1][0] = (%f  %f) ", iS->data[1][0].real, iS->data[1][0].imag);
                LOGD("in[1][1] = (%f  %f) ", iS->data[1][1].real, iS->data[1][1].imag);
                */

                /** 一つ前の音源情報の取得テスト
                SOURCE_DATA_ARY_t *pre_src;
                pre_src = HABufferGetSourceData(GHDSSCount-1);
                LOGD("Curr src %d", num_src);
                for(int s=0; s<num_src; s++){ LOGD(" [%d] : %d", s, ary.data[s].id); }
                LOGD("Pre src %d", num_src_pre[thread_no]);
                for(int s=0; s<num_src_pre[thread_no]; s++){ LOGD(" [%d] : %d", s, pre_src->data[s].id); }
                */

                for(int i = 0; i < num_src; i++){
                    localSrcPos[i].ha_fPhi = 0;
                    localSrcPos[i].ha_fTheta = 0;
                    localSrcPos[i].ha_fX = ary.data[i].x[0];
                    localSrcPos[i].ha_fY = ary.data[i].x[1];
                    localSrcPos[i].ha_fZ = ary.data[i].x[2];
                    localSrcPos[i].ha_idDir = 0;
                    localSrcPos[i].ha_idPos = ary.data[i].id;
                    //LOGD("localSrcPos %d %f %f %f", localSrcPos[i].ha_idPos, localSrcPos[i].ha_fX, localSrcPos[i].ha_fY, localSrcPos[i].ha_fZ);
                }
                //LOGD("GHDSS_core start %d count = %d", thread_no, GHDSSCount);
                ::GHDSS_core(num_src, num_src_pre[thread_no], inputSpec, localSrcPos, GHDSS_outputSpec); // inputSpecとlocaSrcPosからoutputSpecを計算する
            }
            break;
#ifdef BUILD_MODULE_BF
        case SEP_LCMV: // LCMVフローの実行 (BF_executeで実行されるのは設定したアルゴリズムのみ)
        //case SEP_GJ:   // GJフローの実行   (BF_executeで実行されるのは設定したアルゴリズムのみ)
        //case SEP_MSNR: // MSNRフローの実行 (BF_executeで実行されるのは設定したアルゴリズムのみ)
        //case SEP_GSS:  // GSSフローの実行  (BF_executeで実行されるのは設定したアルゴリズムのみ)
        //case SEP_GICA: // GICAフローの実行 (BF_executeで実行されるのは設定したアルゴリズムのみ)
        //case SEP_DS:   // DSフローの実行   (BF_executeで実行されるのは設定したアルゴリズムのみ)
        //case SEP_WDS:  // WDSフローの実行  (BF_executeで実行されるのは設定したアルゴリズムのみ)
        //case SEP_NULL: // NULLフローの実行 (BF_executeで実行されるのは設定したアルゴリズムのみ)
        //case SEP_ILSE: // ILSEフローの実行 (BF_executeで実行されるのは設定したアルゴリズムのみ)
        //case SEP_ML:   // MLフローの実行   (BF_executeで実行されるのは設定したアルゴリズムのみ)
            if(num_src > 0){
                //LOGI("[%d] GHDSS (%d) num_src = %d", GHDSSCount, ary.count, ary.source_num);
                if(iS != NULL){
                    for(int ch = 0; ch < num_mic; ch++){
                        for(int i = 0; i < ARY_NUM_FFT; i++){
                            inputSpec[ch][i].re = iS->data[ch][i].real;
                            inputSpec[ch][i].im = iS->data[ch][i].imag;
                        }
                    }
                }
                else{
                    //LOGI("HABufferGetFFTData --> NULL");
                    ::memset(&inputSpec, 0, sizeof(inputSpec));
                }
                //for(int i=0; i<num_src; i++){ LOGD("ary.data[%d] %d %f %f %f", i, ary.data[i].id, ary.data[i].x[0], ary.data[i].x[1], ary.data[i].x[2]); }
                //LOGD("BF_execute start %d count = %d", thread_no, GHDSSCount);
                BF_SourceLocation currentSourcePositions[num_src];
                for(int 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しない方向はノイズ
                }
                ::BF_execute(num_src, inputSpec, currentSourcePositions, GHDSS_outputSpec); // inputSpecとaryからoutputSpecを計算する
                //::BF_execute(num_src, inputSpec, ary, GHDSS_outputSpec); // inputSpecとaryからoutputSpecを計算する
            }
            break;
#endif // BUILD_MODULE_BF
        case SEP_NONE:
        default: // Unsupported separate type found, same as SEP_NONE.
            if(iS != NULL){
                int close_talking_mic_ch = 0;
                //for(int ch = 0; ch < ARY_NUM_SRC; ch++) {
                for(int ch = 0; ch < num_src; ch++){
                    for(int i = 0; i < ARY_NUM_FFT; i++) {
                        GHDSS_outputSpec[ch][i].re = iS->data[close_talking_mic_ch][i].real;
                        GHDSS_outputSpec[ch][i].im = iS->data[close_talking_mic_ch][i].imag;
                    }
                }
            }
            break;
        }
        //const double end = current_ms();
        //LOGD("GHDSSCount %d / Src Num = %d", GHDSSCount, num_src);
        //LOGI("  GHDSS_core time elapsed = %f ms", end - start);

        //LOGD("GHDSS_out re %f %f %f %f %f", GHDSS_outputSpec[0][0].re, GHDSS_outputSpec[0][1].re, GHDSS_outputSpec[0][2].re, GHDSS_outputSpec[0][3].re, GHDSS_outputSpec[0][4].re);
        //LOGD("GHDSS_out im %f %f %f %f %f", GHDSS_outputSpec[0][0].im, GHDSS_outputSpec[0][1].im, GHDSS_outputSpec[0][2].im, GHDSS_outputSpec[0][3].im, GHDSS_outputSpec[0][4].im);

        //int src_start, src_end, fft_start, fft_end; src_start=0; src_end=/*1*/num_src; fft_start=0; fft_end=257/*4*/;
        //LOGI("GHDSS_out");
        //for(int src=src_start; src<src_end; src++){
        //  LOGI("Src No = %d", src);
        //  for(int fft=fft_start; fft<fft_end; fft++){
        //      LOGD("  [%d][%d] = %f %f", src, fft, GHDSS_outputSpec[src][fft].re, GHDSS_outputSpec[src][fft].im);
        //  }
        //}

        // allocate variables for filter calculation.
        ::HA_Float PowerCalcForMap_outputSpec[ARY_NUM_SRC][ARY_NUM_FFT];    // outputSpec
        ::HA_Float EstimateLeak_outputSpec[ARY_NUM_SRC][ARY_NUM_FFT];       // outputPowerSpec
        ::HA_Float HRLE_outputSpec[ARY_NUM_SRC][ARY_NUM_FFT];               // outputPowerSpec
        ::HA_Float CalcSpecAddPower_outputSpec[ARY_NUM_SRC][ARY_NUM_FFT];
        ::HA_Float CalcSpecSubGain_voiceProb[ARY_NUM_SRC][ARY_NUM_FFT];
        ::HA_Float CalcSpecSubGain_gain[ARY_NUM_SRC][ARY_NUM_FFT];
        ::HA_Float CalcSpecSubGain_outputSpec[ARY_NUM_SRC][ARY_NUM_FFT];
        switch(UseFilter){
        case FILTER_HRLE: // HRLEフローの実行
//          printf("IGARASHI : FILTER_HRLE\n");
            ::PowerCalcForMap(num_src, GHDSS_outputSpec, PowerCalcForMap_outputSpec);     // 複素スペクトルをパワースペクトルに変換する
            ::EstimateLeak(num_src, PowerCalcForMap_outputSpec, EstimateLeak_outputSpec); // 漏れノイズの推定を行う
            //const double start = current_ms();
            ::HRLE(num_src, PowerCalcForMap_outputSpec, HRLE_outputSpec);
            //const double end = current_ms();
            //LOGD("GHDSSCount %d / Src Num = %d", GHDSSCount, num_src);
            //LOGI("  HRLE time elapsed = %f ms", end - start);
            ::CalcSpecAddPower(num_src, HRLE_outputSpec, EstimateLeak_outputSpec, CalcSpecAddPower_outputSpec);
            ::CalcSpecSubGain(num_src, PowerCalcForMap_outputSpec, CalcSpecAddPower_outputSpec, CalcSpecSubGain_voiceProb, CalcSpecSubGain_gain, CalcSpecSubGain_outputSpec);
            ::SpectralGainFilter(num_src, GHDSS_outputSpec, CalcSpecSubGain_voiceProb, CalcSpecSubGain_gain, SpectralGainFilter_outputSpec);
            break;
        case FILTER_NONE: // default
//          printf("IGARASHI : FILTER_NONE\n");
        default: // Unsupported filter type found, same as FILTER_NONE.
            //for(int ch = 0; ch < ARY_NUM_SRC; ch++){
            for(int ch = 0; ch < num_src; ch++){
                for(int i = 0; i < ARY_NUM_FFT; i++){
                    SpectralGainFilter_outputSpec[ch][i].re = GHDSS_outputSpec[ch][i].re;
                    SpectralGainFilter_outputSpec[ch][i].im = GHDSS_outputSpec[ch][i].im;
                }
            }
            break;
        }

#if 0 /* 2013.02.15 分離音スペクトル保存 */
        /****************************/
        /*  Create Spectral File    */
        /****************************/
        if(filtered_num_src > 0){
            HA_Float write_data_[1][ARY_NUM_FFT*2];
            int i_reg, p_reg;

            for(i_reg = 0, p_reg = 0; i_reg < ARY_NUM_FFT; i_reg++){
                write_data_[0][p_reg] = SpectralGainFilter_outputSpec[0][i_reg].re;
                p_reg++;
                write_data_[0][p_reg] = SpectralGainFilter_outputSpec[0][i_reg].im;
                p_reg++;
            }
            FILE *fp_;
            char write_file_[ARY_PATH_LENGTH] = SPT_FILE_NAME;

            if ((fp_ = fopen(write_file_, "ab")) == NULL) {
                fprintf(stderr, "file open error!!\n");
            }
            else{
                fwrite(write_data_[0], sizeof(HA_Float), ARY_NUM_FFT*2, fp_);
                fclose(fp_);
            }
        }
#endif

#ifdef ENABLE_BLUETOOTH
//
//
//
        if(BluetoothTransfer){ // bluetoothフローの実行
            HA_Float write_data[ARY_NUM_SRC][ARY_NUM_WAVE];
            HA_Float lowpassed_write_data[ARY_NUM_SRC][ARY_NUM_WAVE];
            ::Synthesize(num_src, ARY_NUM_FFT, SpectralGainFilter_outputSpec, write_data);
            
                SOURCE_DATA_ARY_t *pre_src;
                pre_src = HABufferGetSourceData(GHDSSCount - 1); /* ひとつ前の音源リストへのポインタを取得 */
                if(UseSourceFilter){
                    for(int i = 0; i < num_src_pre[thread_no]; i++){
                        if(pre_src->data[i].mask & Mask_Use_Output){
                            int flag = checkterminate(pre_src->data[i].id, num_src, ary);
                            if(flag == TERMINATED_ID){
                                bt_finalizerawdata(i, pre_src->data[i].id);
                            }
                        }
                    }
                    for(int i = 0; i < num_src; i++) {
                        if(ary.data[i].mask & Mask_Use_Output){
                            int flag = checkid(pre_src, num_src_pre[thread_no], ary.data[i].id);
                            //LOGI("i = %d, id = %d, flag = %d", i, ary.data[i].id, flag);
                            bt_writerawdata(write_data, i, ary.data[i].id, ary.data[i].x[0], ary.data[i].x[1], flag);
                            //LOGE("cnt_reg1 = %d", cnt_reg1);
                        }
                    }
                }
                else{
                    for(int i = 0; i < num_src_pre[thread_no]; i++){
                        int flag = checkterminate(pre_src->data[i].id, num_src, ary);
                        if(flag == TERMINATED_ID){
                            bt_finalizerawdata(i, pre_src->data[i].id);
                        }
                    }
                    for(int i = 0; i < num_src; i++) {
                        int flag = checkid(pre_src, num_src_pre[thread_no], ary.data[i].id);
                        //LOGI("i = %d, id = %d, flag = %d", i, ary.data[i].id, flag);
                        bt_writerawdata(write_data, i, ary.data[i].id, ary.data[i].x[0], ary.data[i].x[1], flag);
                        //LOGE("cnt_reg1 = %d", cnt_reg1);
                    }
                }
        }
//
//
//
#endif	// ENABLE_BLUETOOTH

        if(SendPort & (SEND_PORT_F | SEND_PORT_F_FLAC)){ UseSynthesize = 1; } // temporary easy implementation
        if(UseSynthesize){ // Synthesizeフローの実行
            HA_Float write_data[ARY_NUM_SRC][ARY_NUM_WAVE];
            HA_Float lowpassed_write_data[ARY_NUM_SRC][ARY_NUM_WAVE];
            ::Synthesize(num_src, ARY_NUM_FFT, SpectralGainFilter_outputSpec, write_data);
            if(UseZeroCross){
                //LOGD("  LowpassFilter Start [%d]", GHDSSCount);
                ::LowpassFilter(num_src, write_data, lowpassed_write_data);
                //LOGD("  ZeroCross_s Start [%d]", GHDSSCount);
                ::ZeroCross_s(num_src, lowpassed_write_data, &ary);
                if(SaveSource){
                    SaveSourceLocation(num_src, &ary); // 2013.04.22 miyazaki
                }
                HABufferSetSourceData(GHDSSCount, &ary);
            }

            if(SendPort & (SEND_PORT_F | SEND_PORT_F_FLAC)){ /* 2013.02.15 分離音スペクトルを音声に変換し保存 */
                SOURCE_DATA_ARY_t *pre_src;
                pre_src = HABufferGetSourceData(GHDSSCount - 1); /* ひとつ前の音源リストへのポインタを取得 */
                ////int pre_src_mask[8]; // Must larger than all source
                if(UseSourceFilter){
                    ////for(int i=0; i<8; i++){ pre_src_mask[i] = -1; }
                    // TAKIGAHIRA : modified code for use mask
                    //for(int i=0; i<pre_src->source_num; i++) {
                    //  for(int j=0; j<filter_ary.source_num; j++) {
                    //      if((filter_ary.data[j].x[0] == pre_src->data[i].x[0])
                    //      && (filter_ary.data[j].x[1] == pre_src->data[i].x[1])
                    //      && (filter_ary.data[j].x[2] == pre_src->data[i].x[2])){ src_mask[i] = pre_src->data[i].id; }
                    //  }
                    //}
                    ////for(int i=0; i<pre_src->source_num; i++) {
                    ////    if(pre_src->data[i].mask && Mask_Use_Output){ src_mask[i] = pre_src->data[i].id; }
                    ////}
                    for(int i = 0; i < num_src_pre[thread_no]; i++){
                        if(pre_src->data[i].mask & Mask_Use_Output){
                            int flag = checkterminate(pre_src->data[i].id, num_src, ary);
                            if(flag == TERMINATED_ID){
                                finalizerawdata(i, pre_src->data[i].id);
                            }
                        }
                    }
                    for(int i = 0; i < num_src; i++) {
                        if(ary.data[i].mask & Mask_Use_Output){
                            int flag = checkid(pre_src, num_src_pre[thread_no], ary.data[i].id);
                            //LOGI("i = %d, id = %d, flag = %d", i, ary.data[i].id, flag);
                            writerawdata(write_data, i, ary.data[i].id, flag);
                            //LOGE("cnt_reg1 = %d", cnt_reg1);
                        }
                    }
                }
                else{
                    for(int i = 0; i < num_src_pre[thread_no]; i++){
                        int flag = checkterminate(pre_src->data[i].id, num_src, ary);
                        if(flag == TERMINATED_ID){
                            finalizerawdata(i, pre_src->data[i].id);
                        }
                    }
                    for(int i = 0; i < num_src; i++) {
                        int flag = checkid(pre_src, num_src_pre[thread_no], ary.data[i].id);
                        //LOGI("i = %d, id = %d, flag = %d", i, ary.data[i].id, flag);
                        writerawdata(write_data, i, ary.data[i].id, flag);
                        //LOGE("cnt_reg1 = %d", cnt_reg1);
                    }
                }
#if 0
                /****************************/
                /*  Create output.raw File  */
                /****************************/
                /*
                if(num_src > 0){
                    FILE *fp;
                    char write_file[ARY_PATH_LENGTH] = OUT_FILE_NAME;
                    short int write_data_sint[ARY_NUM_SRC][ARY_NUM_WAVE];
                    int i_reg;

                    if ((fp = fopen(write_file, "ab")) == NULL) {
                        fprintf(stderr, "file open error!!\n");
                    }
                    else{
                        for(i_reg = 0; i_reg < ARY_NUM_WAVE; i_reg++){
                            write_data_sint[0][i_reg] = (short int)(write_data[0][i_reg]);
                        }
                        fwrite(write_data_sint[0], sizeof(short int), ARY_NUM_WAVE, fp);
                        fclose(fp);
                    }
                }
                */

                /* 2013.02.16 音源ID=0,1,2のみ保存 */
                if(num_src > 0)
                {
                    FILE *fp;
                    char write_file[ARY_PATH_LENGTH];
                    short int write_data_sint[ARY_NUM_SRC][ARY_NUM_WAVE];
                    for(int s=0; s<3; s++){
                        if(ary.data[s].id == s){
                            sprintf(write_file, "%s/And-%d.raw", OUT_FILE_PATH, s);
                            if ((fp = fopen(write_file, "ab")) == NULL) {
                                LOGI("%s open error!!\n", write_file);
                            }
                            else
                            {
                                for(int i_reg = 0; i_reg < ARY_NUM_WAVE; i_reg++)
                                {
                                    write_data_sint[0][i_reg] = (short int)(write_data[s][i_reg]);
                                }
                                fwrite(write_data_sint[0], sizeof(short int), ARY_NUM_WAVE, fp);
                                fclose(fp);
                            }
                        }
                    }
                }
#endif
            }
        }
        //LOGD("GHDSS_core end %d count = %d", thread_no, GHDSSCount);

        num_src_pre[GetNextGo(thread_no)] = num_src;    // 次の人

        ::HD_Header hdr;
        hdr.type = PACKET_SRC_FFT;
        hdr.advance = param.advance;
        hdr.count = GHDSSCount++;

        //LOGD("  GoNextGHDSS[%d] : %d", ary.count, thread_no);
        //GoNextGHDSS(thread_no);

        if(SendPort & (SEND_PORT_D | SEND_PORT_F | SEND_PORT_F_FLAC)){
            ::HDH_SrcInfo srcinfo[num_src]; // num_src is already known
            ::HDH_SrcData srcdata[num_src]; // num_src is already known
            ::HDH_SrcData w_srcdata[num_src]; // num_src is already known
            new_i = 0;
            if(UseSourceFilter){
                for(int i = 0; i < num_src; i++) {
                    if(ary.data[i].mask & Mask_Use_Output){
                        srcinfo[new_i].src_id = ary.data[i].id;
                        srcinfo[new_i].x[0] = ary.data[i].x[0];
                        srcinfo[new_i].x[1] = ary.data[i].x[1];
                        srcinfo[new_i].x[2] = ary.data[i].x[2];
                        srcinfo[new_i].power = ary.data[i].power;
                        //LOGD("sending count %d %f %f %f ************************************************", j, srcinfo[j].x[0], srcinfo[j].x[1], srcinfo[j].x[2]);
                        new_i++;
                    }
                }
                if(SendPort & SEND_PORT_D){
                    const int datnum = ARY_NUM_FFT;
                    for(int i = 0; i < filtered_num_src; i++) {
                        srcdata[i].length = datnum * 2;
                        srcdata[i].data_bytes = sizeof(float) * datnum * 2;
                    }
                    float re_order[datnum * 2 * num_src]; // num_src is already known
                    new_i = 0;
                    for(int num = 0; num < num_src; num++) {
                        if(ary.data[num].mask & Mask_Use_Output){
                            for(int i = 0; i < datnum; i++) {
                                re_order[new_i * datnum * 2 + i] = SpectralGainFilter_outputSpec[num][i].re;
                                re_order[new_i * datnum * 2 + datnum + i] = SpectralGainFilter_outputSpec[num][i].im;
                            }
                            new_i++;
                        }
                    }
                    SendPortD(&hdr, filtered_num_src, srcinfo, srcdata, re_order);
                    //LOGD("SG re %f %f %f %f %f", SpectralGainFilter_outputSpec[0][0].re, SpectralGainFilter_outputSpec[0][1].re, SpectralGainFilter_outputSpec[0][2].re,
                    //      SpectralGainFilter_outputSpec[0][3].re, SpectralGainFilter_outputSpec[0][4].re);
                    //LOGD("SG_out im %f %f %f %f %f", SpectralGainFilter_outputSpec[0][0].im, SpectralGainFilter_outputSpec[0][1].im, SpectralGainFilter_outputSpec[0][2].im,
                    //      SpectralGainFilter_outputSpec[0][3].im, SpectralGainFilter_outputSpec[0][4].im);

                    //LOGD("SG re %f im %f", SpectralGainFilter_outputSpec[0][0].re, SpectralGainFilter_outputSpec[0][0].im);

                    //LOGD("GHDSS sending end %d count = %d", thread_no, GHDSSCount);
                }
                if(SendPort & (SEND_PORT_F | SEND_PORT_F_FLAC)){
                    for(int i = 0; i < filtered_num_src; i++) {
                      w_srcdata[i].length = advance;
                      w_srcdata[i].data_bytes = sizeof(float) * advance;
                    }
                    float w_re_order[advance * num_src]; // advance and num_src is already known
                    new_i = 0;
                    for(int num = 0; num < num_src; num++) {
                        if(ary.data[num].mask & Mask_Use_Output){
                            for(int i = 0; i < advance; i++) {
                                //w_re_order[new_i * advance + i] = wavedata[num][i];
                                w_re_order[new_i * advance + i] = tcp_data[num][i];
                            }
                            new_i++;
                        }
                    }
                    if(SendPort & SEND_PORT_F){
                        SendPortF(&hdr, filtered_num_src, srcinfo, w_srcdata, w_re_order);
                    }
                    if(SendPort & SEND_PORT_F_FLAC){
                        SendPortF_flac(&hdr, filtered_num_src, srcinfo, w_srcdata, w_re_order);
                    }
                    //__android_log_print(ANDROID_LOG_DEBUG, "Frame::Info", "ARY_Count: %d , HDR_Count: %d , GHDSS_Count: %d", ary.count, hdr.count, GHDSSCount);
                    //__android_log_print(ANDROID_LOG_DEBUG, "SRC::Info", "NUM_SRC: %d , SRC_ID: %d", num_src, srcinfo->src_id);
                }
            }
            else{
                for(int i = 0; i < num_src; i++) {
                    srcinfo[i].src_id = ary.data[i].id;
                    srcinfo[i].x[0] = ary.data[i].x[0];
                    srcinfo[i].x[1] = ary.data[i].x[1];
                    srcinfo[i].x[2] = ary.data[i].x[2];
                    srcinfo[i].power = ary.data[i].power;
                    //LOGD("sending count %d %f %f %f ************************************************", i, srcinfo[i].x[0], srcinfo[i].x[1], srcinfo[i].x[2]);
                }
                if(SendPort & SEND_PORT_D){
                    const int datnum = ARY_NUM_FFT;
                    for(int i = 0; i < num_src; i++) {
                        srcdata[i].length = datnum * 2;
                        srcdata[i].data_bytes = sizeof(float) * datnum * 2;
                    }
                    float re_order[datnum * 2 * num_src]; // num_src is already known
                    for(int num = 0; num < num_src; num++) {
                        for(int i = 0; i < datnum; i++) {
                            re_order[num * datnum * 2 + i] = SpectralGainFilter_outputSpec[num][i].re;
                            re_order[num * datnum * 2 + datnum + i] = SpectralGainFilter_outputSpec[num][i].im;
                        }
                    }
                    SendPortD(&hdr, num_src, srcinfo, srcdata, re_order);
                    //LOGD("SG re %f %f %f %f %f", SpectralGainFilter_outputSpec[0][0].re, SpectralGainFilter_outputSpec[0][1].re, SpectralGainFilter_outputSpec[0][2].re,
                    //      SpectralGainFilter_outputSpec[0][3].re, SpectralGainFilter_outputSpec[0][4].re);
                    //LOGD("SG_out im %f %f %f %f %f", SpectralGainFilter_outputSpec[0][0].im, SpectralGainFilter_outputSpec[0][1].im, SpectralGainFilter_outputSpec[0][2].im,
                    //      SpectralGainFilter_outputSpec[0][3].im, SpectralGainFilter_outputSpec[0][4].im);

                    //LOGD("SG re %f im %f", SpectralGainFilter_outputSpec[0][0].re, SpectralGainFilter_outputSpec[0][0].im);

                    //LOGD("GHDSS sending end %d count = %d", thread_no, GHDSSCount);
                }
                if(SendPort & (SEND_PORT_F | SEND_PORT_F_FLAC)){
                    for(int i = 0; i < num_src; i++) {
                      w_srcdata[i].length = advance;
                      w_srcdata[i].data_bytes = sizeof(float) * advance;
                    }
                    float w_re_order[advance * num_src]; // advance and num_src is already known
                    for(int num = 0; num < num_src; num++) {
                        for(int i = 0; i < advance; i++) {
                            //w_re_order[num * advance + i] = wavedata[num][i];
                            w_re_order[num * advance + i] = tcp_data[num][i];
                        }
                    }
                    if(SendPort & SEND_PORT_F){
                        SendPortF(&hdr, num_src, srcinfo, w_srcdata, w_re_order);
                    }
                    if(SendPort & SEND_PORT_F_FLAC){
                        SendPortF_flac(&hdr, num_src, srcinfo, w_srcdata, w_re_order);
                    }
                    //__android_log_print(ANDROID_LOG_DEBUG, "Frame::Info", "ARY_Count: %d , HDR_Count: %d , GHDSS_Count: %d", ary.count, hdr.count, GHDSSCount);
                    //__android_log_print(ANDROID_LOG_DEBUG, "SRC::Info", "NUM_SRC: %d , SRC_ID: %d", num_src, srcinfo->src_id);
                }
            }
        }

        //LOGD("  GoNextGHDSS[%d] : %d", ary.count, thread_no);
        GoNextGHDSS(thread_no);

        WaitSendGHDSS(thread_no);
        //LOGD("  WaitSendGHDSS pass[%d] : %d", ary.count, thread_no);
        //LOGD("  GoNextSendGHDSS[%d] : %d", ary.count, thread_no);
        GoNextSendGHDSS(thread_no);
    }
    else{
        //num_src_pre[GetNextGo(thread_no)] = num_src;    // 次の人
        
        // K.Takagi 2014.11.20
        num_src_pre[GetNextGo(thread_no)] = 0; // 有効な音源なしなので強制的に0

        // go next
        //LOGD("  GoNextGHDSS[%d] : %d", ary.count, thread_no);
        GoNextGHDSS(thread_no);

        WaitSendGHDSS(thread_no);
        //LOGD("  WaitSendGHDSS pass[%d] : %d", ary.count, thread_no);
        //LOGD("  GoNextSendGHDSS[%d] : %d", ary.count, thread_no);
        GoNextSendGHDSS(thread_no);

        // do nothing
    }

    return(0);
}

int ControlObject::init_OutE()
{
    return(0);
}

int ControlObject::OutE(const int thread_no, const SOURCE_DATA_ARY_t &ary, const bool valid_source, ::HA_Complex SpectralGainFilter_outputSpec[][ARY_NUM_FFT])
{
    //::Param_AudioStreamFromMic_t param;
    //::HAGetParamAudioStreamFromMic(&param);
    const ::Param_AudioStreamFromMic_t &param(audio_info);

    const int num_src = std::min(ary.source_num, ARY_NUM_SRC);

    WaitOutE(thread_no);

    /* 2013.03.01 代入位置を後ろに移動
    src_data_pre[GetNextGo(thread_no)] = ary;   // 次の人
    */
    
    if(valid_source){
        OutECount = ary.count; // 2013.02.06 K.Takagi 音源情報のフレーム番号と一致させる

        ::HA_Complex        WhiteNoiseAdder_outputSpec[ARY_NUM_SRC][ARY_NUM_FFT];   // WhiteNoiseAdderの出力スペクトル
        ::HA_Complex        PreEmphasis_outputSpec[ARY_NUM_SRC][ARY_NUM_FFT];       //
        HA_Float        MelFilterBank_fbank[ARY_NUM_SRC][ARY_NUM_FBANK*2];      // メルフィルターバンク
        HA_Float        MSLSExtraction_fbank[ARY_NUM_SRC][ARY_NUM_FBANK_DELTA_POWER];   // メルフィルターバンク+パワー項
        HA_Float        Delta_fbank[ARY_NUM_SRC][ARY_NUM_FBANK_DELTA_POWER];            // 動的特徴量を追加
        HA_Float        FeatureRemover_fbank[ARY_NUM_SRC][ARY_NUM_FBANK_DELTA_POWER];   // 静的特徴量を削除
        int new_i;

        if(SendPort & (SEND_PORT_E | SEND_JULIUS)){ UseCalcFeature = 1; }
        if(UseCalcFeature){
            ::WhiteNoiseAdder(num_src,
                    SpectralGainFilter_outputSpec,
                    WhiteNoiseAdder_outputSpec
                    );
            ::PreEmphasis(num_src,
                    OutECount,
                    WhiteNoiseAdder_outputSpec,
                    PreEmphasis_outputSpec
                    );
            ::MelFilterBank(num_src,
                    OutECount,
                    PreEmphasis_outputSpec,
                    MelFilterBank_fbank
                    );
            ::MSLSExtraction(num_src,
                    PreEmphasis_outputSpec,
                    MelFilterBank_fbank,
                    MSLSExtraction_fbank
                    );
            ::Delta(num_src,
                    OutECount,
                    MSLSExtraction_fbank,
                    Delta_fbank
                    );
            ::PowerFeatureRemover(num_src,
                    Delta_fbank,
                    FeatureRemover_fbank
                    );

            //LOGE("NO SOURCE %d", OutECount);
            //
            // MARK: julius
            //
            if(SendPort & SEND_JULIUS){

                const float coef = 180.0f / M_PI;
                struct feature f;
                if(UseSourceFilter){
                    for(int i = 0; i < num_src; i++){
                        if(ary.data[i].mask & Mask_Use_Output){
                            const int id = ary.data[i].id;

                            //struct feature f;
                            for(int j = 0; j < fbank_count * 2 + 1; j++) {
                                f.feature[j] = FeatureRemover_fbank[i][j];
                            }

                            //LOGD("push_back id %d", id);
                            const float azimuth   = coef * atan2f(ary.data[i].x[1], ary.data[i].x[0]);
                            const float elevation = coef * asinf(ary.data[i].x[2]); //asin=>asinf
                            register_feature_src_info(id, f, azimuth, elevation);
                        }
                    }
                }
                else{
                    for(int i = 0; i < num_src; i++){
                        const int id = ary.data[i].id;

                        //struct feature f;
                        for(int j = 0; j < fbank_count * 2 + 1; j++) {
                            f.feature[j] = FeatureRemover_fbank[i][j];
                        }

                        //LOGD("push_back id %d", id);
                        const float azimuth   = coef * atan2f(ary.data[i].x[1], ary.data[i].x[0]);
                        const float elevation = coef * asinf(ary.data[i].x[2]); //asin=>asinf
                        register_feature_src_info(id, f, azimuth, elevation);
                    }
                }

                //  減った音源を捜して
                std::vector<int> ids;
                ::find_disappearance(src_data_pre[thread_no], ary, ids);

                if(ids.size() > 0){
                    //  送る
                    for(std::vector<int>::iterator iter = ids.begin(); iter != ids.end(); iter++) {
                        const int id = *iter;
#if 0
                        const int size = features[id].size();
                        LOGI("src_id %d", id);
                        LOGI("size %d", size);
                        if (id == 0) {
                            for(int i = 0; i < std::min(6, size); i++) {
                                for(int j = 0; j < 27; j++) {
                                    LOGI("%d : %f", j, features[id][i].feature[j]);
                                }
                            }
                        }
#endif

                        if(SaveSepFeature){
                            union u_value {
                                int i_value;
                                unsigned char c_value[4];
                            } e_conv;
                            float ave_div_elem;
                            int header[3];
                            char fname[ARY_PATH_LENGTH];
                            FILE *fp = NULL;
                            feature ave, send;

                            switch(SaveSepFeature){
                            case FEATURE_SAVE_NOSMN:
                                switch(SaveFeatureType & FEATURE_MASK){
                                case FEATURE_MFCC: //MFCC format is not support yet
                                    sprintf(fname, "%s%03d.%s", UserParamConfigSave_output_feature_file_name, id, "mfc");
                                    if((fp = fopen(fname, "wb")) == NULL){
                                        fprintf(stderr, "save feature : file open error!!\n");
                                    }
                                    else{
                                        int feature_size;
                                        header[2] = 12;
                                        if(SaveFeatureType & FEATURE_USE_E){ header[2]++; }
                                        switch(SaveFeatureType & (FEATURE_USE_D | FEATURE_USE_A)){
                                        case 0x0300: //(FEATURE_USE_D | FEATURE_USE_A)
                                            header[2] *= 3;
                                            break;
                                        case FEATURE_USE_D:
                                            header[2] *= 2;
                                            break;
                                        default:
                                            break;
                                        }
                                        if(SaveFeatureType & FEATURE_USE_N){ header[2]--; }
                                        feature_size = header[2];
                                        header[2] *= 4; //float is 4Byte
                                        header[2] <<= 16;
                                        header[2] |= 0x0006; //0x0006 is MFCC
                                        e_conv.i_value = header[2]; //((27[dim]*4[Byte])<<16) + (0x0009[USER])
                                        header[2] = ((e_conv.c_value[0] << 24)
                                                    |(e_conv.c_value[1] << 16)
                                                    |(e_conv.c_value[2] <<  8)
                                                    |(e_conv.c_value[3] <<  0));
                                        e_conv.i_value = 100000; //100[ns] ==> 0x000186A0
                                        header[1] = ((e_conv.c_value[0] << 24)
                                                    |(e_conv.c_value[1] << 16)
                                                    |(e_conv.c_value[2] <<  8)
                                                    |(e_conv.c_value[3] <<  0));
                                        e_conv.i_value = features[id].size();
                                        header[0] = ((e_conv.c_value[0] << 24)
                                                    |(e_conv.c_value[1] << 16)
                                                    |(e_conv.c_value[2] <<  8)
                                                    |(e_conv.c_value[3] <<  0));
                                        fwrite(header, sizeof(int) * 3, 1, fp); //write 12Byte header
                                        for(int i = 0; i < e_conv.i_value; i++){ //e_conv.i_value is features[id].size()
                                            fwrite(&features[id][i].feature[0], sizeof(float) * feature_size, 1, fp);
                                        }
                                        fclose(fp);
                                    }
                                    break;
                                case FEATURE_USER: //MSLS format supported only
                                    sprintf(fname, "%s%03d.%s", UserParamConfigSave_output_feature_file_name, id, "Nfbank");
                                    if((fp = fopen(fname, "wb")) == NULL){
                                        fprintf(stderr, "save feature : file open error!!\n");
                                    }
                                    else{
                                        e_conv.i_value = 0x006C0009; //((27[dim]*4[Byte])<<16) + (0x0009[USER])
                                        header[2] = ((e_conv.c_value[0] << 24)
                                                    |(e_conv.c_value[1] << 16)
                                                    |(e_conv.c_value[2] <<  8)
                                                    |(e_conv.c_value[3] <<  0));
                                        e_conv.i_value = 100000; //100[ns] ==> 0x000186A0
                                        header[1] = ((e_conv.c_value[0] << 24)
                                                    |(e_conv.c_value[1] << 16)
                                                    |(e_conv.c_value[2] <<  8)
                                                    |(e_conv.c_value[3] <<  0));
                                        e_conv.i_value = features[id].size();
                                        header[0] = ((e_conv.c_value[0] << 24)
                                                    |(e_conv.c_value[1] << 16)
                                                    |(e_conv.c_value[2] <<  8)
                                                    |(e_conv.c_value[3] <<  0));
                                        fwrite(header, sizeof(int) * 3, 1, fp); //write 12Byte header
                                        for(int i = 0; i < e_conv.i_value; i++){ //e_conv.i_value is features[id].size()
                                            fwrite(&features[id][i].feature[0], sizeof(float) * 27, 1, fp);
                                        }
                                        fclose(fp);
                                    }
                                    break;
                                case FEATURE_NOHEADER: //MSLS format supported only
                                    sprintf(fname, "%s%03d.%s", UserParamConfigSave_output_feature_file_name, id, "spec");
                                    if((fp = fopen(fname, "wb")) == NULL){
                                        fprintf(stderr, "save feature : file open error!!\n");
                                    }
                                    else{
                                        header[0] = features[id].size();
                                        fwrite(header, sizeof(int) * 3, 1, fp); //write 12Byte header
                                        for(int i = 0; i < header[0]; i++){ //e_conv.i_value is features[id].size()
                                            fwrite(&features[id][i].feature[0], sizeof(float) * 27, 1, fp);
                                        }
                                        fclose(fp);
                                    }
                                    break;
                                default:
                                    break;
                                }
                                break;
                            case FEATURE_SAVE_SMN:
                                ave_div_elem = 1.0f / features[id].size();
                                // 静的特徴量部のみを平均除去
                                for(int i = 0; i < NELEM(ave.feature); i++) {
                                    ave.feature[i] = 0.0f;
                                }
                                for(int i = 0; i < features[id].size(); i++) {
                                    for(int j = 0; j < NELEM(ave.feature)/2; j++) {
                                        ave.feature[j] += features[id][i].feature[j];
                                    }
                                }
                                for(int i = 0; i < NELEM(ave.feature)/2; i++) {
                                    ave.feature[i] *= ave_div_elem;
                                }
                                switch(SaveFeatureType & FEATURE_MASK){
                                case FEATURE_MFCC: //MFCC format is not support yet
                                    sprintf(fname, "%s%03d.%s", UserParamConfigSave_output_feature_file_name, id, "mfc");
                                    if((fp = fopen(fname, "wb")) == NULL){
                                        fprintf(stderr, "save feature : file open error!!\n");
                                    }
                                    else{
                                        int feature_size;
                                        header[2] = 12;
                                        if(SaveFeatureType & FEATURE_USE_E){ header[2]++; }
                                        switch(SaveFeatureType & (FEATURE_USE_D | FEATURE_USE_A)){
                                        case 0x0300: //(FEATURE_USE_D | FEATURE_USE_A)
                                            header[2] *= 3;
                                            break;
                                        case FEATURE_USE_D:
                                            header[2] *= 2;
                                            break;
                                        default:
                                            break;
                                        }
                                        if(SaveFeatureType & FEATURE_USE_N){ header[2]--; }
                                        feature_size = header[2];
                                        header[2] *= 4; //float is 4Byte
                                        header[2] <<= 16;
                                        header[2] |= 0x0006; //0x0006 is MFCC
                                        e_conv.i_value = header[2]; //((27[dim]*4[Byte])<<16) + (0x0009[USER])
                                        header[2] = ((e_conv.c_value[0] << 24)
                                                    |(e_conv.c_value[1] << 16)
                                                    |(e_conv.c_value[2] <<  8)
                                                    |(e_conv.c_value[3] <<  0));
                                        e_conv.i_value = 100000; //100[ns] ==> 0x000186A0
                                        header[1] = ((e_conv.c_value[0] << 24)
                                                    |(e_conv.c_value[1] << 16)
                                                    |(e_conv.c_value[2] <<  8)
                                                    |(e_conv.c_value[3] <<  0));
                                        e_conv.i_value = features[id].size();
                                        header[0] = ((e_conv.c_value[0] << 24)
                                                    |(e_conv.c_value[1] << 16)
                                                    |(e_conv.c_value[2] <<  8)
                                                    |(e_conv.c_value[3] <<  0));
                                        fwrite(header, sizeof(int) * 3, 1, fp); //write 12Byte header
                                        for(int i = 0; i < e_conv.i_value; i++){ //e_conv.i_value is features[id].size()
                                            for(int j = 0; j < NELEM(ave.feature); j++) {
                                                send.feature[j] = features[id][i].feature[j] - ave.feature[j];
                                            }
                                            fwrite(&send.feature[0], sizeof(float) * feature_size, 1, fp);
                                        }
                                        fclose(fp);
                                    }
                                    break;
                                case FEATURE_USER: //MSLS format supported only
                                    sprintf(fname, "%s%03d.%s", UserParamConfigSave_output_feature_file_name, id, "Nfbank");
                                    if((fp = fopen(fname, "wb")) == NULL){
                                        fprintf(stderr, "save feature : file open error!!\n");
                                    }
                                    else{
                                        e_conv.i_value = 0x006C0009; //((27[dim]*4[Byte])<<16) + (0x0009[USER])
                                        header[2] = ((e_conv.c_value[0] << 24)
                                                    |(e_conv.c_value[1] << 16)
                                                    |(e_conv.c_value[2] <<  8)
                                                    |(e_conv.c_value[3] <<  0));
                                        e_conv.i_value = 100000; //100[ns] ==> 0x000186A0
                                        header[1] = ((e_conv.c_value[0] << 24)
                                                    |(e_conv.c_value[1] << 16)
                                                    |(e_conv.c_value[2] <<  8)
                                                    |(e_conv.c_value[3] <<  0));
                                        e_conv.i_value = features[id].size();
                                        header[0] = ((e_conv.c_value[0] << 24)
                                                    |(e_conv.c_value[1] << 16)
                                                    |(e_conv.c_value[2] <<  8)
                                                    |(e_conv.c_value[3] <<  0));
                                        fwrite(header, sizeof(int) * 3, 1, fp); //write 12Byte header
                                        for(int i = 0; i < e_conv.i_value; i++){ //e_conv.i_value is features[id].size()
                                            for(int j = 0; j < NELEM(ave.feature); j++) {
                                                send.feature[j] = features[id][i].feature[j] - ave.feature[j];
                                            }
                                            fwrite(&send.feature[0], sizeof(float) * 27, 1, fp);
                                        }
                                        fclose(fp);
                                    }
                                    break;
                                case FEATURE_NOHEADER: //MSLS format supported only
                                    sprintf(fname, "%s%03d.%s", UserParamConfigSave_output_feature_file_name, id, "spec");
                                    if((fp = fopen(fname, "wb")) == NULL){
                                        fprintf(stderr, "save feature : file open error!!\n");
                                    }
                                    else{
                                        header[0] = features[id].size();
                                        for(int i = 0; i < header[0]; i++){ //e_conv.i_value is features[id].size()
                                            for(int j = 0; j < NELEM(ave.feature); j++) {
                                                send.feature[j] = features[id][i].feature[j] - ave.feature[j];
                                            }
                                            fwrite(&send.feature[0], sizeof(float) * 27, 1, fp); // 27 => ARY_NUM_FBANK * 2 + 1
                                        }
                                        fclose(fp);
                                    }
                                    break;
                                default:
                                    break;
                                }
                                break;
                            case FEATURE_SAVE_NONE:
                            default:
                                break;
                            }
                            //LOGE("ID -s-: %d", id);
                        }
                        int port(HA_PORT_JULIUS);
                        //LOGI("julius MFT host %s", juliusMFThostname.c_str());
                        //if (juliusMFThostname.find(":") != std::string::npos) {
                        //  LOGI("find : port");
                        //}
                        //::sendASRParam("192.168.33.195", HA_PORT_JULIUS, source_info[id], features[id]);
                        ::sendASRParam(juliusMFThostname.c_str(), port, source_info[id], features[id]);
                    }
                    //  用済みは消す
                    erase_features_src_info(ids);
#ifndef IS_ANDROID
                    if(TerminateInputFile != 0){ this->Stop(); }
#endif
                }
            }
        }

        src_data_pre[GetNextGo(thread_no)] = ary;   // 次の人

        ::HD_Header hdr;
        hdr.type = PACKET_SRC_FEATURE;
        hdr.advance = param.advance;
        hdr.count = OutECount++;

        GoNextOutE(thread_no);

        if(SendPort & SEND_PORT_E){
            ::HDH_SrcInfo srcinfo[ARY_NUM_SRC];
            ::HDH_SrcData srcdata[ARY_NUM_SRC];

            if(UseSourceFilter){
                new_i = 0;
                for(int i = 0; i < num_src; i++) {
                    if(ary.data[i].mask & Mask_Use_Output){
                        srcinfo[new_i].src_id = ary.data[i].id;
                        srcinfo[new_i].x[0] = ary.data[i].x[0];
                        srcinfo[new_i].x[1] = ary.data[i].x[1];
                        srcinfo[new_i].x[2] = ary.data[i].x[2];
                        srcinfo[new_i].power = ary.data[i].power;
                        //LOGD("sending count %d %f %f %f ************************************************", i, srcinfo[i].x[0], srcinfo[i].x[1], srcinfo[i].x[2]);
                        new_i++;
                    }
                }
                for(int i = 0; i < new_i; i++) { //num_src=>new_i
                    srcdata[i].length = ARY_NUM_FBANK * 2; // 13 => ARY_NUM_FBANK
                    srcdata[i].data_bytes = sizeof(float) * ARY_NUM_FBANK * 2; // 13 => ARY_NUM_FBANK
                }
            }
            else{
                for(int i = 0; i < num_src; i++) {
                    srcinfo[i].src_id = ary.data[i].id;
                    srcinfo[i].x[0] = ary.data[i].x[0];
                    srcinfo[i].x[1] = ary.data[i].x[1];
                    srcinfo[i].x[2] = ary.data[i].x[2];
                    srcinfo[i].power = ary.data[i].power;
                    //LOGD("sending count %d %f %f %f ************************************************", i, srcinfo[i].x[0], srcinfo[i].x[1], srcinfo[i].x[2]);
                }
                for(int i = 0; i < num_src; i++) {
                    srcdata[i].length = ARY_NUM_FBANK * 2; // 13 => ARY_NUM_FBANK
                    srcdata[i].data_bytes = sizeof(float) * ARY_NUM_FBANK * 2; // 13 => ARY_NUM_FBANK
                }
                new_i = num_src;
            }
            SendPortE(&hdr, new_i, srcinfo, srcdata, FeatureRemover_fbank); //num_src=>new_i
        }

        //::HDH_SrcData srcdata[8];
        //for(int i = 0; i < num_src; i++) {
        //    srcdata[i].length = 13 * 2;
        //    srcdata[i].data_bytes = sizeof(float) * 13 * 2;
        //}
        // send
        WaitSendOutE(thread_no);
        //if(SendPort & SEND_PORT_E){
        //    SendPortE(&hdr, new_i, srcinfo, srcdata, FeatureRemover_fbank); //num_src=>new_i
        //}
        GoNextSendOutE(thread_no);
    }
    else{
        src_data_pre[GetNextGo(thread_no)] = ary;   // 次の人

        //LOGE("NO VALID SOURCE %d", OutECount);
        // go next
        GoNextOutE(thread_no);
        // send
        WaitSendOutE(thread_no);
        GoNextSendOutE(thread_no);
        // do nothing
    }
    return(0);
}

int ControlObject::initSaveSourceLocation(){
    if ((source_location_fp = fopen(UserParamConfigSave_output_source_file_name, "wt")) == NULL){
        LOGE("%s open error.", UserParamConfigSave_output_source_file_name);
    }

    return(0);
}

int ControlObject::SaveSourceLocation(int   num_src, SOURCE_DATA_ARY_t *sources){
    fprintf(source_location_fp, "%d ", sources->count);

    for(int idx = 0; idx < sources->source_num; idx++){
        fprintf(source_location_fp, "%d %f %f %f\n", sources->data[idx].id, sources->data[idx].x[0], sources->data[idx].x[1], sources->data[idx].x[2]);
    }

    return(OK);
}

void ControlObject::finalizeSaveSourceLocation(){
    fclose(source_location_fp);
}

struct startinfo {
    const int thread_num;
    const bool device_available;
    startinfo();
    startinfo(int athread_num, bool adev) : thread_num(athread_num), device_available(adev) {}
};

static void *loop(void *arg)
{
    //LOGD("Loop Start.\n");
    std::auto_ptr<startinfo> p(reinterpret_cast<startinfo *>(arg));
#ifdef ENABLE_JNI_FOR_ANDROID
    JNIEnv *env = NULL;
    if(::g_vm->AttachCurrentThread(&env, NULL) != JNI_OK){ LOGE("AttachCurrentThread Error"); return(NULL); }
#endif // ENABLE_JNI_FOR_ANDROID
    {
        MULTI_FFT_INFO_t *fft_info = HARKControl->init_fft(p->thread_num);

        class cleanup {
        private:
            MULTI_FFT_INFO_t *fft_info;
        public:
            cleanup();
            cleanup(MULTI_FFT_INFO_t *a) : fft_info(a) {}
            ~cleanup() {
                if(fft_info){ ::ReleaseMultiFFT(fft_info); }
#ifdef ENABLE_JNI_FOR_ANDROID
                if(::g_vm->DetachCurrentThread() != JNI_OK){ LOGE("DetachCurrentThread Error"); }
#endif // ENABLE_JNI_FOR_ANDROID
            }
        };

        cleanup clean(fft_info);

        const int thread_num = p->thread_num;
        const bool debug = (p->device_available ? false : true);

        //float **raw_data = raw_data = (float **)MemoryAllocate2D(8, 512, sizeof(float));
        float **raw_data = raw_data = (float **)MemoryAllocate2D(ARY_NUM_MIC, ARY_NUM_WAVE, sizeof(float));
        if(raw_data == NULL){ LOGE("MemoryAllocate2D Error in raw_data allocate\n"); return(NULL); }
        autofree_2dptr<float> rawdatap(raw_data);

        //COMPLEX_FLOAT **fft_data = (COMPLEX_FLOAT **)MemoryAllocate2D(8, (512 / 2) + 1 , sizeof(COMPLEX_FLOAT));
        COMPLEX_FLOAT **fft_data = (COMPLEX_FLOAT **)MemoryAllocate2D(ARY_NUM_MIC, ARY_NUM_FFT, sizeof(COMPLEX_FLOAT));
        if(fft_data == NULL){ LOGE("MemoryAllocate2D Error in fft_data allocate\n"); return(NULL); }
        autofree_2dptr<COMPLEX_FLOAT> fftdatap(fft_data);

        SOURCE_DATA_ARY_t source;
        SOURCE_DATA_ARY_t filter_source;
        //
        //
        //
        HARKControl->launched(thread_num);
        
        char ts[21];

        while(1) {
            // MARK: メインループ
            //LOGD("%d Raw Start.", thread_num);
            int stat = HARKControl->Raw(thread_num, raw_data, &ts[0]);
            //int stat = HARKControl->Raw(thread_num, debug, raw_data, &ts[0]); // デバイスがつながってないdebug時はデバッグ用データを出力
            if(stat == -1){ break; }
            //LOGD("%d FFT Start.", thread_num);
            stat = HARKControl->Fft(thread_num, fft_info, raw_data, fft_data, ts);
            if(stat == -1){ break; }
            bool valid_source(false);
            //LOGD("%d Lm Start.", thread_num);
            stat = HARKControl->Lm(thread_num, fft_data, source, filter_source, valid_source, ts);
            if(stat == -1){ break; }
            ::HA_Complex    SpectralGainFilter_outputSpec[ARY_NUM_SRC][ARY_NUM_FFT];    // 出力音声
            //LOGD("%d GHDSS Start.", thread_num);
            stat = HARKControl->GHDSS(thread_num, source, filter_source, valid_source, SpectralGainFilter_outputSpec, ts);
            if(stat == -1){ break; }

            if(HARKControl->GetParamBypassOutE() == 0)
            {
                //LOGD("%d OutE Start.", thread_num);
                stat = HARKControl->OutE(thread_num, source, valid_source, SpectralGainFilter_outputSpec);
                if(stat == -1){ break; }
            }
        }
        //LOGD("exit produce thread %d", thread_num);
    }
    return(NULL);
}

#ifdef ENABLE_JNI_FOR_ANDROID
int ControlObject::Start(JNIEnv *env, jobject thiz)
#else
int ControlObject::Start()
#endif // ENABLE_JNI_FOR_ANDROID
{
    lockobject lock(&Start_Stop_mutex);
    
    if (!isStarted()) {
    
        init_vars();
        ResetEventFlag();
        init_julius();

#ifdef ENABLE_BLUETOOTH
        init_bluetooth();
#endif	

        if (SendPort & SEND_PORT_F_FLAC) {
            flac_sep_h_connect();
        }

        // fftinit
        ::SetFFTWindowGain(1.0);
//      ::SetFFTWindowGain(FFT_GAIN);
        //::SetFFTWindowGain(0.05);

        // LM init
        //init_lm();

        //init_GHDSS();
        //init_OutE();
        /* 2013.08.06 K.Takagi init_lmの後ろに移動
        if(init_GHDSS() != 0){ LOGE("init_GHDSS error"); return(-1); }
        if(init_OutE() != 0){  LOGE("init_OutE error");  return(-1); };
        */

        //for (int ch = 0; ch < audio_info.logical_channel_count; ch++) {
        for (int ch = 0; ch < ARY_NUM_MIC; ch++) {
            std::fill(&audio_pre_data[ch][0], &audio_pre_data[ch][audio_info.length], 0);
        }

        bufferObj.clear();
        //
        // MARK: デバイスを決める
        //
        // debug
/* Legacy code for refer
        LOGI("RASP IP : %s", RaspZXhostname.c_str());
        LOGI("NetWork Connect %d", RaspZXConnect);
*/
        LOGI("Microphone IP/host : %s", SocketMicHostname.c_str());
        LOGI("NetWork is Connected? %d", SocketMicConnected);

        if(SocketMicConnected){

            LOGI("Socket Microphone open...");
            socketMicObj.SetHostName(SocketMicHostname.c_str());
            selectedDeviceObj = static_cast<DeviceObject *>(&socketMicObj);
            DeviceAvailable = true;

        }else{
        
//// for USB microphone start
            //int xx = usbMicObj.InitDevice();
            //int xx = usbMicObj.InitDevice(0x23a7, 0xf100, 0xff00);
            //LOGI("xx : %d", xx);
            //selectedDeviceObj = static_cast<DeviceObject *>(&usbMicObj);
            //DeviceAvailable = true;
//// for USB microphone end
#if 0
            LOGI("USB Microphone open...");
#ifdef ENABLE_JNI_FOR_ANDROID
            usbMicObj.SetDeviceType(MicDevice);
            usbMicObj.SetDevice(MicChannels, MicBits);
            usbMicObj.SetInterface(USBMicIfNo, USBMicEpAddr, USBMicMaxPacketSize);
            usbMicObj.SetFd(USBMicFd);
#else // ENABLE_JNI_FOR_ANDROID
#ifdef IS_APPLE_IOS
            usbMicObj.setBitsPerChannel(audio_info.nbits);
            usbMicObj.setSampleRate(audio_info.sampling_rate);
#endif // IS_APPLE_IOS
#endif // ENABLE_JNI_FOR_ANDROID
            selectedDeviceObj = static_cast<DeviceObject *>(&usbMicObj);
            DeviceAvailable = true;
#else
            LOGI("MX Microphone open...");
            /*
            raspMXObj.SetChannelOffset(UserParamMicChannelOffset);
            */
#ifdef ENABLE_RASPMX
            selectedDeviceObj = static_cast<DeviceObject *>(&raspMXObj);
            DeviceAvailable = true;
#endif // ENABLE_RASPMX            
            
#endif

        }

/* Legacy code for refer
        if(RaspZXConnect){
            LOGI("RASP-ZX open...");
            raspZXObj.SetHostName(RaspZXhostname.c_str());
            selectedDeviceObj = static_cast<DeviceObject *>(&raspZXObj);
            DeviceAvailable = true;
        }else{
            LOGI("RASP-LC open...");
#ifdef ENABLE_JNI_FOR_ANDROID
            raspLCObj.SetDevice(RaspLCChannels, RaspLCBits);
            raspLCObj.SetInterface(RaspLCIfNo, RaspLCEpAddr, RaspLCMaxPacketSize);
            raspLCObj.SetFd(RaspLCFd);
#else
#ifdef IS_APPLE_IOS
            raspLCObj.setBitsPerChannel(audio_info.nbits);
            raspLCObj.setSampleRate(audio_info.sampling_rate);
#endif
#endif
            selectedDeviceObj = static_cast<DeviceObject *>(&raspLCObj);
            DeviceAvailable = true;
        }
*/

#ifdef NEVER
        // HW initializes
        Param_AudioStreamFromMic_t audio_param;
        audio_param.device_type    = _DEVICE_TYPE_;
        audio_param.length         = 512;
        //audio_param.advance        = 512;
        audio_param.advance        = _ADVANCE_VAL_;
        audio_param.channel_count  = _DEV_CH_VAL_;
        audio_param.channel_offset = _CH_OFFSET_VAL_;
        audio_param.nbits          = _BIT_VAL_;
        audio_param.sampling_rate  = 16000;

        ::HASetParamAudioStreamFromMic(&audio_param);

        int stat = ::RaspLc_Init();
        if (stat < 0) {
            LOGD("Device Not Found.\n");
            DeviceAvailable = false;
            // LM init
            init_lm(false);

            if(UseReadWavFile){
                //LOGD("OpenWaveFile.\n");
                Param_AudioStreamFromWave_t init;
                init.advance = _ADVANCE_VAL_;
                init.length = 512;
                ::HASetParamAudioStreamFromWave(&init);
                ::OpenWaveFile(WAV_FILE_NAME);
            }
        } else {
            LOGD("Device Found.\n");
            // LM init
            init_lm(true);

            stat = ::RaspLc_Start();
            // 2014.03.15
            LOGD("RaspLC_Start : %d", stat);
            if(stat){ return 0; }
            DeviceAvailable = true;
        }
#endif

        

        // device open
        if(selectedDeviceObj->open() != 0){
            if(UserParamConfigInput_pcm_file_name[0] == '\0') ::strcpy(UserParamConfigInput_pcm_file_name, WAV_FILE_NAME);
            //wavFileObj.SetFileName(WAV_FILE_NAME);
            wavFileObj.SetFileName(UserParamConfigInput_pcm_file_name);
            LOGI("Wav file open... %s", wavFileObj.getFileName().c_str());
            if(wavFileObj.open() != 0){ LOGE("wav file can not open!!!"); return(-1); }
            
            selectedDeviceObj = static_cast<DeviceObject *>(&wavFileObj);
            DeviceAvailable = false;

        	// デバイスと接続できなければWave用
            //audio_info.advance = 160;
            //audio_info.logical_channel_count = 8;
            audio_info.advance = 160;
            //audio_info.advance = 512;
            audio_info.logical_channel_count = selectedDeviceObj->GetChannels();
            audio_info.channel_count  = selectedDeviceObj->GetChannels();
            audio_info.channel_offset = 0;

            /* 2013.08.21 K.Takagi
             *   Waveファイルでの動作を確認
             */
            //audio_info.advance = UserParamConfigAudio.advance;
        }
        else{
        	/* デバイスと接続できたらユーザ設定値 */
            audio_info.advance = UserParamConfigAudio.advance;
            audio_info.logical_channel_count = UserParamConfigAudio.logical_channel_count;
            
            audio_info.channel_offset = UserParamMicChannelOffset;
        }

        audio_info.nbits = selectedDeviceObj->GetBits();
        ////LOGI("bits %d %d", audio_info.nbits, selectedDeviceObj->GetBits());

        //if(audio_info.advance > _ADVANCE_VAL_){             audio_info.advance = _ADVANCE_VAL_; }
        //if(audio_info.logical_channel_count > ARY_NUM_MIC){ audio_info.logical_channel_count = ARY_NUM_MIC; }
        if(audio_info.advance > _ADVANCE_VAL_){
            audio_info.advance = _ADVANCE_VAL_;
        }
        if((audio_info.logical_channel_count > ARY_NUM_MIC) && (audio_info.logical_channel_count > selectedDeviceObj->GetChannels())){
            audio_info.logical_channel_count = std::min(ARY_NUM_MIC, selectedDeviceObj->GetChannels()); //設定値が 確保済みの配列、マイクデバイスのChannel数の小さいほうを超過したらリミットをかける
        }

        // advanceBufferサイズを変更
        advanceBuffer.resize(audio_info.advance);

        // debug
        LOGI("audio_info");
        LOGD(" advance               %d", audio_info.advance);
        LOGD(" channel_count         %d", audio_info.channel_count);
        LOGD(" logical_channel_count %d", audio_info.logical_channel_count);
        LOGD(" channel_offset        %d", audio_info.channel_offset);
        LOGD(" length                %d", audio_info.length);
        LOGD(" advanceBuffer.size    %d", advanceBuffer.size());

        // FLAC
        flac_mic_set_channel(audio_info.logical_channel_count);

        //
        //
        //
        init_lm(DeviceAvailable);
        //init_lm(true);
        
        if(init_GHDSS(DeviceAvailable) != 0){ LOGE("init_GHDSS error"); return(-1); }
        if(init_OutE() != 0){ LOGE("init_OutE error"); return(-1); }

        //
//        ::strcpy(UserParamConfigSave_input_pcm_file_name, "/mnt/sdcard/hark2/input");
//        ::strcpy(UserParamConfigSave_input_pcm_file_name, "./hark-data/input");
        /*
        ::strcpy(UserParamConfigSave_input_pcm_file_name, MIC_IN_FILE_NAME);
        ::strcpy(UserParamConfigSave_output_pow_spec_file_name, SPT_FILE_NAME);
        ::strcpy(UserParamConfigSave_output_feature_file_name, OUT_FILE_NAME);
        ::strcpy(UserParamConfigSave_output_pcm_file_name, OUT_FILE_NAME);
        ::strcpy(UserParamConfigSave_output_pcm_tmp_file_name, OUT_FILE_NAME_TMP);
        ::strcpy(UserParamConfigSave_output_source_file_name, LOCATION_FILE_NAME);
        */
        if(UserParamConfigSave_input_pcm_file_name[0]       == '\0') ::strcpy(UserParamConfigSave_input_pcm_file_name, MIC_IN_FILE_NAME);
        if(UserParamConfigSave_output_pow_spec_file_name[0] == '\0')::strcpy(UserParamConfigSave_output_pow_spec_file_name, SPT_FILE_NAME);
        if(UserParamConfigSave_output_feature_file_name[0]  == '\0')::strcpy(UserParamConfigSave_output_feature_file_name, OUT_FILE_NAME);
        if(UserParamConfigSave_output_pcm_file_name[0]      == '\0')::strcpy(UserParamConfigSave_output_pcm_file_name, OUT_FILE_NAME);
        if(UserParamConfigSave_output_pcm_tmp_file_name[0]  == '\0')::strcpy(UserParamConfigSave_output_pcm_tmp_file_name, OUT_FILE_NAME_TMP);
        if(UserParamConfigSave_output_source_file_name[0]   == '\0')::strcpy(UserParamConfigSave_output_source_file_name, LOCATION_FILE_NAME);

        if(SaveSource){ initSaveSourceLocation(); } // 2013.04.22 miyazaki

        // 2013.03.15
        if(SaveSepRaw){
            switch(SaveSepRaw){
            case PCM_WAV_SINT16:
                // RIFF header
                SepWavFileHeader[0]  = WAVE_HEADER_RIFF;
                SepWavFileHeader[1]  = 0x00000000;
                SepWavFileHeader[2]  = WAVE_HEADER_WAVE;
                // fmt chunk
                SepWavFileHeader[3]  = WAVE_HEADER_FMT;
                SepWavFileHeader[4]  = WAVE_HEADER_FMT_SIZE;
                SepWavFileHeader[5]  = 0x00010000 | WAVE_PARAM_FMT_PCM;
                SepWavFileHeader[6]  = WAVE_PARAM_SR_16000;
                SepWavFileHeader[7]  = WAVE_PARAM_SR_16000 * WAVE_PARAM_BLOCK_BITS_16;
                SepWavFileHeader[8]  = WAVE_PARAM_BITS_16 | WAVE_PARAM_BLOCK_BITS_16;
                // data chunk
                SepWavFileHeader[9]  = WAVE_HEADER_DATA;
                SepWavFileHeader[10] = 0x00000000;
                break;
            case PCM_WAV_SINT24:
                // RIFF header
                SepWavFileHeader[0]  = WAVE_HEADER_RIFF;
                SepWavFileHeader[1]  = 0x00000000;
                SepWavFileHeader[2]  = WAVE_HEADER_WAVE;
                // fmt chunk
                SepWavFileHeader[3]  = WAVE_HEADER_FMT;
                SepWavFileHeader[4]  = WAVE_HEADER_FMT_SIZE;
                SepWavFileHeader[5]  = 0x00010000 | WAVE_PARAM_FMT_PCM;
                SepWavFileHeader[6]  = WAVE_PARAM_SR_16000;
                SepWavFileHeader[7]  = WAVE_PARAM_SR_16000 * WAVE_PARAM_BLOCK_BITS_24;
                SepWavFileHeader[8]  = WAVE_PARAM_BITS_24 | WAVE_PARAM_BLOCK_BITS_24;
                // data chunk
                SepWavFileHeader[9]  = WAVE_HEADER_DATA;
                SepWavFileHeader[10] = 0x00000000;
                break;
            case PCM_WAV_SINT32:
                // RIFF header
                SepWavFileHeader[0]  = WAVE_HEADER_RIFF;
                SepWavFileHeader[1]  = 0x00000000;
                SepWavFileHeader[2]  = WAVE_HEADER_WAVE;
                // fmt chunk
                SepWavFileHeader[3]  = WAVE_HEADER_FMT;
                SepWavFileHeader[4]  = WAVE_HEADER_FMT_SIZE;
                SepWavFileHeader[5]  = 0x00010000 | WAVE_PARAM_FMT_PCM;
                SepWavFileHeader[6]  = WAVE_PARAM_SR_16000;
                SepWavFileHeader[7]  = WAVE_PARAM_SR_16000 * WAVE_PARAM_BLOCK_BITS_32;
                SepWavFileHeader[8]  = WAVE_PARAM_BITS_32 | WAVE_PARAM_BLOCK_BITS_32;
                // data chunk
                SepWavFileHeader[9]  = WAVE_HEADER_DATA;
                SepWavFileHeader[10] = 0x00000000;
                break;
            case PCM_WAV_FLOAT32:
                // RIFF header
                SepWavFileHeader[0]  = WAVE_HEADER_RIFF;
                SepWavFileHeader[1]  = 0x00000000;
                SepWavFileHeader[2]  = WAVE_HEADER_WAVE;
                // fmt chunk
                SepWavFileHeader[3]  = WAVE_HEADER_FMT;
                SepWavFileHeader[4]  = WAVE_HEADER_FMT_SIZE;
                SepWavFileHeader[5]  = 0x00010000 | WAVE_PARAM_FMT_IEEE_FLOAT;
                SepWavFileHeader[6]  = WAVE_PARAM_SR_16000;
                SepWavFileHeader[7]  = WAVE_PARAM_SR_16000 * WAVE_PARAM_BLOCK_BITS_32;
                SepWavFileHeader[8]  = WAVE_PARAM_BITS_32 | WAVE_PARAM_BLOCK_BITS_32;
                // data chunk
                SepWavFileHeader[9]  = WAVE_HEADER_DATA;
                SepWavFileHeader[10] = 0x00000000;
                break;
            case PCM_RAW_SINT16:
            case PCM_RAW_FLOAT32:
            case PCM_RAW_RAWFLOAT:
            case PCM_NONE:
            default:
                break;
            }
        }

printf("SaveMicRaw = %d\n",SaveMicRaw);
        if(SaveMicRaw){
            char ifname[ARY_PATH_LENGTH];
            switch(SaveMicRaw){
            case PCM_WAV_SINT32:
                sprintf(ifname, "%s.wav", UserParamConfigSave_input_pcm_file_name);
                if((input_raw_fp = fopen(ifname, "wb")) == NULL){ LOGE("%s open error.", ifname); }
                else{
                    switch(audio_info.nbits){
                    case 24:
                        LOGD("Warrning : SaveMicRaw was PCM_WAV_SINT32, however device is 24bit.\n");
                        break;
                    case 16:
                        LOGD("Warrning : SaveMicRaw was PCM_WAV_SINT32, however device is 16bit.\n");
                        break;
                    default:
                        LOGD("Warrning : SaveMicRaw was PCM_WAV_SINT32, however this device is set to unsupported bits type.\n");
                        break;
                    }
                    // RIFF header
                    MicWavFileHeader[0]  = WAVE_HEADER_RIFF;
                    MicWavFileHeader[1]  = 0x00000000;
                    MicWavFileHeader[2]  = WAVE_HEADER_WAVE;
                    // fmt chunk
                    MicWavFileHeader[3]  = WAVE_HEADER_FMT;
                    MicWavFileHeader[4]  = WAVE_HEADER_FMT_SIZE;
                    //MicWavFileHeader[5]  = (_CH_VAL_ << 16) | WAVE_PARAM_FMT_PCM;
                    MicWavFileHeader[5]  = (audio_info.logical_channel_count << 16) | WAVE_PARAM_FMT_PCM;
                    MicWavFileHeader[6]  = WAVE_PARAM_SR_16000;
                    //MicWavFileHeader[7]  = WAVE_PARAM_SR_16000 * WAVE_PARAM_BLOCK_BITS_32 * _CH_VAL_;
                    MicWavFileHeader[7]  = WAVE_PARAM_SR_16000 * WAVE_PARAM_BLOCK_BITS_32 * audio_info.logical_channel_count;
                    //MicWavFileHeader[8]  = WAVE_PARAM_BITS_32 | (WAVE_PARAM_BLOCK_BITS_32 * _CH_VAL_);
                    MicWavFileHeader[8]  = WAVE_PARAM_BITS_32 | (WAVE_PARAM_BLOCK_BITS_32 * audio_info.logical_channel_count);
                    // data chunk
                    MicWavFileHeader[9]  = WAVE_HEADER_DATA;
                    MicWavFileHeader[10] = 0x00000000;
                    fwrite(MicWavFileHeader, sizeof(int) * 11, 1, input_raw_fp);
                }
                break;
            case PCM_WAV_SINT24:
                sprintf(ifname, "%s.wav", UserParamConfigSave_input_pcm_file_name);
                if((input_raw_fp = fopen(ifname, "wb")) == NULL){ LOGE("%s open error.", ifname); }
                else{
                    switch(audio_info.nbits){
                    case 24:
                        break;
                    case 16:
                        LOGD("Warrning : SaveMicRaw was PCM_WAV_SINT24, however device is 16bit.\n");
                        break;
                    default:
                        LOGD("Warrning : SaveMicRaw was PCM_WAV_SINT24, however this device is set to unsupported bits type.\n");
                        break;
                    }
                    // RIFF header
                    MicWavFileHeader[0]  = WAVE_HEADER_RIFF;
                    MicWavFileHeader[1]  = 0x00000000;
                    MicWavFileHeader[2]  = WAVE_HEADER_WAVE;
                    // fmt chunk
                    MicWavFileHeader[3]  = WAVE_HEADER_FMT;
                    MicWavFileHeader[4]  = WAVE_HEADER_FMT_SIZE;
                    //MicWavFileHeader[5]  = (_CH_VAL_ << 16) | WAVE_PARAM_FMT_PCM;
                    MicWavFileHeader[5]  = (audio_info.logical_channel_count << 16) | WAVE_PARAM_FMT_PCM;
                    MicWavFileHeader[6]  = WAVE_PARAM_SR_16000;
                    //MicWavFileHeader[7]  = WAVE_PARAM_SR_16000 * WAVE_PARAM_BLOCK_BITS_24 * _CH_VAL_;
                    MicWavFileHeader[7]  = WAVE_PARAM_SR_16000 * WAVE_PARAM_BLOCK_BITS_24 * audio_info.logical_channel_count;
                    //MicWavFileHeader[8]  = WAVE_PARAM_BITS_24 | (WAVE_PARAM_BLOCK_BITS_24 * _CH_VAL_);
                    MicWavFileHeader[8]  = WAVE_PARAM_BITS_24 | (WAVE_PARAM_BLOCK_BITS_24 * audio_info.logical_channel_count);
                    // data chunk
                    MicWavFileHeader[9]  = WAVE_HEADER_DATA;
                    MicWavFileHeader[10] = 0x00000000;
                    fwrite(MicWavFileHeader, sizeof(int) * 11, 1, input_raw_fp);
                }
                break;
            case PCM_WAV_SINT16:
                sprintf(ifname, "%s.wav", UserParamConfigSave_input_pcm_file_name);
                if((input_raw_fp = fopen(ifname, "wb")) == NULL){ LOGE("%s open error.", ifname); }
                else{
                    switch(audio_info.nbits){
                    case 16:
                        break;
                    case 24:
                        LOGD("Warrning : SaveMicRaw was PCM_WAV_SINT16, however device is 24bit.\n");
                        break;
                    default:
                        LOGD("Warrning : SaveMicRaw was PCM_WAV_SINT16, however this device is set to unsupported bits type.\n");
                        break;
                    }
                    // RIFF header
                    MicWavFileHeader[0]  = WAVE_HEADER_RIFF;
                    MicWavFileHeader[1]  = 0x00000000;
                    MicWavFileHeader[2]  = WAVE_HEADER_WAVE;
                    // fmt chunk
                    MicWavFileHeader[3]  = WAVE_HEADER_FMT;
                    MicWavFileHeader[4]  = WAVE_HEADER_FMT_SIZE;
                    //MicWavFileHeader[5]  = (_CH_VAL_ << 16) | WAVE_PARAM_FMT_PCM;
                    MicWavFileHeader[5]  = (audio_info.logical_channel_count << 16) | WAVE_PARAM_FMT_PCM;
                    MicWavFileHeader[6]  = WAVE_PARAM_SR_16000;
                    //MicWavFileHeader[7]  = WAVE_PARAM_SR_16000 * WAVE_PARAM_BLOCK_BITS_16 * _CH_VAL_;
                    MicWavFileHeader[7]  = WAVE_PARAM_SR_16000 * WAVE_PARAM_BLOCK_BITS_16 * audio_info.logical_channel_count;
                    //MicWavFileHeader[8]  = WAVE_PARAM_BITS_16 | (WAVE_PARAM_BLOCK_BITS_16 * _CH_VAL_);
                    MicWavFileHeader[8]  = WAVE_PARAM_BITS_16 | (WAVE_PARAM_BLOCK_BITS_16 * audio_info.logical_channel_count);
                    // data chunk
                    MicWavFileHeader[9]  = WAVE_HEADER_DATA;
                    MicWavFileHeader[10] = 0x00000000;
                    fwrite(MicWavFileHeader, sizeof(int) * 11, 1, input_raw_fp);
                }
                break;
            case PCM_RAW_SINT32:
                sprintf(ifname, "%s.raw", UserParamConfigSave_input_pcm_file_name);
                if((input_raw_fp = fopen(ifname, "wb")) == NULL){ LOGE("%s open error.", ifname); }
                else{
                    switch(audio_info.nbits){
                    case 24:
                        LOGD("Warrning : SaveMicRaw was PCM_RAW_SINT32, however device is 24bit.\n");
                        break;
                    case 16:
                        LOGD("Warrning : SaveMicRaw was PCM_RAW_SINT32, however device is 16bit.\n");
                        break;
                    default:
                        LOGD("Warrning : SaveMicRaw was PCM_RAW_SINT32, however this device is set to unsupported bits type.\n");
                        break;
                    }
                }
                break;
            case PCM_RAW_SINT24:
                sprintf(ifname, "%s.raw", UserParamConfigSave_input_pcm_file_name);
                if((input_raw_fp = fopen(ifname, "wb")) == NULL){ LOGE("%s open error.", ifname); }
                else{
                    switch(audio_info.nbits){
                    case 24:
                        break;
                    case 16:
                        LOGD("Warrning : SaveMicRaw was PCM_RAW_SINT24, however device is 16bit.\n");
                        break;
                    default:
                        LOGD("Warrning : SaveMicRaw was PCM_RAW_SINT24, however this device is set to unsupported bits type.\n");
                        break;
                    }
                }
                break;
            case PCM_RAW_SINT16:
                sprintf(ifname, "%s.raw", UserParamConfigSave_input_pcm_file_name);
                if((input_raw_fp = fopen(ifname, "wb")) == NULL){ LOGE("%s open error.", ifname); }
                else{
                    switch(audio_info.nbits){
                    case 16:
                        break;
                    case 24:
                        LOGD("Warrning : SaveMicRaw was PCM_RAW_SINT16, however device is 24bit.\n");
                        break;
                    default:
                        LOGD("Warrning : SaveMicRaw was PCM_RAW_SINT16, however this device is set to unsupported bits type.\n");
                        break;
                    }
                }
                break;
            case PCM_NONE:
            default:
                break;
            }
printf("%s\n", ifname);
        }

        for(int i = 0; i < WorkerThreadNum; i++) {
            launch[i].Reset();
        }

        // thread start
        for (int i = 0; i < WorkerThreadNum; i++) {
            startinfo *p = new startinfo(i, DeviceAvailable);
            int rr = ::pthread_create(&thread_id[i], NULL, loop, reinterpret_cast<void *>(p));
            if (rr != 0) {
                delete p;
                LOGE("pthread_create ERROR");

                SetBeingStopped();
                for (int j = 0; j < i; j++) {
                    void *ret;
                    ::pthread_join(thread_id[j], &ret);
                }
                ResetBeingStopped();

                return(-1);
            }
        }
        for(int i = 0; i < WorkerThreadNum; i++){ launch[i].Wait(); }
        
        //
        // device start
        //
        if(selectedDeviceObj->start(bufferObj) != 0){ LOGE("device start error"); return(-1); }
        
        SetStarted();
        
    } else {
        LOGD("already started");
    }
    return(0);
}

int ControlObject::Stop()
{
    lockobject lock(&Start_Stop_mutex);
    if (isStarted()) {
        SetBeingStopped();
        
        //LOGI("STOP wait worker thread");
        // とまるまでまつ
        for(int i = 0; i < WorkerThreadNum; i++) {
            void *ret;
            if(::pthread_join(thread_id[i], &ret) != 0){ LOGE("pthread_join ERROR"); }
        }

#ifdef NEVER
        if(DeviceAvailable){ RaspLc_Stop(); }
        else{
            if(UseReadWavFile){ ::CloseWaveFile(); }
        }
#endif
        
        //LOGI("STOP wait device");
        // device stop
        if(selectedDeviceObj->stop() != 0){ LOGE("device stop error"); return(-1); }
        
        //LOGI("STOP close");
        // device close
        if(selectedDeviceObj->close() != 0){ LOGE("device close error"); return(-1); }
        
        //LOGI("STOP wait savesource");
        if(SaveSource){ finalizeSaveSourceLocation(); } // 2013.04.22 miyazaki
        
        // 2013.03.15
        int riff_size, data_size;
        struct stat file_stat;
        char ifname[ARY_PATH_LENGTH];
        if((input_raw_fp = fopen(ifname, "wb")) == NULL){ LOGE("%s open error.", ifname); }

        switch(SaveMicRaw){
        case PCM_WAV_SINT24:
        case PCM_WAV_SINT16:
            if(input_raw_fp == NULL){
                fprintf(stderr, "input wav file is null!!\n");
            }
            else{
                fclose(input_raw_fp);
            }
            sprintf(ifname, "%s.wav", UserParamConfigSave_input_pcm_file_name);
            if((input_raw_fd = open(ifname, O_RDWR)) < 0){
                fprintf(stderr, "file descriptor open error!!\n");
                LOGE("file descriptor open error, case of SaveMicRaw->PCM_WAV_SINT16/24->HeaderWrite");
            }
            else{
                if(fstat(input_raw_fd, &file_stat) < 0){ fprintf(stderr, "file stat error!!\n"); break; }
                if((input_raw_fp = fdopen(input_raw_fd, "wb")) == NULL){
                    fprintf(stderr, "file open error!!\n");
                    LOGE("file open error, case of SaveMicRaw->PCM_WAV_SINT16/24->HeaderWrite");
                }
                else{
                    riff_size = (int) (file_stat.st_size < 0xFFFFFFFF ? file_stat.st_size : 0xFFFFFFFF) - 8;
                    data_size = riff_size - 36;
                    fseek(input_raw_fp, 4, SEEK_SET);
                    fwrite(&riff_size, sizeof(int), 1, input_raw_fp);
                    fseek(input_raw_fp, 32, SEEK_CUR);
                    fwrite(&data_size, sizeof(int), 1, input_raw_fp);
                    fclose(input_raw_fp);
                }
                close(input_raw_fd);
            }
            break;
        case PCM_RAW_SINT24:
        case PCM_RAW_SINT16:
            if(input_raw_fp == NULL){
                fprintf(stderr, "input raw file is null!!\n");
            }
            else{
                fclose(input_raw_fp);
            }
            break;
        case PCM_NONE:
        default:
            if(input_raw_fp != NULL){
                fclose(input_raw_fp);
            }
            break;
        }

        /* バッファ解放 */
        ::HAReleaseLocalizeMUSIC();
        ::HABufferRelease();

        clear_features_src_info();

        if (SendPort & SEND_PORT_F_FLAC) {
            flac_sep_clear();
        }

        ResetBeingStopped();
        ResetStarted();
    }
    return(0);
}

#ifdef ENABLE_JNI_FOR_ANDROID
int ControlObject::SetParam(JNIEnv *env, jobject thiz)
#else
int ControlObject::SetParam()
#endif // ENABLE_JNI_FOR_ANDROID
{
    // Param Set and Restart
    Stop();
    //
#ifdef ENABLE_JNI_FOR_ANDROID
    Start(env, thiz);
#else
    Start();
#endif // ENABLE_JNI_FOR_ANDROID
    return(0);
}

#ifdef ENABLE_JNI_FOR_ANDROID
int ControlObject::GetParam(JNIEnv *env, jobject thiz)
#else
int ControlObject::GetParam()
#endif // ENABLE_JNI_FOR_ANDROID
{
    return(0);
}

int ControlObject::SetStarted()
{
    lockobject lock(&Started_mutex);
    Started = true;
    return(0);
}

int ControlObject::ResetStarted()
{
    lockobject lock(&Started_mutex);
    Started = false;
    return(0);
}

bool ControlObject::isStarted()
{
    lockobject lock(&Started_mutex);
    const bool val = Started;
    return(val);
}

int ControlObject::SetBeingStopped()
{
    lockobject lock(&Being_Stopped_mutex);
    BeingStopped = true;
    return(0);
}

int ControlObject::ResetBeingStopped()
{
    lockobject lock(&Being_Stopped_mutex);
    BeingStopped = false;
    return(0);
}

bool ControlObject::isBeingStopped()
{
    lockobject lock(&Being_Stopped_mutex);
    const bool val = BeingStopped;
    return(val);
}

/*
int ControlObject::RaspLc_Stop()
{
    lockobject lock(&RaspLc_Stop_mutex);
    ::RaspLc_Stop();
    return(0);
}
*/

//
//
//
int ControlObject::AddSocket(const int port, const int fd)
{
    //LOGD("add port %d socket %d", port, fd);
    switch(port) {
    case HA_PORT_A:
        {
            lockobject lock(&PortASockets_mutex);
            PortASockets.push_back(fd);
        }
        break;
    case HA_PORT_B:
        {
            lockobject lock(&PortBSockets_mutex);
            PortBSockets.push_back(fd);
        }
        break;
    case HA_PORT_C:
        {
            lockobject lock(&PortCSockets_mutex);
            PortCSockets.push_back(fd);
        }
        break;
    case HA_PORT_D:
        {
            lockobject lock(&PortDSockets_mutex);
            PortDSockets.push_back(fd);
        }
        break;
    case HA_PORT_E:
        {
            lockobject lock(&PortESockets_mutex);
            PortESockets.push_back(fd);
        }
        break;
    case HA_PORT_F:
        {
            lockobject lock(&PortFSockets_mutex);
            PortFSockets.push_back(fd);
        }
        break;
    case HA_PORT_A_FLAC_HEADER:
        {
            lockobject lock(&PortA_FLAC_Sockets_mutex);
            PortA_FLAC_Sockets.push_back(fd);
        }
        break;
    //case HA_COMMAND_PORT:
    //    {
    //        lockobject lock(&CommandPortSockets_mutex);
    //        CommandPortSockets.push_back(fd);
    //    }
    //    break;
    //case HA_IMPORT_PARAM_PORT:
    //    {
    //        lockobject lock(&ImportParamPortSockets_mutex);
    //        ImportParamPortSockets.push_back(fd);
    //    }
    //    break;
    //case HA_EXPORT_PARAM_PORT:
    //    {
    //        lockobject lock(&ExportParamPortSockets_mutex);
    //        ExportParamPortSockets.push_back(fd);
    //    }
    //    break;
    default:
        return(-1);
    }
    return(0);
}

int ControlObject::RemoveSocket(const int port, const int fd)
{
    LOGD("remove port %d socket %d", port, fd);
    switch(port) {
    case HA_PORT_A:
        {
            lockobject lock(&PortASockets_mutex);
            std::vector<int>::iterator end_iter = std::remove(PortASockets.begin(), PortASockets.end(), fd);
            PortASockets.erase( end_iter, PortASockets.end() );
        }
        break;
    case HA_PORT_B:
        {
            lockobject lock(&PortBSockets_mutex);
            std::vector<int>::iterator end_iter = std::remove(PortBSockets.begin(), PortBSockets.end(), fd);
            PortBSockets.erase( end_iter, PortBSockets.end() );
        }
        break;
    case HA_PORT_C:
        {
            lockobject lock(&PortCSockets_mutex);
            std::vector<int>::iterator end_iter = std::remove(PortCSockets.begin(), PortCSockets.end(), fd);
            PortCSockets.erase( end_iter, PortCSockets.end() );
        }
        break;
    case HA_PORT_D:
        {
            lockobject lock(&PortDSockets_mutex);
            std::vector<int>::iterator end_iter = std::remove(PortDSockets.begin(), PortDSockets.end(), fd);
            PortDSockets.erase( end_iter, PortDSockets.end() );
        }
        break;
    case HA_PORT_E:
        {
            lockobject lock(&PortESockets_mutex);
            std::vector<int>::iterator end_iter = std::remove(PortESockets.begin(), PortESockets.end(), fd);
            PortESockets.erase( end_iter, PortESockets.end() );
        }
        break;
    case HA_PORT_F:
        {
            lockobject lock(&PortFSockets_mutex);
            std::vector<int>::iterator end_iter = std::remove(PortFSockets.begin(), PortFSockets.end(), fd);
            PortFSockets.erase( end_iter, PortFSockets.end() );
        }
        break;
    case HA_PORT_A_FLAC_HEADER:
        {
            lockobject lock(&PortA_FLAC_Sockets_mutex);
            std::vector<int>::iterator end_iter = std::remove(PortA_FLAC_Sockets.begin(), PortA_FLAC_Sockets.end(), fd);
            PortA_FLAC_Sockets.erase( end_iter, PortA_FLAC_Sockets.end() );
        }
        break;
    //case HA_COMMAND_PORT:
    //    {
    //        lockobject lock(&CommandPortSockets_mutex);
    //        std::vector<int>::iterator end_iter = std::remove(CommandPortSockets.begin(), CommandPortSockets.end(), fd);
    //        CommandPortSockets.erase( end_iter, CommandPortSockets.end() );
    //    }
    //    break;
    //case HA_IMPORT_PARAM_PORT:
    //    {
    //        lockobject lock(&ImportParamPortSockets_mutex);
    //        std::vector<int>::iterator end_iter = std::remove(ImportParamPortSockets.begin(), ImportParamPortSockets.end(), fd);
    //        ImportParamPortSockets.erase( end_iter, ImportParamPortSockets.end() );
    //    }
    //    break;
    //case HA_EXPORT_PARAM_PORT:
    //    {
    //        lockobject lock(&ExportParamPortSockets_mutex);
    //        std::vector<int>::iterator end_iter = std::remove(ExportParamPortSockets.begin(), ExportParamPortSockets.end(), fd);
    //        ExportParamPortSockets.erase( end_iter, ExportParamPortSockets.end() );
    //    }
    //    break;
    default:
        return(-1);
    }
    return(0);
}

int ControlObject::SendPortA(const void *addr, const size_t len) const
{
    std::vector<int>::const_iterator iter;
    for(iter = PortASockets.begin(); iter != PortASockets.end(); iter++) {
        ::writesock(*iter, addr, len, NULL, NULL);
    }
    return(0);
}

int ControlObject::SendPortA(const ::HD_Header *hdr, const ::HDH_MicData *mic, const float *data)
{
    lockobject lock(&PortASockets_mutex);
    SendPortA(hdr, sizeof(*hdr));
    SendPortA(mic, sizeof(*mic));
    SendPortA(data, mic->data_bytes);
    return(0);
}

int ControlObject::ClosePortA()
{
    lockobject lock(&PortASockets_mutex);
    std::vector<int>::const_iterator iter;
    for(iter = PortASockets.begin(); iter != PortASockets.end(); iter++) {
        ::close(*iter);
    }
    PortASockets.clear();
    return(0);
}
    
int ControlObject::SendPortB(const void *addr, const size_t len) const
{
    std::vector<int>::const_iterator iter;
    for(iter = PortBSockets.begin(); iter != PortBSockets.end(); iter++) {
        ::writesock(*iter, addr, len, NULL, NULL);
    }
    return(0);
}

int ControlObject::SendPortB(const ::HD_Header *hdr, const ::HDH_MicData *mic, const float *data)
{
    lockobject lock(&PortBSockets_mutex);
    SendPortB(hdr, sizeof(*hdr));
    SendPortB(mic, sizeof(*mic));
    SendPortB(data, mic->data_bytes);
    return(0);
}

int ControlObject::ClosePortB()
{
    lockobject lock(&PortBSockets_mutex);
    std::vector<int>::const_iterator iter;
    for(iter = PortBSockets.begin(); iter != PortBSockets.end(); iter++) {
        ::close(*iter);
    }
    PortBSockets.clear();
    return(0);
}

int ControlObject::SendPortC(const void *addr, const size_t len) const
{
    std::vector<int>::const_iterator iter;
    for(iter = PortCSockets.begin(); iter != PortCSockets.end(); iter++) {
        ::writesock(*iter, addr, len, NULL, NULL);
    }
    return(0);
}

int ControlObject::SendPortCwithTS(const ::HD_Header *hdr, const int num, const ::HDH_SrcInfo *srcinfo, char* ts)
{
    lockobject lock(&PortCSockets_mutex);
    SendPortC(hdr, sizeof(*hdr));
    SendPortC(ts, /*sizeof(*ts)*/21); //max digits of %ull
    SendPortC(&num, sizeof(num));
    if (num > 0) {
        SendPortC(srcinfo, sizeof(*srcinfo) * num);
    }
    return(0);
}

int ControlObject::SendPortC(const ::HD_Header *hdr, const int num, const ::HDH_SrcInfo *srcinfo)
{
    lockobject lock(&PortCSockets_mutex);
    SendPortC(hdr, sizeof(*hdr));
    SendPortC(&num, sizeof(num));
    if (num > 0) {
        SendPortC(srcinfo, sizeof(*srcinfo) * num);
    }
    return(0);
}

int ControlObject::ClosePortC()
{
    lockobject lock(&PortCSockets_mutex);
    std::vector<int>::const_iterator iter;
    for(iter = PortCSockets.begin(); iter != PortCSockets.end(); iter++) {
        ::close(*iter);
    }
    PortCSockets.clear();
    return(0);
}

int ControlObject::SendPortD(const void *addr, const size_t len) const
{
    std::vector<int>::const_iterator iter;
    for(iter = PortDSockets.begin(); iter != PortDSockets.end(); iter++) {
        ::writesock(*iter, addr, len, NULL, NULL);
    }
    return(0);
}

int ControlObject::SendPortD(const ::HD_Header *hdr, const int num, const ::HDH_SrcInfo *srcinfo, const ::HDH_SrcData *srcdata, const float *data)
{
    int num_fft_x2;
    lockobject lock(&PortDSockets_mutex);
    SendPortD(hdr, sizeof(*hdr));
    SendPortD(&num, sizeof(num));
    for (int i = 0; i < num; i++) {
        SendPortD(&srcinfo[i], sizeof(*srcinfo));
        SendPortD(&srcdata[i], sizeof(*srcdata));
        num_fft_x2 = srcdata[i].length;
        SendPortD(data + num_fft_x2 * i, srcdata[i].data_bytes); // 257 * 2 => num_fft_x2
    }
    return(0);
}

int ControlObject::ClosePortD()
{
    lockobject lock(&PortDSockets_mutex);
    std::vector<int>::const_iterator iter;
    for(iter = PortDSockets.begin(); iter != PortDSockets.end(); iter++) {
        ::close(*iter);
    }
    PortDSockets.clear();
    return(0);
}

int ControlObject::SendPortE(const void *addr, const size_t len) const
{
    std::vector<int>::const_iterator iter;
    for(iter = PortESockets.begin(); iter != PortESockets.end(); iter++) {
        ::writesock(*iter, addr, len, NULL, NULL);
    }
    return(0);
}

int ControlObject::SendPortE(const ::HD_Header *hdr, const int num, const ::HDH_SrcInfo *srcinfo, const ::HDH_SrcData *srcdata, const float data[][ARY_NUM_FBANK_DELTA_POWER])
{
    lockobject lock(&PortESockets_mutex);
    SendPortE(hdr, sizeof(*hdr));
    SendPortE(&num, sizeof(num));
    for (int i = 0; i < num; i++) {
        SendPortE(&srcinfo[i], sizeof(*srcinfo));
        SendPortE(&srcdata[i], sizeof(*srcdata));
        SendPortE(data[i], srcdata[i].data_bytes);
    }
    return(0);
}

int ControlObject::ClosePortE()
{
    lockobject lock(&PortESockets_mutex);
    std::vector<int>::const_iterator iter;
    for(iter = PortESockets.begin(); iter != PortESockets.end(); iter++) {
        ::close(*iter);
    }
    PortESockets.clear();
    return(0);
}

int ControlObject::SendPortF(const void *addr, const size_t len) const
{
    std::vector<int>::const_iterator iter;
    for(iter = PortFSockets.begin(); iter != PortFSockets.end(); iter++) {
        ::writesock(*iter, addr, len, NULL, NULL);
    }
    return(0);
}

int ControlObject::SendPortF(const ::HD_Header *hdr, const int num, const ::HDH_SrcInfo *srcinfo, const ::HDH_SrcData *srcdata, const float *data)
{
	int advance;

    lockobject lock(&PortFSockets_mutex);
    SendPortF(hdr, sizeof(*hdr));
    SendPortF(&num, sizeof(num));
    for (int i = 0; i < num; i++) {
        SendPortF(&srcinfo[i], sizeof(*srcinfo));
        SendPortF(&srcdata[i], sizeof(*srcdata));

        advance = srcdata[i].length;
        SendPortF(data + advance * i, srcdata[i].data_bytes);
    }
    return(0);
}

int ControlObject::ClosePortF()
{
    lockobject lock(&PortFSockets_mutex);
    std::vector<int>::const_iterator iter;
    for(iter = PortFSockets.begin(); iter != PortFSockets.end(); iter++) {
        ::close(*iter);
    }
    PortFSockets.clear();
    return(0);
}


int ControlObject::SendPortA_flac(const void *addr, const size_t len) const
{
    std::vector<int>::const_iterator iter;
    for(iter = PortA_FLAC_Sockets.begin(); iter != PortA_FLAC_Sockets.end(); iter++) {
        ::writesock(*iter, addr, len, NULL, NULL);
    }
    return(0);
}

int ControlObject::SendPortA_flac(const ::HD_Header *hdr, const ::HDH_MicData *mic, const float *data)
{
  
    //std::cout << "sendporta call" << std::endl;

    lockobject lock_a(&PortA_FLAC_Sockets_mutex);
    lockobject lock_b(&PortA_FLAC_DATA_Sockets_mutex);

    //const unsigned int channels = mic->nch;
    const unsigned int channels = flac_mic_channel;

    SendPortA_flac(hdr, sizeof(*hdr));
    SendPortA_flac(mic, sizeof(*mic));
    
    // 重複部分は送らないように調整
    int offset;
    offset = 0;
    if(hdr->count != 0)
    {
        offset = mic->length - hdr->advance;
    }

    // flac data
    const float *ptr = data;

    //for(int i = 0; i < mic->length; i++) {
    for(int i = offset; i < mic->length; i++) {
      
      //FLAC__int32 idata[HA_PORT_A_FLAC_DATA_NUM * 2] = {0}; // bug 0814
      FLAC__int32 idata[HA_PORT_A_FLAC_DATA_NUM * 8] = {0};

      for(int ch = 0; ch < channels; ch++) {
        //idata[ch] = *(ptr + ch * mic->length);
        idata[ch] = *(ptr + ch * mic->length + offset);
      }
      
      for(int j = 0; j < flac_mic_port_use; j++) {
	
        FLAC__int32 *iptr = &idata[j * 8];
        
        std::vector<flac_mic_data>::iterator iter = PortA_FLAC_DATA_Sockets[j].begin();

        while(iter != PortA_FLAC_DATA_Sockets[j].end()) {
	  
          FLAC__StreamEncoder *encoder = iter->encoder;
          FLAC__bool ok = FLAC__stream_encoder_process_interleaved(encoder, 
                                                                   iptr,
                                                                   1);
          if (!ok) {

            std::cerr << "FLAC: "
        	      << ::FLAC__StreamEncoderStateString[FLAC__stream_encoder_get_state(encoder)]
                  << std::endl;

            iter->dealloc();

            iter = PortA_FLAC_DATA_Sockets[j].erase(iter);

          } else {
            iter++;
          }

        }

      }
      
      ptr++;
    }

    return(0);
}

int ControlObject::ClosePortA_flac()
{
    lockobject lock_a(&PortA_FLAC_Sockets_mutex);
    lockobject lock_b(&PortA_FLAC_DATA_Sockets_mutex);

    for(std::vector<int>::const_iterator iter = PortA_FLAC_Sockets.begin(); iter != PortA_FLAC_Sockets.end(); iter++) {
        ::close(*iter);
    }
    PortA_FLAC_Sockets.clear();
    
    return(0);
}


int ControlObject::SendPortF_flac_h(const void *addr, const size_t len)
{

  if (flac_sep_sock_fd != -1) {

    ::fd_set rfds;
    ::fd_set wfds;
    
    FD_ZERO(&rfds);
    FD_ZERO(&wfds);
    
    FD_SET(flac_sep_sock_fd, &rfds);
    FD_SET(flac_sep_sock_fd, &wfds);
    
    int status;

    if ((status = ::select(flac_sep_sock_fd + 1, &rfds, &wfds, NULL, NULL)) > 0) {

      if (FD_ISSET(flac_sep_sock_fd, &rfds)) {
	int dummy;
	if (::recv(flac_sep_sock_fd, &dummy, sizeof(dummy), MSG_PEEK) == 0) {
	  close(flac_sep_sock_fd);
	  flac_sep_sock_fd = -1;
	  return(-1);
	}
      }

      if (FD_ISSET(flac_sep_sock_fd, &wfds)) {
	::writesock(flac_sep_sock_fd, addr, len, NULL, NULL);
      }

    } else if (status < 0) {
      // error
    } else {
      // timeout
    }

  }

  return(0);
}

int ControlObject::SendPortF_flac(const ::HD_Header *hdr, const int num, const ::HDH_SrcInfo *srcinfo, const ::HDH_SrcData *srcdata, const float *data)
{
  
  if (flac_sep_sock_fd != -1) {

    //std::cout << "pass 0" << std::endl;

    flac_sep_erase(num, srcinfo);
    flac_sep_register(num, srcinfo);

    SendPortF_flac_h(hdr, sizeof(*hdr));
    SendPortF_flac_h(&num, sizeof(num));

    for (int i = 0; i < num; i++) {

      // header
      SendPortF_flac_h(&srcinfo[i], sizeof(*srcinfo));
      SendPortF_flac_h(&srcdata[i], sizeof(*srcdata));

      // data
      const int src_id = srcinfo[i].src_id;

      FLAC__StreamEncoder *encoder = flac_sep_map[src_id].encoder;

      const int advance = srcdata[i].length;
      //SendPortF_flac(data + advance * i, srcdata[i].data_bytes);

      const int datnum = srcdata[i].data_bytes / sizeof(float);

      std::vector<int> buf(datnum);
      std::copy(data + advance * i, data + advance * i + datnum, &buf[0]);

      if ((flac_sep_sock_fd != -1) && (flac_sep_map[src_id].fd != -1) && (encoder != NULL)) {

	FLAC__bool ok = FLAC__stream_encoder_process_interleaved(encoder, 
								 &buf[0],
								 datnum);
	if (!ok) {
	  
	  std::cerr << "FLAC: "
		    << ::FLAC__StreamEncoderStateString[FLAC__stream_encoder_get_state(encoder)]
		    << std::endl;
	  
	  flac_sep_map[src_id].dealloc();
	  flac_sep_map.erase(src_id);
	  
	}

      }

    }

    //std::cout << "pass 1" << std::endl;

    return(0);

  } else {

    return(-1);

  }
}

static void progress_callback(const FLAC__StreamEncoder *encoder,
			      FLAC__uint64 bytes_written,
			      FLAC__uint64 samples_written,
			      unsigned frames_written,
			      unsigned total_frames_estimate,
			      void *client_data)
{
  (void)encoder, (void)client_data;
  
  //fprintf(stderr, "wrote %llu bytes, %llu samples, %u frames\n", (unsigned long long)bytes_written, (unsigned long long)samples_written, total_frames_estimate);
}

int ControlObject::flac_sep_register(const int num, const ::HDH_SrcInfo *srcinfo)
{

  // src_id が存在しなければつくる

  for(int i = 0; i < num; i++) {

    const int src_id = srcinfo[i].src_id;

    std::map<int, flac_sep_data>::const_iterator iter = flac_sep_map.find(src_id);

    if (iter == flac_sep_map.end()) {
      //std::cout << "src_id " << src_id << " not found. so create it!" << std::endl;
      int fd;
      if (flac_sep_d_connect(fd) != -1) {
	flac_sep_data data;
	if (data.alloc(fd, src_id, audio_info.sampling_rate, flac_blocksize, flac_sep_max_lpc_order, flac_sep_rice_partition_order, HARKAndroid::progress_callback) != -1) {
	  flac_sep_map[src_id] = data;
	} else {
	  flac_sep_map[src_id] = data;
	  std::cerr << __func__ << ": flac alloc() Error." << std::endl;
	  return(-1);
	}
      } else {
	std::cerr << __func__ << ": Socket Create Error." << std::endl;
	return(-1);
      }
    }

  }


  return(0);
}


int ControlObject::flac_sep_erase(const int num, const ::HDH_SrcInfo *srcinfo)
{

  // なくなったものを探して

  std::vector<int> disappearance;

  for(std::map<int, flac_sep_data>::const_iterator iter = flac_sep_map.begin(); iter != flac_sep_map.end(); iter++) {
  
    bool found = false;
    for(int i = 0; i < num; i++) {
      const int src_id = srcinfo[i].src_id;
      if (src_id == iter->first) {
	found = true;
	break;
      }
    }
    
    if (!found) {
      disappearance.push_back(iter->first);
    } 
    
  }

  // けす

  for(std::vector<int>::const_iterator iter = disappearance.begin(); iter != disappearance.end(); iter++) {
    flac_sep_map[*iter].dealloc();
    flac_sep_map.erase(*iter);
    //std::cout << "src_id " << *iter << " removed" << std::endl;
  }

  return(0);
}

int ControlObject::flac_sep_clear()
{

  for(std::map<int, flac_sep_data>::iterator iter = flac_sep_map.begin(); 
      iter != flac_sep_map.end(); 
      iter++) {
    iter->second.dealloc();
  }

  flac_sep_map.erase(flac_sep_map.begin(), flac_sep_map.end());

  return(0);
}

int ControlObject::ClosePortF_flac()
{

  if (flac_sep_sock_fd != -1) {
    close(flac_sep_sock_fd);
    flac_sep_sock_fd = -1;
  }
  return(0);
}

/*
int ControlObject::CommandPort(const void *addr, const size_t len) const
{
    std::vector<int>::const_iterator iter;
    for(iter = CommandPortSockets.begin(); iter != CommandPortSockets.end(); iter++) {
        ::writesock(*iter, addr, len, NULL, NULL);
    }
    return(0);
}

int ControlObject::CommandPort(const ::HD_Header *hdr, const int num, const ::HDH_SrcInfo *srcinfo, const ::HDH_SrcData *srcdata, const float *data)
{
	int advance;

    lockobject lock(&CommandPortSockets_mutex);
    CommandPort(hdr, sizeof(*hdr));
    CommandPort(&num, sizeof(num));
    for (int i = 0; i < num; i++) {
        CommandPort(&srcinfo[i], sizeof(*srcinfo));
        CommandPort(&srcdata[i], sizeof(*srcdata));

        advance = srcdata[i].length;
        CommandPort(data + advance * i, srcdata[i].data_bytes);
    }
    return(0);
}

int ControlObject::CloseCommandPort()
{
    lockobject lock(&CommandPortSockets_mutex);
    std::vector<int>::const_iterator iter;
    for(iter = CommandPortSockets.begin(); iter != CommandPortSockets.end(); iter++) {
        ::close(*iter);
    }
    CommandPortSockets.clear();
    return(0);
}
    
int ControlObject::ImportParamPort(const void *addr, const size_t len) const
{
    std::vector<int>::const_iterator iter;
    for(iter = ImportParamPortSockets.begin(); iter != ImportParamPortSockets.end(); iter++) {
        ::writesock(*iter, addr, len, NULL, NULL);
    }
    return(0);
}

int ControlObject::ImportParamPort(const ::HD_Header *hdr, const int num, const ::HDH_SrcInfo *srcinfo, const ::HDH_SrcData *srcdata, const float *data)
{
	int advance;

    lockobject lock(&ImportParamPortSockets_mutex);
    ImportParamPort(hdr, sizeof(*hdr));
    ImportParamPort(&num, sizeof(num));
    for (int i = 0; i < num; i++) {
        ImportParamPort(&srcinfo[i], sizeof(*srcinfo));
        ImportParamPort(&srcdata[i], sizeof(*srcdata));

        advance = srcdata[i].length;
        ImportParamPort(data + advance * i, srcdata[i].data_bytes);
    }
    return(0);
}

int ControlObject::CloseImportParamPort()
{
    lockobject lock(&ImportParamPortSockets_mutex);
    std::vector<int>::const_iterator iter;
    for(iter = ImportParamPortSockets.begin(); iter != ImportParamPortSockets.end(); iter++) {
        ::close(*iter);
    }
    ImportParamPortSockets.clear();
    return(0);
}

int ControlObject::ExportParamPort(const void *addr, const size_t len) const
{
    std::vector<int>::const_iterator iter;
    for(iter = ExportParamPortSockets.begin(); iter != ExportParamPortSockets.end(); iter++) {
        ::writesock(*iter, addr, len, NULL, NULL);
    }
    return(0);
}

int ControlObject::ExportParamPort(const ::HD_Header *hdr, const int num, const ::HDH_SrcInfo *srcinfo, const ::HDH_SrcData *srcdata, const float *data)
{
	int advance;

    lockobject lock(&ExportParamPortSockets_mutex);
    ExportParamPort(hdr, sizeof(*hdr));
    ExportParamPort(&num, sizeof(num));
    for (int i = 0; i < num; i++) {
        ExportParamPort(&srcinfo[i], sizeof(*srcinfo));
        ExportParamPort(&srcdata[i], sizeof(*srcdata));

        advance = srcdata[i].length;
        ExportParamPort(data + advance * i, srcdata[i].data_bytes);
    }
    return(0);
}

int ControlObject::CloseExportParamPort()
{
    lockobject lock(&ExportParamPortSockets_mutex);
    std::vector<int>::const_iterator iter;
    for(iter = ExportParamPortSockets.begin(); iter != ExportParamPortSockets.end(); iter++) {
        ::close(*iter);
    }
    ExportParamPortSockets.clear();
    return(0);
}
*/

int ControlObject::AddServerSocket(const int port, const int fd) {
    ServerSockets[port] = fd;
    return(0);
};

int ControlObject::CloseServer() {

    std::map<int, int>::iterator iter;
    for(iter = ServerSockets.begin(); iter!=ServerSockets.end(); iter++) {
        ::close(iter->second);
        iter->second = -1;
    }
    
    ClosePortA();
    ClosePortB();
    ClosePortC();
    ClosePortD();
    ClosePortE();
    ClosePortF();

    ClosePortA_flac();
    ClosePortF_flac();

    //CloseCommandPort();
    //CloseImportParamPort();
    //CloseExportParamPort();
    
    return(0);
}

int ControlObject::AddFLACMicDataSocket(const flac_mic_data &fdata)
{

  lockobject lock(&PortA_FLAC_DATA_Sockets_mutex);

  const unsigned int sel = fdata.port - HA_PORT_A_FLAC_DATA_ORG;

  PortA_FLAC_DATA_Sockets[sel].push_back(fdata);

#if 0
  std::cout << "adding sel " 
	    << sel 
	    << " port "
	    << fdata.port
	    << " fd "
	    << fdata.fd
	    << " encoder "
	    << fdata.encoder
	    << std::endl;
#endif

  return(0);
}


int ControlObject::flac_sep_connect(const std::string& flac_sep_host, int& fd, const int port)
{

  ::in_addr server_ip_addr;

  int addr = ::inet_aton(flac_sep_host.c_str(), &server_ip_addr);
  if(addr == 0) {

    std::cerr << __func__ << ": Server IP Address Error." << std::endl;
    std::cerr << flac_sep_host.c_str() << " ???" << std::endl;
    return(-1);
  }

  /* ソケットの作成 */
  fd = socket(AF_INET, SOCK_STREAM, 0);
  if(fd == -1) {
    std::cerr << __func__ << ": Socket Create Error." << std::endl;
    return(-1);
  }

  struct sockaddr_in socket_addr;
  
  /* ソケットの構造体を初期化 */
  socket_addr.sin_family      = AF_INET;
  socket_addr.sin_port        = htons(port);
  socket_addr.sin_addr.s_addr = server_ip_addr.s_addr;

  int status = flac_connect_with_timeout(fd,
					 (struct sockaddr *)&(socket_addr),
					 sizeof(struct sockaddr_in), 3000);
  if(status == -1) {
    perror("socket?");
    std::cerr << __func__ << ": Socket Connect Error." << std::endl;
    close(fd);
    fd = -1;
    return(-1);
  }
  

  return(0);
}

int ControlObject::flac_sep_h_connect()
{

  if (flac_sep_sock_fd != -1) {
    std::cerr << __func__ << ": FLAC Sepserver is already connected." << std::endl;
    return(-1);
  }

  return(flac_sep_connect(flac_sep_host, flac_sep_sock_fd, HA_PORT_F_FLAC_HEADER)); 

}

int ControlObject::flac_sep_d_connect(int &fd)
{

  return(flac_sep_connect(flac_sep_host, fd, HA_PORT_F_FLAC_DATA)); 

}

int ControlObject::flac_sep_h_close()
{

  if (flac_sep_sock_fd != -1) {
    ::close(flac_sep_sock_fd);
    flac_sep_sock_fd = -1;
  }

  return(0);
}

int ControlObject::flac_connect_with_timeout(const int socket, 
					     const struct sockaddr *address, 
					     const socklen_t address_len, 
					     const int timeout_ms)
{

  // ソケットを非ブロッキングモードに
  int retval;
#ifdef WIN32
  unsigned long arg = 1;
  retval = ioctlsocket(socket, FIONBIO, &arg);
  if (retval != 0) {
    fprintf(stderr, "ERROR: set socket nonblock, filename = %s, line = %d\n", __FILE__, __LINE__);
    return(-1);
  }
#else // WIN32
  retval = fcntl(socket, F_SETFL, O_NONBLOCK);
  if (retval == -1) {
    fprintf(stderr, "ERROR: set socket nonblock, filename = %s, line = %d\n", __FILE__, __LINE__);
    return(-1);
  }
#endif // WIN32
  
  retval = connect(socket, address, address_len);
  if(retval != 0)  {
#ifdef WIN32
    if (WSAGetLastError() == WSAEWOULDBLOCK) {
#else // WIN32
    if (errno == EINPROGRESS) {
#endif // WIN32
	      
      fd_set wfds;
      struct timeval tv;
      
      tv.tv_sec = timeout_ms / 1000;
      tv.tv_usec = (timeout_ms % 1000) * 1000;
      
      FD_ZERO(&wfds);
      FD_SET(socket, &wfds);
      
      retval = select(socket + 1, NULL, &wfds, NULL, &tv);
      if (retval < 0) {
	fprintf(stderr, "ERROR: select, filename = %s, line = %d\n", __FILE__, __LINE__);
	return(-1);
      } else if (retval > 0) {
	// 書き込み可能になっているので結果判定
	int val;
	socklen_t len = sizeof(val);
	if(getsockopt(socket, SOL_SOCKET, SO_ERROR, &val, &len) == 0) {
	  if (val != 0) {
	    fprintf(stderr, "ERROR: connect, val = %d filename = %s, line = %d\n", val, __FILE__, __LINE__);
	    return(-1);
	  }
	} else {
	  fprintf(stderr, "ERROR: getsockopt, filename = %s, line = %d\n", __FILE__, __LINE__);
	  return(-1);
	}
      } else {
	// timeout
	fprintf(stderr, "ERROR: connection timeout, filename = %s, line = %d\n", __FILE__, __LINE__);
	return(-1);
      }
	      
    } else {
      // 接続中以外のエラー
      perror("connect error:");
      fprintf(stderr, "ERROR: connect, filename = %s, line = %d\n", __FILE__, __LINE__);
      return(-1);
    }
      
  }
      
    // ソケットをブロッキングモードにもどす
#ifdef WIN32
  arg = 0;
  retval = ioctlsocket(socket, FIONBIO, &arg);
  if (retval != 0) {
    fprintf(stderr, "ERROR: set socket block, filename = %s, line = %d\n", __FILE__, __LINE__);
    return(-1);
  }
#else // WIN32
  retval = fcntl(socket, F_SETFL, 0);
  if (retval == -1) {
    fprintf(stderr, "ERROR: set socket block, filename = %s, line = %d\n", __FILE__, __LINE__);
    return(-1);
  }
#endif // WIN32
      
  return(0);
}

#ifdef IS_APPLE_IOS
inline void ControlObject::setFullPath(char* s1, const char* s2){
	::strcpy(s1, ::getFilenameWithDocumentsPath(s2));
}
#else // IS_APPLE_IOS
inline void ControlObject::setFullPath(char* s1, const char* s2){
	::strcpy(s1, s2);
}
#endif // IS_APPLE_IOS

} // end of namespace
