Quake II RTX doxygen  1.0 dev
dsound.c File Reference
#include "client.h"
#include "client/sound/dma.h"
#include <mmsystem.h>
#include <dsound.h>

Go to the source code of this file.

Macros

#define SECONDARY_BUFFER_SIZE   0x10000
 

Typedefs

typedef HRESULT(WINAPI * LPDIRECTSOUNDCREATE) (LPCGUID, LPDIRECTSOUND *, LPUNKNOWN)
 

Functions

static const char * DSoundError (int error)
 
static void DS_DestroyBuffers (void)
 
static void DS_Shutdown (void)
 
static qboolean DS_CreateBuffers (void)
 
static sndinitstat_t DS_Init (void)
 
static void DS_BeginPainting (void)
 
static void DS_Submit (void)
 
static void DS_Activate (qboolean active)
 
void DS_FillAPI (snddmaAPI_t *api)
 

Variables

static int sample16
 
static DWORD locksize
 
static MMTIME mmstarttime
 
static LPDIRECTSOUND pDS
 
static LPDIRECTSOUNDBUFFER pDSBuf
 
static LPDIRECTSOUNDBUFFER pDSPBuf
 
static HINSTANCE hInstDS
 
static DWORD gSndBufSize
 

Macro Definition Documentation

◆ SECONDARY_BUFFER_SIZE

#define SECONDARY_BUFFER_SIZE   0x10000

Definition at line 26 of file dsound.c.

Typedef Documentation

◆ LPDIRECTSOUNDCREATE

typedef HRESULT(WINAPI * LPDIRECTSOUNDCREATE) (LPCGUID, LPDIRECTSOUND *, LPUNKNOWN)

Definition at line 24 of file dsound.c.

Function Documentation

◆ DS_Activate()

static void DS_Activate ( qboolean  active)
static

Definition at line 385 of file dsound.c.

386 {
387  if (!pDS) {
388  return;
389  }
390  if (active) {
391  if (!DS_CreateBuffers()) {
392  Com_EPrintf("DS_Activate: DS_CreateBuffers failed\n");
393  DS_Shutdown();
394  }
395  } else {
397  }
398 }

Referenced by DS_FillAPI().

◆ DS_BeginPainting()

static void DS_BeginPainting ( void  )
static

Definition at line 307 of file dsound.c.

308 {
309  int reps, s;
310  DWORD dwSize2;
311  DWORD *pbuf, *pbuf2;
312  HRESULT hresult;
313  DWORD dwStatus, dwWrite;
314  MMTIME mmtime;
315 
316  if (!pDSBuf)
317  return;
318 
319  // get sample pos
320  mmtime.wType = TIME_SAMPLES;
321  IDirectSoundBuffer_GetCurrentPosition(pDSBuf, &mmtime.u.sample, &dwWrite);
322  s = (mmtime.u.sample - mmstarttime.u.sample) >> sample16;
323  dma.samplepos = s & (dma.samples - 1);
324 
325  // if the buffer was lost or stopped, restore it and/or restart it
326  if (IDirectSoundBuffer_GetStatus(pDSBuf, &dwStatus) != DS_OK) {
327  Com_EPrintf("DS_BeginPainting: Couldn't get sound buffer status\n");
328  DS_Shutdown();
329  return;
330  }
331 
332  if (dwStatus & DSBSTATUS_BUFFERLOST)
333  IDirectSoundBuffer_Restore(pDSBuf);
334 
335  if (!(dwStatus & DSBSTATUS_PLAYING))
336  IDirectSoundBuffer_Play(pDSBuf, 0, 0, DSBPLAY_LOOPING);
337 
338  // lock the dsound buffer
339 
340  reps = 0;
341  dma.buffer = NULL;
342 
343  while ((hresult = IDirectSoundBuffer_Lock(pDSBuf, 0, gSndBufSize, (void **)&pbuf, &locksize,
344  (void **)&pbuf2, &dwSize2, 0)) != DS_OK) {
345  if (hresult != DSERR_BUFFERLOST) {
346  Com_EPrintf("DS_BeginPainting: Lock failed with error '%s'\n", DSoundError(hresult));
347  DS_Shutdown();
348  return;
349  }
350 
351  IDirectSoundBuffer_Restore(pDSBuf);
352 
353  if (++reps > 2)
354  return;
355  }
356  dma.buffer = (byte *)pbuf;
357 }

Referenced by DS_FillAPI().

◆ DS_CreateBuffers()

static qboolean DS_CreateBuffers ( void  )
static

Definition at line 118 of file dsound.c.

