/* (c)Copyright 1996-2000 NTT Cyber Space Laboratories */
/*                Released on 2000.09.06 by N. Iwakami */
/*                Modified on 2000.09.22 by N. Iwakami */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include "twinvq.h"
#include "bfile.h"
#include "bstream_e.h"
#include "tvqenc.h"
#include "ChunkHelper.h"

/*----------------------------------------------------------------------------*/
/* 定義                                                                       */
/*----------------------------------------------------------------------------*/
#define YES 1
#define NO  0

#define min(x, y) ( (x) < (y) ? (x) : (y) )
#define DISP_FRAME   YES		 /* YES: エンコード処理進行を表示 */
#define INIT_ERR_DISP_MBOX  YES  /* YES: 初期化エラー時に、エンコーダ DLL がエラーメッセージボックスを出す */

#define TEST_PROGRAM_VERSION "2.3.0.02 (open version), API-C, HD2.0"
#define COPYRIGHT            "Copyright (C) 1996-2000 NTT Cyber Space Laboratories."

#if defined (_MSC_VER)
#  define stat _stat
#endif

/* WAVE ファイルのヘッダ情報 */
static const int WAVE_ID_SIZE = 4;
typedef struct {
	char  riffID[WAVE_ID_SIZE+1];
	long  riffSize;
	char  waveID[WAVE_ID_SIZE+1];
	char  fmt_ID[WAVE_ID_SIZE+1];
	long  fmt_Size;
	short format;
	short numChannels;
	long  samplingRate;
	long  byteRate;
	short blockSize;
	short numBitsPerSample;
	char  dataID[WAVE_ID_SIZE+1];
	long  dataSize;
} WAVE_HEADER;

/*----------------------------------------------------------------------------*/
/* 静的変数                                                                   */
/*----------------------------------------------------------------------------*/
static char *error_message[] = {   // エラーメッセージテーブル（エラーコードと対応）
	"no error",
	"an error",
	"wrong version",
	"wrong channel mode",
	"unsupported coding mode",
	"inner parameter setting error.  Check bitrate",
	"wrong number of VQ pre-selection candidates",
};

// ファイルタイプ関連の定義
static enum {
	fileTypeWav = 0,
	fileTypeRaw,
} fileTypeNumber;

static char *fileTypeName[] = {	// ファイルタイプ名、fileType フラグと連動している。
	"wav",
	"raw",
	NULL
};


/**********************************/
/**** 初期化用スタティック関数 ****/
/**********************************/

/*----------------------------------------------------------------------------*/
/* Name:        usage()                                                       */
/* Description: プログラムの使用方法を表示する。                              */
/* Return:      なし                                                          */
/* Access:      static                                                        */
/*----------------------------------------------------------------------------*/
static
void usage (char *p)
{
	fprintf(stderr, "Usage: %s [<options>] infile outfile\n\n", p);
	fprintf(stderr, "Options:\n");
	fprintf(stderr, "    -c <#>\t: CH_MODE<0,1>\t\t(default=1 (stereo))\n");
	fprintf(stderr, "    -f <#>\t: ISAMPF<8,..,22,44>\t(default=44)\n");
	fprintf(stderr, "    -b <#>\t: IBPS<8,10,..,80,96>\t(default=96)\n");
	fprintf(stderr, "    -n <#>\t: N_CAN\t\t\t(default=16)\n");
	//    fprintf(stderr, "    -s\t\t: set enable to save vqf\t(default=no)\n");
	fprintf(stderr, "    -T <string>\t: title string\t\t(default=none)\n");
	fprintf(stderr, "    -C <string>\t: comment string\t(default=none)\n");
	fprintf(stderr, "    -A <string>\t: author string\t(default=\"\")\n");
	fprintf(stderr, "    -R <string>\t: copyright information string\t(default=\"\")\n");
	fprintf(stderr, "    -h <string>\t: directory for header info files (default=\"header_info\")\n" );
	fprintf(stderr, "    --version: print program version\n" );
	return;
}


