/************************************************************
**
**     Object name : 
**
**     Description
**     -- -- -- -- -- -- -- --
**     16bit または 24bit のWaveファイルからのデータ読み出し
**
**     History
**     -- -- -- -- -- -- -- --
**     2013.05.13 M.Takigahira Build有無指定に対応
**     2013.04.03 K.Takagi     ConvertVectorToMatrixの変更により呼び出しを修正
**     2013.01.17 K.Takagi     メモリのチェック追加
**     2012.12.04 K.Takagi     モジュールパラメータを追加
**     2012.12.03 K.Takagi     配列変換を外部関数に移行
**     2012.11.20 K.Takagi     多次元配列を動的確保
**     2012.09.20 K.Takagi     新規作成
**
**     Copyright (c) 2012-2013
**     System In Frontier,Inc.
**     All rights reserved. 
**
**     当社の許可なしに複製および転載を禁ず
**
*/

///////////////////////////////////////////////////////////////
//  Include Files
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "build_modules.h"
#include "HA_log.h"
#include "android_hark.h"

#include "MatrixMemoryAllocate.h"
#include "AudioStreamFromWave.h"
#include "ConvertVectorToMatrix.h"

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

#if !defined BUILD_MODULE_AUDIO_STREAM_FROM_WAVE
///////////////////////////////////////////////////////////////
//  Dummy Functions for build empty methods.
int OpenWaveFile(const char *file_name){ return 0; }
void CloseWaveFile(void){ }
int GetWaveDataChannels(void){ return 0; }
int HASetParamAudioStreamFromWave(Param_AudioStreamFromWave_t *param){ return 0; }
//int ReadWaveData(float **data, int length, int advance, int use_wait)
int ReadWaveData(int frame_count, float **data){ return 0; }
#ifdef STANDALON_TEST
int main(int argc, char **argv){ return 0; }
#endif // STANDALON_TEST
#else // #if defined BUILD_MODULE_AUDIO_STREAM_FROM_WAVE
///////////////////////////////////////////////////////////////
//  Parameter
static Param_AudioStreamFromWave_t audio_wave_info;

typedef struct _AUDIO_STREAM_WAVE_INFO_t_
{
    FILE *fp;
    int first_read;
    int channels;
    int rate;
    int nbits;
    int nbytes;
}AUDIO_STREAM_WAVE_INFO_t;

static AUDIO_STREAM_WAVE_INFO_t asw_info;
static char *asw_tmp_buf;
static float **asw_pre_data;

///////////////////////////////////////////////////////////////
//  Local Buffer

///////////////////////////////////////////////////////////////
//  Clear

///////////////////////////////////////////////////////////////
//  Initialize