119 {
120  DSBUFFERDESC dsbuf;
121  DSBCAPS dsbcaps;
122  WAVEFORMATEX format;
123  DWORD dwWrite;
124 
125  memset(&format, 0, sizeof(format));
126  format.wFormatTag = WAVE_FORMAT_PCM;
127  format.nChannels = dma.channels;
128  format.wBitsPerSample = dma.samplebits;
129  format.nSamplesPerSec = dma.speed;
130  format.nBlockAlign = format.nChannels * format.wBitsPerSample / 8;
131  format.cbSize = sizeof(format);
132  format.nAvgBytesPerSec = format.nSamplesPerSec * format.nBlockAlign;
133 
134  Com_DPrintf("Creating DS buffer\n");
135 
136  Com_DPrintf("...setting PRIORITY coop level: ");
137  if (DS_OK != IDirectSound_SetCooperativeLevel(pDS, win.wnd, DSSCL_PRIORITY)) {
138  Com_DPrintf("failed\n");
139  return qfalse;
140  }
141  Com_DPrintf("ok\n");
142 
143 // create the secondary buffer we'll actually work with
144  memset(&dsbuf, 0, sizeof(dsbuf));
145  dsbuf.dwSize = sizeof(DSBUFFERDESC);
146  dsbuf.dwFlags = DSBCAPS_CTRLFREQUENCY | DSBCAPS_LOCHARDWARE;
147  dsbuf.dwBufferBytes = SECONDARY_BUFFER_SIZE;
148  dsbuf.lpwfxFormat = &format;
149 
150  memset(&dsbcaps, 0, sizeof(dsbcaps));
151  dsbcaps.dwSize = sizeof(dsbcaps);
152 
153  Com_DPrintf("...creating secondary buffer: ");
154  if (DS_OK != IDirectSound_CreateSoundBuffer(pDS, &dsbuf, &pDSBuf, NULL)) {
155  dsbuf.dwFlags = DSBCAPS_CTRLFREQUENCY | DSBCAPS_LOCSOFTWARE;
156  if (DS_OK != IDirectSound_CreateSoundBuffer(pDS, &dsbuf, &pDSBuf, NULL)) {
157  Com_DPrintf("failed\n");
158  return qfalse;
159  }
160 
161  Com_DPrintf("ok\n...forced to software\n");
162  } else {
163  Com_DPrintf("ok\n...locked hardware\n");
164  }
165 
166  dma.channels = format.nChannels;
167  dma.samplebits = format.wBitsPerSample;
168  dma.speed = format.nSamplesPerSec;
169 
170  if (DS_OK != IDirectSoundBuffer_GetCaps(pDSBuf, &dsbcaps)) {
171  Com_DPrintf("*** GetCaps failed ***\n");
172  return qfalse;
173  }
174 
175  // Make sure mixer is active
176  if (DS_OK != IDirectSoundBuffer_Play(pDSBuf, 0, 0, DSBPLAY_LOOPING)) {
177  Com_DPrintf("*** Play failed ***\n");
178  return qfalse;
179  }
180 
181  Com_DPrintf(" %d channel(s)\n"
182  " %d bits/sample\n"
183  " %d bytes/sec\n",
184  dma.channels, dma.samplebits, dma.speed);
185 
186  gSndBufSize = dsbcaps.dwBufferBytes;
187 
188  IDirectSoundBuffer_Stop(pDSBuf);
189  IDirectSoundBuffer_GetCurrentPosition(pDSBuf, &mmstarttime.u.sample, &dwWrite);
190  IDirectSoundBuffer_Play(pDSBuf, 0, 0, DSBPLAY_LOOPING);
191 
192  dma.samples = gSndBufSize / (dma.samplebits / 8);
193  dma.samplepos = 0;
194  dma.submission_chunk = 1;
195  dma.buffer = NULL;
196  sample16 = (dma.samplebits / 8) - 1;
197 
198  return qtrue;
199 }

Referenced by DS_Activate(), and DS_Init().

◆ DS_DestroyBuffers()

static void DS_DestroyBuffers ( void  )
static

Definition at line 61 of file dsound.c.