/*----------------------------------------------------------------------------*/
/* Name:        SetDefault()                                                  */
/* Description: TwinVQ セットアップ情報のデフォルト値を設定                   */
/* Return:      none                                                          */
/* Access:      static                                                        */
/*----------------------------------------------------------------------------*/
static
void SetDefault( headerInfo *setupInfo, encSpecificInfo *encInfo, int *fileType, char *headerInfoDir )
{
	TvqGetVersionID( V2, setupInfo->ID );  // デフォルトのバージョンを Ver.2 にする
	setupInfo->channelMode = 1;		// チャネル：ステレオ
	setupInfo->samplingRate = 44;   // サンプリング周波数： 44.1 khz
	setupInfo->bitRate = 96;       // ビットレート：96 kbit/s
	strcpy(setupInfo->Name, "");    // ヘッダ補助情報
	strcpy(setupInfo->Comt, "");
	strcpy(setupInfo->Auth, "");
	strcpy(setupInfo->Cpyr, "");
	strcpy(setupInfo->File, "");
	setupInfo->Dsiz = 0;
	setupInfo->securityLevel = 0;
	
	encInfo->N_CAN_GLOBAL = 16;      // VQ の予備選択数：16

	*fileType = fileTypeWav;		// デフォルトのファイルタイプ

	sprintf( headerInfoDir, "header_info" );	// ヘッダ情報を格納するディレクトリ
}

/*--------------------------------------------------------------------------------------------*/
/* Name:        CheckWaveChunkHeader()                                                        */
/* Description: WAVE データファイルのチャンクID を読み込みチェックする                        */
/* Return:      (int) 読み込んだIDが参照IDと同じなら0, 小さければ負の整数、大きければ正の整数 */
/* Access:      static                                                                        */
/*--------------------------------------------------------------------------------------------*/
static
int CheckWaveChunkHeader( char* ID, char* refID, FILE *fp )
{
	fread( ID, WAVE_ID_SIZE, sizeof(char), fp );
	ID[WAVE_ID_SIZE] = '\0';
	return strcmp( ID, refID );
}

/*----------------------------------------------------------------------------*/
/* Name:        ReadWaveHeader()                                              */
/* Description: WAVE データファイルのヘッダを読み込む。                       */
/* Return:      (int) エラーがあれば１、なければ０                            */
/* Access:      static                                                        */
/*----------------------------------------------------------------------------*/
static
int ReadWaveHeader( WAVE_HEADER* waveHeader, FILE* fp_i )
{
	/* read and check "RIFF" header */
	if ( CheckWaveChunkHeader( waveHeader->riffID, "RIFF", fp_i ) ) {
		fprintf( stderr, "Error: Not a RIFF format file.\n" );
		return 1;
	}
	fread( &waveHeader->riffSize, 1, sizeof(long), fp_i ); // RIFF chunk size
	
	/* read and check "WAVE" header */
	if( CheckWaveChunkHeader( waveHeader->waveID, "WAVE", fp_i ) ){
		fprintf(stderr, "%s: Error: Not a WAVE format file.\n", waveHeader->waveID);
		return 1;
	}

	/* read and check "fmt " header */
	if ( CheckWaveChunkHeader( waveHeader->fmt_ID, "fmt ", fp_i ) ) {
		fprintf( stderr, "Error: \"fmt \" chunk not found in wave file format.\n" );
		return 1;
	}
	fread( &waveHeader->fmt_Size, 1, sizeof(long), fp_i ); // fmt chunk size

	// read data of "fmt " header
	fread( &waveHeader->format, 1, sizeof(short), fp_i );			// data type
	fread( &waveHeader->numChannels, 1, sizeof(short), fp_i );		// number of channels
	fread( &waveHeader->samplingRate, 1, sizeof(long), fp_i );		// sampling frequency
	fread( &waveHeader->byteRate, 1, sizeof(long), fp_i );			// number of bytes per second
	fread( &waveHeader->blockSize, 1, sizeof(short), fp_i );		// block size
	fread( &waveHeader->numBitsPerSample, 1, sizeof(short), fp_i );	// number of bits per sample
	
	/* detect data chunk */
	int readIdSize;
	waveHeader->dataID[WAVE_ID_SIZE] = '\0';
	do {
		readIdSize = fread( waveHeader->dataID, WAVE_ID_SIZE, sizeof(char), fp_i );
		fread( &waveHeader->dataSize, 1, sizeof(long), fp_i );
	} while ( readIdSize == WAVE_ID_SIZE && strcmp( waveHeader->dataID, "data" ) );
	if ( strcmp(waveHeader->dataID, "data") ) {
		fprintf( stderr, "Error: data chunk not found in WAVE file.\n" );
		return 1;
	}

	return 0;
}

