2
===========================================================================
3
Copyright (C) 1999-2005 Id Software, Inc.
5
This file is part of Quake III Arena source code.
7
Quake III Arena source code is free software; you can redistribute it
8
and/or modify it under the terms of the GNU General Public License as
9
published by the Free Software Foundation; either version 2 of the License,
10
or (at your option) any later version.
12
Quake III Arena source code is distributed in the hope that it will be
13
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
14
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
GNU General Public License for more details.
17
You should have received a copy of the GNU General Public License
18
along with Quake III Arena source code; if not, write to the Free Software
19
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20
===========================================================================
24
#include "../client/snd_local.h"
25
#include "win_local.h"
27
HRESULT (WINAPI *pDirectSoundCreate)(GUID FAR *lpGUID, LPDIRECTSOUND FAR *lplpDS, IUnknown FAR *pUnkOuter);
28
#define iDirectSoundCreate(a,b,c) pDirectSoundCreate(a,b,c)
30
#define SECONDARY_BUFFER_SIZE 0x10000
33
static qboolean dsound_init;
35
static DWORD gSndBufSize;
36
static DWORD locksize;
37
static LPDIRECTSOUND pDS;
38
static LPDIRECTSOUNDBUFFER pDSBuf, pDSPBuf;
39
static HINSTANCE hInstDS;
42
static const char *DSoundError( int error ) {
44
case DSERR_BUFFERLOST:
45
return "DSERR_BUFFERLOST";
46
case DSERR_INVALIDCALL:
47
return "DSERR_INVALIDCALLS";
48
case DSERR_INVALIDPARAM:
49
return "DSERR_INVALIDPARAM";
50
case DSERR_PRIOLEVELNEEDED:
51
return "DSERR_PRIOLEVELNEEDED";
62
void SNDDMA_Shutdown( void ) {
63
Com_DPrintf( "Shutting down sound system\n" );
66
Com_DPrintf( "Destroying DS buffers\n" );
69
Com_DPrintf( "...setting NORMAL coop level\n" );
70
pDS->lpVtbl->SetCooperativeLevel( pDS, g_wv.hWnd, DSSCL_PRIORITY );
75
Com_DPrintf( "...stopping and releasing sound buffer\n" );
76
pDSBuf->lpVtbl->Stop( pDSBuf );
77
pDSBuf->lpVtbl->Release( pDSBuf );
80
// only release primary buffer if it's not also the mixing buffer we just released
81
if ( pDSPBuf && ( pDSBuf != pDSPBuf ) )
83
Com_DPrintf( "...releasing primary buffer\n" );
84
pDSPBuf->lpVtbl->Release( pDSPBuf );
91
Com_DPrintf( "...releasing DS object\n" );
92
pDS->lpVtbl->Release( pDS );
96
Com_DPrintf( "...freeing DSOUND.DLL\n" );
97
FreeLibrary( hInstDS );
104
dsound_init = qfalse;
105
memset ((void *)&dma, 0, sizeof (dma));
113
Initialize direct sound
114
Returns false if failed
117
qboolean SNDDMA_Init(void) {
119
memset ((void *)&dma, 0, sizeof (dma));
124
if ( !SNDDMA_InitDS () ) {
130
Com_DPrintf("Completed successfully\n" );
137
#define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
139
= { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } }
141
// DirectSound Component GUID {47D4D946-62E8-11CF-93BC-444553540000}
142
DEFINE_GUID(CLSID_DirectSound, 0x47d4d946, 0x62e8, 0x11cf, 0x93, 0xbc, 0x44, 0x45, 0x53, 0x54, 0x0, 0x0);
144
// DirectSound 8.0 Component GUID {3901CC3F-84B5-4FA4-BA35-AA8172B8A09B}
145
DEFINE_GUID(CLSID_DirectSound8, 0x3901cc3f, 0x84b5, 0x4fa4, 0xba, 0x35, 0xaa, 0x81, 0x72, 0xb8, 0xa0, 0x9b);
147
DEFINE_GUID(IID_IDirectSound8, 0xC50A7E93, 0xF395, 0x4834, 0x9E, 0xF6, 0x7F, 0xA9, 0x9D, 0xE5, 0x09, 0x66);
148
DEFINE_GUID(IID_IDirectSound, 0x279AFA83, 0x4981, 0x11CE, 0xA5, 0x21, 0x00, 0x20, 0xAF, 0x0B, 0xE5, 0x60);
159
Com_Printf( "Initializing DirectSound\n");
162
// Create IDirectSound using the primary sound device
163
if( FAILED( hresult = CoCreateInstance(&CLSID_DirectSound8, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectSound8, (void **)&pDS))) {
165
if( FAILED( hresult = CoCreateInstance(&CLSID_DirectSound, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectSound, (void **)&pDS))) {
166
Com_Printf ("failed\n");
172
hresult = pDS->lpVtbl->Initialize( pDS, NULL);
174
Com_DPrintf( "ok\n" );
176
Com_DPrintf("...setting DSSCL_PRIORITY coop level: " );
178
if ( DS_OK != pDS->lpVtbl->SetCooperativeLevel( pDS, g_wv.hWnd, DSSCL_PRIORITY ) ) {
179
Com_Printf ("failed\n");
183
Com_DPrintf("ok\n" );
186
// create the secondary buffer we'll actually work with
190
// if (s_khz->integer == 44)
191
// dma.speed = 44100;
192
// else if (s_khz->integer == 22)
193
// dma.speed = 22050;
195
// dma.speed = 11025;
198
memset (&format, 0, sizeof(format));
199
format.wFormatTag = WAVE_FORMAT_PCM;
200
format.nChannels = dma.channels;
201
format.wBitsPerSample = dma.samplebits;
202
format.nSamplesPerSec = dma.speed;
203
format.nBlockAlign = format.nChannels * format.wBitsPerSample / 8;
205
format.nAvgBytesPerSec = format.nSamplesPerSec*format.nBlockAlign;
207
memset (&dsbuf, 0, sizeof(dsbuf));
208
dsbuf.dwSize = sizeof(DSBUFFERDESC);
210
// Micah: take advantage of 2D hardware.if available.
211
dsbuf.dwFlags = DSBCAPS_LOCHARDWARE;
213
dsbuf.dwFlags |= DSBCAPS_GETCURRENTPOSITION2;
215
dsbuf.dwBufferBytes = SECONDARY_BUFFER_SIZE;
216
dsbuf.lpwfxFormat = &format;
218
memset(&dsbcaps, 0, sizeof(dsbcaps));
219
dsbcaps.dwSize = sizeof(dsbcaps);
221
Com_DPrintf( "...creating secondary buffer: " );
222
if (DS_OK == pDS->lpVtbl->CreateSoundBuffer(pDS, &dsbuf, &pDSBuf, NULL)) {
223
Com_Printf( "locked hardware. ok\n" );
226
// Couldn't get hardware, fallback to software.
227
dsbuf.dwFlags = DSBCAPS_LOCSOFTWARE;
229
dsbuf.dwFlags |= DSBCAPS_GETCURRENTPOSITION2;
231
if (DS_OK != pDS->lpVtbl->CreateSoundBuffer(pDS, &dsbuf, &pDSBuf, NULL)) {
232
Com_Printf( "failed\n" );
236
Com_DPrintf( "forced to software. ok\n" );
239
// Make sure mixer is active
240
if ( DS_OK != pDSBuf->lpVtbl->Play(pDSBuf, 0, 0, DSBPLAY_LOOPING) ) {
241
Com_Printf ("*** Looped sound play failed ***\n");
246
// get the returned buffer size
247
if ( DS_OK != pDSBuf->lpVtbl->GetCaps (pDSBuf, &dsbcaps) ) {
248
Com_Printf ("*** GetCaps failed ***\n");
253
gSndBufSize = dsbcaps.dwBufferBytes;
255
dma.channels = format.nChannels;
256
dma.samplebits = format.wBitsPerSample;
257
dma.speed = format.nSamplesPerSec;
258
dma.samples = gSndBufSize/(dma.samplebits/8);
259
dma.submission_chunk = 1;
260
dma.buffer = NULL; // must be locked first
262
sample16 = (dma.samplebits/8) - 1;
264
SNDDMA_BeginPainting ();
266
memset(dma.buffer, 0, dma.samples * dma.samplebits/8);
274
return the current sample position (in mono samples read)
275
inside the recirculating dma buffer, so the mixing code will know
276
how many sample are required to fill it up.
279
int SNDDMA_GetDMAPos( void ) {
284
if ( !dsound_init ) {
288
mmtime.wType = TIME_SAMPLES;
289
pDSBuf->lpVtbl->GetCurrentPosition(pDSBuf, &mmtime.u.sample, &dwWrite);
295
s &= (dma.samples-1);
304
Makes sure dma.buffer is valid
307
void SNDDMA_BeginPainting( void ) {
318
// if the buffer was lost or stopped, restore it and/or restart it
319
if ( pDSBuf->lpVtbl->GetStatus (pDSBuf, &dwStatus) != DS_OK ) {
320
Com_Printf ("Couldn't get sound buffer status\n");
323
if (dwStatus & DSBSTATUS_BUFFERLOST)
324
pDSBuf->lpVtbl->Restore (pDSBuf);
326
if (!(dwStatus & DSBSTATUS_PLAYING))
327
pDSBuf->lpVtbl->Play(pDSBuf, 0, 0, DSBPLAY_LOOPING);
329
// lock the dsound buffer
334
while ((hresult = pDSBuf->lpVtbl->Lock(pDSBuf, 0, gSndBufSize, (LPVOID)&pbuf, &locksize,
335
(LPVOID)&pbuf2, &dwSize2, 0)) != DS_OK)
337
if (hresult != DSERR_BUFFERLOST)
339
Com_Printf( "SNDDMA_BeginPainting: Lock failed with error '%s'\n", DSoundError( hresult ) );
345
pDSBuf->lpVtbl->Restore( pDSBuf );
351
dma.buffer = (unsigned char *)pbuf;
358
Send sound to device if buffer isn't really the dma buffer
359
Also unlocks the dsound buffer
362
void SNDDMA_Submit( void ) {
363
// unlock the dsound buffer
365
pDSBuf->lpVtbl->Unlock(pDSBuf, dma.buffer, locksize, NULL, 0);
374
When we change windows we need to do this
377
void SNDDMA_Activate( void ) {
382
if ( DS_OK != pDS->lpVtbl->SetCooperativeLevel( pDS, g_wv.hWnd, DSSCL_PRIORITY ) ) {
383
Com_Printf ("sound SetCooperativeLevel failed\n");