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