//
// 指定した入力wavファイルからF0ファイルを生成する
// world(2016/1/17時点の版。恐らくv0.2.0 5)で作成。
//
// g++ -o getF0Dio.exe -static -I../src getF0Dio.cpp ../build/dio.o ../build/matlabfunctions.o ../build/stonemask.o ../build/libworld.a
// strip getF0Dio.exe
//
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "dio.h"
#include "stonemask.h"
#include "matlabfunctions.h"
 
void usage(const char *argv0, const char *pref){
    if (! pref) fprintf(stderr, "%s\n", pref);
    fprintf(stderr, "usage: %s [-period num|-max max|-min min|-dioonly] inWavFile [outF0File]\n", argv0);
    fprintf(stderr, "    -period num ... frame period. unit is msec.\n");
    fprintf(stderr, "    -max num    ... F0 max value. unit is Hz.\n");
    fprintf(stderr, "    -min num    ... F0 min value. unit is Hz.\n");
    fprintf(stderr, "    -dioonly    ... discard StoneMask\n");
    exit(1);
}
    
int main(int argc, char *argv[])
{
    int fs, inBit, x_length;
    double *x;  // 波形瞬時値
    int i;
    char *inWavFile, *outF0File, *ends;
    double frame_period = 10.0;      // 分析の間隔(単位=msec)
    double max = 800.0;              // F0最大値(Hz)
    double min = 71.0;               // F0最小値(Hz)
    int dioonly = 0;

    // 引数チェック
    i = 1;
    while (i+1 < argc && argv[i][0] == '-'){
        if (strcmp(argv[i], "-period") == 0 && i+1 < argc){
            frame_period = strtod(argv[i+1], &ends);
            if (frame_period <= 0) usage(argv[0], "error: period must be positive number.");
            i += 2;
            continue;
        } else if (strcmp(argv[i], "-max") == 0 && i+1 < argc){
            max = strtod(argv[i+1], &ends);
            if (max <= 0) usage(argv[0], "error: period must be positive number.");
            i += 2;
            continue;
        } else if (strcmp(argv[i], "-min") == 0 && i+1 < argc){
            min = strtod(argv[i+1], &ends);
            if (min <= 0) usage(argv[0], "error: period must be positive number.");
            i += 2;
            continue;
        } else if (strcmp(argv[i], "-dioonly") == 0){
            dioonly = 1;
            i++;
            continue;
        }
        usage(argv[0], NULL);
    }
    if (i >= argc) usage(argv[0], NULL);
    inWavFile = argv[i];
    if (i + 1 < argc) {
        outF0File = argv[i+1];
        if (strcmp(inWavFile, outF0File) == 0){
            fprintf(stderr, "error: input file and output file is same.\n");
            exit(1);
        }
    } else outF0File = NULL;
 
    // ファイル読み込み
    if ( ! (x = wavread(inWavFile, &fs, &inBit, &x_length)) ) return 1;
 
    int f0_length = GetSamplesForDIO(fs, x_length, frame_period);
    double *f0   = new double[f0_length];
    double *refined_f0 = new double[f0_length];
    double *time_axis = new double[f0_length];
 
    DioOption option;
    InitializeDioOption(&option);
    option.frame_period = frame_period;
    option.speed = 1;   // 速度ではなく精度を最優先する
    option.f0_floor = min;
    option.f0_ceil  = max;
    option.allowed_range = 0.1;    // The value from 0.02 to 0.2 would be reasonable.

    // F0抽出
    Dio(x, x_length, fs, option, time_axis, f0);
    StoneMask(x, x_length, fs, time_axis, f0, f0_length, refined_f0);

    // 結果保存
    FILE *fp;
    if (outF0File){
        if (! (fp = fopen(outF0File, "w"))){
            fprintf(stderr, "can not write to %s\n", argv[2]);
            return 1;
        }
    } else {
        fp = stdout;
    }
    for(int i = 0; i < f0_length; i++) {
        if (dioonly){
            fprintf(fp, "%f\n", f0[i]);
        } else {
            fprintf(fp, "%f\n", refined_f0[i]);
        }
    }
    fclose(fp);
 
    delete[] f0;
    delete[] time_axis;
    delete[] x;
 
    return 0;
}