/************************************************************
**  History :
**    2012.09.20 K.Takagi 新規作成
*/
// Public : Waveファイルを開き、ヘッダをチェック
int OpenWaveFile(const char *file_name)
{
//    int ch;
    unsigned int size;
    char buf[5];
    
    short nbits;
    short channels;
    int   rate;
    
    /* 各種初期化 */
    if(asw_info.fp != NULL){
        fclose(asw_info.fp);
        asw_info.fp = NULL;
    }
    bzero(&asw_info, sizeof(asw_info));
    asw_info.first_read = 1;
    
    bzero(buf, sizeof(buf));
    
    /* ファイルを開く */
    asw_info.fp = fopen(file_name, "rb");
    if(asw_info.fp == NULL){
        LOGD("File Open Error.\n");
        return -1;
    }
    
    /* RIFF */
    fread(buf, sizeof(char), 4, asw_info.fp);
    if(strcmp(buf, "RIFF") != 0){
        LOGD("No RIFF\n");
        goto FileErrEnd;
    }
    
    fread(&size, sizeof(int), 1, asw_info.fp);
    //printf("size = %d\n", size);
    
    /* WAVE */
    fread(buf, sizeof(char), 4, asw_info.fp);
    if(strcmp(buf, "WAVE") != 0){
        LOGD("No WAVE\n");
        goto FileErrEnd;
    }
    
    while(feof(asw_info.fp) == 0){
        fread(buf, sizeof(char), 4, asw_info.fp);
        
        if((strcmp(buf, "fact") == 0) || (strcmp(buf, "LIST") == 0)){
            /* fact/LISTの情報は使用しないのでスキップ */
            fread(&size, sizeof(int), 1, asw_info.fp);
            fseek(asw_info.fp, size, SEEK_CUR);
        }
        else if(strcmp(buf, "fmt ") == 0){
            fread(&size, sizeof(int), 1, asw_info.fp);
            fseek(asw_info.fp, 2, SEEK_CUR);
            
            fread(&channels, sizeof(short), 1, asw_info.fp);
            fread(&rate, sizeof(int), 1, asw_info.fp);
            fseek(asw_info.fp, 6, SEEK_CUR);
            fread(&nbits, sizeof(short), 1, asw_info.fp);
            
            asw_info.channels = channels;
            asw_info.rate     = rate;
            asw_info.nbits    = nbits;
            asw_info.nbytes   = nbits / 8;
            
            /* 16bit , 24bit以外はサポートしない */
            if((nbits != 16) && (nbits != 24)){
                goto FileErrEnd;
            }
            
            /* 拡張部はスキップ */
            size = size - 16;
            if(size > 0){
                fseek(asw_info.fp, size, SEEK_CUR);
            }
        }
        else if(strcmp(buf, "data") == 0){
            /* データサイズは使用しないのでスキップ */
            fseek(asw_info.fp, 4, SEEK_CUR);
            break;
        }
        else{
            goto FileErrEnd;
        }
    }
    LOGD("Wave File Open");
    
    return 0;

FileErrEnd:
    fclose(asw_info.fp);
    asw_info.fp = NULL;
    bzero(&asw_info, sizeof(asw_info));
    
    return -1;
}

/************************************************************
**  History :
**    2013.01.17 K.Takagi メモリチェックを追加
**    2012.09.20 K.Takagi 新規作成
*/
// Public : Waveファイルを閉じる
void CloseWaveFile(void)
{
//    int ch;
    if(asw_info.fp != NULL){
        fclose(asw_info.fp);
        asw_info.fp = NULL;
    }
    bzero(&asw_info, sizeof(asw_info));
    /* バッファを開放 */
    if(asw_pre_data != NULL){
        free(asw_pre_data[0]);
        free(asw_pre_data);
        asw_pre_data = NULL;
    }
    if(asw_tmp_buf != NULL){
        free(asw_tmp_buf);
        asw_tmp_buf = NULL;
    }
}

/************************************************************
**  History :
**    2012.09.20 K.Takagi 新規作成
*/
// Public : Waveファイルに含まれるデータのチャネル数の取得
int GetWaveDataChannels(void)
{
    return asw_info.channels;
}

///////////////////////////////////////////////////////////////
//  SetParam
/******************************************************************************
**  History :
**    2012.12.04 K.Takagi 新規作成
*/
// Public : パラメータ設定　読み出しを始める前までに実行すること
int HASetParamAudioStreamFromWave(Param_AudioStreamFromWave_t *param)
{
    audio_wave_info.length  = param->length;
    audio_wave_info.advance = param->advance;
    
    return 0;
}

#if NEVER
/************************************************************
**  History :
**    2012.09.20 K.Takagi 新規作成
*/
// [Code separation] refer to ConvertVectorToMatrix.c
// Private : Waveファイルから読み出した16bitまたは24bitデータをfloat型に変換
//           また配列を[lenght][ch] から [ch][length] の構成に並び替え
/*
static int ConvertVectorToMatrix(char *in_data, float **out_data, int length, int offset_pos)
{
    int  val;
    char *ptr;
    int  ch;
    int  index;
    
    ptr = (char *)&val;
    if(asw_info.nbits == 16){
        for(index=0; index<length; index++){
            for(ch=0; ch<asw_info.channels; ch++){
                val = 0;
                ptr[2] = *in_data++;
                ptr[3] = *in_data++;
                
                val = val >> 16;
                out_data[ch][offset_pos + index] = (float)val;
            }
        }
    }
    else if(asw_info.nbits == 24){
        for(index=0; index<length; index++){
            for(ch=0; ch<asw_info.channels; ch++){
                val = 0;
                ptr[1] = *in_data++;
                ptr[2] = *in_data++;
                ptr[3] = *in_data++;
                
                val = val >> 8;
                out_data[ch][offset_pos + index] = (float)val;
            }
        }
    }
    else{
        return -1;
    }
    return 0;
}
*/
#endif

