/** * @file adin_sndfile.c * * * @brief ファイル入力:libsndfile を用いた音声ファイル読み込み * * libsndfile を用いて音声ファイルからの入力を行なう関数です. * Microsoft WAVE形式の音声ファイル,およびヘッダ無し(RAW)ファイルの他に, * AU, AND, NIST, ADPCM など様々な形式のファイルを読み込むことができます. * なお,チャンネル数は1(モノラル)に限られます.またRAWファイルの場合, * データのバイトオーダーは big endian である必要があります. * * ファイルのサンプリングレートはシステムの要求するサンプリングレート * (adin_standby() で指定される値)と一致する必要があります. * ファイルのサンプリングレートがこの指定値と一致しなければエラーとなります. * RAWファイル入力の場合は,ファイルにヘッダ情報が無く録音時の * サンプリングレートが不明なため,チェック無しでファイルの * サンプリングレートが adin_standby() で指定された値である * と仮定して処理されます. * * 入力ファイル名は,標準入力から読み込まれます. * ファイル名を列挙したファイルリストファイルが指定された場合, * そのファイルから入力ファイル名が順次読み込まれます. * * libsndfile はconfigure 時に自動検出されます.検出に失敗した場合, * ファイル入力には adin_file.c 内の関数が使用されます. * * Libsndfile のバージョンは 1.0.x に対応しています. * * @sa http://www.mega-nerd.com/libsndfile/ * * * @brief Audio input from file using libsndfile library. * * Functions to get input from wave file using libsndfile library. * Many file formats are supported, including Microsoft WAVE format, * and RAW (no header) format, AU, SND, NIST and so on. The channel number * should be 1 (monaural). * 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. * * libsndfile should be installed before compilation. The library and header * will be automatically detected by configure script. When failed to detect, * Julius uses adin_file.c instead for file input. * * This file will work on libsndfile version 1.0.x. * * @sa http://www.mega-nerd.com/libsndfile/ * * * @author Akinobu LEE * @date Mon Feb 14 12:13:27 2005 * * $Revision: 1.6 $ * */ /* * 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 #ifdef HAVE_LIBSNDFILE /* sound header */ #include static int sfreq; ///< Required sampling frequency in Hz static SF_INFO sinfo; ///< Wavefile information static SNDFILE *sp; ///< File handler static boolean from_file; ///< TRUE if reading filename from listfile static FILE *fp_list; ///< File pointer used for the listfile static char speechfilename[MAXPATHLEN]; ///< Buffer to hold input file name /// Check if the file format is 16bit, monoral. static boolean check_format(SF_INFO *s) { if ((s->format & SF_FORMAT_TYPEMASK) != SF_FORMAT_RAW) { if (s->samplerate != sfreq) { jlog("Error: adin_sndfile: sample rate != %d, it's %d Hz data\n", sfreq, s->samplerate); return FALSE; } } if (s->channels != 1) { jlog("Error: adin_sndfile: channel num != 1, it has %d channels\n", s->channels); return FALSE; } #ifdef HAVE_LIBSNDFILE_VER1 if ((s->format & SF_FORMAT_SUBMASK) != SF_FORMAT_PCM_16) { jlog("Error: adin_sndfile: not 16-bit data\n"); return FALSE; } #else if (s->pcmbitwidth != 16) { jlog("Error: adin_sndfile: not 16-bit data, it's %d bit\n", s->pcmbitwidth); return FALSE; } #endif return TRUE; } /// Output format information to stdout (compliant to libsnd-0.0.23) static void print_format(SF_INFO *s) { switch(s->format & SF_FORMAT_TYPEMASK) { case SF_FORMAT_WAV: jlog("Stat: adin_sndfile: input format = Microsoft WAV\n"); break; case SF_FORMAT_AIFF: jlog("Stat: adin_sndfile: input format = Apple/SGI AIFF\n"); break; case SF_FORMAT_AU: jlog("Stat: adin_sndfile: input format = Sun/NeXT AU\n"); break; #ifndef HAVE_LIBSNDFILE_VER1 case SF_FORMAT_AULE: jlog("Stat: adin_sndfile: input format = DEC AU\n"); break; #endif case SF_FORMAT_RAW: jlog("Stat: adin_sndfile: input format = RAW\n"); break; case SF_FORMAT_PAF: jlog("Stat: adin_sndfile: input format = Ensoniq PARIS\n"); break; case SF_FORMAT_SVX: jlog("Stat: adin_sndfile: input format = Amiga IFF / SVX8 / SV16\n"); break; case SF_FORMAT_NIST: jlog("Stat: adin_sndfile: input format = Sphere NIST\n"); break; #ifdef HAVE_LIBSNDFILE_VER1 case SF_FORMAT_VOC: jlog("Stat: adin_sndfile: input format = VOC file\n"); break; case SF_FORMAT_IRCAM: jlog("Stat: adin_sndfile: input format = Berkeley/IRCAM/CARL\n"); break; case SF_FORMAT_W64: jlog("Stat: adin_sndfile: input format = Sonic Foundry's 64bit RIFF/WAV\n"); break; case SF_FORMAT_MAT4: jlog("Stat: adin_sndfile: input format = Matlab (tm) V4.2 / GNU Octave 2.0\n"); break; case SF_FORMAT_MAT5: jlog("Stat: adin_sndfile: input format = Matlab (tm) V5.0 / GNU Octave 2.1\n"); break; #endif default: jlog("Stat: adin_sndfile: input format = UNKNOWN TYPE\n"); break; } switch(s->format & SF_FORMAT_SUBMASK) { #ifdef HAVE_LIBSNDFILE_VER1 case SF_FORMAT_PCM_U8: jlog("Stat: adin_sndfile: input type = Unsigned 8 bit PCM\n"); break; case SF_FORMAT_PCM_S8: jlog("Stat: adin_sndfile: input type = Signed 8 bit PCM\n"); break; case SF_FORMAT_PCM_16: jlog("Stat: adin_sndfile: input type = Signed 16 bit PCM\n"); break; case SF_FORMAT_PCM_24: jlog("Stat: adin_sndfile: input type = Signed 24 bit PCM\n"); break; case SF_FORMAT_PCM_32: jlog("Stat: adin_sndfile: input type = Signed 32 bit PCM\n"); break; case SF_FORMAT_FLOAT: jlog("Stat: adin_sndfile: input type = 32bit float\n"); break; case SF_FORMAT_DOUBLE: jlog("Stat: adin_sndfile: input type = 64bit float\n"); break; case SF_FORMAT_ULAW: jlog("Stat: adin_sndfile: input type = U-Law\n"); break; case SF_FORMAT_ALAW: jlog("Stat: adin_sndfile: input type = A-Law\n"); break; case SF_FORMAT_IMA_ADPCM: jlog("Stat: adin_sndfile: input type = IMA ADPCM\n"); break; case SF_FORMAT_MS_ADPCM: jlog("Stat: adin_sndfile: input type = Microsoft ADPCM\n"); break; case SF_FORMAT_GSM610: jlog("Stat: adin_sndfile: input type = GSM 6.10, \n"); break; case SF_FORMAT_G721_32: jlog("Stat: adin_sndfile: input type = 32kbs G721 ADPCM\n"); break; case SF_FORMAT_G723_24: jlog("Stat: adin_sndfile: input type = 24kbs G723 ADPCM\n"); break; case SF_FORMAT_G723_40: jlog("Stat: adin_sndfile: input type = 40kbs G723 ADPCM\n"); break; #else case SF_FORMAT_PCM: jlog("Stat: adin_sndfile: input type = PCM\n"); break; case SF_FORMAT_FLOAT: jlog("Stat: adin_sndfile: input type = floats\n"); break; case SF_FORMAT_ULAW: jlog("Stat: adin_sndfile: input type = U-Law\n"); break; case SF_FORMAT_ALAW: jlog("Stat: adin_sndfile: input type = A-Law\n"); break; case SF_FORMAT_IMA_ADPCM: jlog("Stat: adin_sndfile: input type = IMA ADPCM\n"); break; case SF_FORMAT_MS_ADPCM: jlog("Stat: adin_sndfile: input type = Microsoft ADPCM\n"); break; case SF_FORMAT_PCM_BE: jlog("Stat: adin_sndfile: input type = Big endian PCM\n"); break; case SF_FORMAT_PCM_LE: jlog("Stat: adin_sndfile: input type = Little endian PCM\n"); break; case SF_FORMAT_PCM_S8: jlog("Stat: adin_sndfile: input type = Signed 8 bit PCM\n"); break; case SF_FORMAT_PCM_U8: jlog("Stat: adin_sndfile: input type = Unsigned 8 bit PCM\n"); break; case SF_FORMAT_SVX_FIB: jlog("Stat: adin_sndfile: input type = SVX Fibonacci Delta\n"); break; case SF_FORMAT_SVX_EXP: jlog("Stat: adin_sndfile: input type = SVX Exponential Delta\n"); break; case SF_FORMAT_GSM610: jlog("Stat: adin_sndfile: input type = GSM 6.10, \n"); break; case SF_FORMAT_G721_32: jlog("Stat: adin_sndfile: input type = 32kbs G721 ADPCM\n"); break; case SF_FORMAT_G723_24: jlog("Stat: adin_sndfile: input type = 24kbs G723 ADPCM\n"); break; #endif default: jlog("Stat: adin_sndfile: input type = UNKNOWN SUBTYPE\n"); break; } #ifdef HAVE_LIBSNDFILE_VER1 switch(s->format & SF_FORMAT_ENDMASK) { case SF_ENDIAN_FILE: jlog("Stat: adin_sndfile: endian = file native endian\n"); break; case SF_ENDIAN_LITTLE: jlog("Stat: adin_sndfile: endian = forced little endian\n"); break; case SF_ENDIAN_BIG: jlog("Stat: adin_sndfile: endian = forced big endian\n"); break; case SF_ENDIAN_CPU: jlog("Stat: adin_sndfile: endian = forced CPU native endian\n"); break; } jlog("Stat: adin_sndfile: %d Hz, %d channels\n", s->samplerate, s->channels); #else jlog("Stat: adin_sndfile: %d bit, %d Hz, %d channels\n", s->pcmbitwidth, s->samplerate, s->channels); #endif } /** * Initialization: if listfile is specified, open it here. Else, just store * the required frequency. * * @param freq [in] required sampling frequency * @param arg [in] file name of listfile, or NULL if not use * * @return TRUE on success, FALSE on failure. */ boolean adin_sndfile_standby(int freq, void *arg) { char *fname = arg; if (fname != NULL) { /* read input filename from file */ if ((fp_list = fopen(fname, "r")) == NULL) { jlog("Error: adin_sndfile: failed to open %s\n", fname); return(FALSE); } from_file = TRUE; } else { /* read filename from stdin */ from_file = FALSE; } /* store sampling frequency */ sfreq = freq; return(TRUE); } /** * @brief Open a file and check the format * * @param filename [in] file name to open * * @return TRUE on success, FALSE on failure. */ static boolean adin_sndfile_open(char *filename) { #ifndef HAVE_LIBSNDFILE_VER1 sinfo.samplerate = sfreq; sinfo.pcmbitwidth = 16; sinfo.channels = 1; #endif sinfo.format = 0x0; if ((sp = #ifdef HAVE_LIBSNDFILE_VER1 sf_open(filename, SFM_READ, &sinfo) #else sf_open_read(filename, &sinfo) #endif ) == NULL) { /* retry assuming raw format */ sinfo.samplerate = sfreq; sinfo.channels = 1; #ifdef HAVE_LIBSNDFILE_VER1 sinfo.format = SF_FORMAT_RAW | SF_FORMAT_PCM_16 | SF_ENDIAN_BIG; #else sinfo.pcmbitwidth = 16; sinfo.format = SF_FORMAT_RAW | SF_FORMAT_PCM_BE; #endif if ((sp = #ifdef HAVE_LIBSNDFILE_VER1 sf_open(filename, SFM_READ, &sinfo) #else sf_open_read(filename, &sinfo) #endif ) == NULL) { sf_perror(sp); jlog("Error: adin_sndfile: failed to open speech data: \"%s\"\n",filename); } } if (sp == NULL) { /* open failure */ return FALSE; } /* check its format */ if (! check_format(&sinfo)) { return FALSE; } return TRUE; } /** * @brief Begin reading audio data from a file. * * If listfile was specified in adin_sndfile_standby(), the next filename * will be read from the listfile. Otherwise, the * filename will be obtained from stdin. Then the file will be opened here. * * @param filename [in] file name to open or NULL for prompt * * @return TRUE on success, FALSE on failure. */ boolean adin_sndfile_begin(char *filename) { boolean readp; if (filename != NULL) { if (adin_sndfile_open(filename) == FALSE) { jlog("Error: adin_sndfile: invalid format: \"%s\"\n", filename); print_format(&sinfo); return FALSE; } jlog("Stat: adin_sndfile: input speechfile: %s\n", filename); print_format(&sinfo); strcpy(speechfilename, filename); return TRUE; } /* ready to read next input */ readp = FALSE; while(readp == FALSE) { if (from_file) { /* read file name from listfile */ do { if (getl_fp(speechfilename, MAXPATHLEN, fp_list) == NULL) { /* end of input */ fclose(fp_list); return(FALSE); /* end of input */ } } while (speechfilename[0] == '#'); /* skip comment */ } else { /* read file name from stdin */ if (get_line_from_stdin(speechfilename, MAXPATHLEN, "enter filename->") == NULL) { return (FALSE); /* end of input */ } } if (adin_sndfile_open(speechfilename) == FALSE) { jlog("Error: adin_sndfile: invalid format: \"%s\"\n",speechfilename); print_format(&sinfo); } else { jlog("Stat: adin_sndfile: input speechfile: %s\n",speechfilename); print_format(&sinfo); 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_sndfile_read(SP16 *buf, int sampnum) { int cnt; cnt = sf_read_short(sp, buf, sampnum); if (cnt == 0) { /* EOF */ return -1; } else if (cnt < 0) { /* error */ sf_perror(sp); sf_close(sp); return -2; /* error */ } return cnt; } /** * End recording. * * @return TRUE on success, FALSE on failure. */ boolean adin_sndfile_end() { /* close files */ if (sf_close(sp) != 0) { sf_perror(sp); jlog("Error: adin_sndfile: failed to close\n"); return FALSE; } return TRUE; } /** * * A tiny function to get current input raw speech file name. * * @return string of current input speech file. * */ char * adin_sndfile_get_current_filename() { return(speechfilename); } #endif /* ~HAVE_LIBSNDFILE */