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