~ubuntu-branches/ubuntu/precise/openarena/precise

« back to all changes in this revision

Viewing changes to code/win32/win_snd.c

  • Committer: Bazaar Package Importer
  • Author(s): Bruno "Fuddl" Kleinert
  • Date: 2007-01-20 12:28:09 UTC
  • Revision ID: james.westby@ubuntu.com-20070120122809-2yza5ojt7nqiyiam
Tags: upstream-0.6.0
ImportĀ upstreamĀ versionĀ 0.6.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
===========================================================================
 
3
Copyright (C) 1999-2005 Id Software, Inc.
 
4
 
 
5
This file is part of Quake III Arena source code.
 
6
 
 
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.
 
11
 
 
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.
 
16
 
 
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
===========================================================================
 
21
*/
 
22
#include <float.h>
 
23
 
 
24
#include "../client/snd_local.h"
 
25
#include "win_local.h"
 
26
 
 
27
HRESULT (WINAPI *pDirectSoundCreate)(GUID FAR *lpGUID, LPDIRECTSOUND FAR *lplpDS, IUnknown FAR *pUnkOuter);
 
28
#define iDirectSoundCreate(a,b,c)       pDirectSoundCreate(a,b,c)
 
29
 
 
30
#define SECONDARY_BUFFER_SIZE   0x10000
 
31
 
 
32
 
 
33
static qboolean dsound_init;
 
34
static int              sample16;
 
35
static DWORD    gSndBufSize;
 
36
static DWORD    locksize;
 
37
static LPDIRECTSOUND pDS;
 
38
static LPDIRECTSOUNDBUFFER pDSBuf, pDSPBuf;
 
39
static HINSTANCE hInstDS;
 
40
 
 
41
 
 
42
static const char *DSoundError( int error ) {
 
43
        switch ( 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";
 
52
        }
 
53
 
 
54
        return "unknown";
 
55
}
 
56
 
 
57
/*
 
58
==================
 
59
SNDDMA_Shutdown
 
60
==================
 
61
*/
 
62
void SNDDMA_Shutdown( void ) {
 
63
        Com_DPrintf( "Shutting down sound system\n" );
 
64
 
 
65
        if ( pDS ) {
 
66
                Com_DPrintf( "Destroying DS buffers\n" );
 
67
                if ( pDS )
 
68
                {
 
69
                        Com_DPrintf( "...setting NORMAL coop level\n" );
 
70
                        pDS->lpVtbl->SetCooperativeLevel( pDS, g_wv.hWnd, DSSCL_PRIORITY );
 
71
                }
 
72
 
 
73
                if ( pDSBuf )
 
74
                {
 
75
                        Com_DPrintf( "...stopping and releasing sound buffer\n" );
 
76
                        pDSBuf->lpVtbl->Stop( pDSBuf );
 
77
                        pDSBuf->lpVtbl->Release( pDSBuf );
 
78
                }
 
79
 
 
80
                // only release primary buffer if it's not also the mixing buffer we just released
 
81
                if ( pDSPBuf && ( pDSBuf != pDSPBuf ) )
 
82
                {
 
83
                        Com_DPrintf( "...releasing primary buffer\n" );
 
84
                        pDSPBuf->lpVtbl->Release( pDSPBuf );
 
85
                }
 
86
                pDSBuf = NULL;
 
87
                pDSPBuf = NULL;
 
88
 
 
89
                dma.buffer = NULL;
 
90
 
 
91
                Com_DPrintf( "...releasing DS object\n" );
 
92
                pDS->lpVtbl->Release( pDS );
 
93
        }
 
94
 
 
95
        if ( hInstDS ) {
 
96
                Com_DPrintf( "...freeing DSOUND.DLL\n" );
 
97
                FreeLibrary( hInstDS );
 
98
                hInstDS = NULL;
 
99
        }
 
100
 
 
101
        pDS = NULL;
 
102
        pDSBuf = NULL;
 
103
        pDSPBuf = NULL;
 
104
        dsound_init = qfalse;
 
105
        memset ((void *)&dma, 0, sizeof (dma));
 
106
        CoUninitialize( );
 
107
}
 
108
 
 
109
/*
 
110
==================
 
111
SNDDMA_Init
 
112
 
 
113
Initialize direct sound
 
114
Returns false if failed
 
115
==================
 
116
*/
 
117
qboolean SNDDMA_Init(void) {
 
118
 
 
119
        memset ((void *)&dma, 0, sizeof (dma));
 
120
        dsound_init = 0;
 
121
 
 
122
        CoInitialize(NULL);
 
123
 
 
124
        if ( !SNDDMA_InitDS () ) {
 
125
                return qfalse;
 
126
        }
 
127
 
 
128
        dsound_init = qtrue;
 
129
 
 
130
        Com_DPrintf("Completed successfully\n" );
 
131
 
 
132
    return qtrue;
 
133
}
 