62 {
63  Com_DPrintf("Destroying DS buffers\n");
64  if (pDS) {
65  Com_DPrintf("...setting NORMAL coop level\n");
66  IDirectSound_SetCooperativeLevel(pDS, win.wnd, DSSCL_NORMAL);
67  }
68 
69  if (pDSBuf) {
70  Com_DPrintf("...stopping and releasing sound buffer\n");
71  IDirectSoundBuffer_Stop(pDSBuf);
72  IDirectSoundBuffer_Release(pDSBuf);
73  }
74 
75  // only release primary buffer if it's not also the mixing buffer we just released
76  if (pDSPBuf && (pDSBuf != pDSPBuf)) {
77  Com_DPrintf("...releasing primary buffer\n");
78  IDirectSoundBuffer_Release(pDSPBuf);
79  }
80  pDSBuf = NULL;
81  pDSPBuf = NULL;
82 
83  dma.buffer = NULL;
84 }

Referenced by DS_Activate(), and DS_Shutdown().

◆ DS_FillAPI()

void DS_FillAPI ( snddmaAPI_t *  api)

Definition at line 400 of file dsound.c.

401 {
402  api->Init = DS_Init;
403  api->Shutdown = DS_Shutdown;
404  api->BeginPainting = DS_BeginPainting;
405  api->Submit = DS_Submit;
406  api->Activate = DS_Activate;
407 }

Referenced by DMA_Init().

◆ DS_Init()

static sndinitstat_t DS_Init ( void  )
static

Definition at line 210 of file dsound.c.

211 {
212  DSCAPS dscaps;
213  HRESULT hresult;
214  LPDIRECTSOUNDCREATE pDirectSoundCreate;
215 
216  memset(&dma, 0, sizeof(dma));
217  dma.channels = 2;
218  dma.samplebits = 16;
219 
220  switch (s_khz->integer) {
221  case 48:
222  dma.speed = 48000;
223  break;
224  case 44:
225  dma.speed = 44100;
226  break;
227  case 22:
228  dma.speed = 22050;
229  break;
230  default:
231  dma.speed = 11025;
232  break;
233  }
234 
235  Com_DPrintf("Initializing DirectSound\n");
236 
237  if (!hInstDS) {
238  Com_DPrintf("...loading dsound.dll: ");
239  hInstDS = LoadLibrary("dsound.dll");
240  if (hInstDS == NULL) {
241  Com_DPrintf("failed\n");
242  return SIS_FAILURE;
243  }
244  Com_DPrintf("ok\n");
245  }
246 
247  pDirectSoundCreate = (LPDIRECTSOUNDCREATE)
248  GetProcAddress(hInstDS, "DirectSoundCreate");
249  if (!pDirectSoundCreate) {
250  Com_DPrintf("...couldn't get DS proc addr\n");
251  return SIS_FAILURE;
252  }
253 
254  Com_DPrintf("...creating DS object: ");
255  while ((hresult = pDirectSoundCreate(NULL, &pDS, NULL)) != DS_OK) {
256  if (hresult != DSERR_ALLOCATED) {
257  Com_DPrintf("failed\n");
258  return SIS_FAILURE;
259  }
260 
261  if (MessageBox(NULL,
262  "The sound hardware is in use by another app.\n\n"
263  "Select Retry to try to start sound again or Cancel to run " PRODUCT " with no sound.",
264  "Sound not available",
265  MB_RETRYCANCEL | MB_SETFOREGROUND | MB_ICONEXCLAMATION) != IDRETRY) {
266  Com_DPrintf("failed, hardware already in use\n");
267  return SIS_NOTAVAIL;
268  }
269  }
270  Com_DPrintf("ok\n");
271 
272  dscaps.dwSize = sizeof(dscaps);
273 
274  if (DS_OK != IDirectSound_GetCaps(pDS, &dscaps)) {
275  Com_DPrintf("...couldn't get DS caps\n");
276  DS_Shutdown();
277  return SIS_FAILURE;
278  }
279 
280  if (dscaps.dwFlags & DSCAPS_EMULDRIVER) {
281  Com_DPrintf("...no DSound driver found\n");
282  DS_Shutdown();
283  return SIS_FAILURE;
284  }
285 
286  if (!DS_CreateBuffers()) {
287  DS_Shutdown();
288  return SIS_FAILURE;
289  }
290 
291  Com_Printf("DirectSound initialized\n");
292 
293  return SIS_SUCCESS;
294 }

Referenced by DS_FillAPI().

◆ DS_Shutdown()

static void DS_Shutdown ( void  )
static

Definition at line 93 of file dsound.c.

94 {
95  Com_Printf("Shutting down DirectSound\n");
96 
97  if (pDS) {
99 
100  Com_DPrintf("...releasing DS object\n");
101  IDirectSound_Release(pDS);
102  }
103 
104  if (hInstDS) {
105  Com_DPrintf("...freeing DSOUND.DLL\n");
106  FreeLibrary(hInstDS);
107  hInstDS = NULL;
108  }
109 
110  pDS = NULL;
111  pDSBuf = NULL;
112  pDSPBuf = NULL;
113 }