/*----------------------------------------------------------------------------*/
/* Name:        InitAudioFile()                                               */
/* Description: オーディオファイルを初期化し、必要なパラメータを取得する      */
/* Return:      (int) エラーがあれば１、なければ０                            */
/* Access:      static                                                        */
/*----------------------------------------------------------------------------*/
static
int InitAudioFile( char *namein, FILE **fp_i, int *data_size, int fileType, int *channelMode, int *samplingRate )
{
	WAVE_HEADER waveHeader;

	if ( (*fp_i=fopen(namein,"rb")) == NULL ){    // 入力ファイルをオープン
		fprintf( stderr, "%s: File not found\n", namein );
		return 1;
	}

	/* read header of wave format file */
	if( fileType == fileTypeWav ){ 
		// read header info
		if ( ReadWaveHeader( &waveHeader, *fp_i ) ) return 1;

		// check "fmt " info
		if ( waveHeader.format != 1 ) { // not a PCM file
			fprintf( stderr, "Error: unsupported WAVE data format.\n" );
			return 1;
		}
		if ( waveHeader.numBitsPerSample != 8 * sizeof(short) ) {	// not 16 bit integer
			fprintf( stderr, "Error: unsupported WAVE data format.\n" );
		}

		// get neccessary parameters
		*channelMode = waveHeader.numChannels - 1;			// number of channels (override)
		*samplingRate = waveHeader.samplingRate / 1000;		// sampling rate (override)
		*data_size = waveHeader.dataSize / sizeof(short);	// audio data size

	} /* if( fileType == fileTypeWav ) */
	else{ /* raw file format */
		struct stat buffer;
		stat( namein, &buffer );
		*data_size = buffer.st_size / sizeof(short);
	}

	return 0;
}


