SphinxBase 0.6
|
00001 /* -*- c-basic-offset: 4; indent-tabs-mode: nil -*- */ 00002 /* ==================================================================== 00003 * Copyright (c) 1999-2001 Carnegie Mellon University. All rights 00004 * reserved. 00005 * 00006 * Redistribution and use in source and binary forms, with or without 00007 * modification, are permitted provided that the following conditions 00008 * are met: 00009 * 00010 * 1. Redistributions of source code must retain the above copyright 00011 * notice, this list of conditions and the following disclaimer. 00012 * 00013 * 2. Redistributions in binary form must reproduce the above copyright 00014 * notice, this list of conditions and the following disclaimer in 00015 * the documentation and/or other materials provided with the 00016 * distribution. 00017 * 00018 * This work was supported in part by funding from the Defense Advanced 00019 * Research Projects Agency and the National Science Foundation of the 00020 * United States of America, and the CMU Sphinx Speech Consortium. 00021 * 00022 * THIS SOFTWARE IS PROVIDED BY CARNEGIE MELLON UNIVERSITY ``AS IS'' AND 00023 * ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 00024 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 00025 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY 00026 * NOR ITS EMPLOYEES BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 00027 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 00028 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 00029 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 00030 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 00031 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 00032 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00033 * 00034 * ==================================================================== 00035 * 00036 */ 00037 00038 /* 00039 * rec.c -- low level audio recording for Windows NT/95. 00040 * 00041 * HISTORY 00042 * 00043 * 19-Jan-1999 M K Ravishankar (rkm@cs.cmu.edu) at Carnegie Mellon University 00044 * Added AD_ return codes. Added ad_open_sps_bufsize(), and 00045 * ad_rec_t.n_buf. 00046 * 00047 * 07-Mar-98 M K Ravishankar (rkm@cs.cmu.edu) at Carnegie Mellon University 00048 * Added ad_open_sps(), and made ad_open() call it. 00049 * 00050 * 10-Jun-96 M K Ravishankar (rkm@cs.cmu.edu) at Carnegie Mellon University 00051 * Added ad_rec_t type to all calls. 00052 * 00053 * 03-Jun-96 M K Ravishankar (rkm@cs.cmu.edu) at Carnegie Mellon University 00054 * Created. 00055 */ 00056 00057 00058 #include <windows.h> 00059 #include <mmsystem.h> 00060 #include <stdio.h> 00061 #include <stdlib.h> 00062 #include <string.h> 00063 00064 #include "sphinxbase/prim_type.h" 00065 #include "sphinxbase/ad.h" 00066 00067 00068 #define DEFAULT_N_WI_BUF 32 /* #Recording bufs */ 00069 #define WI_BUFSIZE 2500 /* Samples/buf (Why this specific value?? 00070 So that at reasonable sampling rates 00071 data is returned frequently enough.) */ 00072 00073 /* Silvio Moioli: using OutputDebugStringW instead of OutputDebugString */ 00074 #ifdef _WIN32_WCE 00075 #include "ckd_alloc.h" 00076 static void 00077 wavein_error(char *src, int32 ret) 00078 { 00079 TCHAR errbuf[512]; 00080 wchar_t* werrbuf; 00081 size_t len; 00082 00083 waveOutGetErrorText(ret, errbuf, sizeof(errbuf)); 00084 len = mbstowcs(NULL, errbuf, 0) + 1; 00085 werrbuf = ckd_calloc(len, sizeof(*werrbuf)); 00086 mbstowcs(werrbuf, errbuf, len); 00087 00088 OutputDebugStringW(werrbuf); 00089 } 00090 00091 #else 00092 static void 00093 wavein_error(char *src, int32 ret) 00094 { 00095 char errbuf[1024]; 00096 00097 waveInGetErrorText(ret, errbuf, sizeof(errbuf)); 00098 fprintf(stderr, "%s error %d: %s\n", src, ret, errbuf); 00099 } 00100 #endif 00101 00102 00103 static void 00104 wavein_free_buf(ad_wbuf_t * b) 00105 { 00106 GlobalUnlock(b->h_whdr); 00107 GlobalFree(b->h_whdr); 00108 GlobalUnlock(b->h_buf); 00109 GlobalFree(b->h_buf); 00110 } 00111 00112 00113 static int32 00114 wavein_alloc_buf(ad_wbuf_t * b, int32 samples_per_buf) 00115 { 00116 HGLOBAL h_buf; /* handle to data buffer */ 00117 LPSTR p_buf; /* pointer to data buffer */ 00118 HGLOBAL h_whdr; /* handle to header */ 00119 LPWAVEHDR p_whdr; /* pointer to header */ 00120 00121 /* Allocate data buffer */ 00122 h_buf = 00123 GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, 00124 samples_per_buf * sizeof(int16)); 00125 if (!h_buf) { 00126 fprintf(stderr, "GlobalAlloc failed\n"); 00127 return -1; 00128 } 00129 if ((p_buf = GlobalLock(h_buf)) == NULL) { 00130 GlobalFree(h_buf); 00131 fprintf(stderr, "GlobalLock failed\n"); 00132 return -1; 00133 } 00134 00135 /* Allocate WAVEHDR structure */ 00136 h_whdr = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, sizeof(WAVEHDR)); 00137 if (h_whdr == NULL) { 00138 GlobalUnlock(h_buf); 00139 GlobalFree(h_buf); 00140 00141 fprintf(stderr, "GlobalAlloc failed\n"); 00142 return -1; 00143 } 00144 if ((p_whdr = GlobalLock(h_whdr)) == NULL) { 00145 GlobalUnlock(h_buf); 00146 GlobalFree(h_buf); 00147 GlobalFree(h_whdr); 00148 00149 fprintf(stderr, "GlobalLock failed\n"); 00150 return -1; 00151 } 00152 00153 b->h_buf = h_buf; 00154 b->p_buf = p_buf; 00155 b->h_whdr = h_whdr; 00156 b->p_whdr = p_whdr; 00157 00158 p_whdr->lpData = p_buf; 00159 p_whdr->dwBufferLength = samples_per_buf * sizeof(int16); 00160 p_whdr->dwUser = 0L; 00161 p_whdr->dwFlags = 0L; 00162 p_whdr->dwLoops = 0L; 00163 00164 return 0; 00165 } 00166 00167 00168 static int32 00169 wavein_enqueue_buf(HWAVEIN h, LPWAVEHDR whdr) 00170 { 00171 int32 st; 00172 00173 if ((st = waveInPrepareHeader(h, whdr, sizeof(WAVEHDR))) != 0) { 00174 wavein_error("waveInPrepareHeader", st); 00175 return -1; 00176 } 00177 if ((st = waveInAddBuffer(h, whdr, sizeof(WAVEHDR))) != 0) { 00178 wavein_error("waveInAddBuffer", st); 00179 return -1; 00180 } 00181 00182 return 0; 00183 } 00184 00185 00186 static HWAVEIN 00187 wavein_open(int32 samples_per_sec, int32 bytes_per_sample) 00188 { 00189 WAVEFORMATEX wfmt; 00190 int32 st; 00191 HWAVEIN h; 00192 00193 if (bytes_per_sample != sizeof(int16)) { 00194 fprintf(stderr, "bytes/sample != %d\n", sizeof(int16)); 00195 return NULL; 00196 } 00197 00198 wfmt.wFormatTag = WAVE_FORMAT_PCM; 00199 wfmt.nChannels = 1; 00200 wfmt.nSamplesPerSec = samples_per_sec; 00201 wfmt.nAvgBytesPerSec = samples_per_sec * bytes_per_sample; 00202 wfmt.nBlockAlign = bytes_per_sample; 00203 wfmt.wBitsPerSample = 8 * bytes_per_sample; 00204 00205 /* There should be a check here for a device of the desired type; later... */ 00206 00207 st = waveInOpen((LPHWAVEIN) & h, WAVE_MAPPER, 00208 (LPWAVEFORMATEX) & wfmt, (DWORD) 0L, 0L, 00209 (DWORD) CALLBACK_NULL); 00210 if (st != 0) { 00211 wavein_error("waveInOpen", st); 00212 return NULL; 00213 } 00214 00215 return h; 00216 } 00217 00218 00219 static int32 00220 wavein_close(ad_rec_t * r) 00221 { 00222 int32 i, st; 00223 00224 /* Unprepare all buffers; multiple unprepares of the same buffer are benign */ 00225 for (i = 0; i < r->n_buf; i++) { 00226 /* Unpreparing an unprepared buffer, on the other hand, fails 00227 on Win98/WinME, though this is not documented - dhuggins@cs, 00228 2004-07-14 */ 00229 if (!(r->wi_buf[i].p_whdr->dwFlags & WHDR_PREPARED)) 00230 continue; 00231 st = waveInUnprepareHeader(r->h_wavein, 00232 r->wi_buf[i].p_whdr, sizeof(WAVEHDR)); 00233 if (st != 0) { 00234 wavein_error("waveInUnprepareHeader", st); 00235 return -1; 00236 } 00237 } 00238 00239 /* Free buffers */ 00240 for (i = 0; i < r->n_buf; i++) 00241 wavein_free_buf(&(r->wi_buf[i])); 00242 free(r->wi_buf); 00243 00244 if ((st = waveInClose(r->h_wavein)) != 0) { 00245 wavein_error("waveInClose", st); 00246 return -1; 00247 } 00248 00249 free(r); 00250 00251 return 0; 00252 } 00253 00254 00255 ad_rec_t * 00256 ad_open_sps_bufsize(int32 sps, int32 bufsize_msec) 00257 { 00258 ad_rec_t *r; 00259 int32 i, j; 00260 HWAVEIN h; 00261 00262 if ((h = wavein_open(sps, sizeof(int16))) == NULL) 00263 return NULL; 00264 00265 if ((r = (ad_rec_t *) malloc(sizeof(ad_rec_t))) == NULL) { 00266 fprintf(stderr, "malloc(%d) failed\n", sizeof(ad_rec_t)); 00267 waveInClose(h); 00268 return NULL; 00269 } 00270 00271 r->n_buf = ((sps * bufsize_msec) / 1000) / WI_BUFSIZE; 00272 if (r->n_buf < DEFAULT_N_WI_BUF) 00273 r->n_buf = DEFAULT_N_WI_BUF; 00274 printf("Allocating %d buffers of %d samples each\n", r->n_buf, 00275 WI_BUFSIZE); 00276 00277 if ((r->wi_buf = 00278 (ad_wbuf_t *) calloc(r->n_buf, sizeof(ad_wbuf_t))) == NULL) { 00279 fprintf(stderr, "calloc(%d,%d) failed\n", r->n_buf, 00280 sizeof(ad_wbuf_t)); 00281 free(r); 00282 waveInClose(h); 00283 00284 return NULL; 00285 } 00286 for (i = 0; i < r->n_buf; i++) { 00287 if (wavein_alloc_buf(&(r->wi_buf[i]), WI_BUFSIZE) < 0) { 00288 for (j = 0; j < i; j++) 00289 wavein_free_buf(&(r->wi_buf[j])); 00290 free(r->wi_buf); 00291 free(r); 00292 waveInClose(h); 00293 00294 return NULL; 00295 } 00296 } 00297 00298 r->h_wavein = h; 00299 r->opened = 1; 00300 r->recording = 0; 00301 r->curbuf = r->n_buf - 1; /* current buffer with data for application */ 00302 r->curlen = 0; /* #samples in curbuf remaining to be consumed */ 00303 r->lastbuf = r->curbuf; 00304 r->sps = sps; 00305 r->bps = sizeof(int16); /* HACK!! Hardwired value for bytes/sec */ 00306 00307 return r; 00308 } 00309 00310 /* FIXME: Dummy function, doesn't actually use dev. */ 00311 ad_rec_t * 00312 ad_open_dev(const char *dev, int32 sps) 00313 { 00314 return (ad_open_sps_bufsize 00315 (sps, WI_BUFSIZE * DEFAULT_N_WI_BUF * 1000 / sps)); 00316 } 00317 00318 00319 ad_rec_t * 00320 ad_open_sps(int32 sps) 00321 { 00322 return (ad_open_sps_bufsize 00323 (sps, WI_BUFSIZE * DEFAULT_N_WI_BUF * 1000 / sps)); 00324 } 00325 00326 00327 ad_rec_t * 00328 ad_open(void) 00329 { 00330 return (ad_open_sps(DEFAULT_SAMPLES_PER_SEC)); /* HACK!! Rename this constant */ 00331 } 00332 00333 00334 int32 00335 ad_close(ad_rec_t * r) 00336 { 00337 if (!r->opened) 00338 return AD_ERR_NOT_OPEN; 00339 00340 if (r->recording) 00341 if (ad_stop_rec(r) < 0) 00342 return AD_ERR_WAVE; 00343 00344 if (wavein_close(r) < 0) 00345 return AD_ERR_WAVE; 00346 00347 return 0; 00348 } 00349 00350 00351 int32 00352 ad_start_rec(ad_rec_t * r) 00353 { 00354 int32 i; 00355 00356 if ((!r->opened) || r->recording) 00357 return -1; 00358 00359 for (i = 0; i < r->n_buf; i++) 00360 if (wavein_enqueue_buf(r->h_wavein, r->wi_buf[i].p_whdr) < 0) 00361 return AD_ERR_WAVE; 00362 r->curbuf = r->n_buf - 1; /* current buffer with data for application */ 00363 r->curlen = 0; /* #samples in curbuf remaining to be consumed */ 00364 00365 if (waveInStart(r->h_wavein) != 0) 00366 return AD_ERR_WAVE; 00367 00368 r->recording = 1; 00369 00370 return 0; 00371 } 00372 00373 00374 int32 00375 ad_stop_rec(ad_rec_t * r) 00376 { 00377 int32 i, st; 00378 00379 if ((!r->opened) || (!r->recording)) 00380 return -1; 00381 00382 if (waveInStop(r->h_wavein) != 0) 00383 return AD_ERR_WAVE; 00384 00385 if ((st = waveInReset(r->h_wavein)) != 0) { 00386 wavein_error("waveInReset", st); 00387 return AD_ERR_WAVE; 00388 } 00389 00390 /* Wait until all buffers marked done */ 00391 for (i = 0; i < r->n_buf; i++) 00392 while (!(r->wi_buf[i].p_whdr->dwFlags & WHDR_DONE)); 00393 00394 if ((r->lastbuf = r->curbuf - 1) < 0) 00395 r->lastbuf = r->n_buf - 1; 00396 00397 r->recording = 0; 00398 00399 return 0; 00400 } 00401 00402 00403 int32 00404 ad_read(ad_rec_t * r, int16 * buf, int32 max) 00405 { 00406 int32 t, st, len; 00407 LPWAVEHDR whdr; 00408 int16 *sysbufp; 00409 00410 if (!r->opened) 00411 return AD_ERR_NOT_OPEN; 00412 00413 /* Check if all recorded data exhausted */ 00414 if ((!r->recording) && (r->curbuf == r->lastbuf) 00415 && (r->curlen == 0)) 00416 return AD_EOF; 00417 00418 len = 0; 00419 while (max > 0) { 00420 /* Look for next buffer with recording data */ 00421 if (r->curlen == 0) { 00422 /* No current buffer with data; get next buffer in sequence if available */ 00423 t = r->curbuf + 1; 00424 if (t >= r->n_buf) 00425 t = 0; 00426 00427 if (!(r->wi_buf[t].p_whdr->dwFlags & WHDR_DONE)) 00428 return len; 00429 00430 r->curbuf = t; 00431 r->curlen = r->wi_buf[t].p_whdr->dwBytesRecorded >> 1; 00432 r->curoff = 0; 00433 } 00434 00435 /* Copy data from curbuf to buf */ 00436 whdr = r->wi_buf[r->curbuf].p_whdr; 00437 t = (max < r->curlen) ? max : r->curlen; /* #Samples to copy */ 00438 00439 if (t > 0) { 00440 sysbufp = (int16 *) (whdr->lpData); 00441 memcpy(buf, sysbufp + r->curoff, t * sizeof(int16)); 00442 00443 buf += t; 00444 max -= t; 00445 r->curoff += t; 00446 r->curlen -= t; 00447 len += t; 00448 } 00449 00450 /* If curbuf empty recycle it to system if still recording */ 00451 if (r->curlen == 0) { 00452 if (r->recording) { 00453 /* Return empty buffer to system */ 00454 st = waveInUnprepareHeader(r->h_wavein, 00455 whdr, sizeof(WAVEHDR)); 00456 if (st != 0) { 00457 wavein_error("waveInUnprepareHeader", st); 00458 return AD_ERR_WAVE; 00459 } 00460 00461 if (wavein_enqueue_buf(r->h_wavein, whdr) < 0) 00462 return AD_ERR_WAVE; 00463 00464 } 00465 else if (r->curbuf == r->lastbuf) { 00466 return len; 00467 } 00468 } 00469 } 00470 00471 return len; 00472 }