1 /**
2  * @file   adin_sndfile.c
3  *
4  * <JA>
5  * @brief  �ե��������ϡ�libsndfile ���Ѥ��������ե������ɤ߹���
6  *
7  * libsndfile ���Ѥ��Ʋ����ե����뤫������Ϥ�Ԥʤ��ؿ��Ǥ���
8  * Microsoft WAVE�����β����ե����롤����ӥإå�̵����RAW�˥ե������¾��,
9  * AU, AND, NIST, ADPCM �ʤ��͡��ʷ����Υե�������ɤ߹��ळ�Ȥ��Ǥ��ޤ���
10  * �ʤ��������ͥ���ϣ�(��Υ��)�˸¤��ޤ����ޤ�RAW�ե�����ξ�硤
11  * �ǡ����ΥХ��ȥ��������� big endian �Ǥ���ɬ�פ�����ޤ���
12  *
13  * �ե�����Υ���ץ���졼�Ȥϥ����ƥ���׵᤹�륵��ץ���졼��
14  * ��adin_standby() �ǻ��ꤵ����͡ˤȰ��פ���ɬ�פ�����ޤ���
15  * �ե�����Υ���ץ���졼�Ȥ����λ����ͤȰ��פ��ʤ���Х��顼�Ȥʤ�ޤ���
16  * RAW�ե��������Ϥξ��ϡ��ե�����˥إå�����̵��Ͽ������
17  * ����ץ���졼�Ȥ������ʤ��ᡤ�����å�̵���ǥե������
18  * ����ץ���졼�Ȥ� adin_standby() �ǻ��ꤵ�줿�ͤǤ���
19  * �Ȳ��ꤷ�ƽ�������ޤ���
20  *
21  * ���ϥե�����̾�ϡ�ɸ�����Ϥ����ɤ߹��ޤ�ޤ���
22  * �ե�����̾��������ե�����ꥹ�ȥե����뤬���ꤵ�줿��硤
23  * ���Υե����뤫�����ϥե�����̾���缡�ɤ߹��ޤ�ޤ���
24  *
25  * libsndfile ��configure ���˼�ư���Ф���ޤ������Ф˼��Ԥ�����硤
26  * �ե��������Ϥˤ� adin_file.c ��δؿ������Ѥ���ޤ���
27  *
28  * Libsndfile �ΥС������� 1.0.x ���б����Ƥ��ޤ���
29  *
30  * @sa http://www.mega-nerd.com/libsndfile/
31  * </JA>
32  * <EN>
33  * @brief  Audio input from file using libsndfile library.
34  *
35  * Functions to get input from wave file using libsndfile library.
36  * Many file formats are supported, including Microsoft WAVE format,
37  * and RAW (no header) format, AU, SND, NIST and so on.  The channel number
38  * should be 1 (monaural).
39  * On RAW file input, the data byte order must be in big endian.
40  *
41  * The sampling rate of input file must be equal to the system requirement
42  * value which is specified by adin_standby() . For WAVE format file,
43  * the sampling rate of the input file described in its header is checked
44  * against the system value, and rejected if not matched.  But for RAW format
45  * file, no check will be applied since it has no header information about
46  * the recording sampling rate, so be careful of the sampling rate setting.
47  *
48  * When file input mode, the file name will be read from standard input.
49  * If a filelist file is specified, the file names are read from the file
50  * sequencially instead.
51  *
52  * libsndfile should be installed before compilation.  The library and header
53  * will be automatically detected by configure script.  When failed to detect,
54  * Julius uses adin_file.c instead for file input.
55  *
56  * This file will work on libsndfile version 1.0.x.
57  *
58  * @sa http://www.mega-nerd.com/libsndfile/
59  * </EN>
60  *
61  * @author Akinobu LEE
62  * @date   Mon Feb 14 12:13:27 2005
63  *
64  * $Revision: 1.3 $
65  *
66  */
67 /*
68  * Copyright (c) 1991-2007 Kawahara Lab., Kyoto University
69  * Copyright (c) 2000-2005 Shikano Lab., Nara Institute of Science and Technology
70  * Copyright (c) 2005-2007 Julius project team, Nagoya Institute of Technology
71  * All rights reserved
72  */
73 
74 #include <sent/stddefs.h>
75 #include <sent/speech.h>
76 #include <sent/adin.h>
77 
78 #ifdef HAVE_LIBSNDFILE
79 
80 /* sound header */
81 #include <sndfile.h>
82 
83 static int sfreq;		///< Required sampling frequency in Hz
84 static SF_INFO sinfo;		///< Wavefile information
85 static SNDFILE *sp;		///< File handler
86 static boolean from_file;	///< TRUE if reading filename from listfile
87 static FILE *fp_list;		///< File pointer used for the listfile
88 static char speechfilename[MAXPATHLEN];	///< Buffer to hold input file name
89 
90 /// Check if the file format is 16bit, monoral.
91 static boolean
check_format(SF_INFO * s)92 check_format(SF_INFO *s)
93 {
94   if ((s->format & SF_FORMAT_TYPEMASK) != SF_FORMAT_RAW) {
95     if (s->samplerate != sfreq) {
96       jlog("Error: adin_sndfile: sample rate != %d, it's %d Hz data\n", sfreq, s->samplerate);
97       return FALSE;
98     }
99   }
100   if (s->channels != 1) {
101     jlog("Error: adin_sndfile: channel num != 1, it has %d channels\n", s->channels);
102     return FALSE;
103   }
104 #ifdef HAVE_LIBSNDFILE_VER1
105   if ((s->format & SF_FORMAT_SUBMASK) != SF_FORMAT_PCM_16) {
106     jlog("Error: adin_sndfile: not 16-bit data\n");
107     return FALSE;
108   }
109 #else
110   if (s->pcmbitwidth != 16) {
111     jlog("Error: adin_sndfile: not 16-bit data, it's %d bit\n", s->pcmbitwidth);
112     return FALSE;
113   }
114 #endif
115   return TRUE;
116 }
117 
118 /// Output format information to stdout (compliant to libsnd-0.0.23)
119 static void
print_format(SF_INFO * s)120 print_format(SF_INFO *s)
121 {
122   switch(s->format & SF_FORMAT_TYPEMASK) {
123   case SF_FORMAT_WAV:    jlog("Stat: adin_sndfile: input format = Microsoft WAV\n"); break;
124   case SF_FORMAT_AIFF:   jlog("Stat: adin_sndfile: input format = Apple/SGI AIFF\n"); break;
125   case SF_FORMAT_AU:     jlog("Stat: adin_sndfile: input format = Sun/NeXT AU\n"); break;
126 #ifndef HAVE_LIBSNDFILE_VER1
127   case SF_FORMAT_AULE:   jlog("Stat: adin_sndfile: input format = DEC AU\n"); break;
128 #endif
129   case SF_FORMAT_RAW:    jlog("Stat: adin_sndfile: input format = RAW\n"); break;
130   case SF_FORMAT_PAF:    jlog("Stat: adin_sndfile: input format = Ensoniq PARIS\n"); break;
131   case SF_FORMAT_SVX:    jlog("Stat: adin_sndfile: input format = Amiga IFF / SVX8 / SV16\n"); break;
132   case SF_FORMAT_NIST:   jlog("Stat: adin_sndfile: input format = Sphere NIST\n"); break;
133 #ifdef HAVE_LIBSNDFILE_VER1
134   case SF_FORMAT_VOC:	 jlog("Stat: adin_sndfile: input format = VOC file\n"); break;
135   case SF_FORMAT_IRCAM:  jlog("Stat: adin_sndfile: input format = Berkeley/IRCAM/CARL\n"); break;
136   case SF_FORMAT_W64:	 jlog("Stat: adin_sndfile: input format = Sonic Foundry's 64bit RIFF/WAV\n"); break;
137   case SF_FORMAT_MAT4:   jlog("Stat: adin_sndfile: input format = Matlab (tm) V4.2 / GNU Octave 2.0\n"); break;
138   case SF_FORMAT_MAT5:   jlog("Stat: adin_sndfile: input format = Matlab (tm) V5.0 / GNU Octave 2.1\n"); break;
139 #endif
140   default: jlog("Stat: adin_sndfile: input format = UNKNOWN TYPE\n"); break;
141   }
142   switch(s->format & SF_FORMAT_SUBMASK) {
143 #ifdef HAVE_LIBSNDFILE_VER1
144   case SF_FORMAT_PCM_U8:    jlog("Stat: adin_sndfile: input type = Unsigned 8 bit PCM\n"); break;
145   case SF_FORMAT_PCM_S8:    jlog("Stat: adin_sndfile: input type = Signed 8 bit PCM\n"); break;
146   case SF_FORMAT_PCM_16:    jlog("Stat: adin_sndfile: input type = Signed 16 bit PCM\n"); break;
147   case SF_FORMAT_PCM_24:    jlog("Stat: adin_sndfile: input type = Signed 24 bit PCM\n"); break;
148   case SF_FORMAT_PCM_32:    jlog("Stat: adin_sndfile: input type = Signed 32 bit PCM\n"); break;
149   case SF_FORMAT_FLOAT:     jlog("Stat: adin_sndfile: input type = 32bit float\n"); break;
150   case SF_FORMAT_DOUBLE:    jlog("Stat: adin_sndfile: input type = 64bit float\n"); break;
151   case SF_FORMAT_ULAW:      jlog("Stat: adin_sndfile: input type = U-Law\n"); break;
152   case SF_FORMAT_ALAW:      jlog("Stat: adin_sndfile: input type = A-Law\n"); break;
153   case SF_FORMAT_IMA_ADPCM: jlog("Stat: adin_sndfile: input type = IMA ADPCM\n"); break;
154   case SF_FORMAT_MS_ADPCM:  jlog("Stat: adin_sndfile: input type = Microsoft ADPCM\n"); break;
155   case SF_FORMAT_GSM610:    jlog("Stat: adin_sndfile: input type = GSM 6.10, \n"); break;
156   case SF_FORMAT_G721_32:   jlog("Stat: adin_sndfile: input type = 32kbs G721 ADPCM\n"); break;
157   case SF_FORMAT_G723_24:   jlog("Stat: adin_sndfile: input type = 24kbs G723 ADPCM\n"); break;
158   case SF_FORMAT_G723_40:   jlog("Stat: adin_sndfile: input type = 40kbs G723 ADPCM\n"); break;
159 #else
160   case SF_FORMAT_PCM:       jlog("Stat: adin_sndfile: input type = PCM\n"); break;
161   case SF_FORMAT_FLOAT:     jlog("Stat: adin_sndfile: input type = floats\n"); break;
162   case SF_FORMAT_ULAW:      jlog("Stat: adin_sndfile: input type = U-Law\n"); break;
163   case SF_FORMAT_ALAW:      jlog("Stat: adin_sndfile: input type = A-Law\n"); break;
164   case SF_FORMAT_IMA_ADPCM: jlog("Stat: adin_sndfile: input type = IMA ADPCM\n"); break;
165   case SF_FORMAT_MS_ADPCM:  jlog("Stat: adin_sndfile: input type = Microsoft ADPCM\n"); break;
166   case SF_FORMAT_PCM_BE:    jlog("Stat: adin_sndfile: input type = Big endian PCM\n"); break;
167   case SF_FORMAT_PCM_LE:    jlog("Stat: adin_sndfile: input type = Little endian PCM\n"); break;
168   case SF_FORMAT_PCM_S8:    jlog("Stat: adin_sndfile: input type = Signed 8 bit PCM\n"); break;
169   case SF_FORMAT_PCM_U8:    jlog("Stat: adin_sndfile: input type = Unsigned 8 bit PCM\n"); break;
170   case SF_FORMAT_SVX_FIB:   jlog("Stat: adin_sndfile: input type = SVX Fibonacci Delta\n"); break;
171   case SF_FORMAT_SVX_EXP:   jlog("Stat: adin_sndfile: input type = SVX Exponential Delta\n"); break;
172   case SF_FORMAT_GSM610:    jlog("Stat: adin_sndfile: input type = GSM 6.10, \n"); break;
173   case SF_FORMAT_G721_32:   jlog("Stat: adin_sndfile: input type = 32kbs G721 ADPCM\n"); break;
174   case SF_FORMAT_G723_24:   jlog("Stat: adin_sndfile: input type = 24kbs G723 ADPCM\n"); break;
175 #endif
176   default: jlog("Stat: adin_sndfile: input type = UNKNOWN SUBTYPE\n"); break;
177   }
178 
179 #ifdef HAVE_LIBSNDFILE_VER1
180   switch(s->format & SF_FORMAT_ENDMASK) {
181   case SF_ENDIAN_FILE:      jlog("Stat: adin_sndfile: endian = file native endian\n"); break;
182   case SF_ENDIAN_LITTLE:    jlog("Stat: adin_sndfile: endian = forced little endian\n"); break;
183   case SF_ENDIAN_BIG:       jlog("Stat: adin_sndfile: endian = forced big endian\n"); break;
184   case SF_ENDIAN_CPU:       jlog("Stat: adin_sndfile: endian = forced CPU native endian\n"); break;
185   }
186   jlog("Stat: adin_sndfile: %d Hz, %d channels\n", s->samplerate, s->channels);
187 #else
188   jlog("Stat: adin_sndfile: %d bit, %d Hz, %d channels\n", s->pcmbitwidth, s->samplerate, s->channels);
189 #endif
190 }
191 
192 /**
193  * Initialization: if listfile is specified, open it here. Else, just store
194  * the required frequency.
195  *
196  * @param freq [in] required sampling frequency
197  * @param arg [in] file name of listfile, or NULL if not use
198  *
199  * @return TRUE on success, FALSE on failure.
200  */
201 boolean
adin_sndfile_standby(int freq,void * arg)202 adin_sndfile_standby(int freq, void *arg)
203 {
204   char *fname = arg;
205   if (fname != NULL) {
206     /* read input filename from file */
207     if ((fp_list = fopen(fname, "r")) == NULL) {
208       jlog("Error: adin_sndfile: failed to open %s\n", fname);
209       return(FALSE);
210     }
211     from_file = TRUE;
212   } else {
213     /* read filename from stdin */
214     from_file = FALSE;
215   }
216   /* store sampling frequency */
217   sfreq = freq;
218 
219   return(TRUE);
220 }
221 
222 /**
223  * @brief  Begin reading audio data from a file.
224  *
225  * If listfile was specified in adin_sndfile_standby(), the next filename
226  * will be read from the listfile.  Otherwise, the
227  * filename will be obtained from stdin.  Then the file will be opened here.
228  *
229  * @return TRUE on success, FALSE on failure.
230  */
231 boolean
adin_sndfile_begin()232 adin_sndfile_begin()
233 {
234   boolean readp;
235 
236   /* ready to read next input */
237   readp = FALSE;
238   while(readp == FALSE) {
239     if (from_file) {
240       /* read file name from listfile */
241       do {
242 	if (getl_fp(speechfilename, MAXPATHLEN, fp_list) == NULL) { /* end of input */
243 	  fclose(fp_list);
244 	  return(FALSE); /* end of input */
245 	}
246       } while (speechfilename[0] == '#'); /* skip comment */
247     } else {
248       /* read file name from stdin */
249       if (get_line_from_stdin(speechfilename, MAXPATHLEN, "enter filename->") == NULL) {
250 	return (FALSE);	/* end of input */
251       }
252     }
253     /* open input file */
254 #ifndef HAVE_LIBSNDFILE_VER1
255     sinfo.samplerate = sfreq;
256     sinfo.pcmbitwidth = 16;
257     sinfo.channels = 1;
258 #endif
259     sinfo.format = 0x0;
260     if ((sp =
261 #ifdef HAVE_LIBSNDFILE_VER1
262 	 sf_open(speechfilename, SFM_READ, &sinfo)
263 #else
264 	 sf_open_read(speechfilename, &sinfo)
265 #endif
266 	 ) == NULL) {
267       /* retry assuming raw format */
268       sinfo.samplerate = sfreq;
269       sinfo.channels = 1;
270 #ifdef HAVE_LIBSNDFILE_VER1
271       sinfo.format = SF_FORMAT_RAW | SF_FORMAT_PCM_16 | SF_ENDIAN_BIG;
272 #else
273       sinfo.pcmbitwidth = 16;
274       sinfo.format = SF_FORMAT_RAW | SF_FORMAT_PCM_BE;
275 #endif
276       if ((sp =
277 #ifdef HAVE_LIBSNDFILE_VER1
278 	   sf_open(speechfilename, SFM_READ, &sinfo)
279 #else
280 	   sf_open_read(speechfilename, &sinfo)
281 #endif
282 	   ) == NULL) {
283 	sf_perror(sp);
284 	jlog("Error: adin_sndfile: failed to open speech data: \"%s\"\n",speechfilename);
285       }
286     }
287     if (sp != NULL) {		/* open success */
288       if (! check_format(&sinfo)) {
289 	jlog("Error: adin_sndfile: invalid format: \"%s\"\n",speechfilename);
290 	print_format(&sinfo);
291       } else {
292 	jlog("Stat: adin_sndfile: input speechfile: %s\n",speechfilename);
293 	print_format(&sinfo);
294 	readp = TRUE;
295       }
296     }
297   }
298   return TRUE;
299 }
300 
301 /**
302  * Try to read @a sampnum samples and returns actual sample num recorded.
303  *
304  * @param buf [out] samples obtained in this function
305  * @param sampnum [in] wanted number of samples to be read
306  *
307  * @return actural number of read samples, -1 if EOF, -2 if error.
308  */
309 int
adin_sndfile_read(SP16 * buf,int sampnum)310 adin_sndfile_read(SP16 *buf, int sampnum)
311 {
312   int cnt;
313 
314   cnt = sf_read_short(sp, buf, sampnum);
315   if (cnt == 0) {		/* EOF */
316     return -1;
317   } else if (cnt < 0) {		/* error */
318     sf_perror(sp);
319     sf_close(sp);
320     return -2;		/* error */
321   }
322   return cnt;
323 }
324 
325 /**
326  * End recording.
327  *
328  * @return TRUE on success, FALSE on failure.
329  */
330 boolean
adin_sndfile_end()331 adin_sndfile_end()
332 {
333   /* close files */
334   if (sf_close(sp) != 0) {
335     sf_perror(sp);
336     jlog("Error: adin_sndfile: failed to close\n");
337     return FALSE;
338   }
339   return TRUE;
340 }
341 
342 /**
343  *
344  * A tiny function to get current input raw speech file name.
345  *
346  * @return string of current input speech file.
347  *
348  */
349 char *
adin_sndfile_get_current_filename()350 adin_sndfile_get_current_filename()
351 {
352   return(speechfilename);
353 }
354 
355 #endif /* ~HAVE_LIBSNDFILE */
356