Referenced by DS_Activate(), DS_BeginPainting(), DS_FillAPI(), and DS_Init().

◆ DS_Submit()

static void DS_Submit ( void  )
static

Definition at line 367 of file dsound.c.

368 {
369  if (!pDSBuf)
370  return;
371 
372  // unlock the dsound buffer
373  IDirectSoundBuffer_Unlock(pDSBuf, dma.buffer, locksize, NULL, 0);
374 }

Referenced by DS_FillAPI().

◆ DSoundError()

static const char* DSoundError ( int  error)
static

Definition at line 42 of file dsound.c.

43 {
44  switch (error) {
45  case DSERR_BUFFERLOST:
46  return "DSERR_BUFFERLOST";
47  case DSERR_INVALIDCALL:
48  return "DSERR_INVALIDCALL";
49  case DSERR_INVALIDPARAM:
50  return "DSERR_INVALIDPARAM";
51  case DSERR_PRIOLEVELNEEDED:
52  return "DSERR_PRIOLEVELNEEDED";
53  }
54 
55  return "<unknown error>";
56 }

Referenced by DS_BeginPainting().

Variable Documentation

◆ gSndBufSize

DWORD gSndBufSize
static

Definition at line 40 of file dsound.c.

Referenced by DS_BeginPainting(), and DS_CreateBuffers().

◆ hInstDS

HINSTANCE hInstDS
static

Definition at line 38 of file dsound.c.

Referenced by DS_Init(), and DS_Shutdown().

◆ locksize

DWORD locksize
static

Definition at line 31 of file dsound.c.

Referenced by DS_BeginPainting(), and DS_Submit().

◆ mmstarttime

MMTIME mmstarttime
static

Definition at line 33 of file dsound.c.

Referenced by DS_BeginPainting(), and DS_CreateBuffers().

◆ pDS

LPDIRECTSOUND pDS
static

Definition at line 35 of file dsound.c.

Referenced by DS_Activate(), DS_CreateBuffers(), DS_DestroyBuffers(), DS_Init(), and DS_Shutdown().

◆ pDSBuf

LPDIRECTSOUNDBUFFER pDSBuf
static

◆ pDSPBuf

LPDIRECTSOUNDBUFFER pDSPBuf
static

Definition at line 36 of file dsound.c.

Referenced by DS_DestroyBuffers(), and DS_Shutdown().

◆ sample16

int sample16
static

Definition at line 29 of file dsound.c.

Referenced by DS_BeginPainting(), and DS_CreateBuffers().

dma
dma_t dma
Definition: dma.c:22
s_khz
cvar_t * s_khz
Definition: dma.c:24
pDS
static LPDIRECTSOUND pDS
Definition: dsound.c:35
DSoundError
static const char * DSoundError(int error)
Definition: dsound.c:42
SECONDARY_BUFFER_SIZE
#define SECONDARY_BUFFER_SIZE
Definition: dsound.c:26
DS_BeginPainting
static void DS_BeginPainting(void)
Definition: dsound.c:307
mmstarttime
static MMTIME mmstarttime
Definition: dsound.c:33
locksize
static DWORD locksize
Definition: dsound.c:31
LPDIRECTSOUNDCREATE
HRESULT(WINAPI * LPDIRECTSOUNDCREATE)(LPCGUID, LPDIRECTSOUND *, LPUNKNOWN)
Definition: dsound.c:24
DS_Shutdown
static void DS_Shutdown(void)
Definition: dsound.c:93
DS_Activate
static void DS_Activate(qboolean active)
Definition: dsound.c:385
DS_Init
static sndinitstat_t DS_Init(void)
Definition: dsound.c:210
hInstDS
static HINSTANCE hInstDS
Definition: dsound.c:38
pDSPBuf
static LPDIRECTSOUNDBUFFER pDSPBuf
Definition: dsound.c:36
DS_CreateBuffers
static qboolean DS_CreateBuffers(void)
Definition: dsound.c:118
pDSBuf
static LPDIRECTSOUNDBUFFER pDSBuf
Definition: dsound.c:36
gSndBufSize
static DWORD gSndBufSize
Definition: dsound.c:40
DS_Submit
static void DS_Submit(void)
Definition: dsound.c:367
sample16
static int sample16
Definition: dsound.c:29
win
win_state_t win
Definition: client.c:33
DS_DestroyBuffers
static void DS_DestroyBuffers(void)
Definition: dsound.c:61