/*----------------------------------------------------------------------------*/
/* Name:        ReceiveArguments()                                            */
/* Description: 引数を取得                                                    */
/* Return:      (int) エラーがあれば 1, なければ 0                            */
/* Access:      static                                                        */
/*----------------------------------------------------------------------------*/
static int check_iarg( int iarg, int argc, char *comname )
{
	if ( iarg >= argc ) {
		usage( comname );
		return 1;
	}
	return 0;
}
static
int ReceiveArguments(int argc, char *argv[],
					 headerInfo *setupInfo,
					 encSpecificInfo *encInfo,
					 char **namein,
					 char **nameout,
					 FILE **fp_i,
					 int *fileType,
					 int *data_size,
					 char *headerInfoDir)
{
	int iarg=0;

	// 引数の数をチェック
	if ( argc < 3 ) {
		if ( check_iarg( ++iarg, argc, argv[0]) ) return 1;
		if ( ! strcmp( argv[iarg], "--version" ) ) {
			char module_version[256];
			TvqEncGetModuleVersion( module_version );
			printf("TwinVQ test encoder version %s,\n", TEST_PROGRAM_VERSION );
			printf("using TwinVQ encoder module version %s.\n", module_version );
			printf("\n%s\n", COPYRIGHT );
		}
		return 1;
	}

	// 入出力ファイル名を取得
	*namein  = argv[argc-2];
	*nameout = argv[argc-1];

	// 入力ファイル名の拡張子を調べデフォルトのファイルタイプを設定する。
	int ichar = 0;
	char* strTmp = *namein;
	for ( ichar=strlen(strTmp); ichar>0 && strTmp[ichar-1] != '.'; ichar-- );
	if ( ! strcmp( &strTmp[ichar], "wav" ) || ! strcmp( &strTmp[ichar], "WAV" ) ) {
		*fileType = fileTypeWav;
	}
	else {
		*fileType = fileTypeRaw;
	}

	// 入力ファイルから必要なパラメータを取得する。
	if ( InitAudioFile( *namein, fp_i, data_size, *fileType, &setupInfo->channelMode, &setupInfo->samplingRate ) ) {
		fprintf( stderr, "Error in opening audio file.\n" );
		return TVQ_ERROR;
	}

	// オプションの読み込み
	while( ++iarg < argc && argv[iarg][0]=='-' ){
		switch ( argv[iarg][1] ){
		case 'c': // channel mode
			if ( check_iarg(++iarg, argc, argv[0]) ) return 1;
			if ( (setupInfo->channelMode=atoi(argv[iarg]) ) < 0) {
				fprintf(stderr, "Error: CH_MODE(%d)\n", setupInfo->channelMode);
				return 1;
			}
			break;
		case 'f': // sampling frequency mode
			if ( check_iarg(++iarg, argc, argv[0]) ) return 1;
			if ((setupInfo->samplingRate=atoi(argv[iarg])) < 0) {
				fprintf(stderr, "Error: ISAMPF(%d)\n", setupInfo->samplingRate);
				return 1;
			}
			break;
		case 'b':  // bitrate
			if ( check_iarg(++iarg, argc, argv[0]) ) return 1;
			if ((setupInfo->bitRate=atoi(argv[iarg])) < 0) {
				fprintf(stderr, "Error: IBPS(%d)\n", setupInfo->bitRate);
				return 1;
			}
			break;
		case 'n':  // number of conjugate VQ candidates
			if ( check_iarg(++iarg, argc, argv[0]) ) return 1;
			if ((encInfo->N_CAN_GLOBAL=atoi(argv[iarg])) < 0) {
				fprintf(stderr, "Error: N_CAN_GLOBAL(%d)\n", encInfo->N_CAN_GLOBAL);
				return 1;
			}
			break;
			//		case 's':  // save flag
			//			save_flag++;
			//			strcpy(setupInfo->File, nameout);
			//			break;
		case 'T':  // title
			if ( check_iarg(++iarg, argc, argv[0]) ) return 1;
			sprintf( setupInfo->Name, "%s", argv[iarg] );
			break;
		case 'C':  // comment
			if ( check_iarg(++iarg, argc, argv[0]) ) return 1;
			sprintf( setupInfo->Comt, "%s", argv[iarg] );
			break;
		case 'A':
			if ( check_iarg(++iarg, argc, argv[0]) ) return 1;
			sprintf( setupInfo->Auth, "%s", argv[iarg] );
			break;
		case 'R':
			if ( check_iarg(++iarg, argc, argv[0]) ) return 1;
			sprintf( setupInfo->Cpyr, "%s", argv[iarg] );
			break;
		case 't':
			if( check_iarg(++iarg, argc, argv[0]) ) return 1;
			{
				int itype;
				for ( itype=0; fileTypeName[itype]; itype++ ) {
					if( strcmp(argv[iarg], fileTypeName[itype]) == 0 ){
						*fileType = itype;
					}
					break;
				}
				if ( fileTypeName[itype] == NULL ) {
					usage( argv[0] );
					return 1;
				}
			}
			break;
		case 'h':
			if ( check_iarg(++iarg, argc, argv[0]) ) return 1;
			sprintf( headerInfoDir, "%s", argv[iarg] );
			break;
		default:
			usage(argv[0]);
			return 1;
			break;
		}
	}
	
	return 0;
}

