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_InitDirect (void);
70 qboolean SNDDMA_InitWav (void);
78 void S_BlockSound (void)
81 // DirectSound takes care of blocking itself
88 waveOutReset (hWaveOut);
99 void S_UnblockSound (void)
102 // DirectSound takes care of blocking itself
115 void FreeSound (void)
121 pDSBuf->lpVtbl->Stop(pDSBuf);
122 pDSBuf->lpVtbl->Release(pDSBuf);
125 // only release primary buffer if it's not also the mixing buffer we just released
126 if (pDSPBuf && (pDSBuf != pDSPBuf))
128 pDSPBuf->lpVtbl->Release(pDSPBuf);
133 pDS->lpVtbl->SetCooperativeLevel (pDS, mainwindow, DSSCL_NORMAL);
134 pDS->lpVtbl->Release(pDS);
139 waveOutReset (hWaveOut);
143 for (i=0 ; i< WAV_BUFFERS ; i++)
144 waveOutUnprepareHeader (hWaveOut, lpWaveHdr+i, sizeof(WAVEHDR));
147 waveOutClose (hWaveOut);
151 GlobalUnlock(hWaveHdr);
152 GlobalFree(hWaveHdr);
183 sndinitstat SNDDMA_InitDirect (void)
187 DWORD dwSize, dwWrite;
189 WAVEFORMATEX format, pformat;
193 memset ((void *)&sn, 0, sizeof (sn));
198 shm->samplebits = 16;
201 memset (&format, 0, sizeof(format));
202 format.wFormatTag = WAVE_FORMAT_PCM;
203 format.nChannels = shm->channels;
204 format.wBitsPerSample = shm->samplebits;
205 format.nSamplesPerSec = shm->speed;
206 format.nBlockAlign = format.nChannels
207 *format.wBitsPerSample / 8;
209 format.nAvgBytesPerSec = format.nSamplesPerSec
214 hInstDS = LoadLibrary("dsound.dll");
218 Con_SafePrintf ("Couldn't load dsound.dll\n");
222 pDirectSoundCreate = (void *)GetProcAddress(hInstDS,"DirectSoundCreate");
224 if (!pDirectSoundCreate)
226 Con_SafePrintf ("Couldn't get DS proc addr\n");
231 while ((hresult = iDirectSoundCreate(NULL, &pDS, NULL)) != DS_OK)
233 if (hresult != DSERR_ALLOCATED)
235 Con_SafePrintf ("DirectSound create failed\n");
239 if (MessageBox (NULL,
240 "The sound hardware is in use by another app.\n\n"
241 "Select Retry to try to start sound again or Cancel to run Quake with no sound.",
242 "Sound not available",
243 MB_RETRYCANCEL | MB_SETFOREGROUND | MB_ICONEXCLAMATION) != IDRETRY)
245 Con_SafePrintf ("DirectSoundCreate failure\n"
246 " hardware already in use\n");
251 dscaps.dwSize = sizeof(dscaps);
253 if (DS_OK != pDS->lpVtbl->GetCaps (pDS, &dscaps))
255 Con_SafePrintf ("Couldn't get DS caps\n");
258 if (dscaps.dwFlags & DSCAPS_EMULDRIVER)
260 Con_SafePrintf ("No DirectSound driver installed\n");
265 if (DS_OK != pDS->lpVtbl->SetCooperativeLevel (pDS, mainwindow, DSSCL_EXCLUSIVE))
267 Con_SafePrintf ("Set coop level failed\n");
272 // get access to the primary buffer, if possible, so we can set the
273 // sound hardware format
274 memset (&dsbuf, 0, sizeof(dsbuf));
275 dsbuf.dwSize = sizeof(DSBUFFERDESC);
276 dsbuf.dwFlags = DSBCAPS_PRIMARYBUFFER;
277 dsbuf.dwBufferBytes = 0;
278 dsbuf.lpwfxFormat = NULL;
280 memset(&dsbcaps, 0, sizeof(dsbcaps));
281 dsbcaps.dwSize = sizeof(dsbcaps);
282 primary_format_set = false;
284 if (!COM_CheckParm ("-snoforceformat"))
286 if (DS_OK == pDS->lpVtbl->CreateSoundBuffer(pDS, &dsbuf, &pDSPBuf, NULL))
290 if (DS_OK != pDSPBuf->lpVtbl->SetFormat (pDSPBuf, &pformat))
293 Con_SafePrintf ("Set primary sound buffer format: no\n");
298 Con_SafePrintf ("Set primary sound buffer format: yes\n");
300 primary_format_set = true;
305 if (!primary_format_set || !COM_CheckParm ("-primarysound"))
307 // create the secondary buffer we'll actually work with
308 memset (&dsbuf, 0, sizeof(dsbuf));
309 dsbuf.dwSize = sizeof(DSBUFFERDESC);
310 dsbuf.dwFlags = DSBCAPS_CTRLFREQUENCY | DSBCAPS_LOCSOFTWARE;
311 dsbuf.dwBufferBytes = SECONDARY_BUFFER_SIZE;
312 dsbuf.lpwfxFormat = &format;
314 memset(&dsbcaps, 0, sizeof(dsbcaps));
315 dsbcaps.dwSize = sizeof(dsbcaps);
317 if (DS_OK != pDS->lpVtbl->CreateSoundBuffer(pDS, &dsbuf, &pDSBuf, NULL))
319 Con_SafePrintf ("DS:CreateSoundBuffer Failed");
324 shm->channels = format.nChannels;
325 shm->samplebits = format.wBitsPerSample;
326 shm->speed = format.nSamplesPerSec;
328 if (DS_OK != pDSBuf->lpVtbl->GetCaps (pDSBuf, &dsbcaps))
330 Con_SafePrintf ("DS:GetCaps failed\n");
336 Con_SafePrintf ("Using secondary sound buffer\n");
340 if (DS_OK != pDS->lpVtbl->SetCooperativeLevel (pDS, mainwindow, DSSCL_WRITEPRIMARY))
342 Con_SafePrintf ("Set coop level failed\n");
347 if (DS_OK != pDSPBuf->lpVtbl->GetCaps (pDSPBuf, &dsbcaps))
349 Con_Printf ("DS:GetCaps failed\n");
354 Con_SafePrintf ("Using primary sound buffer\n");
357 // Make sure mixer is active
358 pDSBuf->lpVtbl->Play(pDSBuf, 0, 0, DSBPLAY_LOOPING);
361 Con_SafePrintf(" %d channel(s)\n"
364 shm->channels, shm->samplebits, shm->speed);
366 gSndBufSize = dsbcaps.dwBufferBytes;
368 // initialize the buffer
371 while ((hresult = pDSBuf->lpVtbl->Lock(pDSBuf, 0, gSndBufSize, &lpData, &dwSize, NULL, NULL, 0)) != DS_OK)
373 if (hresult != DSERR_BUFFERLOST)
375 Con_SafePrintf ("SNDDMA_InitDirect: DS::Lock Sound Buffer Failed\n");
382 Con_SafePrintf ("SNDDMA_InitDirect: DS: couldn't restore buffer\n");
389 memset(lpData, 0, dwSize);
390 // lpData[4] = lpData[5] = 0x7f; // force a pop for debugging
392 pDSBuf->lpVtbl->Unlock(pDSBuf, lpData, dwSize, NULL, 0);
394 /* we don't want anyone to access the buffer directly w/o locking it first. */
397 pDSBuf->lpVtbl->Stop(pDSBuf);
398 pDSBuf->lpVtbl->GetCurrentPosition(pDSBuf, &mmstarttime.u.sample, &dwWrite);
399 pDSBuf->lpVtbl->Play(pDSBuf, 0, 0, DSBPLAY_LOOPING);
401 shm->soundalive = true;
402 shm->splitbuffer = false;
403 shm->samples = gSndBufSize/(shm->samplebits/8);
405 shm->submission_chunk = 1;
406 shm->buffer = (unsigned char *) lpData;
407 sample16 = (shm->samplebits/8) - 1;
419 Crappy windows multimedia base
422 qboolean SNDDMA_InitWav (void)
434 shm->samplebits = 16;
437 memset (&format, 0, sizeof(format));
438 format.wFormatTag = WAVE_FORMAT_PCM;
439 format.nChannels = shm->channels;
440 format.wBitsPerSample = shm->samplebits;
441 format.nSamplesPerSec = shm->speed;
442 format.nBlockAlign = format.nChannels
443 *format.wBitsPerSample / 8;
445 format.nAvgBytesPerSec = format.nSamplesPerSec
448 /* Open a waveform device for output using window callback. */
449 while ((hr = waveOutOpen((LPHWAVEOUT)&hWaveOut, WAVE_MAPPER,
451 0, 0L, CALLBACK_NULL)) != MMSYSERR_NOERROR)
453 if (hr != MMSYSERR_ALLOCATED)
455 Con_SafePrintf ("waveOutOpen failed\n");
459 if (MessageBox (NULL,
460 "The sound hardware is in use by another app.\n\n"
461 "Select Retry to try to start sound again or Cancel to run Quake with no sound.",
462 "Sound not available",
463 MB_RETRYCANCEL | MB_SETFOREGROUND | MB_ICONEXCLAMATION) != IDRETRY)
465 Con_SafePrintf ("waveOutOpen failure;\n"
466 " hardware already in use\n");
472 * Allocate and lock memory for the waveform data. The memory
473 * for waveform data must be globally allocated with
474 * GMEM_MOVEABLE and GMEM_SHARE flags.
477 gSndBufSize = WAV_BUFFERS*WAV_BUFFER_SIZE;
478 hData = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, gSndBufSize);
481 Con_SafePrintf ("Sound: Out of memory.\n");
485 lpData = GlobalLock(hData);
488 Con_SafePrintf ("Sound: Failed to lock.\n");
492 memset (lpData, 0, gSndBufSize);
495 * Allocate and lock memory for the header. This memory must
496 * also be globally allocated with GMEM_MOVEABLE and
499 hWaveHdr = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE,
500 (DWORD) sizeof(WAVEHDR) * WAV_BUFFERS);
502 if (hWaveHdr == NULL)
504 Con_SafePrintf ("Sound: Failed to Alloc header.\n");
509 lpWaveHdr = (LPWAVEHDR) GlobalLock(hWaveHdr);
511 if (lpWaveHdr == NULL)
513 Con_SafePrintf ("Sound: Failed to lock header.\n");
518 memset (lpWaveHdr, 0, sizeof(WAVEHDR) * WAV_BUFFERS);
520 /* After allocation, set up and prepare headers. */
521 for (i=0 ; i<WAV_BUFFERS ; i++)
523 lpWaveHdr[i].dwBufferLength = WAV_BUFFER_SIZE;
524 lpWaveHdr[i].lpData = lpData + i*WAV_BUFFER_SIZE;
526 if (waveOutPrepareHeader(hWaveOut, lpWaveHdr+i, sizeof(WAVEHDR)) !=
529 Con_SafePrintf ("Sound: failed to prepare wave headers\n");
535 shm->soundalive = true;
536 shm->splitbuffer = false;
537 shm->samples = gSndBufSize/(shm->samplebits/8);
539 shm->submission_chunk = 1;
540 shm->buffer = (unsigned char *) lpData;
541 sample16 = (shm->samplebits/8) - 1;
552 Try to find a sound device to mix for.
553 Returns false if nothing is found.
557 int SNDDMA_Init(void)
561 if (COM_CheckParm ("-wavonly"))
564 dsound_init = wav_init = 0;
566 stat = SIS_FAILURE; // assume DirectSound won't initialize
568 /* Init DirectSound */
571 if (snd_firsttime || snd_isdirect)
573 stat = SNDDMA_InitDirect ();;
575 if (stat == SIS_SUCCESS)
580 Con_SafePrintf ("DirectSound initialized\n");
584 snd_isdirect = false;
585 Con_SafePrintf ("DirectSound failed to init\n");
590 // if DirectSound didn't succeed in initializing, try to initialize
591 // waveOut sound, unless DirectSound failed because the hardware is
592 // already allocated (in which case the user has already chosen not
594 if (!dsound_init && (stat != SIS_NOTAVAIL))
596 if (snd_firsttime || snd_iswave)
599 snd_iswave = SNDDMA_InitWav ();
604 Con_SafePrintf ("Wave sound initialized\n");
608 Con_SafePrintf ("Wave sound failed to init\n");
613 snd_firsttime = false;
615 if (!dsound_init && !wav_init)
617 // if (snd_firsttime)
618 // Con_SafePrintf ("No sound device initialized\n");
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;
655 s &= (shm->samples-1);
664 Send sound to device if buffer isn't really the dma buffer
667 void SNDDMA_Submit(void)
676 // find which sound blocks have completed
680 if ( snd_completed == snd_sent )
682 Con_DPrintf ("Sound overrun\n");
686 if ( ! (lpWaveHdr[ snd_completed & WAV_MASK].dwFlags & WHDR_DONE) )
691 snd_completed++; // this buffer has been played
695 // submit two new sound blocks
697 while (((snd_sent - snd_completed) >> sample16) < 4)
699 h = lpWaveHdr + ( snd_sent&WAV_MASK );
703 * Now the data block can be sent to the output device. The
704 * waveOutWrite function returns immediately and waveform
705 * data is sent to the output device in the background.
707 wResult = waveOutWrite(hWaveOut, h, sizeof(WAVEHDR));
709 if (wResult != MMSYSERR_NOERROR)
711 Con_SafePrintf ("Failed to write block to device\n");
722 Reset the sound device for exiting
725 void SNDDMA_Shutdown(void)