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

src/libsphinxad/play_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  * HISTORY
00040  * 
00041  * 17-Apr-98    M K Ravishankar (rkm@cs.cmu.edu) at Carnegie Mellon University
00042  *              Added ad_open_play_sps(), and made ad_open_play() call it.
00043  * 
00044  * 10-Jun-96    M K Ravishankar (rkm@cs.cmu.edu) at Carnegie Mellon University
00045  *              Added ad_play_t type to all calls.
00046  * 
00047  * 03-Jun-96    M K Ravishankar (rkm@cs.cmu.edu) at Carnegie Mellon University
00048  *              Created.
00049  */
00050 
00051 
00052 #include <windows.h>
00053 #include <mmsystem.h>
00054 #include <stdio.h>
00055 #include <stdlib.h>
00056 #include <string.h>
00057 
00058 #include "prim_type.h"
00059 #include "ad.h"
00060 
00061 
00062 #define WO_BUFSIZE      3200    /* Samples/buf */
00063 #define N_WO_BUF        2       /* #Playback bufs */
00064 
00065 #ifdef _WIN32_WCE
00066 waveout_error(char *src, int32 ret)
00067 {
00068     TCHAR errbuf[512];
00069 
00070     waveOutGetErrorText(ret, errbuf, sizeof(errbuf));
00071         OutputDebugString(errbuf);
00072  }
00073 
00074 #else
00075 static void
00076 waveout_error(char *src, int32 ret)
00077 {
00078     char errbuf[1024];
00079 
00080     waveOutGetErrorText(ret, errbuf, sizeof(errbuf));
00081     fprintf(stderr, "%s error %d: %s\n", src, ret, errbuf);
00082 }
00083 #endif
00084 
00085 
00086 static void
00087 waveout_free_buf(ad_wbuf_t * b)
00088 {
00089     GlobalUnlock(b->h_whdr);
00090     GlobalFree(b->h_whdr);
00091     GlobalUnlock(b->h_buf);
00092     GlobalFree(b->h_buf);
00093 }
00094 
00095 
00096 static int32
00097 waveout_alloc_buf(ad_wbuf_t * b, int32 samples_per_buf)
00098 {
00099     HGLOBAL h_buf;
00100     LPSTR p_buf;
00101     HGLOBAL h_whdr;
00102     LPWAVEHDR p_whdr;
00103 
00104     /* Allocate data buffer */
00105     h_buf =
00106         GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE,
00107                     samples_per_buf * sizeof(int16));
00108     if (!h_buf) {
00109         fprintf(stderr, "GlobalAlloc failed\n");
00110         return -1;
00111     }
00112     if ((p_buf = GlobalLock(h_buf)) == NULL) {
00113         GlobalFree(h_buf);
00114         fprintf(stderr, "GlobalLock failed\n");
00115         return -1;
00116     }
00117 
00118     /* Allocate WAVEHDR structure */
00119     h_whdr = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, sizeof(WAVEHDR));
00120     if (h_whdr == NULL) {
00121         GlobalUnlock(h_buf);
00122         GlobalFree(h_buf);
00123 
00124         fprintf(stderr, "GlobalAlloc failed\n");
00125         return -1;
00126     }
00127     if ((p_whdr = GlobalLock(h_whdr)) == NULL) {
00128         GlobalUnlock(h_buf);
00129         GlobalFree(h_buf);
00130         GlobalFree(h_whdr);
00131 
00132         fprintf(stderr, "GlobalLock failed\n");
00133         return -1;
00134     }
00135 
00136     b->h_buf = h_buf;
00137     b->p_buf = p_buf;
00138     b->h_whdr = h_whdr;
00139     b->p_whdr = p_whdr;
00140 
00141     p_whdr->lpData = p_buf;
00142     p_whdr->dwBufferLength = samples_per_buf * sizeof(int16);
00143     p_whdr->dwUser = 0L;
00144     p_whdr->dwFlags = 0L;
00145     p_whdr->dwLoops = 0L;
00146 
00147     return 0;
00148 }
00149 
00150 
00151 static int32
00152 waveout_enqueue_buf(HWAVEOUT h, LPWAVEHDR whdr)
00153 {
00154     int32 st;
00155 
00156     if ((st = waveOutPrepareHeader(h, whdr, sizeof(WAVEHDR))) != 0) {
00157         waveout_error("waveOutPrepareHeader", st);
00158         return -1;
00159     }
00160 
00161     if ((st = waveOutWrite(h, whdr, sizeof(WAVEHDR))) != 0) {
00162         waveout_error("waveOutWrite", st);
00163         return -1;
00164     }
00165 
00166     return 0;
00167 }
00168 
00169 
00170 static HWAVEOUT
00171 waveout_open(int32 samples_per_sec, int32 bytes_per_sample)
00172 {
00173     WAVEFORMATEX wfmt;
00174     int32 st;
00175     HWAVEOUT h;
00176 
00177     if (bytes_per_sample != sizeof(int16)) {
00178         fprintf(stderr, "bytes/sample != %d\n", sizeof(int16));
00179         return NULL;
00180     }
00181 
00182     wfmt.wFormatTag = WAVE_FORMAT_PCM;
00183     wfmt.nChannels = 1;
00184     wfmt.nSamplesPerSec = samples_per_sec;
00185     wfmt.nAvgBytesPerSec = samples_per_sec * bytes_per_sample;
00186     wfmt.nBlockAlign = bytes_per_sample;
00187     wfmt.wBitsPerSample = 8 * bytes_per_sample;
00188     wfmt.cbSize = 0;
00189 
00190     /* There should be a check here for a device of the desired type; later... */
00191 
00192     st = waveOutOpen((LPHWAVEOUT) & h, WAVE_MAPPER,
00193                      (LPWAVEFORMATEX) & wfmt, (DWORD) 0L, 0L,
00194                      (DWORD) CALLBACK_NULL);
00195     if (st != 0) {
00196         waveout_error("waveOutOpen", st);
00197         return NULL;
00198     }
00199 
00200     return h;
00201 }
00202 
00203 
00204 static void
00205 waveout_mem_cleanup(ad_play_t * p, int32 n_buf)
00206 {
00207     int32 i;
00208 
00209     for (i = 0; i < n_buf; i++)
00210         waveout_free_buf(&(p->wo_buf[i]));
00211     if (p->wo_buf)
00212         free(p->wo_buf);
00213     if (p->busy)
00214         free(p->busy);
00215 }
00216 
00217 
00218 static int32
00219 waveout_close(ad_play_t * p)
00220 {
00221     int32 st;
00222 
00223     waveout_mem_cleanup(p, N_WO_BUF);
00224 
00225     if ((st = waveOutClose(p->h_waveout)) != 0) {
00226         waveout_error("waveOutClose", st);
00227         return -1;
00228     }
00229 
00230     free(p);
00231 
00232     return 0;
00233 }
00234 
00235 
00236 ad_play_t *
00237 ad_open_play_sps(int32 sps)
00238 {
00239     ad_play_t *p;
00240     int32 i;
00241     HWAVEOUT h;
00242 
00243     if ((h = waveout_open(sps, sizeof(int16))) == NULL)
00244         return NULL;
00245 
00246     if ((p = (ad_play_t *) calloc(1, sizeof(ad_play_t))) == NULL) {
00247         fprintf(stderr, "calloc(1,%d) failed\n", sizeof(ad_play_t));
00248         waveOutClose(h);
00249         return NULL;
00250     }
00251     if ((p->wo_buf =
00252          (ad_wbuf_t *) calloc(N_WO_BUF, sizeof(ad_wbuf_t))) == NULL) {
00253         fprintf(stderr, "calloc(%d,%d) failed\n", N_WO_BUF,
00254                 sizeof(ad_wbuf_t));
00255         free(p);
00256         waveOutClose(h);
00257 
00258         return NULL;
00259     }
00260     if ((p->busy = (char *) calloc(N_WO_BUF, sizeof(char))) == NULL) {
00261         fprintf(stderr, "calloc(%d,%d) failed\n", N_WO_BUF, sizeof(char));
00262         waveout_mem_cleanup(p, 0);
00263         free(p);
00264         waveOutClose(h);
00265 
00266         return NULL;
00267     }
00268     for (i = 0; i < N_WO_BUF; i++) {
00269         if (waveout_alloc_buf(&(p->wo_buf[i]), WO_BUFSIZE) < 0) {
00270             waveout_mem_cleanup(p, i);
00271             free(p);
00272             waveOutClose(h);
00273 
00274             return NULL;
00275         }
00276     }
00277 
00278     p->h_waveout = h;
00279     p->playing = 0;
00280     p->opened = 1;
00281     p->nxtbuf = 0;
00282     p->sps = sps;
00283     p->bps = sizeof(int16);     /* HACK!! Hardwired value for bytes/sec */
00284 
00285     return p;
00286 }
00287 
00288 
00289 ad_play_t *
00290 ad_open_play(void)
00291 {
00292     return (ad_open_play_sps(DEFAULT_SAMPLES_PER_SEC));
00293 }
00294 
00295 
00296 int32
00297 ad_close_play(ad_play_t * p)
00298 {
00299     if (!p->opened)
00300         return 0;
00301 
00302     if (p->playing)
00303         if (ad_stop_play(p) < 0)
00304             return -1;
00305 
00306     if (waveout_close(p) < 0)
00307         return -1;
00308 
00309     return 0;
00310 }
00311 
00312 
00313 int32
00314 ad_start_play(ad_play_t * p)
00315 {
00316     int32 i;
00317 
00318     if ((!p->opened) || p->playing)
00319         return -1;
00320 
00321     for (i = 0; i < N_WO_BUF; i++)
00322         p->busy[i] = 0;
00323     p->nxtbuf = 0;
00324     p->playing = 1;
00325 
00326     return 0;
00327 }
00328 
00329 
00330 int32
00331 ad_stop_play(ad_play_t * p)
00332 {
00333     int32 i, st;
00334     LPWAVEHDR whdr;
00335 
00336     if ((!p->opened) || (!p->playing))
00337         return -1;
00338 
00339 #if 0
00340     whdr->dwUser = (plen <= 0) ? 1 : 0;
00341 #endif
00342 
00343     /* Wait for all buffers to be emptied and unprepare them */
00344     for (i = 0; i < N_WO_BUF; i++) {
00345         whdr = p->wo_buf[i].p_whdr;
00346 
00347         while (p->busy[i] && (!(whdr->dwFlags & WHDR_DONE)))
00348             Sleep(100);
00349 
00350         st = waveOutUnprepareHeader(p->h_waveout, whdr, sizeof(WAVEHDR));
00351         if (st != 0) {
00352             waveout_error("waveOutUnprepareHeader", st);
00353             return -1;
00354         }
00355 
00356         p->busy[i] = 0;
00357     }
00358 
00359     return 0;
00360 }
00361 
00362 
00363 int32
00364 ad_write(ad_play_t * p, int16 * buf, int32 size)
00365 {
00366     int32 i, k, len, st;
00367     LPWAVEHDR whdr;
00368 
00369     if ((!p->opened) || (!p->playing))
00370         return -1;
00371 
00372     len = 0;
00373 
00374     for (i = 0; (i < N_WO_BUF) && (size > 0); i++) {
00375         whdr = p->wo_buf[p->nxtbuf].p_whdr;
00376 
00377         if (p->busy[p->nxtbuf]) {
00378             if (!(whdr->dwFlags & WHDR_DONE))
00379                 return len;
00380 
00381             st = waveOutUnprepareHeader(p->h_waveout, whdr,
00382                                         sizeof(WAVEHDR));
00383             if (st != 0) {
00384                 waveout_error("waveOutUnprepareHeader", st);
00385                 return -1;
00386             }
00387 
00388             p->busy[p->nxtbuf] = 0;
00389         }
00390 
00391         k = (size > WO_BUFSIZE) ? WO_BUFSIZE : size;
00392 
00393         whdr->dwBufferLength = k * sizeof(int16);
00394         memcpy(whdr->lpData, (LPSTR) buf, k * sizeof(int16));
00395 
00396         if (waveout_enqueue_buf(p->h_waveout, whdr) < 0)
00397             return -1;
00398 
00399         buf += k;
00400         size -= k;
00401         len += k;
00402 
00403         p->busy[(p->nxtbuf)++] = 1;
00404         if (p->nxtbuf >= N_WO_BUF)
00405             p->nxtbuf = 0;
00406     }
00407 
00408     return len;
00409 }

Generated on Fri Jan 14 2011 for SphinxBase by  doxygen 1.7.1