/*----------------------------------------------------------------------------*/
/* Name:        InitializeProgram()                                           */
/* Description: プログラムを初期化                                            */
/* Return:      (int) エラーがあれば 1, なければ 0                            */
/* Access:      static                                                        */
/*----------------------------------------------------------------------------*/
static
int InitializeProgram(int   argc,      // Input: number of arguments
					  char  *argv[],   // Input: the arguments
					  headerInfo      *setupInfo,  // Output: setup parameters
					  encSpecificInfo *encInfo,    // Output: encoder specific setup parameters
					  char  **namein,			// Output: input file name
					  FILE  **fp_i,
					  int   *fileType,
					  int   *data_size,
					  char  **nameout,
					  char  *headerInfoDir)
{
	/*--- セットアップ情報のデフォルト値を設定 ---*/
	SetDefault( setupInfo, encInfo, fileType, headerInfoDir );

	/*--- 引数を取得・セットアップ情報と入出力ファイル名を取得 ---*/
	if ( ReceiveArguments(argc, argv, setupInfo, encInfo, namein, nameout, fp_i, fileType, data_size, headerInfoDir) ){
		return 1;
	}
	
	return 0;
}
	
/*----------------------------------------------------------------------------*/
/* Name:        message()                                                     */
/* Description: 初期化パラメータを表示する。                                  */
/* Return:      なし                                                          */
/* Access:      static                                                        */
/*----------------------------------------------------------------------------*/
static
void message(char	*namein,
	     char    *nameout,
	     char    *title,
	     char    *comment,
		 int     fileType)
{
	headerInfo hd;
	TvqEncGetSetupInfo(&hd);

	int numChannels = TvqEncGetNumChannels();
	float samplingRate = TvqEncGetSamplingRate();
	int bitRate = TvqEncGetBitRate();
	int NBITS_FR = TvqEncGetNumFixedBitsPerFrame();

    fprintf( stderr, "\n<<>><<>> TwinVQ encoder DLL test program <<>><<>>\n" );
    fprintf( stderr, "\n" );
		fprintf(stderr, "### Version: %s\n", hd.ID);
    fprintf( stderr, "### Input data file name:          %s\n", namein );
    fprintf( stderr, "### Output data file name:         %s\n", nameout );
	fprintf( stderr, "### Input audio data file type:    %s\n", fileTypeName[fileType] );
//    fprintf( stderr, "### Title:   %s\n", title );
//    fprintf( stderr, "### Comment: %s\n", comment );

    fprintf( stderr, "\n" );
    fprintf( stderr, "### Sampling frequency:    %8.1f kHz\n", samplingRate/1000.);
    fprintf( stderr, "### Total Bitrate (fixed part):         %8.1f kbit/s\n",
	    (float)bitRate );
    fprintf( stderr, "### Number of channels:         %d\n", numChannels );

//    fprintf( stderr, "### Num of Bits per frame:  %5d\n", NBITS_FR );

	fprintf(stderr, "\n");

}