///////////////////////////////////////////////////////////////
//  MAIN
/************************************************************
**  History : 
**    2013.04.03 K.Takagi ConvertVectorToMatrixの変更により呼び出しを修正
**    2012.12.05 K.Takagi frame_count引数追加
**    2012.12.04 K.Takagi 引数を変更
**    2012.09.20 K.Takagi 新規作成
**
**  Description
**  -----------
**  Waveファイルからデータを読み出す
**
**  *data[]
**  length長の1次元配列へのポインタをch数分格納したポインタの配列
**
**  Waveファイル上は[length][ch数]のデータ配列なので
**  作業バッファに読み出してから並び替えをする
**
**  戻り値
**  -1 : エラー
**   0 : 正常読み出し
**   1 : 正常読み出し＆ファイル終端
*/
// Public : Waveファイルからデータを読み出す
//int ReadWaveData(float **data, int length, int advance, int use_wait)
int ReadWaveData(int frame_count, float **data)
{
    int ch;
    int index;
    
    int read_req_size;
    int read_size;
    
    int length;
    int advance;
    
    length  = audio_wave_info.length;
    advance = audio_wave_info.advance;
    
    /* すでにファイルの終端であればエラー */
    if(asw_info.fp && (feof(asw_info.fp) != 0)){
        return -1;
    }

    if(asw_info.first_read){ // frame_count == 0 でもよい
        asw_info.first_read = 0;
        
        /* バッファ確保 */
        asw_tmp_buf = (char *)malloc(sizeof(char) * asw_info.channels * length * asw_info.nbytes);
        if(asw_tmp_buf == NULL){
            return -1;
        }
        
        /*
        for(ch=0; ch<asw_info.channels; ch++){
            asw_pre_data[ch] = (float *)malloc(sizeof(float) * length);
            if(asw_pre_data[ch] == NULL){
                do{
                    free(asw_pre_data[ch]);
                    asw_pre_data[ch] = NULL;
                    ch--;
                }while(ch>=0);
                free(asw_tmp_buf);
                asw_tmp_buf = NULL;
                return -1;
            }
        }
        */
        asw_pre_data = (float **)MemoryAllocate2D(asw_info.channels, length, sizeof(float));
        if(asw_pre_data == NULL){
            return -1;
        }

        /* データ読み出し */
        read_req_size = sizeof(char) * asw_info.channels * length * asw_info.nbytes;
        read_size = fread(asw_tmp_buf, sizeof(char), read_req_size, asw_info.fp);
        
        /* データ配列の並び替え */
        //ConvertVectorToMatrix(asw_tmp_buf, data, length, 0);
        //ConvertVectorToMatrix(asw_tmp_buf, data, asw_info.channels, length, 0, asw_info.nbits);
        //ConvertVectorToMatrix(asw_tmp_buf, data, asw_info.channels, _CH_OFFSET_VAL_, length, 0, asw_info.nbits);
        ConvertVectorToMatrix(asw_tmp_buf, data, asw_info.channels, 0, length, 0, asw_info.nbits);
    }
    else{
        /* 前フレームのオーバーラップ部分をコピー */
        for(ch=0; ch<asw_info.channels; ch++){
            for(index=0; index<(length - advance); index++){
                data[ch][index] = asw_pre_data[ch][index];
            }
        }
        
        /* データ読み出し */
        read_req_size = sizeof(char) * asw_info.channels * advance * asw_info.nbytes;
        read_size = fread(asw_tmp_buf, sizeof(char), read_req_size, asw_info.fp);
        
        if(read_size < read_req_size){
            bzero(&asw_tmp_buf[read_size], (read_req_size - read_size));
        }
        
        /* データ配列の並び替え */
        //ConvertVectorToMatrix(asw_tmp_buf, data, advance, (length - advance));
        //ConvertVectorToMatrix(asw_tmp_buf, data, asw_info.channels, advance, (length - advance), asw_info.nbits);
        //ConvertVectorToMatrix(asw_tmp_buf, data, asw_info.channels, _CH_OFFSET_VAL_, advance, (length - advance), asw_info.nbits);
        ConvertVectorToMatrix(asw_tmp_buf, data, asw_info.channels, 0, advance, (length - advance), asw_info.nbits);
    }
    
    /* オーバーラップ部分を保持 */
    for(ch=0; ch<asw_info.channels; ch++){
        for(index=0; index<(length - advance); index++){
             asw_pre_data[ch][index] = data[ch][advance + index];
        }
    }
    return 0;
}