134
 
 
135
#undef DEFINE_GUID
 
136
 
 
137
#define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
 
138
        const GUID name \
 
139
                = { l, w1, w2, { b1, b2,  b3,  b4,  b5,  b6,  b7,  b8 } }
 
140
 
 
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);
 
143
 
 
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);
 
146
 
 
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);
 
149
 
 
150
 
 
151
int SNDDMA_InitDS ()
 
152
{
 
153
        HRESULT                 hresult;
 
154
        DSBUFFERDESC    dsbuf;
 
155
        DSBCAPS                 dsbcaps;
 
156
        WAVEFORMATEX    format;
 
157
        int                             use8;
 
158
 
 
159
        Com_Printf( "Initializing DirectSound\n");
 
160
 
 
161
        use8 = 1;
 
162
    // Create IDirectSound using the primary sound device
 
163
    if( FAILED( hresult = CoCreateInstance(&CLSID_DirectSound8, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectSound8, (void **)&pDS))) {
 
164
                use8 = 0;
 
165
            if( FAILED( hresult = CoCreateInstance(&CLSID_DirectSound, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectSound, (void **)&pDS))) {
 
166
                        Com_Printf ("failed\n");
 
167
                        SNDDMA_Shutdown ();
 
168
                        return qfalse;
 
169
                }
 
170
        }
 
171
 
 
172
        hresult = pDS->lpVtbl->Initialize( pDS, NULL);
 
173
 
 
174
        Com_DPrintf( "ok\n" );
 
175
 
 
176
        Com_DPrintf("...setting DSSCL_PRIORITY coop level: " );
 
177
 
 
178
        if ( DS_OK != pDS->lpVtbl->SetCooperativeLevel( pDS, g_wv.hWnd, DSSCL_PRIORITY ) )      {
 
179
                Com_Printf ("failed\n");
 
180
                SNDDMA_Shutdown ();
 
181
                return qfalse;
 
182
        }
 
183
        Com_DPrintf("ok\n" );
 
184
 
 
185
 
 
186
        // create the secondary buffer we'll actually work with
 
187
        dma.channels = 2;
 
188
        dma.samplebits = 16;
 
189
 
 
190
//      if (s_khz->integer == 44)
 
191
//              dma.speed = 44100;
 
192
//      else if (s_khz->integer == 22)
 
193
//              dma.speed = 22050;
 
194
//      else
 
195
//              dma.speed = 11025;
 
196
 
 
197
        dma.speed = 22050;
 
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;
 
204
    format.cbSize = 0;
 
205
    format.nAvgBytesPerSec = format.nSamplesPerSec*format.nBlockAlign; 
 
206
 
 
207
        memset (&dsbuf, 0, sizeof(dsbuf));
 
208
        dsbuf.dwSize = sizeof(DSBUFFERDESC);
 
209
 
 
210
        // Micah: take advantage of 2D hardware.if available.
 
211
        dsbuf.dwFlags = DSBCAPS_LOCHARDWARE;
 
212
        if (use8) {
 
213
                dsbuf.dwFlags |= DSBCAPS_GETCURRENTPOSITION2;
 
214
        }
 
215
        dsbuf.dwBufferBytes = SECONDARY_BUFFER_SIZE;
 
216
        dsbuf.lpwfxFormat = &format;
 
217
        
 
218
        memset(&dsbcaps, 0, sizeof(dsbcaps));
 
219
        dsbcaps.dwSize = sizeof(dsbcaps);
 
220
        
 
221
        Com_DPrintf( "...creating secondary buffer: " );
 
222
        if (DS_OK == pDS->lpVtbl->CreateSoundBuffer(pDS, &dsbuf, &pDSBuf, NULL)) {
 
223
                Com_Printf( "locked hardware.  ok\n" );
 
224
        }
 
225
        else {
 
226
                // Couldn't get hardware, fallback to software.
 
227
                dsbuf.dwFlags = DSBCAPS_LOCSOFTWARE;
 
228
                if (use8) {
 
229
                        dsbuf.dwFlags |= DSBCAPS_GETCURRENTPOSITION2;
 
230
                }
 
231
                if (DS_OK != pDS->lpVtbl->CreateSoundBuffer(pDS, &dsbuf, &pDSBuf, NULL)) {
 
232
                        Com_Printf( "failed\n" );
 
233
                        SNDDMA_Shutdown ();
 
234
                        return qfalse;
 
235
                }
 
236
                Com_DPrintf( "forced to software.  ok\n" );
 
237
        }
 
238
                
 
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");
 
242
                SNDDMA_Shutdown ();
 
243
                return qfalse;
 
244
        }
 
245
 
 
246
        // get the returned buffer size
 