/*----------------------------------------------------------------------------*/
/* Name:        InitializeEncoder()                                           */
/* Description: エンコーダを初期化                                            */
/* Return:      初期化エラーコード (twinvq.h を見よ)                          */
/* Access:      static                                                        */
/*----------------------------------------------------------------------------*/
static
int InitializeEncoder(headerInfo *setupInfo,
					  encSpecificInfo *encInfo,
					  int *frameSize,
					  int *numChannels,
					  INDEX *index,
					  float **in,
					  short **bufin,
					  BFILE **bfp_cw,
					  char  *namein,
					  char  *nameout,
					  int   fileType,
					  char  *headerInfoDir)
{
	int errorCode;

	/*--- ステップ１：TwinVQ エンコーダ DLL モジュールを初期化 ---*/
	if ( errorCode = TvqEncInitialize( setupInfo, encInfo, index, INIT_ERR_DISP_MBOX ) ) return errorCode;

	/*--- ステップ２：ビットストリーム書き込みモジュールを初期化 ---*/
	if ( (*bfp_cw=bopen(nameout,"wb")) == NULL ){ // 出力ビットストリームファイルをオープン
		fprintf( stderr, "%s: File open error.\n", nameout );
		return TVQ_ERROR;
	}
	TvqInitBsWriter(); // モジュールの初期化

	/*--- ステップ３：オーディオデータ入力部を初期化 ---*/
	*frameSize = TvqEncGetFrameSize();				// オーディオデータバッファを初期化
	*numChannels = TvqEncGetNumChannels();
	*in    = new float[ *frameSize * *numChannels ];
	*bufin = new short[ *frameSize * *numChannels ];

	/*--- ステップ４：ビットストリームヘッダオブジェクトを作成 ---*/
	CChunkChunk* twinChunk = TvqCreateHeaderChunk( setupInfo, headerInfoDir );
	if ( twinChunk == NULL ) return TVQ_ERROR;

	/*--- ステップ５：ビットストリームヘッダを書き込み ---*/
	TvqPutBsHeaderInfo( *bfp_cw, *twinChunk );
	delete twinChunk;	// ヘッダの書き込みが終わったらヘッダチャンクは消去する
	
	/*--- セットアップ情報を表示 ---*/
	message( namein, nameout, setupInfo->Name, setupInfo->Comt, fileType );

	return TVQ_NO_ERROR;
}

/******************************************/
/**** エンコード処理用スタティック関数 ****/
/******************************************/
/*----------------------------------------------------------------------------*/
/* Name:        buftofr()                                                     */
/* Description: 入力オーディオファイルデータのバッファ形式を変換              */
/* Return:      なし                                                          */
/* Access:      static                                                        */
/*----------------------------------------------------------------------------*/
static
void buftofr(int    blen,      /* Input  --- read data length */
			 short  bufin[],   /* Input  --- input data buffer array */
			 float in[],      /* Output --- output data frame */
			 int	frameSize,
			 int	numChannels)
{
	/*--- Variables ---*/
	int	ismp, ich, blen_ch;
	
	/*--- Initialization ---*/
	blen_ch = blen/numChannels;
	/*--- Main operation ---*/
	for ( ich=0; ich<numChannels; ich++ ){
		for ( ismp=0; ismp<blen_ch; ismp++ ){
			in[ich*frameSize+ismp] = (float)bufin[ismp*numChannels+ich];
		}
		for (ismp=blen_ch; ismp<frameSize; ismp++){
			in[ich*frameSize+ismp] = 0.;
		}
	}
}

/*----------------------------------------------------------------------------*/
/* Name:        mark()                                                        */
/* Description: エンコードの進行状況を表示する。                              */
/* Return:      なし                                                          */
/* Access:      static                                                        */
/*----------------------------------------------------------------------------*/
static
void mark(int ndata)
{
	fprintf(stderr, "Frame %6d      \r", ndata);
}


