/** * @file adin_file.c * * * @brief ファイル入力:WAV/RAWファイルおよび標準入力からの読み込み * * 音声ファイルからの入力を行なう関数です.サポートしているファイル形式は * Microsoft WAVE形式の音声ファイル,およびヘッダ無し(RAW)ファイルです. * オーディオ形式は,無圧縮PCM,16bit,モノラルに限られています. * RAWファイルの場合,データのバイトオーダーが big endian であることを * 前提としていますので,注意してください. * * ファイルのサンプリングレートはシステムの要求するサンプリングレート * (adin_standby() で指定される値)と一致する必要があります. * WAVE形式のファイルの場合は, * ファイルのサンプリングレートがこの指定値と一致しなければエラーとなります. * RAWファイル入力の場合は,ファイルにヘッダ情報が無く録音時の * サンプリングレートが不明なため,チェック無しでファイルの * サンプリングレートが adin_standby() で指定された値である * と仮定して処理されます. * * 入力ファイル名は,標準入力から読み込まれます. * ファイル名を列挙したファイルリストファイルが指定された場合, * そのファイルから入力ファイル名が順次読み込まれます. * * libsndfile を使用する場合,adin_sndfile.c 内の関数が使用されます. * この場合,このファイルの関数は使用されません. * * このファイル内では int を 4byte, short を 2byte と仮定しています. * * * @brief Audio input from file or stdin * * Functions to get input from wave file or standard input. * Two file formats are supported, Microsoft WAVE format and RAW (no header) * format. The audio format should be uncompressed PCM, 16bit, monoral. * On RAW file input, the data byte order must be in big endian. * * The sampling rate of input file must be equal to the system requirement * value which is specified by adin_standby() . For WAVE format file, * the sampling rate of the input file described in its header is checked * against the system value, and rejected if not matched. But for RAW format * file, no check will be applied since it has no header information about * the recording sampling rate, so be careful of the sampling rate setting. * * When file input mode, the file name will be read from standard input. * If a filelist file is specified, the file names are read from the file * sequencially instead. * * When compiled with libsndfile support, the functions in adin_sndfile.c * is used for file input instead of functions below. * * In this file, assume sizeof(int)=4, sizeof(short)=2 * * * @author Akinobu LEE * @date Sun Feb 13 13:31:20 2005 * * $Revision: 1.10 $ * */ /* * Copyright (c) 1991-2012 Kawahara Lab., Kyoto University * Copyright (c) 2000-2005 Shikano Lab., Nara Institute of Science and Technology * Copyright (c) 2005-2012 Julius project team, Nagoya Institute of Technology * All rights reserved */ #include #include #include static FILE *gfp; ///< File pointer of current input file static boolean wav_p; ///< TRUE if input is WAVE file, FALSE if RAW file static int maxlen; ///< Number of samples, described in the header of WAVE file static int nowlen; ///< Current number of read samples /** * When file input, the first 4 bytes of the file are read at first to * identify whether it is WAVE file format. This work area is used to * keep back the 4 bytes if the input is actually a RAW format. */ static SP16 pre_data[2]; static boolean has_pre; ///< TRUE if pre_data is available static unsigned int sfreq; ///< Sampling frequency in Hz, specified by adin_standby() static char speechfilename[MAXPATHLEN]; ///< Buffer to hold input file name static char *stdin_buf = NULL; /* read .wav data with endian conversion */ /* (all .wav datas are in little endian) */ /** * Read a header value from WAVE file with endian conversion. * If required number of data has not been read, it produces error. * * @param buf [out] Pointer to store read data * @param unitbyte [in] Unit size * @param unitnum [in] Required number of units to read * @param fp [in] File pointer * * @return TRUE on success, FALSE if required number of data has not been read. */ static boolean myread(void *buf, size_t unitbyte, int unitnum, FILE *fp) { int tmp; if ((tmp = fread(buf, unitbyte, unitnum, fp)) < unitnum) { return(FALSE); } #ifdef WORDS_BIGENDIAN swap_bytes(buf, unitbyte, unitnum); #endif return(TRUE); } /// Abbreviation for header reading #define MYREAD(A,B,C,D) if (!myread(A, B, C, D)) {jlog("Error: adin_file: file is corrupted\n"); return -1;} /** * @brief Parse header part of a WAVE file to prepare for data reading * * The audio format will be checked here, and data length is also read from * the header. Then the pointer is moved to the start point of data part. * * When called, the file pointer should be located just after * the first 4 bytes, "RIFF". It also sets @a maxlen and @a nowlen . * * @param fp [in] File pointer * * @return TRUE if check successfully passed, FALSE if an error occured. */ static boolean setup_wav(FILE *fp) { char dummy[9]; unsigned int i, len; unsigned short s; /* 4 byte: byte num of rest ( = filesize - 8) */ /* --- just skip them */ MYREAD(dummy, 1, 4, fp); /* first part: WAVE format specifications */ /* 4 byte: "WAVE" */ MYREAD(dummy, 1, 4, fp); if (dummy[0] != 'W' || dummy[1] != 'A' || dummy[2] != 'V' || dummy[3] != 'E') { jlog("Error: adin_file: WAVE header not found, file corrupted?\n"); return FALSE; } /* format chunk: "fmt " */ MYREAD(dummy, 1, 4, fp); if (dummy[0] != 'f' || dummy[1] != 'm' || dummy[2] != 't' || dummy[3] != ' ') { jlog("Error: adin_file: fmt chunk not found, file corrupted?\n"); return FALSE; } /* 4byte: byte size of this part */ MYREAD(&len, 4, 1, fp); /* 2byte: data format */ MYREAD(&s, 2, 1, fp); if (s != 1) { jlog("Error: adin_file: data format != PCM (id=%d)\n", s); return FALSE; } /* 2byte: channel num */ MYREAD(&s, 2, 1, fp); if (s >= 2) { jlog("Error: adin_file: channel num != 1 (%d)\n", s); return FALSE; } /* 4byte: sampling rate */ MYREAD(&i, 4, 1, fp); if (i != sfreq) { jlog("Error: adin_file: sampling rate != %d (%d)\n", sfreq, i); return FALSE; } /* 4byte: bytes per second */ MYREAD(&i, 4, 1, fp); if (i != sfreq * sizeof(SP16)) { jlog("Error: adin_file: bytes per second != %d (%d)\n", sfreq * sizeof(SP16), i); return FALSE; } /* 2bytes: bytes per frame ( = (bytes per sample) x channel ) */ MYREAD(&s, 2, 1, fp); if (s != 2) { jlog("Error: adin_file: (bytes per sample) x channel != 2 (%d)\n", s); return FALSE; } /* 2bytes: bits per sample */ MYREAD(&s, 2, 1, fp); if (s != 16) { jlog("Error: adin_file: bits per sample != 16 (%d)\n", s); return FALSE; } /* skip rest */ if (len > 16) { len -= 16; while (len > 0) { if (len > 8) { MYREAD(dummy, 1, 8, fp); len -= 8; } else { MYREAD(dummy, 1, len, fp); len = 0; } } } /* end of fmt part */ /* seek for 'data' part */ while (myread(dummy, 1, 4, fp)) { MYREAD(&len, 4, 1, fp); if (dummy[0] == 'd' && dummy[1] == 'a' && dummy[2] == 't' && dummy[3] == 'a') { break; } for (i=0;i") == NULL) { return (FALSE); /* end of input */ } } /* open input file */ if (adin_file_open(speechfilename) == FALSE) { jlog("Error: adin_file: failed to read speech data: \"%s\"\n", speechfilename); } else { jlog("Stat: adin_file: input speechfile: %s\n", speechfilename); readp = TRUE; } } return TRUE; } /** * Try to read @a sampnum samples and returns actual sample num recorded. * * @param buf [out] samples obtained in this function * @param sampnum [in] wanted number of samples to be read * * @return actural number of read samples, -1 if EOF, -2 if error. */ int adin_file_read(SP16 *buf, int sampnum) { FILE *fp; int cnt; fp = gfp; if (wav_p) { cnt = fread(buf, sizeof(SP16), sampnum, fp); if (cnt == 0) { if (feof(fp)) return -1; /* EOF */ if (ferror(fp)) { jlog("Error: adin_file: an error occured while reading file\n"); adin_file_close(); return -2; /* error */ } } if (nowlen + cnt > maxlen) { cnt = maxlen - nowlen; } nowlen += cnt; } else { if (has_pre) { buf[0] = pre_data[0]; buf[1] = pre_data[1]; has_pre = FALSE; cnt = fread(&(buf[2]), sizeof(SP16), sampnum - 2, fp); if (cnt == 0) { if (feof(fp)) return -1; /* EOF */ if (ferror(fp)) { jlog("Error: adin_file: an error occured file reading file\n"); adin_file_close(); return -2; /* error */ } } cnt += 2; } else { cnt = fread(buf, sizeof(SP16), sampnum, fp); if (cnt == 0) { if (feof(fp)) return -1; /* EOF */ if (ferror(fp)) { jlog("Error: adin_file: an error occured file reading file\n"); adin_file_close(); return -2; /* error */ } } } } /* all .wav data are in little endian */ /* assume .raw data are in big endian */ #ifdef WORDS_BIGENDIAN if (wav_p) swap_sample_bytes(buf, cnt); #else if (!wav_p) swap_sample_bytes(buf, cnt); #endif return cnt; } /** * End recording. * * @return TRUE on success, FALSE on failure. */ boolean adin_file_end() { /* nothing needed */ adin_file_close(); return TRUE; } /** * Initialization for speech input via stdin. * * @param freq [in] required sampling frequency. * @param arg dummy, ignored * * @return TRUE on success, FALSE on failure. */ boolean adin_stdin_standby(int freq, void *arg) { /* store sampling frequency */ sfreq = freq; return(TRUE); } /** * @brief Begin reading audio data from stdin * * @param pathname [in] dummy * * @return TRUE on success, FALSE on failure. */ boolean adin_stdin_begin(char *pathname) { if (feof(stdin)) { /* already reached the end of input stream */ jlog("Error: adin_stdin: stdin reached EOF\n"); return FALSE; /* terminate search here */ } else { /* open input stream */ if (adin_file_open(NULL) == FALSE) { jlog("Error: adin_stdin: failed to read speech data from stdin\n"); return FALSE; } jlog("Stat: adin_stdin: reading wavedata from stdin...\n"); } return TRUE; } /** * Try to read @a sampnum samples and returns actual sample num recorded. * * @param buf [out] samples obtained in this function * @param sampnum [in] wanted number of samples to be read * * @return actural number of read samples, -1 if EOF, -2 if error. */ int adin_stdin_read(SP16 *buf, int sampnum) { int cnt; if (wav_p) { cnt = fread(buf, sizeof(SP16), sampnum, stdin); if (cnt == 0) { if (feof(stdin)) return -1; /* EOF */ if (ferror(stdin)) { jlog("Error: adin_stdin: an error occured while reading stdin\n"); return -2; /* error */ } } } else { if (has_pre) { buf[0] = pre_data[0]; buf[1] = pre_data[1]; has_pre = FALSE; cnt = fread(&(buf[2]), sizeof(SP16), sampnum - 2, stdin); if (cnt == 0) { if (feof(stdin)) return -1; /* EOF */ if (ferror(stdin)) { jlog("Error: adin_stdin: an error occured while reading stdin\n"); return -2; /* error */ } } cnt += 2; } else { cnt = fread(buf, sizeof(SP16), sampnum, stdin); if (cnt == 0) { if (feof(stdin)) return -1; /* EOF */ if (ferror(stdin)) { jlog("Error: adin_stdin: an error occured while reading stdin\n"); return -2; /* error */ } } } } /* all .wav data are in little endian */ /* assume .raw data are in big endian */ #ifdef WORDS_BIGENDIAN if (wav_p) swap_sample_bytes(buf, cnt); #else if (!wav_p) swap_sample_bytes(buf, cnt); #endif return cnt; } /** * * A tiny function to get current input raw speech file name. * * @return string of current input speech file. * */ char * adin_file_get_current_filename() { return(speechfilename); } /** * * A tiny function to get current input raw speech file name. * * @return string of current input speech file. * */ char * adin_stdin_input_name() { return("stdin"); }