• Main Page
  • Related Pages
  • Data Structures
  • Files
  • File List
  • Globals

src/libsphinxad/rec_win32.c

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 "prim_type.h"
00065 #include "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 #ifdef _WIN32_WCE
00074 static void
00075 wavein_error(char *src, int32 ret)
00076 {
00077     TCHAR errbuf[512];
00078 
00079     waveInGetErrorText(ret, errbuf, sizeof(errbuf));
00080         OutputDebugString(errbuf);
00081 }
00082 
00083 #else
00084 static void
00085 wavein_error(char *src, int32 ret)
00086 {
00087     char errbuf[1024];
00088 
00089     waveInGetErrorText(ret, errbuf, sizeof(errbuf));
00090     fprintf(stderr, "%s error %d: %s\n", src, ret, errbuf);
00091 }
00092 #endif
00093 
00094 
00095 static void
00096 wavein_free_buf(ad_wbuf_t * b)
00097 {
00098     GlobalUnlock(b->h_whdr);
00099     GlobalFree(b->h_whdr);
00100     GlobalUnlock(b->h_buf);
00101     GlobalFree(b->h_buf);
00102 }
00103 
00104 
00105 static int32
00106 wavein_alloc_buf(ad_wbuf_t * b, int32 samples_per_buf)
00107 {
00108     HGLOBAL h_buf;              /* handle to data buffer */
00109     LPSTR p_buf;                /* pointer to data buffer */
00110     HGLOBAL h_whdr;             /* handle to header */
00111     LPWAVEHDR p_whdr;           /* pointer to header */
00112 
00113     /* Allocate data buffer */
00114     h_buf =
00115         GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE,
00116                     samples_per_buf * sizeof(int16));
00117     if (!h_buf) {
00118         fprintf(stderr, "GlobalAlloc failed\n");
00119         return -1;
00120     }
00121     if ((p_buf = GlobalLock(h_buf)) == NULL) {
00122         GlobalFree(h_buf);
00123         fprintf(stderr, "GlobalLock failed\n");
00124         return -1;
00125     }
00126 
00127     /* Allocate WAVEHDR structure */
00128     h_whdr = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, sizeof(WAVEHDR));
00129     if (h_whdr == NULL) {
00130         GlobalUnlock(h_buf);
00131         GlobalFree(h_buf);
00132 
00133         fprintf(stderr, "GlobalAlloc failed\n");
00134         return -1;
00135     }
00136     if ((p_whdr = GlobalLock(h_whdr)) == NULL) {
00137         GlobalUnlock(h_buf);
00138         GlobalFree(h_buf);
00139         GlobalFree(h_whdr);
00140 
00141         fprintf(stderr, "GlobalLock failed\n");
00142         return -1;
00143     }
00144 
00145     b->h_buf = h_buf;
00146     b->p_buf = p_buf;
00147     b->h_whdr = h_whdr;
00148     b->p_whdr = p_whdr;
00149 
00150     p_whdr->lpData = p_buf;
00151     p_whdr->dwBufferLength = samples_per_buf * sizeof(int16);
00152     p_whdr->dwUser = 0L;
00153     p_whdr->dwFlags = 0L;
00154     p_whdr->dwLoops = 0L;
00155 
00156     return 0;
00157 }
00158 
00159 
00160 static int32
00161 wavein_enqueue_buf(HWAVEIN h, LPWAVEHDR whdr)
00162 {
00163     int32 st;
00164 
00165     if ((st = waveInPrepareHeader(h, whdr, sizeof(WAVEHDR))) != 0) {
00166         wavein_error("waveInPrepareHeader", st);
00167         return -1;
00168     }
00169     if ((st = waveInAddBuffer(h, whdr, sizeof(WAVEHDR))) != 0) {
00170         wavein_error("waveInAddBuffer", st);
00171         return -1;
00172     }
00173 
00174     return 0;
00175 }
00176 
00177 
00178 static HWAVEIN
00179 wavein_open(int32 samples_per_sec, int32 bytes_per_sample)
00180 {
00181     WAVEFORMATEX wfmt;
00182     int32 st;
00183     HWAVEIN h;
00184 
00185     if (bytes_per_sample != sizeof(int16)) {
00186         fprintf(stderr, "bytes/sample != %d\n", sizeof(int16));
00187         return NULL;
00188     }
00189 
00190     wfmt.wFormatTag = WAVE_FORMAT_PCM;
00191     wfmt.nChannels = 1;
00192     wfmt.nSamplesPerSec = samples_per_sec;
00193     wfmt.nAvgBytesPerSec = samples_per_sec * bytes_per_sample;
00194     wfmt.nBlockAlign = bytes_per_sample;
00195     wfmt.wBitsPerSample = 8 * bytes_per_sample;
00196 
00197     /* There should be a check here for a device of the desired type; later... */
00198 
00199     st = waveInOpen((LPHWAVEIN) & h, WAVE_MAPPER,
00200                     (LPWAVEFORMATEX) & wfmt, (DWORD) 0L, 0L,
00201                     (DWORD) CALLBACK_NULL);
00202     if (st != 0) {
00203         wavein_error("waveInOpen", st);
00204         return NULL;
00205     }
00206 
00207     return h;
00208 }
00209 
00210 
00211 static int32
00212 wavein_close(ad_rec_t * r)
00213 {
00214     int32 i, st;
00215 
00216     /* Unprepare all buffers; multiple unprepares of the same buffer are benign */
00217     for (i = 0; i < r->n_buf; i++) {
00218         /* Unpreparing an unprepared buffer, on the other hand, fails
00219            on Win98/WinME, though this is not documented - dhuggins@cs,
00220            2004-07-14 */
00221         if (!(r->wi_buf[i].p_whdr->dwFlags & WHDR_PREPARED))
00222             continue;
00223         st = waveInUnprepareHeader(r->h_wavein,
00224                                    r->wi_buf[i].p_whdr, sizeof(WAVEHDR));
00225         if (st != 0) {
00226             wavein_error("waveInUnprepareHeader", st);
00227             return -1;
00228         }
00229     }
00230 
00231     /* Free buffers */
00232     for (i = 0; i < r->n_buf; i++)
00233         wavein_free_buf(&(r->wi_buf[i]));
00234     free(r->wi_buf);
00235 
00236     if ((st = waveInClose(r->h_wavein)) != 0) {
00237         wavein_error("waveInClose", st);
00238         return -1;
00239     }
00240 
00241     free(r);
00242 
00243     return 0;
00244 }
00245 
00246 
00247 ad_rec_t *
00248 ad_open_sps_bufsize(int32 sps, int32 bufsize_msec)
00249 {
00250     ad_rec_t *r;
00251     int32 i, j;
00252     HWAVEIN h;
00253 
00254     if ((h = wavein_open(sps, sizeof(int16))) == NULL)
00255         return NULL;
00256 
00257     if ((r = (ad_rec_t *) malloc(sizeof(ad_rec_t))) == NULL) {
00258         fprintf(stderr, "malloc(%d) failed\n", sizeof(ad_rec_t));
00259         waveInClose(h);
00260         return NULL;
00261     }
00262 
00263     r->n_buf = ((sps * bufsize_msec) / 1000) / WI_BUFSIZE;
00264     if (r->n_buf < DEFAULT_N_WI_BUF)
00265         r->n_buf = DEFAULT_N_WI_BUF;
00266     printf("Allocating %d buffers of %d samples each\n", r->n_buf,
00267            WI_BUFSIZE);
00268 
00269     if ((r->wi_buf =
00270          (ad_wbuf_t *) calloc(r->n_buf, sizeof(ad_wbuf_t))) == NULL) {
00271         fprintf(stderr, "calloc(%d,%d) failed\n", r->n_buf,
00272                 sizeof(ad_wbuf_t));
00273         free(r);
00274         waveInClose(h);
00275 
00276         return NULL;
00277     }
00278     for (i = 0; i < r->n_buf; i++) {
00279         if (wavein_alloc_buf(&(r->wi_buf[i]), WI_BUFSIZE) < 0) {
00280             for (j = 0; j < i; j++)
00281                 wavein_free_buf(&(r->wi_buf[j]));
00282             free(r->wi_buf);
00283             free(r);
00284             waveInClose(h);
00285 
00286             return NULL;
00287         }
00288     }
00289 
00290     r->h_wavein = h;
00291     r->opened = 1;
00292     r->recording = 0;
00293     r->curbuf = r->n_buf - 1;   /* current buffer with data for application */
00294     r->curlen = 0;              /* #samples in curbuf remaining to be consumed */
00295     r->lastbuf = r->curbuf;
00296     r->sps = sps;
00297     r->bps = sizeof(int16);     /* HACK!! Hardwired value for bytes/sec */
00298 
00299     return r;
00300 }
00301 
00302 /* FIXME: Dummy function, doesn't actually use dev. */
00303 ad_rec_t *
00304 ad_open_dev(const char *dev, int32 sps)
00305 {
00306     return (ad_open_sps_bufsize
00307             (sps, WI_BUFSIZE * DEFAULT_N_WI_BUF * 1000 / sps));
00308 }
00309 
00310 
00311 ad_rec_t *
00312 ad_open_sps(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(void)
00321 {
00322     return (ad_open_sps(DEFAULT_SAMPLES_PER_SEC));      /* HACK!! Rename this constant */
00323 }
00324 
00325 
00326 int32
00327 ad_close(ad_rec_t * r)
00328 {
00329     if (!r->opened)
00330         return AD_ERR_NOT_OPEN;
00331 
00332     if (r->recording)
00333         if (ad_stop_rec(r) < 0)
00334             return AD_ERR_WAVE;
00335 
00336     if (wavein_close(r) < 0)
00337         return AD_ERR_WAVE;
00338 
00339     return 0;
00340 }
00341 
00342 
00343 int32
00344 ad_start_rec(ad_rec_t * r)
00345 {
00346     int32 i;
00347 
00348     if ((!r->opened) || r->recording)
00349         return -1;
00350 
00351     for (i = 0; i < r->n_buf; i++)
00352         if (wavein_enqueue_buf(r->h_wavein, r->wi_buf[i].p_whdr) < 0)
00353             return AD_ERR_WAVE;
00354     r->curbuf = r->n_buf - 1;   /* current buffer with data for application */
00355     r->curlen = 0;              /* #samples in curbuf remaining to be consumed */
00356 
00357     if (waveInStart(r->h_wavein) != 0)
00358         return AD_ERR_WAVE;
00359 
00360     r->recording = 1;
00361 
00362     return 0;
00363 }
00364 
00365 
00366 int32
00367 ad_stop_rec(ad_rec_t * r)
00368 {
00369     int32 i, st;
00370 
00371     if ((!r->opened) || (!r->recording))
00372         return -1;
00373 
00374     if (waveInStop(r->h_wavein) != 0)
00375         return AD_ERR_WAVE;
00376 
00377     if ((st = waveInReset(r->h_wavein)) != 0) {
00378         wavein_error("waveInReset", st);
00379         return AD_ERR_WAVE;
00380     }
00381 
00382     /* Wait until all buffers marked done */
00383     for (i = 0; i < r->n_buf; i++)
00384         while (!(r->wi_buf[i].p_whdr->dwFlags & WHDR_DONE));
00385 
00386     if ((r->lastbuf = r->curbuf - 1) < 0)
00387         r->lastbuf = r->n_buf - 1;
00388 
00389     r->recording = 0;
00390 
00391     return 0;
00392 }
00393 
00394 
00395 int32
00396 ad_read(ad_rec_t * r, int16 * buf, int32 max)
00397 {
00398     int32 t, st, len;
00399     LPWAVEHDR whdr;
00400     int16 *sysbufp;
00401 
00402     if (!r->opened)
00403         return AD_ERR_NOT_OPEN;
00404 
00405     /* Check if all recorded data exhausted */
00406     if ((!r->recording) && (r->curbuf == r->lastbuf)
00407         && (r->curlen == 0))
00408         return AD_EOF;
00409 
00410     len = 0;
00411     while (max > 0) {
00412         /* Look for next buffer with recording data */
00413         if (r->curlen == 0) {
00414             /* No current buffer with data; get next buffer in sequence if available */
00415             t = r->curbuf + 1;
00416             if (t >= r->n_buf)
00417                 t = 0;
00418 
00419             if (!(r->wi_buf[t].p_whdr->dwFlags & WHDR_DONE))
00420                 return len;
00421 
00422             r->curbuf = t;
00423             r->curlen = r->wi_buf[t].p_whdr->dwBytesRecorded >> 1;
00424             r->curoff = 0;
00425         }
00426 
00427         /* Copy data from curbuf to buf */
00428         whdr = r->wi_buf[r->curbuf].p_whdr;
00429         t = (max < r->curlen) ? max : r->curlen;        /* #Samples to copy */
00430 
00431         if (t > 0) {
00432             sysbufp = (int16 *) (whdr->lpData);
00433             memcpy(buf, sysbufp + r->curoff, t * sizeof(int16));
00434 
00435             buf += t;
00436             max -= t;
00437             r->curoff += t;
00438             r->curlen -= t;
00439             len += t;
00440         }
00441 
00442         /* If curbuf empty recycle it to system if still recording */
00443         if (r->curlen == 0) {
00444             if (r->recording) {
00445                 /* Return empty buffer to system */
00446                 st = waveInUnprepareHeader(r->h_wavein,
00447                                            whdr, sizeof(WAVEHDR));
00448                 if (st != 0) {
00449                     wavein_error("waveInUnprepareHeader", st);
00450                     return AD_ERR_WAVE;
00451                 }
00452 
00453                 if (wavein_enqueue_buf(r->h_wavein, whdr) < 0)
00454                     return AD_ERR_WAVE;
00455 
00456             }
00457             else if (r->curbuf == r->lastbuf) {
00458                 return len;
00459             }
00460         }
00461     }
00462 
00463     return len;
00464 }

Generated on Fri Jan 14 2011 for SphinxBase by  doxygen 1.7.1