247
        if ( DS_OK != pDSBuf->lpVtbl->GetCaps (pDSBuf, &dsbcaps) ) {
 
248
                Com_Printf ("*** GetCaps failed ***\n");
 
249
                SNDDMA_Shutdown ();
 
250
                return qfalse;
 
251
        }
 
252
        
 
253
        gSndBufSize = dsbcaps.dwBufferBytes;
 
254
 
 
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
 
261
 
 
262
        sample16 = (dma.samplebits/8) - 1;
 
263
 
 
264
        SNDDMA_BeginPainting ();
 
265
        if (dma.buffer)
 
266
                memset(dma.buffer, 0, dma.samples * dma.samplebits/8);
 
267
        SNDDMA_Submit ();
 
268
        return 1;
 
269
}
 
270
/*
 
271
==============
 
272
SNDDMA_GetDMAPos
 
273
 
 
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.
 
277
===============
 
278
*/
 
279
int SNDDMA_GetDMAPos( void ) {
 
280
        MMTIME  mmtime;
 
281
        int             s;
 
282
        DWORD   dwWrite;
 
283
 
 
284
        if ( !dsound_init ) {
 
285
                return 0;
 
286
        }
 
287
 
 
288
        mmtime.wType = TIME_SAMPLES;
 
289
        pDSBuf->lpVtbl->GetCurrentPosition(pDSBuf, &mmtime.u.sample, &dwWrite);
 
290
 
 
291
        s = mmtime.u.sample;
 
292
 
 
293
        s >>= sample16;
 
294
 
 
295
        s &= (dma.samples-1);
 
296
 
 
297
        return s;
 
298
}
 
299
 
 
300
/*
 
301
==============
 
302
SNDDMA_BeginPainting
 
303
 
 
304
Makes sure dma.buffer is valid
 
305
===============
 
306
*/
 
307
void SNDDMA_BeginPainting( void ) {
 
308
        int             reps;
 
309
        DWORD   dwSize2;
 
310
        DWORD   *pbuf, *pbuf2;
 
311
        HRESULT hresult;
 
312
        DWORD   dwStatus;
 
313
 
 
314
        if ( !pDSBuf ) {
 
315
                return;
 
316
        }
 
317
 
 
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");
 
321
        }
 
322
        
 
323
        if (dwStatus & DSBSTATUS_BUFFERLOST)
 
324
                pDSBuf->lpVtbl->Restore (pDSBuf);
 
325
        
 
326
        if (!(dwStatus & DSBSTATUS_PLAYING))
 
327
                pDSBuf->lpVtbl->Play(pDSBuf, 0, 0, DSBPLAY_LOOPING);
 
328
 
 
329
        // lock the dsound buffer
 
330
 
 
331
        reps = 0;
 
332
        dma.buffer = NULL;
 
333
 
 
334
        while ((hresult = pDSBuf->lpVtbl->Lock(pDSBuf, 0, gSndBufSize, (LPVOID)&pbuf, &locksize, 
 
335
                                                                   (LPVOID)&pbuf2, &dwSize2, 0)) != DS_OK)
 
336
        {
 
337
                if (hresult != DSERR_BUFFERLOST)
 
338
                {
 
339
                        Com_Printf( "SNDDMA_BeginPainting: Lock failed with error '%s'\n", DSoundError( hresult ) );
 
340
                        S_Shutdown ();
 
341
                        return;
 
342
                }
 
343
                else
 
344
                {
 
345
                        pDSBuf->lpVtbl->Restore( pDSBuf );
 
346
                }
 
347
 
 
348
                if (++reps > 2)
 
349
                        return;
 
350
        }
 
351
        dma.buffer = (unsigned char *)pbuf;
 
352
}
 
353
 
 
354
/*
 
355
==============
 
356
SNDDMA_Submit
 
357
 
 
358
Send sound to device if buffer isn't really the dma buffer
 
359
Also unlocks the dsound buffer
 
360
===============
 
361
*/
 
362
void SNDDMA_Submit( void ) {
 
363
    // unlock the dsound buffer
 
364
        if ( pDSBuf ) {
 
365
                pDSBuf->lpVtbl->Unlock(pDSBuf, dma.buffer, locksize, NULL, 0);
 
366
        }
 
367
}
 
368
 
 
369
 
 
370
/*
 
371
=================
 
372
SNDDMA_Activate
 
373
 
 
374
When we change windows we need to do this
 
375
=================
 
376
*/
 
377
void SNDDMA_Activate( void ) {
 
378
        if ( !pDS ) {
 
379
                return;
 
380
        }
 
381
 
 
382
        if ( DS_OK != pDS->lpVtbl->SetCooperativeLevel( pDS, g_wv.hWnd, DSSCL_PRIORITY ) )      {
 
383
                Com_Printf ("sound SetCooperativeLevel failed\n");
 
384
                SNDDMA_Shutdown ();
 
385
        }
 
386
}
 
387
 
 
388