00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
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
00063 #define N_WO_BUF 2
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
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
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
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);
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
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 }