#ifdef STANDALON_TEST
/************************************************************
**  History :
**    2012.12.05 K.Takagi フレームカウント用にhark_count追加
**    2012.12.04 K.Takagi パラメータ経由での動作に修正
**    2012.09.20 K.Takagi 新規作成
**
**  Description
**  -----------
**  単体テストのメイン
**
**  サンプルネットワークに含まれていたMultiSpeech.wavで動作を確認
**  CH0のみ出力（オーバーラップあり・なし）
**  全CH出力（オーバーラップなし）
*/
// Public : 単体テストのメイン
int main(int argc, char **argv)
{
    int hark_count;
    int stat;
    int channels;
//    int count;
    int index;
    
//    int ch;
    int length;
    int advance;
    
    /*
    float *data[16];
    */
    float **data;
    
    FILE *fp;
    
    Param_AudioStreamFromWave_t audio_param;
    
    if(argc != 2){
        printf("Usage : %s <wav file>\n", argv[0]);
        return -1;
    }
    
    
    length  = 512;
    advance = 512;
    
    audio_param.length  = length;
    audio_param.advance = advance;
    
    /* パラメータ設定 */
    HASetParamAudioStreamFromWave(&audio_param);
    
    /* 初期化 */
    stat = OpenWaveFile(argv[1]);
    if(stat < 0){
        return -1;
    }
    /* デバック表示 */
    printf("channels = %d\n", asw_info.channels);
    printf("rate     = %d\n", asw_info.rate);
    printf("nbits    = %d\n", asw_info.nbits);
    printf("nbytes   = %d\n", asw_info.nbytes);
    
    
    fp = fopen("data.csv", "wt");
    if(fp != NULL){
        channels = GetWaveDataChannels();
        
        data = (float **)MemoryAllocate2D(channels, length, sizeof(float));
        if(data == NULL){
            fclose(fp);
            return -1;
        }
        
        /* オーバーラップありでCH0の一部を出力 */
        /*
        for(count=0; count<10; count++){
            stat = ReadWaveData(data, length, advance, 0);
            printf("Read stat = %d\n", stat);
            if(stat < 0){
                break;
            }
            
            fprintf(fp, "\n count = %d \n", count);
            for(index=0; index<length; index++){
                fprintf(fp, "%f\n", data[0][index]);
            }
        }
        */
        /* オーバーラップなしでCH0出力 */
        advance = 512;
        hark_count = 0;
        while(1){
            //stat = ReadWaveData(data, length, advance, 0);
            stat = ReadWaveData(hark_count, data);
            printf("Read stat = %d\n", stat);
            if(stat < 0){
                break;
            }
            for(index=0; index<length; index++){
                fprintf(fp, "%f\n", data[0][index]);
            }
            hark_count++;
        }
        
        // オーバーラップなしですべて出力(gnuplotで表示する場合はint型で出力すること)
        /*
        while(1){
            stat = ReadWaveData(data, length, advance, 0);
            printf("Read stat = %d\n", stat);
            if(stat < 0){
                break;
            }
            for(index=0; index<length; index++){
                for(ch=0; ch<channels; ch++){
                    fprintf(fp, "%d, ", (int)data[ch][index]);
                }
                fprintf(fp, "0\n");
            }
        }
        */

        // バッファ開放
        /*
        for(ch=0; ch<channels; ch++){
            free(data[ch]);
        }
        */
        free(data[0]);
        free(data);
        
        fclose(fp);
    }
    CloseWaveFile();
    return 0;
}
#endif // STANDALON_TEST
#endif // BUILD_MODULE_AUDIO_STREAM_FROM_WAVE

/* EOF */