/*----------------------------------------------------------------------------*/
/* Name:        EncodingProcess()                                             */
/* Description: エンコード処理                                                */
/* Return:      エラーがあれば 1 なければ 0                                   */
/* Access:      static                                                        */
/*----------------------------------------------------------------------------*/
static
int EncodingProcess(int   frameSize,   // フレームサイズ
					int   numChannels, // チャネル数
					INDEX *index,      // コードデータ受け渡し用構造体
					float in[],        // 入力 PCM ファイル用バッファ
					short bufin[],     // DLL 入力用バッファ
					FILE  *fp_i,       // 入力ファイルポインタ
					BFILE *bfp_cw,     // 出力ビットストリームファイルポインタ
					int data_size)
{
	int blen;
	int iframe;
	int restSize, numFrames, totalFrameSize;

	totalFrameSize = frameSize * numChannels;
	numFrames      = data_size / totalFrameSize;
	restSize       = data_size % totalFrameSize;

	for( iframe = 0; iframe<numFrames+3; iframe++ ){
		/*--- ファイルからオーディオデータ読み込み ---*/
		int readLength;
		if ( iframe < numFrames )		readLength = totalFrameSize;
		else if ( iframe == numFrames )	readLength = restSize;
		else							readLength = 0;
		blen = fread( bufin, sizeof(*bufin), readLength, fp_i );

		/*--- オーディオデータから入力フレームへの変換 ---*/
		buftofr( blen, bufin, in, frameSize, numChannels );
		/*-- エンコード処理 --*/
		TvqEncodeFrame( in, index );
		
		/*-- ビットストリーム書き込み --*/
		TvqWriteBsFrame( index, bfp_cw );
		
		/*--- エンコード処理進行の表示 ---*/
#if DISP_FRAME
		mark( iframe );
#endif
		
	}

	fprintf( stderr, "\n" );
	return 0;
}

/************************************/
/**** 終了処理用スタティック関数 ****/
/************************************/
/*----------------------------------------------------------------------------*/
/* Name:        TerminateEncoder()                                            */
/* Description: TwinVQ エンコーダの終了処理                                   */
/* Return:      エラーがあれば 1 なければ 0                                   */
/* Access:      static                                                        */
/*----------------------------------------------------------------------------*/
static
int TerminateEncoder( INDEX *index, float *in, short *bufin, FILE* fp_i, BFILE *bfp_cw ){

	TvqEncTerminate( index );
	delete[] in;
	delete[] bufin;
	fclose( fp_i );
	bclose( bfp_cw );

	return 0;
}

/****************************/
/******** メイン関数 ********/
/****************************/
/*============================================================================*/
/* Name:        main()                                                        */
/* Description: the main program                                              */
/* Return:      returns 1 when error or 0                                     */
/* Access:      external                                                      */
/*============================================================================*/
int main(int  argc,
		 char *argv[])
{

	/*--- プログラム実行の準備 ---*/
	char    *namein, *nameout;  // 入出力ファイル名
	FILE	*fp_i;              // 入力オーディオデータファイルポインタ
	BFILE	*bfp_cw;            // 出力ビットストリームファイルポインタ
	headerInfo      setupInfo;  // TwinVQ セットアップ情報
	encSpecificInfo encInfo;    // エンコーダ特有の TwinVQ セットアップ情報
	int fileType;				// ファイルタイプ
	int data_size;				// オーディオデータのサイズ
	char headerInfoDir[BUFSIZ];

	if ( InitializeProgram( argc, argv, &setupInfo, &encInfo, &namein, &fp_i, &fileType, &data_size, &nameout, headerInfoDir ) ){
		return 1;
	}

	/*--- TwinVQ エンコーダを初期化 ---*/
	int frameSize, numChannels; // フレームサイズとチャネル数
	float *in;                  // DLL 用データバッファ
	short *bufin;               // PCM ファイル用データバッファ
	INDEX index;                // コードデータ受け渡し用構造体
	int   errorCode;            // 初期化エラーコード

	if ( errorCode = InitializeEncoder(&setupInfo, &encInfo, &frameSize, &numChannels, &index, &in, &bufin, &bfp_cw, namein, nameout, fileType, headerInfoDir ) ){
		fprintf( stderr, "Initialization failed due to %s.\n", error_message[errorCode] );
		return 1;
	}

	/*--- エンコード処理 ---*/
	if ( EncodingProcess( frameSize, numChannels, &index, in, bufin, fp_i, bfp_cw, data_size ) ){
		return 1;
	}
	
	/*--- 終了処理 ---*/
	TerminateEncoder( &index, in, bufin, fp_i, bfp_cw );
	
	return 0;
}


