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