2 Copyright (C) 1996-1997 Id Software, Inc.
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.
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.
13 See the GNU General Public License for more details.
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.
23 #define iDirectSoundCreate(a,b,c) pDirectSoundCreate(a,b,c)
25 HRESULT (WINAPI *pDirectSoundCreate)(GUID FAR *lpGUID, LPDIRECTSOUND FAR *lplpDS, IUnknown FAR *pUnkOuter);
27 // 64K is > 1 second at 16-bit, 22050 Hz
28 #define WAV_BUFFERS 64
30 #define WAV_BUFFER_SIZE 0x0400
31 #define SECONDARY_BUFFER_SIZE 0x10000
33 typedef enum {SIS_SUCCESS, SIS_FAILURE, SIS_NOTAVAIL} sndinitstat;
35 static qboolean wavonly;
36 static qboolean dsound_init;
37 static qboolean wav_init;
38 static qboolean snd_firsttime = true, snd_isdirect, snd_iswave;
39 static qboolean primary_format_set;
42 static int snd_sent, snd_completed;
46 * Global variables. Must be visible to window-procedure function
47 * so it can unlock and free the data block after it has been played.
51 HPSTR lpData, lpData2;
65 LPDIRECTSOUNDBUFFER pDSBuf, pDSPBuf;
69 qboolean SNDDMA_InitWav (void);
70 sndinitstat SNDDMA_InitDirect (void);
77 void S_BlockSound (void)
80 // DirectSound takes care of blocking itself
87 waveOutReset (hWaveOut);
98 void S_UnblockSound (void)
101 // DirectSound takes care of blocking itself
114 void FreeSound (void)
120 pDSBuf->lpVtbl->Stop(pDSBuf);
121 pDSBuf->lpVtbl->Release(pDSBuf);
124 // only release primary buffer if it's not also the mixing buffer we just released
125 if (pDSPBuf && (pDSBuf != pDSPBuf))
127 pDSPBuf->lpVtbl->Release(pDSPBuf);
132 pDS->lpVtbl->SetCooperativeLevel (pDS, mainwindow, DSSCL_NORMAL);
133 pDS->lpVtbl->Release(pDS);
138 waveOutReset (hWaveOut);
142 for (i=0 ; i< WAV_BUFFERS ; i++)
143 waveOutUnprepareHeader (hWaveOut, lpWaveHdr+i, sizeof(WAVEHDR));
146 waveOutClose (hWaveOut);
150 GlobalUnlock(hWaveHdr);
151 GlobalFree(hWaveHdr);
182 sndinitstat SNDDMA_InitDirect (void)
186 DWORD dwSize, dwWrite;
188 WAVEFORMATEX format, pformat;
193 memset ((void *)&sn, 0, sizeof (sn));
198 shm->samplebits = 16;
199 i = COM_CheckParm ("-sndspeed"); // LordHavoc: -sndspeed option
200 if (i && i != (com_argc - 1))
201 shm->speed = atoi(com_argv[i+1]);
205 memset (&format, 0, sizeof(format));
206 format.wFormatTag = WAVE_FORMAT_PCM;
207 format.nChannels = shm->channels;
208 format.wBitsPerSample = shm->samplebits;
209 format.nSamplesPerSec = shm->speed;
210 format.nBlockAlign = format.nChannels * format.wBitsPerSample / 8;
212 format.nAvgBytesPerSec = format.nSamplesPerSec * format.nBlockAlign;
216 hInstDS = LoadLibrary("dsound.dll");
220 Con_SafePrintf ("Couldn't load dsound.dll\n");
224 pDirectSoundCreate = (void *)GetProcAddress(hInstDS,"DirectSoundCreate");
226 if (!pDirectSoundCreate)
228 Con_SafePrintf ("Couldn't get DS proc addr\n");
233 while ((hresult = iDirectSoundCreate(NULL, &pDS, NULL)) != DS_OK)
235 if (hresult != DSERR_ALLOCATED)
237 Con_SafePrintf ("DirectSound create failed\n");
241 if (MessageBox (NULL,
242 "The sound hardware is in use by another app.\n\n"
243 "Select Retry to try to start sound again or Cancel to run Quake with no sound.",
244 "Sound not available",
245 MB_RETRYCANCEL | MB_SETFOREGROUND | MB_ICONEXCLAMATION) != IDRETRY)
247 Con_SafePrintf ("DirectSoundCreate failure\n"
248 " hardware already in use\n");
253 dscaps.dwSize = sizeof(dscaps);
255 if (DS_OK != pDS->lpVtbl->GetCaps (pDS, &dscaps))
257 Con_SafePrintf ("Couldn't get DS caps\n");
260 if (dscaps.dwFlags & DSCAPS_EMULDRIVER)
262 Con_SafePrintf ("No DirectSound driver installed\n");
267 if (DS_OK != pDS->lpVtbl->SetCooperativeLevel (pDS, mainwindow, DSSCL_EXCLUSIVE))
269 Con_SafePrintf ("Set coop level failed\n");
274 // get access to the primary buffer, if possible, so we can set the
275 // sound hardware format
276 memset (&dsbuf, 0, sizeof(dsbuf));
277 dsbuf.dwSize = sizeof(DSBUFFERDESC);
278 dsbuf.dwFlags = DSBCAPS_PRIMARYBUFFER;
279 dsbuf.dwBufferBytes = 0;
280 dsbuf.lpwfxFormat = NULL;
282 memset(&dsbcaps, 0, sizeof(dsbcaps));
283 dsbcaps.dwSize = sizeof(dsbcaps);
284 primary_format_set = false;
286 if (!COM_CheckParm ("-snoforceformat"))
288 if (DS_OK == pDS->lpVtbl->CreateSoundBuffer(pDS, &dsbuf, &pDSPBuf, NULL))
292 if (DS_OK != pDSPBuf->lpVtbl->SetFormat (pDSPBuf, &pformat))
295 Con_SafePrintf ("Set primary sound buffer format: no\n");
300 Con_SafePrintf ("Set primary sound buffer format: yes\n");
302 primary_format_set = true;
307 if (!primary_format_set || !COM_CheckParm ("-primarysound"))
309 // create the secondary buffer we'll actually work with
310 memset (&dsbuf, 0, sizeof(dsbuf));
311 dsbuf.dwSize = sizeof(DSBUFFERDESC);
312 dsbuf.dwFlags = DSBCAPS_CTRLFREQUENCY | DSBCAPS_LOCSOFTWARE;
313 dsbuf.dwBufferBytes = SECONDARY_BUFFER_SIZE;
314 dsbuf.lpwfxFormat = &format;
316 memset(&dsbcaps, 0, sizeof(dsbcaps));
317 dsbcaps.dwSize = sizeof(dsbcaps);
319 if (DS_OK != pDS->lpVtbl->CreateSoundBuffer(pDS, &dsbuf, &pDSBuf, NULL))
321 Con_SafePrintf ("DS:CreateSoundBuffer Failed");
326 shm->channels = format.nChannels;
327 shm->samplebits = format.wBitsPerSample;
328 shm->speed = format.nSamplesPerSec;
330 if (DS_OK != pDSBuf->lpVtbl->GetCaps (pDSBuf, &dsbcaps))
332 Con_SafePrintf ("DS:GetCaps failed\n");
338 Con_SafePrintf ("Using secondary sound buffer\n");
342 if (DS_OK != pDS->lpVtbl->SetCooperativeLevel (pDS, mainwindow, DSSCL_WRITEPRIMARY))
344 Con_SafePrintf ("Set coop level failed\n");
349 if (DS_OK != pDSPBuf->lpVtbl->GetCaps (pDSPBuf, &dsbcaps))
351 Con_Printf ("DS:GetCaps failed\n");
356 Con_SafePrintf ("Using primary sound buffer\n");
359 // Make sure mixer is active
360 pDSBuf->lpVtbl->Play(pDSBuf, 0, 0, DSBPLAY_LOOPING);
363 Con_SafePrintf(" %d channel(s)\n"
366 shm->channels, shm->samplebits, shm->speed);
368 gSndBufSize = dsbcaps.dwBufferBytes;
370 // initialize the buffer
373 while ((hresult = pDSBuf->lpVtbl->Lock(pDSBuf, 0, gSndBufSize, &lpData, &dwSize, NULL, NULL, 0)) != DS_OK)
375 if (hresult != DSERR_BUFFERLOST)
377 Con_SafePrintf ("SNDDMA_InitDirect: DS::Lock Sound Buffer Failed\n");
384 Con_SafePrintf ("SNDDMA_InitDirect: DS: couldn't restore buffer\n");
391 memset(lpData, 0, dwSize);
393 pDSBuf->lpVtbl->Unlock(pDSBuf, lpData, dwSize, NULL, 0);
395 /* we don't want anyone to access the buffer directly w/o locking it first. */
398 pDSBuf->lpVtbl->Stop(pDSBuf);
399 pDSBuf->lpVtbl->GetCurrentPosition(pDSBuf, &mmstarttime.u.sample, &dwWrite);
400 pDSBuf->lpVtbl->Play(pDSBuf, 0, 0, DSBPLAY_LOOPING);
402 shm->soundalive = true;
403 shm->splitbuffer = false;
404 shm->samples = gSndBufSize/(shm->samplebits/8);
406 shm->submission_chunk = 1;
407 shm->buffer = (unsigned char *) lpData;
408 sample16 = (shm->samplebits/8) - 1;
420 Crappy windows multimedia base
423 qboolean SNDDMA_InitWav (void)
435 shm->samplebits = 16;
436 i = COM_CheckParm ("-sndspeed"); // LordHavoc: -sndspeed option
437 if (i && i != (com_argc - 1))
438 shm->speed = atoi(com_argv[i+1]);
442 memset (&format, 0, sizeof(format));
443 format.wFormatTag = WAVE_FORMAT_PCM;
444 format.nChannels = shm->channels;
445 format.wBitsPerSample = shm->samplebits;
446 format.nSamplesPerSec = shm->speed;
447 format.nBlockAlign = format.nChannels
448 *format.wBitsPerSample / 8;
450 format.nAvgBytesPerSec = format.nSamplesPerSec
453 /* Open a waveform device for output using window callback. */
454 while ((hr = waveOutOpen((LPHWAVEOUT)&hWaveOut, WAVE_MAPPER,
456 0, 0L, CALLBACK_NULL)) != MMSYSERR_NOERROR)
458 if (hr != MMSYSERR_ALLOCATED)
460 Con_SafePrintf ("waveOutOpen failed\n");
464 if (MessageBox (NULL,
465 "The sound hardware is in use by another app.\n\n"
466 "Select Retry to try to start sound again or Cancel to run Quake with no sound.",
467 "Sound not available",
468 MB_RETRYCANCEL | MB_SETFOREGROUND | MB_ICONEXCLAMATION) != IDRETRY)
470 Con_SafePrintf ("waveOutOpen failure;\n"
471 " hardware already in use\n");
477 * Allocate and lock memory for the waveform data. The memory
478 * for waveform data must be globally allocated with
479 * GMEM_MOVEABLE and GMEM_SHARE flags.
482 gSndBufSize = WAV_BUFFERS*WAV_BUFFER_SIZE;
483 hData = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, gSndBufSize);
486 Con_SafePrintf ("Sound: Out of memory.\n");
490 lpData = GlobalLock(hData);
493 Con_SafePrintf ("Sound: Failed to lock.\n");
497 memset (lpData, 0, gSndBufSize);
500 * Allocate and lock memory for the header. This memory must
501 * also be globally allocated with GMEM_MOVEABLE and
504 hWaveHdr = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE,
505 (DWORD) sizeof(WAVEHDR) * WAV_BUFFERS);
507 if (hWaveHdr == NULL)
509 Con_SafePrintf ("Sound: Failed to Alloc header.\n");
514 lpWaveHdr = (LPWAVEHDR) GlobalLock(hWaveHdr);
516 if (lpWaveHdr == NULL)
518 Con_SafePrintf ("Sound: Failed to lock header.\n");
523 memset (lpWaveHdr, 0, sizeof(WAVEHDR) * WAV_BUFFERS);
525 /* After allocation, set up and prepare headers. */
526 for (i=0 ; i<WAV_BUFFERS ; i++)
528 lpWaveHdr[i].dwBufferLength = WAV_BUFFER_SIZE;
529 lpWaveHdr[i].lpData = lpData + i*WAV_BUFFER_SIZE;
531 if (waveOutPrepareHeader(hWaveOut, lpWaveHdr+i, sizeof(WAVEHDR)) !=
534 Con_SafePrintf ("Sound: failed to prepare wave headers\n");
540 shm->soundalive = true;
541 shm->splitbuffer = false;
542 shm->samples = gSndBufSize/(shm->samplebits/8);
544 shm->submission_chunk = 1;
545 shm->buffer = (unsigned char *) lpData;
546 sample16 = (shm->samplebits/8) - 1;
557 Try to find a sound device to mix for.
558 Returns false if nothing is found.
562 qboolean SNDDMA_Init(void)
566 if (COM_CheckParm ("-wavonly"))
569 dsound_init = wav_init = 0;
571 stat = SIS_FAILURE; // assume DirectSound won't initialize
573 /* Init DirectSound */
576 if (snd_firsttime || snd_isdirect)
578 stat = SNDDMA_InitDirect ();;
580 if (stat == SIS_SUCCESS)
585 Con_SafePrintf ("DirectSound initialized\n");
589 snd_isdirect = false;
590 Con_SafePrintf ("DirectSound failed to init\n");
595 // if DirectSound didn't succeed in initializing, try to initialize
596 // waveOut sound, unless DirectSound failed because the hardware is
597 // already allocated (in which case the user has already chosen not
599 if (!dsound_init && (stat != SIS_NOTAVAIL))
601 if (snd_firsttime || snd_iswave)
604 snd_iswave = SNDDMA_InitWav ();
609 Con_SafePrintf ("Wave sound initialized\n");
613 Con_SafePrintf ("Wave sound failed to init\n");
618 snd_firsttime = false;
620 if (!dsound_init && !wav_init)
630 return the current sample position (in mono samples read)
631 inside the recirculating dma buffer, so the mixing code will know
632 how many sample are required to fill it up.
635 int SNDDMA_GetDMAPos(void)
643 mmtime.wType = TIME_SAMPLES;
644 pDSBuf->lpVtbl->GetCurrentPosition(pDSBuf, &mmtime.u.sample, &dwWrite);
645 s = mmtime.u.sample - mmstarttime.u.sample;
649 s = snd_sent * WAV_BUFFER_SIZE;
657 s &= (shm->samples-1);
666 Send sound to device if buffer isn't really the dma buffer
669 void SNDDMA_Submit(void)
678 // find which sound blocks have completed
682 if ( snd_completed == snd_sent )
684 Con_DPrintf ("Sound overrun\n");
688 if ( ! (lpWaveHdr[ snd_completed & WAV_MASK].dwFlags & WHDR_DONE) )
693 snd_completed++; // this buffer has been played
697 // submit two new sound blocks
699 while (((snd_sent - snd_completed) >> sample16) < 4)
701 h = lpWaveHdr + ( snd_sent&WAV_MASK );
705 * Now the data block can be sent to the output device. The
706 * waveOutWrite function returns immediately and waveform
707 * data is sent to the output device in the background.
709 wResult = waveOutWrite(hWaveOut, h, sizeof(WAVEHDR));
711 if (wResult != MMSYSERR_NOERROR)
713 Con_SafePrintf ("Failed to write block to device\n");
724 Reset the sound device for exiting
727 void SNDDMA_Shutdown(void)
733 DWORD dsound_dwSize2;
736 void *S_LockBuffer(void)
745 while ((hresult = pDSBuf->lpVtbl->Lock(pDSBuf, 0, gSndBufSize, &dsound_pbuf, &dsound_dwSize, &dsound_pbuf2, &dsound_dwSize2, 0)) != DS_OK)
747 if (hresult != DSERR_BUFFERLOST)
749 Con_Printf ("S_LockBuffer: DS::Lock Sound Buffer Failed\n");
757 Con_Printf ("S_LockBuffer: DS: couldn't restore buffer\n");
769 void S_UnlockBuffer()
772 pDSBuf->lpVtbl->Unlock(pDSBuf, dsound_pbuf, dsound_dwSize, dsound_pbuf2, dsound_dwSize2);