|
|
1.1 ! root 1: #include <float.h> ! 2: ! 3: #include "../client/client.h" ! 4: #include "../client/snd_loc.h" ! 5: #include "winquake.h" ! 6: ! 7: #define iDirectSoundCreate(a,b,c) pDirectSoundCreate(a,b,c) ! 8: ! 9: HRESULT (WINAPI *pDirectSoundCreate)(GUID FAR *lpGUID, LPDIRECTSOUND FAR *lplpDS, IUnknown FAR *pUnkOuter); ! 10: ! 11: // 64K is > 1 second at 16-bit, 22050 Hz ! 12: #define WAV_BUFFERS 64 ! 13: #define WAV_MASK 0x3F ! 14: #define WAV_BUFFER_SIZE 0x0400 ! 15: #define SECONDARY_BUFFER_SIZE 0x10000 ! 16: ! 17: typedef enum {SIS_SUCCESS, SIS_FAILURE, SIS_NOTAVAIL} sndinitstat; ! 18: ! 19: cvar_t *s_wavonly; ! 20: ! 21: static qboolean dsound_init; ! 22: static qboolean wav_init; ! 23: static qboolean snd_firsttime = true, snd_isdirect, snd_iswave; ! 24: static qboolean primary_format_set; ! 25: ! 26: // starts at 0 for disabled ! 27: static int snd_buffer_count = 0; ! 28: static int sample16; ! 29: static int snd_sent, snd_completed; ! 30: ! 31: /* ! 32: * Global variables. Must be visible to window-procedure function ! 33: * so it can unlock and free the data block after it has been played. ! 34: */ ! 35: ! 36: ! 37: HANDLE hData; ! 38: HPSTR lpData, lpData2; ! 39: ! 40: HGLOBAL hWaveHdr; ! 41: LPWAVEHDR lpWaveHdr; ! 42: ! 43: HWAVEOUT hWaveOut; ! 44: ! 45: WAVEOUTCAPS wavecaps; ! 46: ! 47: DWORD gSndBufSize; ! 48: ! 49: MMTIME mmstarttime; ! 50: ! 51: LPDIRECTSOUND pDS; ! 52: LPDIRECTSOUNDBUFFER pDSBuf, pDSPBuf; ! 53: ! 54: HINSTANCE hInstDS; ! 55: ! 56: qboolean SNDDMA_InitDirect (void); ! 57: qboolean SNDDMA_InitWav (void); ! 58: ! 59: void FreeSound( void ); ! 60: ! 61: static const char *DSoundError( int error ) ! 62: { ! 63: switch ( error ) ! 64: { ! 65: case DSERR_BUFFERLOST: ! 66: return "DSERR_BUFFERLOST"; ! 67: case DSERR_INVALIDCALL: ! 68: return "DSERR_INVALIDCALLS"; ! 69: case DSERR_INVALIDPARAM: ! 70: return "DSERR_INVALIDPARAM"; ! 71: case DSERR_PRIOLEVELNEEDED: ! 72: return "DSERR_PRIOLEVELNEEDED"; ! 73: } ! 74: ! 75: return "unknown"; ! 76: } ! 77: ! 78: /* ! 79: ** DS_CreateBuffers ! 80: */ ! 81: static qboolean DS_CreateBuffers( void ) ! 82: { ! 83: DSBUFFERDESC dsbuf; ! 84: DSBCAPS dsbcaps; ! 85: WAVEFORMATEX pformat, format; ! 86: DWORD dwWrite; ! 87: ! 88: memset (&format, 0, sizeof(format)); ! 89: format.wFormatTag = WAVE_FORMAT_PCM; ! 90: format.nChannels = dma.channels; ! 91: format.wBitsPerSample = dma.samplebits; ! 92: format.nSamplesPerSec = dma.speed; ! 93: format.nBlockAlign = format.nChannels * format.wBitsPerSample / 8; ! 94: format.cbSize = 0; ! 95: format.nAvgBytesPerSec = format.nSamplesPerSec*format.nBlockAlign; ! 96: ! 97: Com_Printf( "Creating DS buffers\n" ); ! 98: ! 99: Com_DPrintf("...setting EXCLUSIVE coop level: " ); ! 100: if ( DS_OK != pDS->lpVtbl->SetCooperativeLevel( pDS, cl_hwnd, DSSCL_EXCLUSIVE ) ) ! 101: { ! 102: Com_Printf ("failed\n"); ! 103: FreeSound (); ! 104: return false; ! 105: } ! 106: Com_DPrintf("ok\n" ); ! 107: ! 108: // get access to the primary buffer, if possible, so we can set the ! 109: // sound hardware format ! 110: memset (&dsbuf, 0, sizeof(dsbuf)); ! 111: dsbuf.dwSize = sizeof(DSBUFFERDESC); ! 112: dsbuf.dwFlags = DSBCAPS_PRIMARYBUFFER; ! 113: dsbuf.dwBufferBytes = 0; ! 114: dsbuf.lpwfxFormat = NULL; ! 115: ! 116: memset(&dsbcaps, 0, sizeof(dsbcaps)); ! 117: dsbcaps.dwSize = sizeof(dsbcaps); ! 118: primary_format_set = false; ! 119: ! 120: Com_DPrintf( "...creating primary buffer: " ); ! 121: if (DS_OK == pDS->lpVtbl->CreateSoundBuffer(pDS, &dsbuf, &pDSPBuf, NULL)) ! 122: { ! 123: pformat = format; ! 124: ! 125: Com_DPrintf( "ok\n" ); ! 126: if (DS_OK != pDSPBuf->lpVtbl->SetFormat (pDSPBuf, &pformat)) ! 127: { ! 128: if (snd_firsttime) ! 129: Com_DPrintf ("...setting primary sound format: failed\n"); ! 130: } ! 131: else ! 132: { ! 133: if (snd_firsttime) ! 134: Com_DPrintf ("...setting primary sound format: ok\n"); ! 135: ! 136: primary_format_set = true; ! 137: } ! 138: } ! 139: else ! 140: Com_Printf( "failed\n" ); ! 141: ! 142: if ( !primary_format_set || !s_primary->value) ! 143: { ! 144: // create the secondary buffer we'll actually work with ! 145: memset (&dsbuf, 0, sizeof(dsbuf)); ! 146: dsbuf.dwSize = sizeof(DSBUFFERDESC); ! 147: dsbuf.dwFlags = DSBCAPS_CTRLFREQUENCY | DSBCAPS_LOCSOFTWARE; ! 148: dsbuf.dwBufferBytes = SECONDARY_BUFFER_SIZE; ! 149: dsbuf.lpwfxFormat = &format; ! 150: ! 151: memset(&dsbcaps, 0, sizeof(dsbcaps)); ! 152: dsbcaps.dwSize = sizeof(dsbcaps); ! 153: ! 154: Com_DPrintf( "...creating secondary buffer: " ); ! 155: if (DS_OK != pDS->lpVtbl->CreateSoundBuffer(pDS, &dsbuf, &pDSBuf, NULL)) ! 156: { ! 157: Com_Printf( "failed\n" ); ! 158: FreeSound (); ! 159: return false; ! 160: } ! 161: Com_DPrintf( "ok\n" ); ! 162: ! 163: dma.channels = format.nChannels; ! 164: dma.samplebits = format.wBitsPerSample; ! 165: dma.speed = format.nSamplesPerSec; ! 166: ! 167: if (DS_OK != pDSBuf->lpVtbl->GetCaps (pDSBuf, &dsbcaps)) ! 168: { ! 169: Com_Printf ("*** GetCaps failed ***\n"); ! 170: FreeSound (); ! 171: return false; ! 172: } ! 173: ! 174: Com_Printf ("...using secondary sound buffer\n"); ! 175: } ! 176: else ! 177: { ! 178: Com_Printf( "...using primary buffer\n" ); ! 179: ! 180: Com_DPrintf( "...setting WRITEPRIMARY coop level: " ); ! 181: if (DS_OK != pDS->lpVtbl->SetCooperativeLevel (pDS, cl_hwnd, DSSCL_WRITEPRIMARY)) ! 182: { ! 183: Com_Printf( "failed\n" ); ! 184: FreeSound (); ! 185: return false; ! 186: } ! 187: Com_DPrintf( "ok\n" ); ! 188: ! 189: if (DS_OK != pDSPBuf->lpVtbl->GetCaps (pDSPBuf, &dsbcaps)) ! 190: { ! 191: Com_Printf ("*** GetCaps failed ***\n"); ! 192: return false; ! 193: } ! 194: ! 195: pDSBuf = pDSPBuf; ! 196: } ! 197: ! 198: // Make sure mixer is active ! 199: pDSBuf->lpVtbl->Play(pDSBuf, 0, 0, DSBPLAY_LOOPING); ! 200: ! 201: if (snd_firsttime) ! 202: Com_Printf(" %d channel(s)\n" ! 203: " %d bits/sample\n" ! 204: " %d bytes/sec\n", ! 205: dma.channels, dma.samplebits, dma.speed); ! 206: ! 207: gSndBufSize = dsbcaps.dwBufferBytes; ! 208: ! 209: /* we don't want anyone to access the buffer directly w/o locking it first. */ ! 210: lpData = NULL; ! 211: ! 212: pDSBuf->lpVtbl->Stop(pDSBuf); ! 213: pDSBuf->lpVtbl->GetCurrentPosition(pDSBuf, &mmstarttime.u.sample, &dwWrite); ! 214: pDSBuf->lpVtbl->Play(pDSBuf, 0, 0, DSBPLAY_LOOPING); ! 215: ! 216: dma.samples = gSndBufSize/(dma.samplebits/8); ! 217: dma.samplepos = 0; ! 218: dma.submission_chunk = 1; ! 219: dma.buffer = (unsigned char *) lpData; ! 220: sample16 = (dma.samplebits/8) - 1; ! 221: ! 222: return true; ! 223: } ! 224: ! 225: /* ! 226: ** DS_DestroyBuffers ! 227: */ ! 228: static void DS_DestroyBuffers( void ) ! 229: { ! 230: Com_DPrintf( "Destroying DS buffers\n" ); ! 231: if ( pDS ) ! 232: { ! 233: Com_DPrintf( "...setting NORMAL coop level\n" ); ! 234: pDS->lpVtbl->SetCooperativeLevel( pDS, cl_hwnd, DSSCL_NORMAL ); ! 235: } ! 236: ! 237: if ( pDSBuf ) ! 238: { ! 239: Com_DPrintf( "...stopping and releasing sound buffer\n" ); ! 240: pDSBuf->lpVtbl->Stop( pDSBuf ); ! 241: pDSBuf->lpVtbl->Release( pDSBuf ); ! 242: } ! 243: ! 244: // only release primary buffer if it's not also the mixing buffer we just released ! 245: if ( pDSPBuf && ( pDSBuf != pDSPBuf ) ) ! 246: { ! 247: Com_DPrintf( "...releasing primary buffer\n" ); ! 248: pDSPBuf->lpVtbl->Release( pDSPBuf ); ! 249: } ! 250: pDSBuf = NULL; ! 251: pDSPBuf = NULL; ! 252: ! 253: dma.buffer = NULL; ! 254: } ! 255: ! 256: /* ! 257: ================== ! 258: FreeSound ! 259: ================== ! 260: */ ! 261: void FreeSound (void) ! 262: { ! 263: int i; ! 264: ! 265: Com_DPrintf( "Shutting down sound system\n" ); ! 266: ! 267: if ( pDS ) ! 268: DS_DestroyBuffers(); ! 269: ! 270: if ( hWaveOut ) ! 271: { ! 272: Com_DPrintf( "...resetting waveOut\n" ); ! 273: waveOutReset (hWaveOut); ! 274: ! 275: if (lpWaveHdr) ! 276: { ! 277: Com_DPrintf( "...unpreparing headers\n" ); ! 278: for (i=0 ; i< WAV_BUFFERS ; i++) ! 279: waveOutUnprepareHeader (hWaveOut, lpWaveHdr+i, sizeof(WAVEHDR)); ! 280: } ! 281: ! 282: Com_DPrintf( "...closing waveOut\n" ); ! 283: waveOutClose (hWaveOut); ! 284: ! 285: if (hWaveHdr) ! 286: { ! 287: Com_DPrintf( "...freeing WAV header\n" ); ! 288: GlobalUnlock(hWaveHdr); ! 289: GlobalFree(hWaveHdr); ! 290: } ! 291: ! 292: if (hData) ! 293: { ! 294: Com_DPrintf( "...freeing WAV buffer\n" ); ! 295: GlobalUnlock(hData); ! 296: GlobalFree(hData); ! 297: } ! 298: ! 299: } ! 300: ! 301: if ( pDS ) ! 302: { ! 303: Com_DPrintf( "...releasing DS object\n" ); ! 304: pDS->lpVtbl->Release( pDS ); ! 305: } ! 306: ! 307: if ( hInstDS ) ! 308: { ! 309: Com_DPrintf( "...freeing DSOUND.DLL\n" ); ! 310: FreeLibrary( hInstDS ); ! 311: hInstDS = NULL; ! 312: } ! 313: ! 314: pDS = NULL; ! 315: pDSBuf = NULL; ! 316: pDSPBuf = NULL; ! 317: hWaveOut = 0; ! 318: hData = 0; ! 319: hWaveHdr = 0; ! 320: lpData = NULL; ! 321: lpWaveHdr = NULL; ! 322: dsound_init = false; ! 323: wav_init = false; ! 324: } ! 325: ! 326: /* ! 327: ================== ! 328: SNDDMA_InitDirect ! 329: ! 330: Direct-Sound support ! 331: ================== ! 332: */ ! 333: sndinitstat SNDDMA_InitDirect (void) ! 334: { ! 335: DSCAPS dscaps; ! 336: HRESULT hresult; ! 337: ! 338: dma.channels = 2; ! 339: dma.samplebits = 16; ! 340: ! 341: if (s_khz->value == 44) ! 342: dma.speed = 44100; ! 343: if (s_khz->value == 22) ! 344: dma.speed = 22050; ! 345: else ! 346: dma.speed = 11025; ! 347: ! 348: Com_Printf( "Initializing DirectSound\n"); ! 349: ! 350: if ( !hInstDS ) ! 351: { ! 352: Com_DPrintf( "...loading dsound.dll: " ); ! 353: ! 354: hInstDS = LoadLibrary("dsound.dll"); ! 355: ! 356: if (hInstDS == NULL) ! 357: { ! 358: Com_Printf ("failed\n"); ! 359: return SIS_FAILURE; ! 360: } ! 361: ! 362: Com_DPrintf ("ok\n"); ! 363: pDirectSoundCreate = (void *)GetProcAddress(hInstDS,"DirectSoundCreate"); ! 364: ! 365: if (!pDirectSoundCreate) ! 366: { ! 367: Com_Printf ("*** couldn't get DS proc addr ***\n"); ! 368: return SIS_FAILURE; ! 369: } ! 370: } ! 371: ! 372: Com_DPrintf( "...creating DS object: " ); ! 373: while ( ( hresult = iDirectSoundCreate( NULL, &pDS, NULL ) ) != DS_OK ) ! 374: { ! 375: if (hresult != DSERR_ALLOCATED) ! 376: { ! 377: Com_Printf( "failed\n" ); ! 378: return SIS_FAILURE; ! 379: } ! 380: ! 381: if (MessageBox (NULL, ! 382: "The sound hardware is in use by another app.\n\n" ! 383: "Select Retry to try to start sound again or Cancel to run Quake with no sound.", ! 384: "Sound not available", ! 385: MB_RETRYCANCEL | MB_SETFOREGROUND | MB_ICONEXCLAMATION) != IDRETRY) ! 386: { ! 387: Com_Printf ("failed, hardware already in use\n" ); ! 388: return SIS_NOTAVAIL; ! 389: } ! 390: } ! 391: Com_DPrintf( "ok\n" ); ! 392: ! 393: dscaps.dwSize = sizeof(dscaps); ! 394: ! 395: if ( DS_OK != pDS->lpVtbl->GetCaps( pDS, &dscaps ) ) ! 396: { ! 397: Com_Printf ("*** couldn't get DS caps ***\n"); ! 398: } ! 399: ! 400: if ( dscaps.dwFlags & DSCAPS_EMULDRIVER ) ! 401: { ! 402: Com_DPrintf ("...no DSound driver found\n" ); ! 403: FreeSound(); ! 404: return SIS_FAILURE; ! 405: } ! 406: ! 407: if ( !DS_CreateBuffers() ) ! 408: return SIS_FAILURE; ! 409: ! 410: dsound_init = true; ! 411: ! 412: Com_DPrintf("...completed successfully\n" ); ! 413: ! 414: return SIS_SUCCESS; ! 415: } ! 416: ! 417: ! 418: /* ! 419: ================== ! 420: SNDDM_InitWav ! 421: ! 422: Crappy windows multimedia base ! 423: ================== ! 424: */ ! 425: qboolean SNDDMA_InitWav (void) ! 426: { ! 427: WAVEFORMATEX format; ! 428: int i; ! 429: HRESULT hr; ! 430: ! 431: Com_Printf( "Initializing wave sound\n" ); ! 432: ! 433: snd_sent = 0; ! 434: snd_completed = 0; ! 435: ! 436: dma.channels = 2; ! 437: dma.samplebits = 16; ! 438: ! 439: if (s_khz->value == 44) ! 440: dma.speed = 44100; ! 441: if (s_khz->value == 22) ! 442: dma.speed = 22050; ! 443: else ! 444: dma.speed = 11025; ! 445: ! 446: memset (&format, 0, sizeof(format)); ! 447: format.wFormatTag = WAVE_FORMAT_PCM; ! 448: format.nChannels = dma.channels; ! 449: format.wBitsPerSample = dma.samplebits; ! 450: format.nSamplesPerSec = dma.speed; ! 451: format.nBlockAlign = format.nChannels ! 452: *format.wBitsPerSample / 8; ! 453: format.cbSize = 0; ! 454: format.nAvgBytesPerSec = format.nSamplesPerSec ! 455: *format.nBlockAlign; ! 456: ! 457: /* Open a waveform device for output using window callback. */ ! 458: Com_DPrintf ("...opening waveform device: "); ! 459: while ((hr = waveOutOpen((LPHWAVEOUT)&hWaveOut, WAVE_MAPPER, ! 460: &format, ! 461: 0, 0L, CALLBACK_NULL)) != MMSYSERR_NOERROR) ! 462: { ! 463: if (hr != MMSYSERR_ALLOCATED) ! 464: { ! 465: Com_Printf ("failed\n"); ! 466: return false; ! 467: } ! 468: ! 469: if (MessageBox (NULL, ! 470: "The sound hardware is in use by another app.\n\n" ! 471: "Select Retry to try to start sound again or Cancel to run Quake 2 with no sound.", ! 472: "Sound not available", ! 473: MB_RETRYCANCEL | MB_SETFOREGROUND | MB_ICONEXCLAMATION) != IDRETRY) ! 474: { ! 475: Com_Printf ("hw in use\n" ); ! 476: return false; ! 477: } ! 478: } ! 479: Com_DPrintf( "ok\n" ); ! 480: ! 481: /* ! 482: * Allocate and lock memory for the waveform data. The memory ! 483: * for waveform data must be globally allocated with ! 484: * GMEM_MOVEABLE and GMEM_SHARE flags. ! 485: ! 486: */ ! 487: Com_DPrintf ("...allocating waveform buffer: "); ! 488: gSndBufSize = WAV_BUFFERS*WAV_BUFFER_SIZE; ! 489: hData = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, gSndBufSize); ! 490: if (!hData) ! 491: { ! 492: Com_Printf( " failed\n" ); ! 493: FreeSound (); ! 494: return false; ! 495: } ! 496: Com_DPrintf( "ok\n" ); ! 497: ! 498: Com_DPrintf ("...locking waveform buffer: "); ! 499: lpData = GlobalLock(hData); ! 500: if (!lpData) ! 501: { ! 502: Com_Printf( " failed\n" ); ! 503: FreeSound (); ! 504: return false; ! 505: } ! 506: memset (lpData, 0, gSndBufSize); ! 507: Com_DPrintf( "ok\n" ); ! 508: ! 509: /* ! 510: * Allocate and lock memory for the header. This memory must ! 511: * also be globally allocated with GMEM_MOVEABLE and ! 512: * GMEM_SHARE flags. ! 513: */ ! 514: Com_DPrintf ("...allocating waveform header: "); ! 515: hWaveHdr = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, ! 516: (DWORD) sizeof(WAVEHDR) * WAV_BUFFERS); ! 517: ! 518: if (hWaveHdr == NULL) ! 519: { ! 520: Com_Printf( "failed\n" ); ! 521: FreeSound (); ! 522: return false; ! 523: } ! 524: Com_DPrintf( "ok\n" ); ! 525: ! 526: Com_DPrintf ("...locking waveform header: "); ! 527: lpWaveHdr = (LPWAVEHDR) GlobalLock(hWaveHdr); ! 528: ! 529: if (lpWaveHdr == NULL) ! 530: { ! 531: Com_Printf( "failed\n" ); ! 532: FreeSound (); ! 533: return false; ! 534: } ! 535: memset (lpWaveHdr, 0, sizeof(WAVEHDR) * WAV_BUFFERS); ! 536: Com_DPrintf( "ok\n" ); ! 537: ! 538: /* After allocation, set up and prepare headers. */ ! 539: Com_DPrintf ("...preparing headers: "); ! 540: for (i=0 ; i<WAV_BUFFERS ; i++) ! 541: { ! 542: lpWaveHdr[i].dwBufferLength = WAV_BUFFER_SIZE; ! 543: lpWaveHdr[i].lpData = lpData + i*WAV_BUFFER_SIZE; ! 544: ! 545: if (waveOutPrepareHeader(hWaveOut, lpWaveHdr+i, sizeof(WAVEHDR)) != ! 546: MMSYSERR_NOERROR) ! 547: { ! 548: Com_Printf ("failed\n"); ! 549: FreeSound (); ! 550: return false; ! 551: } ! 552: } ! 553: Com_DPrintf ("ok\n"); ! 554: ! 555: dma.samples = gSndBufSize/(dma.samplebits/8); ! 556: dma.samplepos = 0; ! 557: dma.submission_chunk = 512; ! 558: dma.buffer = (unsigned char *) lpData; ! 559: sample16 = (dma.samplebits/8) - 1; ! 560: ! 561: wav_init = true; ! 562: ! 563: return true; ! 564: } ! 565: ! 566: /* ! 567: ================== ! 568: SNDDMA_Init ! 569: ! 570: Try to find a sound device to mix for. ! 571: Returns false if nothing is found. ! 572: ================== ! 573: */ ! 574: int SNDDMA_Init(void) ! 575: { ! 576: sndinitstat stat; ! 577: ! 578: memset ((void *)&dma, 0, sizeof (dma)); ! 579: ! 580: s_wavonly = Cvar_Get ("s_wavonly", "0", 0); ! 581: ! 582: dsound_init = wav_init = 0; ! 583: ! 584: stat = SIS_FAILURE; // assume DirectSound won't initialize ! 585: ! 586: /* Init DirectSound */ ! 587: if (!s_wavonly->value) ! 588: { ! 589: if (snd_firsttime || snd_isdirect) ! 590: { ! 591: stat = SNDDMA_InitDirect (); ! 592: ! 593: if (stat == SIS_SUCCESS) ! 594: { ! 595: snd_isdirect = true; ! 596: ! 597: if (snd_firsttime) ! 598: Com_Printf ("dsound init succeeded\n" ); ! 599: } ! 600: else ! 601: { ! 602: snd_isdirect = false; ! 603: Com_Printf ("*** dsound init failed ***\n"); ! 604: } ! 605: } ! 606: } ! 607: ! 608: // if DirectSound didn't succeed in initializing, try to initialize ! 609: // waveOut sound, unless DirectSound failed because the hardware is ! 610: // already allocated (in which case the user has already chosen not ! 611: // to have sound) ! 612: if (!dsound_init && (stat != SIS_NOTAVAIL)) ! 613: { ! 614: if (snd_firsttime || snd_iswave) ! 615: { ! 616: ! 617: snd_iswave = SNDDMA_InitWav (); ! 618: ! 619: if (snd_iswave) ! 620: { ! 621: if (snd_firsttime) ! 622: Com_Printf ("Wave sound init succeeded\n"); ! 623: } ! 624: else ! 625: { ! 626: Com_Printf ("Wave sound init failed\n"); ! 627: } ! 628: } ! 629: } ! 630: ! 631: snd_firsttime = false; ! 632: ! 633: snd_buffer_count = 1; ! 634: ! 635: if (!dsound_init && !wav_init) ! 636: { ! 637: if (snd_firsttime) ! 638: Com_Printf ("*** No sound device initialized ***\n"); ! 639: ! 640: return 0; ! 641: } ! 642: ! 643: return 1; ! 644: } ! 645: ! 646: /* ! 647: ============== ! 648: SNDDMA_GetDMAPos ! 649: ! 650: return the current sample position (in mono samples read) ! 651: inside the recirculating dma buffer, so the mixing code will know ! 652: how many sample are required to fill it up. ! 653: =============== ! 654: */ ! 655: int SNDDMA_GetDMAPos(void) ! 656: { ! 657: MMTIME mmtime; ! 658: int s; ! 659: DWORD dwWrite; ! 660: ! 661: if (dsound_init) ! 662: { ! 663: mmtime.wType = TIME_SAMPLES; ! 664: pDSBuf->lpVtbl->GetCurrentPosition(pDSBuf, &mmtime.u.sample, &dwWrite); ! 665: s = mmtime.u.sample - mmstarttime.u.sample; ! 666: } ! 667: else if (wav_init) ! 668: { ! 669: s = snd_sent * WAV_BUFFER_SIZE; ! 670: } ! 671: ! 672: ! 673: s >>= sample16; ! 674: ! 675: s &= (dma.samples-1); ! 676: ! 677: return s; ! 678: } ! 679: ! 680: /* ! 681: ============== ! 682: SNDDMA_BeginPainting ! 683: ! 684: Makes sure dma.buffer is valid ! 685: =============== ! 686: */ ! 687: DWORD locksize; ! 688: void SNDDMA_BeginPainting (void) ! 689: { ! 690: int reps; ! 691: DWORD dwSize2; ! 692: DWORD *pbuf, *pbuf2; ! 693: HRESULT hresult; ! 694: DWORD dwStatus; ! 695: ! 696: if (!pDSBuf) ! 697: return; ! 698: ! 699: // if the buffer was lost or stopped, restore it and/or restart it ! 700: if (pDSBuf->lpVtbl->GetStatus (pDSBuf, &dwStatus) != DS_OK) ! 701: Com_Printf ("Couldn't get sound buffer status\n"); ! 702: ! 703: if (dwStatus & DSBSTATUS_BUFFERLOST) ! 704: pDSBuf->lpVtbl->Restore (pDSBuf); ! 705: ! 706: if (!(dwStatus & DSBSTATUS_PLAYING)) ! 707: pDSBuf->lpVtbl->Play(pDSBuf, 0, 0, DSBPLAY_LOOPING); ! 708: ! 709: // lock the dsound buffer ! 710: ! 711: reps = 0; ! 712: dma.buffer = NULL; ! 713: ! 714: while ((hresult = pDSBuf->lpVtbl->Lock(pDSBuf, 0, gSndBufSize, &pbuf, &locksize, ! 715: &pbuf2, &dwSize2, 0)) != DS_OK) ! 716: { ! 717: if (hresult != DSERR_BUFFERLOST) ! 718: { ! 719: Com_Printf( "S_TransferStereo16: Lock failed with error '%s'\n", DSoundError( hresult ) ); ! 720: S_Shutdown (); ! 721: return; ! 722: } ! 723: else ! 724: { ! 725: pDSBuf->lpVtbl->Restore( pDSBuf ); ! 726: } ! 727: ! 728: if (++reps > 2) ! 729: return; ! 730: } ! 731: dma.buffer = (unsigned char *)pbuf; ! 732: } ! 733: ! 734: /* ! 735: ============== ! 736: SNDDMA_Submit ! 737: ! 738: Send sound to device if buffer isn't really the dma buffer ! 739: Also unlocks the dsound buffer ! 740: =============== ! 741: */ ! 742: void SNDDMA_Submit(void) ! 743: { ! 744: LPWAVEHDR h; ! 745: int wResult; ! 746: ! 747: if (!dma.buffer) ! 748: return; ! 749: ! 750: // unlock the dsound buffer ! 751: if (pDSBuf) ! 752: pDSBuf->lpVtbl->Unlock(pDSBuf, dma.buffer, locksize, NULL, 0); ! 753: ! 754: if (!wav_init) ! 755: return; ! 756: ! 757: // ! 758: // find which sound blocks have completed ! 759: // ! 760: while (1) ! 761: { ! 762: if ( snd_completed == snd_sent ) ! 763: { ! 764: Com_DPrintf ("Sound overrun\n"); ! 765: break; ! 766: } ! 767: ! 768: if ( ! (lpWaveHdr[ snd_completed & WAV_MASK].dwFlags & WHDR_DONE) ) ! 769: { ! 770: break; ! 771: } ! 772: ! 773: snd_completed++; // this buffer has been played ! 774: } ! 775: ! 776: //Com_Printf ("completed %i\n", snd_completed); ! 777: // ! 778: // submit a few new sound blocks ! 779: // ! 780: while (((snd_sent - snd_completed) >> sample16) < 8) ! 781: { ! 782: h = lpWaveHdr + ( snd_sent&WAV_MASK ); ! 783: if (paintedtime/256 <= snd_sent) ! 784: break; // Com_Printf ("submit overrun\n"); ! 785: //Com_Printf ("send %i\n", snd_sent); ! 786: snd_sent++; ! 787: /* ! 788: * Now the data block can be sent to the output device. The ! 789: * waveOutWrite function returns immediately and waveform ! 790: * data is sent to the output device in the background. ! 791: */ ! 792: wResult = waveOutWrite(hWaveOut, h, sizeof(WAVEHDR)); ! 793: ! 794: if (wResult != MMSYSERR_NOERROR) ! 795: { ! 796: Com_Printf ("Failed to write block to device\n"); ! 797: FreeSound (); ! 798: return; ! 799: } ! 800: } ! 801: } ! 802: ! 803: /* ! 804: ============== ! 805: SNDDMA_Shutdown ! 806: ! 807: Reset the sound device for exiting ! 808: =============== ! 809: */ ! 810: void SNDDMA_Shutdown(void) ! 811: { ! 812: FreeSound (); ! 813: } ! 814: ! 815: ! 816: /* ! 817: =========== ! 818: S_Activate ! 819: ! 820: Called when the main window gains or loses focus. ! 821: The window have been destroyed and recreated ! 822: between a deactivate and an activate. ! 823: =========== ! 824: */ ! 825: void S_Activate (qboolean active) ! 826: { ! 827: if ( active ) ! 828: { ! 829: if ( pDS && cl_hwnd && snd_isdirect ) ! 830: { ! 831: DS_CreateBuffers(); ! 832: } ! 833: } ! 834: else ! 835: { ! 836: if ( pDS && cl_hwnd && snd_isdirect ) ! 837: { ! 838: DS_DestroyBuffers(); ! 839: } ! 840: } ! 841: } ! 842:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.