]> icculus.org git repositories - taylor/freespace2.git/blob - src/sound/ds.cpp
Initial revision
[taylor/freespace2.git] / src / sound / ds.cpp
1 /*
2  * $Logfile: /Freespace2/code/Sound/ds.cpp $
3  * $Revision$
4  * $Date$
5  * $Author$
6  *
7  * C file for interface to DirectSound
8  *
9  * $Log$
10  * Revision 1.1  2002/05/03 03:28:10  root
11  * Initial revision
12  *
13  * 
14  * 18    10/25/99 5:56p Jefff
15  * increase num software channels to the number the users hardware can
16  * handle.  not less than 16, tho.
17  * 
18  * 17    9/08/99 3:22p Dave
19  * Updated builtin mission list.
20  * 
21  * 16    8/27/99 6:38p Alanl
22  * crush the blasted repeating messages bug
23  * 
24  * 15    8/23/99 11:16p Danw
25  * Allow stereo waves
26  * 
27  * 14    8/22/99 11:06p Alanl
28  * fix small bug in ds_close_channel
29  * 
30  * 13    8/19/99 11:25a Alanl
31  * change format of secondary buffer from 44100 to 22050
32  * 
33  * 12    8/17/99 4:11p Danw
34  * AL: temp fix for solving A3D crash
35  * 
36  * 11    8/06/99 2:20p Jasonh
37  * AL: free 3D portion of buffer first
38  * 
39  * 10    8/04/99 9:48p Alanl
40  * fix bug with setting 3D properties on a 2D sound buffer
41  * 
42  * 9     8/04/99 11:42a Danw
43  * tone down EAX reverb
44  * 
45  * 8     8/01/99 2:06p Alanl
46  * increase the rolloff for A3D
47  * 
48  * 7     7/20/99 5:28p Dave
49  * Fixed debug build error.
50  * 
51  * 6     7/20/99 1:49p Dave
52  * Peter Drake build. Fixed some release build warnings.
53  * 
54  * 5     7/14/99 11:32a Danw
55  * AL: add some debug code to catch nefarious A3D problem
56  * 
57  * 4     5/23/99 8:11p Alanl
58  * Added support for EAX
59  * 
60  * 3     10/08/98 4:29p Dave
61  * Removed reference to osdefs.h
62  * 
63  * 2     10/07/98 10:54a Dave
64  * Initial checkin.
65  * 
66  * 1     10/07/98 10:51a Dave
67  * 
68  * 72    6/28/98 6:34p Lawrance
69  * add sanity check in while() loop for releasing channels
70  * 
71  * 71    6/13/98 1:45p Sandeep
72  * 
73  * 70    6/10/98 2:29p Lawrance
74  * don't use COM for initializing DirectSound... appears some machines
75  * don't like it
76  * 
77  * 69    5/26/98 2:10a Lawrance
78  * make sure DirectSound pointer gets freed if Aureal resource manager
79  * fails
80  * 
81  * 68    5/21/98 9:14p Lawrance
82  * remove obsolete registry setting
83  * 
84  * 67    5/20/98 4:28p Allender
85  * upped sound buffers as per alan's request
86  * 
87  * 66    5/15/98 3:36p John
88  * Fixed bug with new graphics window code and standalone server.  Made
89  * hwndApp not be a global anymore.
90  * 
91  * 65    5/06/98 3:37p Lawrance
92  * allow panned sounds geesh
93  * 
94  * 64    5/05/98 4:49p Lawrance
95  * Put in code to authenticate A3D, improve A3D support
96  * 
97  * 63    4/20/98 11:17p Lawrance
98  * fix bug with releasing channels
99  * 
100  * 62    4/20/98 7:34p Lawrance
101  * take out obsolete directsound3d debug command
102  * 
103  * 61    4/20/98 11:10a Lawrance
104  * put correct flags when creating sound buffer
105  * 
106  * 60    4/20/98 12:03a Lawrance
107  * Allow prioritizing of CTRL3D buffers
108  * 
109  * 59    4/19/98 9:31p Lawrance
110  * Use Aureal_enabled flag
111  * 
112  * 58    4/19/98 9:39a Lawrance
113  * use DYNAMIC_LOOPERS for Aureal resource manager
114  * 
115  * 57    4/19/98 4:13a Lawrance
116  * Improve how dsound is initialized
117  * 
118  * 56    4/18/98 9:13p Lawrance
119  * Added Aureal support.
120  * 
121  * 55    4/13/98 5:04p Lawrance
122  * Write functions to determine how many milliseconds are left in a sound
123  * 
124  * 54    4/09/98 5:53p Lawrance
125  * Make DirectSound init more robust
126  * 
127  * 53    4/01/98 9:21p John
128  * Made NDEBUG, optimized build with no warnings or errors.
129  * 
130  * 52    3/31/98 5:19p John
131  * Removed demo/save/restore.  Made NDEBUG defined compile.  Removed a
132  * bunch of debug stuff out of player file.  Made model code be able to
133  * unload models and malloc out only however many models are needed.
134  *  
135  * 
136  * 51    3/29/98 12:56a Lawrance
137  * preload the warp in and explosions sounds before a mission.
138  * 
139  * 50    3/25/98 6:10p Lawrance
140  * Work on DirectSound3D
141  * 
142  * 49    3/24/98 4:28p Lawrance
143  * Make DirectSound3D support more robust
144  * 
145  * 48    3/24/98 11:49a Dave
146  * AL: Change way buffer gets locked.
147  * 
148  * 47    3/24/98 11:27a Lawrance
149  * Use buffer_size for memcpy when locking buffer
150  * 
151  * 46    3/23/98 10:32a Lawrance
152  * Add functions for extracting raw sound data
153  * 
154  * 45    3/19/98 5:36p Lawrance
155  * Add some sound debug functions to see how many sounds are playing, and
156  * to start/stop random looping sounds.
157  * 
158  * 44    3/07/98 3:35p Dave
159  * AL: check for ds being initialized in ds_create_buffer()
160  * 
161  * 43    2/18/98 5:49p Lawrance
162  * Even if the ADPCM codec is unavailable, allow game to continue.
163  * 
164  * 42    2/16/98 7:31p Lawrance
165  * get compression/decompression of voice working
166  * 
167  * 41    2/15/98 11:10p Lawrance
168  * more work on real-time voice system
169  * 
170  * 40    2/15/98 4:43p Lawrance
171  * work on real-time voice
172  * 
173  * 39    2/06/98 7:30p John
174  * Added code to monitor the number of channels of sound actually playing.
175  * 
176  * 38    2/06/98 8:56a Allender
177  * fixed calling convention problem with DLL handles
178  * 
179  * 37    2/04/98 6:08p Lawrance
180  * Read function pointers from dsound.dll, further work on
181  * DirectSoundCapture.
182  * 
183  * 36    2/03/98 11:53p Lawrance
184  * Adding support for DirectSoundCapture
185  * 
186  * 35    1/31/98 5:48p Lawrance
187  * Start on real-time voice recording
188  * 
189  * 34    1/10/98 1:14p John
190  * Added explanation to debug console commands
191  * 
192  * 33    12/21/97 4:33p John
193  * Made debug console functions a class that registers itself
194  * automatically, so you don't need to add the function to
195  * debugfunctions.cpp.  
196  * 
197  * 32    12/08/97 12:24a Lawrance
198  * Allow duplicate sounds to be stopped if less than OR equal to new sound
199  * volume.
200  * 
201  * 31    12/05/97 5:19p Lawrance
202  * re-do sound priorities to make more general and extensible
203  * 
204  * 30    11/28/97 2:09p Lawrance
205  * Overhaul how ADPCM conversion works... use much less memory... safer
206  * too.
207  * 
208  * 29    11/22/97 11:32p Lawrance
209  * decompress ADPCM data into 8 bit (not 16bit) for regular sounds (ie not
210  * music)
211  * 
212  * 28    11/20/97 5:36p Dave
213  * Hooked in a bunch of main hall changes (including sound). Made it
214  * possible to reposition (rewind/ffwd) 
215  * sound buffer pointers. Fixed animation direction change framerate
216  * problem.
217  * 
218  * 27    10/13/97 7:41p Lawrance
219  * store duration of sound
220  * 
221  * 26    10/11/97 6:39p Lawrance
222  * start playing primary buffer, to reduce latency on sounds starting
223  * 
224  * 25    10/08/97 5:09p Lawrance
225  * limit player impact sounds so only one plays at a time
226  * 
227  * 24    9/26/97 5:43p Lawrance
228  * fix a bug that was freeing memory early when playing compressed sound
229  * data
230  * 
231  * 23    9/09/97 3:39p Sandeep
232  * warning level 4 bugs
233  * 
234  * 22    8/16/97 4:05p Lawrance
235  * don't load sounds into hardware if running Lean_and_mean
236  * 
237  * 21    8/05/97 1:39p Lawrance
238  * support compressed stereo playback
239  * 
240  * 20    7/31/97 10:38a Lawrance
241  * return old debug function for toggling DirectSound3D
242  * 
243  * 19    7/29/97 3:27p Lawrance
244  * make console toggle for directsound3d work right
245  * 
246  * 18    7/28/97 11:39a Lawrance
247  * allow individual volume scaling on 3D buffers
248  * 
249  * 17    7/18/97 8:18p Lawrance
250  * fix bug in ds_get_free_channel() that caused sounds to not play when
251  * they should have
252  * 
253  * 16    7/17/97 8:04p Lawrance
254  * allow priority sounds to play if free channel, otherwise stop lowest
255  * volume priority sound of same type
256  * 
257  * 15    7/17/97 5:57p John
258  * made directsound3d config value work
259  * 
260  * 14    7/17/97 5:43p John
261  * added new config stuff
262  * 
263  * 13    7/17/97 4:25p John
264  * First, broken, stage of changing config stuff
265  * 
266  * 12    7/15/97 12:13p Lawrance
267  * don't stop sounds that have highest priority
268  * 
269  * 11    7/15/97 11:15a Lawrance
270  * limit the max instances of simultaneous sound effects, implement
271  * priorities to force critical sounds
272  * 
273  * 10    6/09/97 11:50p Lawrance
274  * integrating DirectSound3D
275  * 
276  * 9     6/08/97 5:59p Lawrance
277  * integrate DirectSound3D into sound system
278  * 
279  * 8     6/04/97 1:19p Lawrance
280  * made hardware mixing robust
281  * 
282  * 7     6/03/97 1:56p Hoffoss
283  * Return correct error code when direct sound init fails.
284  * 
285  * 6     6/03/97 12:07p Lawrance
286  * don't enable 3D sounds in Primary buffer
287  * 
288  * 5     6/02/97 3:45p Dan
289  * temp disable of hardware mixing until problem solved with
290  * CreateBuffer() failing
291  * 
292  * 4     6/02/97 1:45p Lawrance
293  * implementing hardware mixing
294  * 
295  * 3     5/29/97 4:01p Lawrance
296  * let snd_init() have final say on initialization
297  * 
298  * 2     5/29/97 12:04p Lawrance
299  * creation of file to hold DirectSound specific portions
300  *
301  * $NoKeywords: $
302  */
303
304 #include "pstypes.h"
305 #include <windows.h>
306 #include "cfile.h"
307 #include "ds.h"
308 #include "channel.h"
309 #include "ds3d.h"
310 #include "acm.h"
311 #include "osapi.h"
312 #include "dscap.h"
313
314 #include <objbase.h>
315 #include <initguid.h>
316 #include "ia3d.h"
317 #include "verifya3d.h"
318
319 // Pointers to functions contained in DSOUND.dll
320 HRESULT (__stdcall *pfn_DirectSoundCreate)(LPGUID lpGuid, LPDIRECTSOUND *ppDS, IUnknown FAR *pUnkOuter) = NULL;
321 HRESULT (__stdcall *pfn_DirectSoundCaptureCreate)(LPGUID lpGUID, LPDIRECTSOUNDCAPTURE *lplpDSC, LPUNKNOWN pUnkOuter) = NULL;
322 int Ds_dll_loaded=0;
323 HINSTANCE Ds_dll_handle=NULL;
324
325 LPDIRECTSOUND                           pDirectSound = NULL;
326 LPDIRECTSOUNDBUFFER             pPrimaryBuffer = NULL;
327 LPIA3D2                                         pIA3d2 = NULL;
328
329 static LPKSPROPERTYSET                  pPropertySet;           // pointer to sound card property set
330 static LPDIRECTSOUNDBUFFER              Ds_property_set_pdsb = NULL;
331 static LPDIRECTSOUND3DBUFFER    Ds_property_set_pds3db = NULL;
332
333 static int Ds_must_call_couninitialize = 0;
334
335 channel* Channels;              //[MAX_CHANNELS];
336 static int channel_next_sig = 1;
337
338 #define MAX_DS_SOFTWARE_BUFFERS 256
339 typedef struct ds_sound_buffer
340 {
341         LPDIRECTSOUNDBUFFER     pdsb;
342         DSBUFFERDESC                    desc;
343         WAVEFORMATEX                    wfx;
344
345 } ds_sound_buffer;
346
347 ds_sound_buffer ds_software_buffers[MAX_DS_SOFTWARE_BUFFERS];
348
349 #define MAX_DS_HARDWARE_BUFFERS 32
350 ds_sound_buffer ds_hardware_buffers[MAX_DS_HARDWARE_BUFFERS];
351
352 int ds_vol_lookup[101];                                         // lookup table for direct sound volumes
353 int ds_initialized = FALSE;
354
355 static DSCAPS Soundcard_caps;                                   // current soundcard capabilities
356
357 extern int Snd_sram;                                    // mem (in bytes) used up by storing sounds in system memory
358 extern int Snd_hram;                                    // mem (in bytes) used up by storing sounds in soundcard memory
359
360 static int Ds_use_ds3d = 0;
361 static int Ds_use_a3d = 0;
362 static int Ds_use_eax = 0;
363
364 GUID IID_IA3d2_Def = {0xfb80d1e0, 0x98d3, 0x11d1, {0x90, 0xfb, 0x00, 0x60, 0x08, 0xa1, 0xf4, 0x41}};
365 GUID CLSID_A3d_Def = {0xd8f1eee0, 0xf634, 0x11cf, {0x87, 0x0, 0x0, 0xa0, 0x24, 0x5d, 0x91, 0x8b}};
366
367 static bool Stop_logging_sounds = false;
368
369 static int MAX_CHANNELS = 0;            // initialized properly in ds_init_channels()
370
371 ///////////////////////////
372 //
373 // EAX
374 //
375 ///////////////////////////
376
377 // presets
378 //#define EAX_PRESET_GENERIC         EAX_ENVIRONMENT_GENERIC,0.5F,1.493F,0.5F
379 #define EAX_PRESET_GENERIC         EAX_ENVIRONMENT_GENERIC,0.2F,0.2F,1.0F
380 #define EAX_PRESET_PADDEDCELL      EAX_ENVIRONMENT_PADDEDCELL,0.25F,0.1F,0.0F
381 #define EAX_PRESET_ROOM            EAX_ENVIRONMENT_ROOM,0.417F,0.4F,0.666F
382 #define EAX_PRESET_BATHROOM        EAX_ENVIRONMENT_BATHROOM,0.653F,1.499F,0.166F
383 #define EAX_PRESET_LIVINGROOM      EAX_ENVIRONMENT_LIVINGROOM,0.208F,0.478F,0.0F
384 #define EAX_PRESET_STONEROOM       EAX_ENVIRONMENT_STONEROOM,0.5F,2.309F,0.888F
385 #define EAX_PRESET_AUDITORIUM      EAX_ENVIRONMENT_AUDITORIUM,0.403F,4.279F,0.5F
386 #define EAX_PRESET_CONCERTHALL     EAX_ENVIRONMENT_CONCERTHALL,0.5F,3.961F,0.5F
387 #define EAX_PRESET_CAVE            EAX_ENVIRONMENT_CAVE,0.5F,2.886F,1.304F
388 #define EAX_PRESET_ARENA           EAX_ENVIRONMENT_ARENA,0.361F,7.284F,0.332F
389 #define EAX_PRESET_HANGAR          EAX_ENVIRONMENT_HANGAR,0.5F,10.0F,0.3F
390 #define EAX_PRESET_CARPETEDHALLWAY EAX_ENVIRONMENT_CARPETEDHALLWAY,0.153F,0.259F,2.0F
391 #define EAX_PRESET_HALLWAY         EAX_ENVIRONMENT_HALLWAY,0.361F,1.493F,0.0F
392 #define EAX_PRESET_STONECORRIDOR   EAX_ENVIRONMENT_STONECORRIDOR,0.444F,2.697F,0.638F
393 #define EAX_PRESET_ALLEY           EAX_ENVIRONMENT_ALLEY,0.25F,1.752F,0.776F
394 #define EAX_PRESET_FOREST          EAX_ENVIRONMENT_FOREST,0.111F,3.145F,0.472F
395 #define EAX_PRESET_CITY            EAX_ENVIRONMENT_CITY,0.111F,2.767F,0.224F
396 #define EAX_PRESET_MOUNTAINS       EAX_ENVIRONMENT_MOUNTAINS,0.194F,7.841F,0.472F
397 #define EAX_PRESET_QUARRY          EAX_ENVIRONMENT_QUARRY,1.0F,1.499F,0.5F
398 #define EAX_PRESET_PLAIN           EAX_ENVIRONMENT_PLAIN,0.097F,2.767F,0.224F
399 #define EAX_PRESET_PARKINGLOT      EAX_ENVIRONMENT_PARKINGLOT,0.208F,1.652F,1.5F
400 #define EAX_PRESET_SEWERPIPE       EAX_ENVIRONMENT_SEWERPIPE,0.652F,2.886F,0.25F
401 #define EAX_PRESET_UNDERWATER      EAX_ENVIRONMENT_UNDERWATER,1.0F,1.499F,0.0F
402 #define EAX_PRESET_DRUGGED         EAX_ENVIRONMENT_DRUGGED,0.875F,8.392F,1.388F
403 #define EAX_PRESET_DIZZY           EAX_ENVIRONMENT_DIZZY,0.139F,17.234F,0.666F
404 #define EAX_PRESET_PSYCHOTIC       EAX_ENVIRONMENT_PSYCHOTIC,0.486F,7.563F,0.806F
405
406 static LPKSPROPERTYSET Ds_eax_reverb = NULL;
407
408 static int Ds_eax_inited = 0;
409
410 EAX_REVERBPROPERTIES Ds_eax_presets[] = 
411 {
412         {EAX_PRESET_GENERIC},
413         {EAX_PRESET_PADDEDCELL},
414         {EAX_PRESET_ROOM},
415         {EAX_PRESET_BATHROOM},
416         {EAX_PRESET_LIVINGROOM},
417         {EAX_PRESET_STONEROOM},
418         {EAX_PRESET_AUDITORIUM},
419         {EAX_PRESET_CONCERTHALL},
420         {EAX_PRESET_CAVE},
421         {EAX_PRESET_ARENA},
422         {EAX_PRESET_HANGAR},
423         {EAX_PRESET_CARPETEDHALLWAY},
424         {EAX_PRESET_HALLWAY},
425         {EAX_PRESET_STONECORRIDOR},
426         {EAX_PRESET_ALLEY},
427         {EAX_PRESET_FOREST},
428         {EAX_PRESET_CITY},
429         {EAX_PRESET_MOUNTAINS},
430         {EAX_PRESET_QUARRY},
431         {EAX_PRESET_PLAIN},
432         {EAX_PRESET_PARKINGLOT},
433         {EAX_PRESET_SEWERPIPE},
434         {EAX_PRESET_UNDERWATER},
435         {EAX_PRESET_DRUGGED},
436         {EAX_PRESET_DIZZY},
437         {EAX_PRESET_PSYCHOTIC},
438 };
439
440 GUID DSPROPSETID_EAX_ReverbProperties_Def = {0x4a4e6fc1, 0xc341, 0x11d1, {0xb7, 0x3a, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}};
441 GUID DSPROPSETID_EAXBUFFER_ReverbProperties_Def = {0x4a4e6fc0, 0xc341, 0x11d1, {0xb7, 0x3a, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}};
442
443 //----------------------------------------------------------------
444 // prototypes 
445 void ds_get_soundcard_caps(DSCAPS *dscaps);
446
447
448
449
450 //--------------------------------------------------------------------------
451 // ds_is_3d_buffer()
452 //
453 // Determine if a secondary buffer is a 3d secondary buffer.
454 //
455 int ds_is_3d_buffer(LPDIRECTSOUNDBUFFER pdsb)
456 {
457         DSBCAPS                 dsbc;
458         HRESULT                 hr;
459
460         dsbc.dwSize = sizeof(dsbc);
461         hr = pdsb->GetCaps(&dsbc);
462         if ( hr == DS_OK && dsbc.dwFlags & DSBCAPS_CTRL3D ) {
463                 return TRUE;
464         }
465         else {
466                 return FALSE;
467         }
468 }
469
470 //--------------------------------------------------------------------------
471 // ds_is_3d_buffer()
472 //
473 // Determine if a secondary buffer is a 3d secondary buffer.
474 //
475 int ds_is_3d_buffer(int sid)
476 {
477         if ( sid >= 0 ) {
478                 return ds_is_3d_buffer(ds_software_buffers[sid].pdsb);
479         }
480
481         return 0;
482 }
483
484 //--------------------------------------------------------------------------
485 //  ds_build_vol_lookup()
486 //
487 //  Fills up the ds_vol_lookup[] tables that converts from a volume in the form
488 //  0.0 -> 1.0 to -10000 -> 0 (this is the DirectSound method, where units are
489 //  hundredths of decibls)
490 //
491 void ds_build_vol_lookup()
492 {
493         int     i;
494         float   vol;
495
496         ds_vol_lookup[0] = -10000;
497         for ( i = 1; i <= 100; i++ ) {
498                 vol = i / 100.0f;
499                 ds_vol_lookup[i] = fl2i( (log(vol) / log(2.0f)) * 1000.0f);
500         }
501 }
502
503
504 //--------------------------------------------------------------------------
505 // ds_convert_volume()
506 //
507 // Takes volume between 0.0f and 1.0f and converts into
508 // DirectSound style volumes between -10000 and 0.
509 int ds_convert_volume(float volume)
510 {
511         int index;
512
513         index = fl2i(volume * 100.0f);
514         if ( index > 100 )
515                 index = 100;
516         if ( index < 0 )
517                 index = 0;
518
519         return ds_vol_lookup[index];
520 }
521
522 //--------------------------------------------------------------------------
523 // ds_get_percentage_vol()
524 //
525 // Converts -10000 -> 0 range volume to 0 -> 1
526 float ds_get_percentage_vol(int ds_vol)
527 {
528         double vol;
529         vol = pow(2.0, ds_vol/1000.0);
530         return (float)vol;
531 }
532
533 // ---------------------------------------------------------------------------------------
534 // ds_parse_wave() 
535 //
536 // Parse a wave file.
537 //
538 // parameters:          filename                        => file of sound to parse
539 //                                              dest                            => address of pointer of where to store raw sound data (output parm)
540 //                                              dest_size               => number of bytes of sound data stored (output parm)
541 //                                              header                  => address of pointer to a WAVEFORMATEX struct (output parm)
542 //
543 // returns:                     0                                       => wave file successfully parsed
544 //                                              -1                                      => error
545 //
546 //      NOTE: memory is malloced for the header and dest in this function.  It is the responsibility
547 //                      of the caller to free this memory later.
548 //
549 int ds_parse_wave(char *filename, ubyte **dest, uint *dest_size, WAVEFORMATEX **header)
550 {
551         CFILE                           *fp;
552         PCMWAVEFORMAT   PCM_header;
553         int                             cbExtra = 0;
554         unsigned int    tag, size, next_chunk;
555
556         fp = cfopen( filename, "rb" );
557         if ( fp == NULL )       {
558                 nprintf(("Error", "Couldn't open '%s'\n", filename ));
559                 return -1;
560         }
561         
562         // Skip the "RIFF" tag and file size (8 bytes)
563         // Skip the "WAVE" tag (4 bytes)
564         cfseek( fp, 12, CF_SEEK_SET );
565
566         // Now read RIFF tags until the end of file
567
568         while(1)        {
569                 if ( cfread( &tag, sizeof(uint), 1, fp ) != 1 )
570                         break;
571
572                 if ( cfread( &size, sizeof(uint), 1, fp ) != 1 )
573                         break;
574
575                 next_chunk = cftell(fp) + size;
576
577                 switch( tag )   {
578                 case 0x20746d66:                // The 'fmt ' tag
579                         //nprintf(("Sound", "SOUND => size of fmt block: %d\n", size));
580                         cfread( &PCM_header, sizeof(PCMWAVEFORMAT), 1, fp );
581                         if ( PCM_header.wf.wFormatTag != WAVE_FORMAT_PCM ) {
582                                 cbExtra = cfread_short(fp);
583                         }
584
585                         // Allocate memory for WAVEFORMATEX structure + extra bytes
586                         if ( (*header = (WAVEFORMATEX *) malloc ( sizeof(WAVEFORMATEX)+cbExtra )) != NULL ){
587                                 // Copy bytes from temporary format structure
588                                 memcpy (*header, &PCM_header, sizeof(PCM_header));
589                                 (*header)->cbSize = (unsigned short)cbExtra;
590
591                                 // Read those extra bytes, append to WAVEFORMATEX structure
592                                 if (cbExtra != 0) {
593                                         cfread( ((ubyte *)(*header) + sizeof(WAVEFORMATEX)), cbExtra, 1, fp);
594                                 }
595                         }
596                         else {
597                                 Assert(0);              // malloc failed
598                         }
599         
600                         break;
601                 case 0x61746164:                // the 'data' tag
602                         *dest_size = size;
603                         (*dest) = (ubyte *)malloc(size);
604                         Assert( *dest != NULL );
605                         cfread( *dest, size, 1, fp );
606                         break;
607                 default:        // unknown, skip it
608                         break;
609                 }
610                 cfseek( fp, next_chunk, CF_SEEK_SET );
611         }
612         cfclose(fp);
613
614         return 0;
615 }
616
617
618 // ---------------------------------------------------------------------------------------
619 // ds_get_sid()
620 //
621 //      
622 int ds_get_sid()
623 {
624         int i;
625
626         for ( i = 0; i < MAX_DS_SOFTWARE_BUFFERS; i++ ) {
627                 if ( ds_software_buffers[i].pdsb == NULL )
628                 break;
629         }
630
631         if ( i == MAX_DS_SOFTWARE_BUFFERS )     {
632                 return -1;
633         }
634
635         return i;
636 }
637
638 // ---------------------------------------------------------------------------------------
639 // ds_get_hid()
640 //
641 //      
642 int ds_get_hid()
643 {
644         int i;
645
646         for ( i = 0; i < MAX_DS_HARDWARE_BUFFERS; i++ ) {
647                 if ( ds_hardware_buffers[i].pdsb == NULL )
648                 break;
649         }
650
651         if ( i == MAX_DS_HARDWARE_BUFFERS )     {
652                 return -1;
653         }
654
655         return i;
656 }
657
658 // ---------------------------------------------------------------------------------------
659 // Load a DirectSound secondary buffer with sound data.  The sounds data for
660 // game sounds are stored in the DirectSound secondary buffers, and are 
661 // duplicated as needed and placed in the Channels[] array to be played.
662 // 
663 //
664 // parameters:  
665 //                                       sid                              => pointer to software id for sound ( output parm)
666 //                                       hid                              => pointer to hardware id for sound ( output parm)
667 //                                       final_size               => pointer to storage to receive uncompressed sound size (output parm)
668 //              header          => pointer to a WAVEFORMATEX structure
669 //                                       si                               => sound_info structure, contains details on the sound format
670 //                                       flags                    => buffer properties ( DS_HARDWARE , DS_3D )
671 //
672 // returns:     -1           => sound effect could not loaded into a secondary buffer
673 //               0           => sound effect successfully loaded into a secondary buffer
674 //
675 //
676 // NOTE: this function is slow, especially when sounds are loaded into hardware.  Don't call this
677 // function from within gameplay.
678 //
679 int ds_load_buffer(int *sid, int *hid, int *final_size, void *header, sound_info *si, int flags)
680 {
681         Assert( final_size != NULL );
682         Assert( header != NULL );
683         Assert( si != NULL );
684         Assert( si->data != NULL );
685         Assert( si->size > 0 );
686         Assert( si->sample_rate > 0);
687         Assert( si->bits > 0 );
688         Assert( si->n_channels > 0 );
689         Assert( si->n_block_align >= 0 );
690         Assert( si->avg_bytes_per_sec > 0 );
691
692         WAVEFORMATEX    *pwfx = (WAVEFORMATEX *)header;
693         DSBUFFERDESC    BufferDesc;
694         WAVEFORMATEX    WaveFormat;
695         HRESULT                 DSReturn;
696         int                             rc, final_sound_size, DSOUND_load_buffer_result = 0;
697         BYTE                            *pData, *pData2;
698         DWORD                           DataSize, DataSize2;
699
700         // the below two covnert_ variables are only used when the wav format is not 
701         // PCM.  DirectSound only takes PCM sound data, so we must convert to PCM if required
702         ubyte *convert_buffer = NULL;           // storage for converted wav file 
703         int     convert_len;                                    // num bytes of converted wav file
704         uint    src_bytes_used;                         // number of source bytes actually converted (should always be equal to original size)
705
706         // Ensure DirectSound initialized
707         if (!ds_initialized) {
708                 DSOUND_load_buffer_result = -1;
709                 goto DSOUND_load_buffer_done;
710         }
711
712         // Set up buffer information
713         WaveFormat.wFormatTag           = (unsigned short)si->format;
714         WaveFormat.nChannels                    = (unsigned short)si->n_channels;
715         WaveFormat.nSamplesPerSec       = si->sample_rate;
716         WaveFormat.wBitsPerSample       = (unsigned short)si->bits;
717         WaveFormat.cbSize                               = 0;
718         WaveFormat.nBlockAlign          = (unsigned short)si->n_block_align;
719         WaveFormat.nAvgBytesPerSec = si->avg_bytes_per_sec;
720
721         final_sound_size = si->size;    // assume this format will be used, may be over-ridded by convert_len
722
723 //      Assert(WaveFormat.nChannels == 1);
724
725         switch ( si->format ) {
726                 case WAVE_FORMAT_PCM:
727                         break;
728
729                 case WAVE_FORMAT_ADPCM:
730                         
731                         nprintf(( "Sound", "SOUND ==> converting sound from ADPCM to PCM\n" ));
732                         rc = ACM_convert_ADPCM_to_PCM(pwfx, si->data, si->size, &convert_buffer, 0, &convert_len, &src_bytes_used, 8);
733                         if ( rc == -1 ) {
734                                 DSOUND_load_buffer_result = -1;
735                                 goto DSOUND_load_buffer_done;
736                         }
737
738                         if (src_bytes_used != si->size) {
739                                 Int3(); // ACM conversion failed?
740                                 DSOUND_load_buffer_result = -1;
741                                 goto DSOUND_load_buffer_done;
742                         }
743
744                         final_sound_size = convert_len;
745
746                         // Set up the WAVEFORMATEX structure to have the right PCM characteristics
747                         WaveFormat.wFormatTag           = WAVE_FORMAT_PCM;
748                         WaveFormat.nChannels                    = (unsigned short)si->n_channels;
749                         WaveFormat.nSamplesPerSec       = si->sample_rate;
750                         WaveFormat.wBitsPerSample       = 8;
751                         WaveFormat.cbSize                               = 0;
752                         WaveFormat.nBlockAlign          = (unsigned short)(( WaveFormat.nChannels * WaveFormat.wBitsPerSample ) / 8);
753                         WaveFormat.nAvgBytesPerSec = WaveFormat.nBlockAlign * WaveFormat.nSamplesPerSec;
754
755                         nprintf(( "Sound", "SOUND ==> Coverted sound from ADPCM to PCM successfully\n" ));
756                         break;  
757
758                 default:
759                         nprintf(( "Sound", "Unsupported sound encoding\n" ));
760                         DSOUND_load_buffer_result = -1;
761                         goto DSOUND_load_buffer_done;
762                         break;
763         }
764
765         WaveFormat.wFormatTag = WAVE_FORMAT_PCM;                // DirectSound only used PCM wave files
766
767         // Set up a DirectSound buffer
768         ZeroMemory(&BufferDesc, sizeof(BufferDesc));
769         BufferDesc.dwSize = sizeof(BufferDesc);
770         BufferDesc.dwBufferBytes = final_sound_size;
771         BufferDesc.lpwfxFormat = &WaveFormat;
772
773         // check if DirectSound3D is enabled and the sound is flagged for 3D
774         if ((ds_using_ds3d()) && (flags & DS_USE_DS3D)) {
775 //      if (ds_using_ds3d()) {
776                 BufferDesc.dwFlags = DSBCAPS_STATIC | DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRLVOLUME | DSBCAPS_CTRL3D | DSBCAPS_MUTE3DATMAXDISTANCE;
777         } else {
778                 BufferDesc.dwFlags = DSBCAPS_STATIC | DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRLVOLUME | DSBCAPS_LOCSOFTWARE;
779         }
780
781         // Create a new software buffer using the settings for this wave
782         // All sounds are required to have a software buffer
783         *sid = ds_get_sid();
784         if ( *sid == -1 ) {
785                 nprintf(("Sound","SOUND ==> No more software secondary buffers available\n"));
786                 return -1;
787         }
788         DSReturn = pDirectSound->CreateSoundBuffer(&BufferDesc, &ds_software_buffers[*sid].pdsb, NULL );
789
790         if ( DSReturn == DS_OK && ds_software_buffers[*sid].pdsb != NULL )      {
791
792                 ds_software_buffers[*sid].desc = BufferDesc;
793                 ds_software_buffers[*sid].wfx = *BufferDesc.lpwfxFormat;
794
795                 // Lock the buffer and copy in the data
796                 if ((ds_software_buffers[*sid].pdsb)->Lock(0, final_sound_size, (void**)(&pData), &DataSize, (void**)(&pData2), &DataSize2, 0) == DS_OK)        {
797
798                         if ( convert_buffer )
799                                 memcpy(pData, convert_buffer, final_sound_size); // use converted data (PCM format)
800                         else
801                                 memcpy(pData, si->data, final_sound_size);
802
803                         (ds_software_buffers[*sid].pdsb)->Unlock(pData, DataSize, 0, 0);
804                 }
805                 DSOUND_load_buffer_result = 0;
806
807                 // update ram used for sound
808                 Snd_sram += final_sound_size;
809                 *final_size = final_sound_size;
810         }
811         else {
812                 nprintf(("Sound","SOUND => fatal error in DSOUND_load_buffer\n"));
813                 *sid = -1;
814                 DSOUND_load_buffer_result = -1;
815         }
816
817         DSOUND_load_buffer_done:
818         if ( convert_buffer )
819                 free( convert_buffer );
820         return DSOUND_load_buffer_result;
821 }
822
823 // ---------------------------------------------------------------------------------------
824 // ds_init_channels()
825 //
826 // init the Channels[] array
827 //
828 void ds_init_channels()
829 {
830         int i;
831
832         // detect how many channels we can support
833         DSCAPS caps;
834         ds_get_soundcard_caps(&caps);
835
836 //      caps.dwSize = sizeof(DSCAPS);
837 //      pDirectSound->GetCaps(&caps);
838         
839         // minimum 16 channels
840         MAX_CHANNELS = caps.dwMaxHwMixingStaticBuffers;
841         int dbg_channels = MAX_CHANNELS;
842         if (MAX_CHANNELS < 16) {
843                 MAX_CHANNELS = 16;
844         }
845
846         // allocate the channels array
847         Channels = (channel*) malloc(sizeof(channel) * MAX_CHANNELS);
848         if (Channels == NULL) {
849                 Error(LOCATION, "Unable to allocate %d bytes for %d audio channels.", sizeof(channel) * MAX_CHANNELS, MAX_CHANNELS);
850         }
851
852         // init the channels
853         for ( i = 0; i < MAX_CHANNELS; i++ ) {
854                 Channels[i].pdsb = NULL;
855                 Channels[i].pds3db = NULL;
856                 Channels[i].vol = 0;
857         }
858
859         mprintf(("** MAX_CHANNELS set to %d.  DS reported %d.\n", MAX_CHANNELS, dbg_channels));
860 }
861
862 // ---------------------------------------------------------------------------------------
863 // ds_init_software_buffers()
864 //
865 // init the software buffers
866 //
867 void ds_init_software_buffers()
868 {
869         int i;
870
871         for ( i = 0; i < MAX_DS_SOFTWARE_BUFFERS; i++ ) {
872                 ds_software_buffers[i].pdsb = NULL;
873         }
874 }
875
876 // ---------------------------------------------------------------------------------------
877 // ds_init_hardware_buffers()
878 //
879 // init the hardware buffers
880 //
881 void ds_init_hardware_buffers()
882 {
883         int i;
884
885         for ( i = 0; i < MAX_DS_HARDWARE_BUFFERS; i++ ) {
886                 ds_hardware_buffers[i].pdsb = NULL;
887         }
888 }
889
890 // ---------------------------------------------------------------------------------------
891 // ds_init_buffers()
892 //
893 // init the both the software and hardware buffers
894 //
895 void ds_init_buffers()
896 {
897         ds_init_software_buffers();
898         ds_init_hardware_buffers();
899 }
900
901 // Get the current soundcard capabilities
902 void ds_get_soundcard_caps(DSCAPS *dscaps)
903 {
904         HRESULT hr;
905         int             n_hbuffers, hram;
906
907         dscaps->dwSize = sizeof(DSCAPS);
908
909         hr = pDirectSound->GetCaps(dscaps); 
910         if (hr != DS_OK )       {
911                 nprintf(("Sound","SOUND ==> DirectSound GetCaps() failed with code %s\n.",get_DSERR_text(hr) ));
912                 return;
913         }
914         
915         n_hbuffers = dscaps->dwMaxHwMixingStaticBuffers;
916         hram = dscaps->dwTotalHwMemBytes;
917         
918         if ( !(dscaps->dwFlags & DSCAPS_CERTIFIED) ) {
919                 nprintf(("Sound","SOUND ==> Warning: audio driver is not Microsoft certified.\n"));
920         }
921 }
922
923 // ---------------------------------------------------------------------------------------
924 // ds_show_caps()
925 //
926 // init the both the software and hardware buffers
927 //
928 void ds_show_caps(DSCAPS *dscaps)
929 {
930         nprintf(("Sound", "SOUND => Soundcard Capabilities:\n"));
931         nprintf(("Sound", "================================\n"));
932         nprintf(("Sound", "Number of primary buffers: %d\n", dscaps->dwPrimaryBuffers ));
933         nprintf(("Sound", "Number of total hw mixing buffers: %d\n", dscaps->dwMaxHwMixingAllBuffers ));
934         nprintf(("Sound", "Number of total hw mixing static buffers: %d\n", dscaps->dwMaxHwMixingStaticBuffers ));
935         nprintf(("Sound", "Number of total hw mixing streaming buffers: %d\n", dscaps->dwMaxHwMixingStreamingBuffers ));
936         nprintf(("Sound", "Number of free hw mixing buffers: %d\n", dscaps->dwFreeHwMixingAllBuffers ));
937         nprintf(("Sound", "Number of free hw mixing static buffers: %d\n", dscaps->dwFreeHwMixingStaticBuffers ));
938         nprintf(("Sound", "Number of free hw mixing streaming buffers: %d\n", dscaps->dwFreeHwMixingStreamingBuffers ));
939         nprintf(("Sound", "Number of hw 3D buffers: %d\n", dscaps->dwMaxHw3DAllBuffers ));
940         nprintf(("Sound", "Number of hw 3D static buffers: %d\n", dscaps->dwMaxHw3DStaticBuffers ));
941         nprintf(("Sound", "Number of hw 3D streaming buffers: %d\n", dscaps->dwMaxHw3DStreamingBuffers ));
942         nprintf(("Sound", "Number of free hw 3D buffers: %d\n", dscaps->dwFreeHw3DAllBuffers ));
943         nprintf(("Sound", "Number of free hw static 3D buffers: %d\n", dscaps->dwFreeHw3DStaticBuffers ));
944         nprintf(("Sound", "Number of free hw streaming 3D buffers: %d\n", dscaps->dwFreeHw3DStreamingBuffers ));
945         nprintf(("Sound", "Number of total hw bytes: %d\n", dscaps->dwTotalHwMemBytes ));
946         nprintf(("Sound", "Number of free hw bytes: %d\n", dscaps->dwFreeHwMemBytes ));
947         nprintf(("Sound", "================================\n"));
948 }
949
950 // Fill in the waveformat struct with the primary buffer characteristics.
951 void ds_get_primary_format(WAVEFORMATEX *wfx)
952 {
953         // Set 16 bit / 22KHz / mono
954         wfx->wFormatTag = WAVE_FORMAT_PCM;
955         wfx->nChannels = 2;
956         wfx->nSamplesPerSec = 22050;
957         wfx->wBitsPerSample = 16;
958         wfx->cbSize = 0;
959         wfx->nBlockAlign = (unsigned short)(wfx->nChannels * (wfx->wBitsPerSample / 8));
960         wfx->nAvgBytesPerSec = wfx->nBlockAlign * wfx->nSamplesPerSec;
961 }
962 //XSTR:OFF
963 // obtain the function pointers from the dsound.dll
964 void ds_dll_get_functions()
965 {
966         pfn_DirectSoundCreate = (HRESULT(__stdcall *)(LPGUID lpGuid, LPDIRECTSOUND *ppDS, IUnknown FAR *pUnkOuter))GetProcAddress(Ds_dll_handle,"DirectSoundCreate");
967         pfn_DirectSoundCaptureCreate = (HRESULT(__stdcall *)(LPGUID lpGuid, LPDIRECTSOUNDCAPTURE *lplpDSC, IUnknown FAR *pUnkOuter))GetProcAddress(Ds_dll_handle,"DirectSoundCaptureCreate");
968 }
969
970 // Load the dsound.dll, and get funtion pointers
971 // exit:        0       ->      dll loaded successfully
972 //                      !0      ->      dll could not be loaded
973 int ds_dll_load()
974 {
975         if ( !Ds_dll_loaded ) {
976                 Ds_dll_handle = LoadLibrary("dsound.dll");
977                 if ( !Ds_dll_handle ) {
978                         return -1;
979                 }
980                 ds_dll_get_functions();
981                 Ds_dll_loaded=1;
982         }
983         return 0;
984 }
985
986
987 static int ds_init_a3d()
988 {
989         HINSTANCE a3d_handle;
990         HRESULT hr;
991
992         a3d_handle = LoadLibrary("a3d.dll");
993         if (!a3d_handle) {
994                 return -1;
995         } else {
996                 FreeLibrary(a3d_handle);
997         }
998
999         CoInitialize(NULL);
1000         Ds_must_call_couninitialize = 1;
1001
1002         hr = CoCreateInstance(CLSID_A3d_Def, NULL, CLSCTX_INPROC_SERVER, IID_IDirectSound, (void**)&pDirectSound);
1003         if (FAILED(hr)) {
1004                 return -1;
1005         }
1006
1007         Assert(pDirectSound != NULL);
1008         hr = pDirectSound->QueryInterface(IID_IA3d2_Def, (void**)&pIA3d2);
1009         if (FAILED(hr)) {
1010                 return -1;
1011         }
1012
1013         A3DCAPS_SOFTWARE swCaps;
1014  
1015         // Get Dll Software CAP to get DLL version number
1016         ZeroMemory(&swCaps,sizeof(swCaps));
1017
1018         swCaps.dwSize = sizeof(swCaps);
1019         pIA3d2->GetSoftwareCaps(&swCaps);
1020
1021         // Compare version from a3d.dll to header version only return A3D_OK if dll version >= to header version
1022         if (swCaps.dwVersion < A3D_CURRENT_VERSION) {
1023                 pDirectSound->Release();
1024                 pDirectSound = NULL;
1025                 return -1;
1026         }
1027
1028
1029         // verify this is authentic A3D
1030         int aureal_verified;
1031         aureal_verified = VerifyAurealA3D();
1032
1033         if (aureal_verified == FALSE) {
1034                 // This is fake A3D!!! Ignore
1035                 pDirectSound->Release();
1036                 pDirectSound = NULL;
1037                 return -1;
1038         }
1039
1040         // Register our version for backwards compatibility with newer A3d.dll
1041         pIA3d2->RegisterVersion(A3D_CURRENT_VERSION);
1042
1043         hr = pDirectSound->Initialize(NULL);
1044         if (FAILED(hr)) {
1045                 pDirectSound->Release();
1046                 pDirectSound = NULL;
1047                 return -1;
1048         }
1049
1050         pIA3d2->SetResourceManagerMode(A3D_RESOURCE_MODE_DYNAMIC_LOOPERS);
1051
1052         return 0;
1053 }
1054
1055
1056 // Initialize the property set interface.
1057 //
1058 // returns: 0 if successful, otherwise -1.  If successful, the global pPropertySet will
1059 //          set to a non-NULL value.
1060 //
1061 int ds_init_property_set()
1062 {
1063         HRESULT hr;
1064
1065         // Create the secondary buffer required for EAX initialization
1066         WAVEFORMATEX wf;
1067         wf.wFormatTag = WAVE_FORMAT_PCM;
1068         wf.nChannels = 1;
1069         wf.nSamplesPerSec = 22050;
1070         wf.wBitsPerSample = 16;
1071         wf.cbSize = 0;
1072         wf.nBlockAlign = (unsigned short)(wf.nChannels * (wf.wBitsPerSample / 8));
1073         wf.nAvgBytesPerSec = wf.nBlockAlign * wf.nSamplesPerSec;
1074
1075         DSBUFFERDESC dsbd;
1076         ZeroMemory(&dsbd, sizeof(dsbd));
1077         dsbd.dwSize = sizeof(dsbd);
1078         dsbd.dwFlags = DSBCAPS_CTRLDEFAULT | DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_STATIC | DSBCAPS_CTRL3D | DSBCAPS_MUTE3DATMAXDISTANCE;
1079         dsbd.dwBufferBytes = 3 * wf.nAvgBytesPerSec;
1080         dsbd.lpwfxFormat = &wf;
1081
1082         // Create a new buffer using the settings for this wave
1083         hr = pDirectSound->CreateSoundBuffer(&dsbd, &Ds_property_set_pdsb, NULL);
1084         if (FAILED(hr)) {
1085                 pPropertySet = NULL;
1086                 return -1;
1087         }
1088
1089         // Get the 3D interface from the secondary buffer, which is used to query the EAX interface
1090         hr = Ds_property_set_pdsb->QueryInterface(IID_IDirectSound3DBuffer, (void**)&Ds_property_set_pds3db);
1091         if (FAILED(hr)) {
1092                 Ds_property_set_pds3db = NULL;
1093                 return -1;
1094         }
1095
1096         Assert(Ds_property_set_pds3db != NULL);
1097         hr = Ds_property_set_pds3db->QueryInterface(IID_IKsPropertySet, (void**)&pPropertySet);
1098         if ((FAILED(hr)) || (pPropertySet == NULL)) {
1099                 return -1;
1100         }
1101
1102         return 0;
1103 }
1104
1105 // ---------------------------------------------------------------------------------------
1106 // ds_init()
1107 //
1108 // returns:     -1           => init failed
1109 //               0           => init success
1110 int ds_init(int use_a3d, int use_eax)
1111 {
1112         HRESULT                 hr;
1113         HWND                            hwnd;
1114         WAVEFORMATEX    wave_format;
1115         DSBUFFERDESC    BufferDesc;
1116
1117         nprintf(( "Sound", "SOUND ==> Initializing DirectSound...\n" ));
1118
1119         hwnd = (HWND)os_get_window();
1120         if ( hwnd == NULL )     {
1121                 nprintf(( "Sound", "SOUND ==> No window handle, so no sound...\n" ));
1122                 return -1;
1123         }
1124
1125         if ( ds_dll_load() == -1 ) {
1126                 return -1;
1127         }
1128
1129         pDirectSound = NULL;
1130
1131         Ds_use_a3d = use_a3d;
1132         Ds_use_eax = use_eax;
1133
1134         if (Ds_use_a3d || Ds_use_eax) {
1135                 Ds_use_ds3d = 1;
1136         }
1137
1138         if (Ds_use_a3d && Ds_use_eax) {
1139                 Ds_use_eax = 0;
1140         }
1141
1142
1143         // If we want A3D, ensure a3d.dll exists
1144         if (Ds_use_a3d == 1) {
1145                 if (ds_init_a3d() != 0) {
1146                         Ds_use_a3d = 0;
1147                         Ds_use_ds3d = 0;
1148                 }
1149         }
1150
1151
1152         if (Ds_use_a3d == 0) {
1153                 if (!pfn_DirectSoundCreate) {
1154                         nprintf(( "Sound", "SOUND ==> Could not get DirectSoundCreate function pointer\n" ));
1155                         return -1;
1156                 }
1157
1158                 hr = pfn_DirectSoundCreate(NULL, &pDirectSound, NULL);
1159                 if (FAILED(hr)) {
1160                         return -1;
1161                 }
1162         }
1163
1164         // Set up DirectSound for exclusive mode, so we can change the primary buffer if we want to.    
1165         hr = pDirectSound->SetCooperativeLevel(hwnd, DSSCL_EXCLUSIVE);
1166         if (hr != DS_OK) {
1167                 nprintf(("Sound","SOUND ==> DirectSound pDirectSound->SetCooperativeLevel failed with code %s\n.",get_DSERR_text(hr) ));
1168                 pDirectSound = NULL;    
1169                 return -1;
1170         }
1171
1172         // Create the primary buffer
1173         ZeroMemory(&BufferDesc, sizeof(BufferDesc));
1174         BufferDesc.dwSize = sizeof(BufferDesc);
1175
1176         ds_get_soundcard_caps(&Soundcard_caps);
1177
1178         if (Ds_use_ds3d) {
1179                 BufferDesc.dwFlags = DSBCAPS_PRIMARYBUFFER | DSBCAPS_CTRL3D;
1180
1181                 hr = pDirectSound->CreateSoundBuffer(&BufferDesc, &pPrimaryBuffer, 0);
1182                 if (hr != DS_OK) {
1183                         nprintf(("Sound","SOUND ==> Primary Buffer create failed with DSBCAPS_CTRL3D property... disabling DirectSound3D\n"));
1184                         Ds_use_ds3d = 0;
1185                         Ds_use_eax = 0;
1186                         Ds_use_a3d = 0;
1187                 } else {
1188                         nprintf(("Sound","SOUND ==> Primary Buffer created with DirectSound3D enabled\n"));
1189                 }
1190         }
1191
1192         // If not using DirectSound3D, then create a normal primary buffer
1193         if (Ds_use_ds3d == 0) {
1194                 BufferDesc.dwFlags = DSBCAPS_PRIMARYBUFFER;
1195                 hr = pDirectSound->CreateSoundBuffer(&BufferDesc, &pPrimaryBuffer, 0);
1196                 if (hr != DS_OK) {
1197                         nprintf(("Sound","SOUND ==> Primary Buffer create failed with error: %s\n",get_DSERR_text(hr) ));
1198                         pDirectSound = NULL;    
1199                         return -1;
1200                 }
1201                 else {
1202                         nprintf(("Sound","SOUND ==> Primary Buffer created with without DirectSound3D enabled\n"));
1203                 }
1204         }
1205
1206         // Get the primary buffer format
1207         ds_get_primary_format(&wave_format);
1208
1209         hr = pPrimaryBuffer->SetFormat(&wave_format);
1210         if (hr != DS_OK) {
1211                 nprintf(("Sound","SOUND ==> pPrimaryBuffer->SetFormat() failed with code %s\n",get_DSERR_text(hr) ));
1212         }
1213
1214         pPrimaryBuffer->GetFormat(&wave_format, sizeof(wave_format), NULL);
1215         nprintf(("Sound","SOUND ==> Primary Buffer forced to: rate: %d Hz bits: %d n_channels: %d\n",
1216                         wave_format.nSamplesPerSec, wave_format.wBitsPerSample, wave_format.nChannels));
1217
1218         // start the primary buffer playing.  This will reduce sound latency when playing a sound
1219         // if no other sounds are playing.
1220         hr = pPrimaryBuffer->Play(0, 0, DSBPLAY_LOOPING);
1221         if (hr != DS_OK) {
1222                 nprintf(("Sound","SOUND ==> pPrimaryBuffer->Play() failed with code %s\n",get_DSERR_text(hr) ));
1223         }
1224
1225         // Initialize DirectSound3D.  Since software performance of DirectSound3D is unacceptably
1226         // slow, we require the voice manger (a DirectSound extension) to be present.  The 
1227         // exception is when A3D is being used, since A3D has a resource manager built in.
1228         if (Ds_use_ds3d) {
1229                 int vm_required = 1;    // voice manager
1230                 if (Ds_use_a3d == 1) {
1231                         vm_required = 0;
1232                 }
1233
1234                 if (ds3d_init(vm_required) != 0) {
1235                         Ds_use_ds3d = 0;
1236                         //Ds_use_eax = 0;
1237                 }
1238         }
1239
1240         if (Ds_use_eax == 1) {
1241                 ds_init_property_set();
1242                 if (ds_eax_init() != 0) {
1243                         Ds_use_eax = 0;
1244                 }
1245         }
1246
1247         ds_build_vol_lookup();
1248         ds_init_channels();
1249         ds_init_buffers();
1250
1251         ds_show_caps(&Soundcard_caps);
1252
1253         return 0;
1254 }
1255
1256 // ---------------------------------------------------------------------------------------
1257 // get_DSERR_text()
1258 //
1259 // returns the text equivalent for the a DirectSound DSERR_ code
1260 //
1261 char *get_DSERR_text(int DSResult)
1262 {
1263         switch( DSResult ) {
1264
1265                 case DS_OK:
1266                         return "DS_OK";
1267                         break;
1268
1269                 case DSERR_ALLOCATED:
1270                         return "DSERR_ALLOCATED";
1271                         break;
1272
1273                 case DSERR_ALREADYINITIALIZED:
1274                         return "DSERR_ALREADYINITIALIZED";
1275                         break;
1276
1277                 case DSERR_BADFORMAT:
1278                         return "DSERR_BADFORMAT";
1279                         break;
1280
1281                 case DSERR_BUFFERLOST:
1282                         return "DSERR_BUFFERLOST";
1283                         break;
1284
1285                 case DSERR_CONTROLUNAVAIL:
1286                         return "DSERR_CONTROLUNAVAIL";
1287                         break;
1288
1289                 case DSERR_GENERIC:
1290                         return "DSERR_GENERIC";
1291                         break;
1292
1293                 case DSERR_INVALIDCALL:
1294                         return "DSERR_INVALIDCALL";
1295                         break;
1296
1297                 case DSERR_INVALIDPARAM:
1298                         return "DSERR_INVALIDPARAM";
1299                         break;
1300
1301                 case DSERR_NOAGGREGATION:
1302                         return "DSERR_NOAGGREGATION";
1303                         break;
1304
1305                 case DSERR_NODRIVER:
1306                         return "DSERR_NODRIVER";
1307                         break;
1308
1309                 case DSERR_OUTOFMEMORY:
1310                         return "DSERR_OUTOFMEMORY";
1311                         break;
1312
1313                 case DSERR_OTHERAPPHASPRIO:
1314                         return "DSERR_OTHERAPPHASPRIO";
1315                         break;
1316
1317                 case DSERR_PRIOLEVELNEEDED:
1318                         return "DSERR_PRIOLEVELNEEDED";
1319                         break;
1320
1321                 case DSERR_UNINITIALIZED:
1322                         return "DSERR_UNINITIALIZED";
1323                         break;
1324
1325                 case DSERR_UNSUPPORTED:
1326                         return "DSERR_UNSUPPORTED";
1327                         break;
1328
1329                 default:
1330                         return "unknown";
1331                         break;
1332         }
1333 }
1334
1335
1336 // ---------------------------------------------------------------------------------------
1337 // ds_close_channel()
1338 //
1339 // Free a single channel
1340 //
1341 void ds_close_channel(int i)
1342 {
1343         HRESULT hr;
1344
1345         // If a 3D interface exists, free it
1346         if ( Channels[i].pds3db != NULL ) {
1347
1348                 if (Ds_use_a3d) {
1349                         Channels[i].pds3db = NULL;
1350                 } else {
1351                         int attempts = 0;
1352                         while(++attempts < 10) {
1353                                 hr = Channels[i].pds3db->Release();
1354                                 if ( hr == DS_OK ) {
1355                                         break;
1356                                 } else {
1357                                         // nprintf(("Sound", "SOUND ==> Channels[channel].pds3db->Release() failed with return value %s\n", get_DSERR_text(second_hr) ));
1358                                 }
1359                         }
1360
1361                         Channels[i].pds3db = NULL;
1362                 }
1363         }
1364
1365         if ( Channels[i].pdsb != NULL ) {
1366                 // If a 2D interface exists, free it
1367                 if ( Channels[i].pdsb != NULL ) {
1368                         int attempts = 0;
1369                         while(++attempts < 10) {
1370                                 hr = Channels[i].pdsb->Release();
1371                                 if ( hr == DS_OK ) {
1372                                         break;
1373                                 } else {
1374                                         nprintf(("Sound", "SOUND ==> Channels[channel].pdsb->Release() failed with return value %s\n", get_DSERR_text(hr) ));
1375                                 }
1376                         }
1377                 }
1378
1379                 Channels[i].pdsb = NULL;
1380         }
1381 }
1382
1383
1384
1385 // ---------------------------------------------------------------------------------------
1386 // ds_close_all_channels()
1387 //
1388 // Free all the channel buffers
1389 //
1390 void ds_close_all_channels()
1391 {
1392         int             i;
1393
1394         for (i = 0; i < MAX_CHANNELS; i++)      {
1395                 ds_close_channel(i);
1396         }
1397 }
1398
1399 // ---------------------------------------------------------------------------------------
1400 // ds_unload_buffer()
1401 //
1402 //
1403 void ds_unload_buffer(int sid, int hid)
1404 {
1405         HRESULT hr;
1406
1407         if ( sid != -1 ) {
1408                 if ( ds_software_buffers[sid].pdsb != NULL ) {
1409                         hr = ds_software_buffers[sid].pdsb->Release();
1410                         if ( hr != DS_OK ) {
1411                                 Int3();
1412                                 nprintf(("Sound", "SOUND ==> ds_software_buffers[sid]->Release() failed with return value %s\n", get_DSERR_text(hr) ));
1413                         }
1414                         ds_software_buffers[sid].pdsb = NULL;
1415                 }
1416         }
1417
1418         if ( hid != -1 ) {
1419                 if ( ds_hardware_buffers[hid].pdsb != NULL ) {
1420                         hr = ds_hardware_buffers[hid].pdsb->Release();
1421                         if ( hr != DS_OK ) {
1422                                 Int3();
1423                                 nprintf(("Sound", "SOUND ==> ds_hardware_buffers[hid]->Release() failed with return value %s\n", get_DSERR_text(hr) ));
1424                         }
1425                         ds_hardware_buffers[hid].pdsb = NULL;
1426                 }
1427         }
1428 }
1429
1430 // ---------------------------------------------------------------------------------------
1431 // ds_close_software_buffers()
1432 //
1433 //
1434 void ds_close_software_buffers()
1435 {
1436         int             i;
1437         HRESULT hr;
1438
1439         for (i = 0; i < MAX_DS_SOFTWARE_BUFFERS; i++)   {
1440                 if ( ds_software_buffers[i].pdsb != NULL ) {
1441                         hr = ds_software_buffers[i].pdsb->Release();
1442                         if ( hr != DS_OK ) {
1443                                 Int3();
1444                                 nprintf(("Sound", "SOUND ==> ds_software_buffers[i]->Release() failed with return value %s\n", get_DSERR_text(hr) ));
1445                         }
1446                         ds_software_buffers[i].pdsb = NULL;
1447                 }
1448         }
1449 }
1450
1451 // ---------------------------------------------------------------------------------------
1452 // ds_close_hardware_buffers()
1453 //
1454 //
1455 void ds_close_hardware_buffers()
1456 {
1457         int             i;
1458         HRESULT hr;
1459
1460         for (i = 0; i < MAX_DS_HARDWARE_BUFFERS; i++)   {
1461                 if ( ds_hardware_buffers[i].pdsb != NULL ) {
1462                         hr = ds_hardware_buffers[i].pdsb->Release();
1463                         if ( hr != DS_OK ) {
1464                                 Int3();
1465                                 nprintf(("Sound", "SOUND ==> ds_hardware_buffers[i]->Release() failed with return value %s\n", get_DSERR_text(hr) ));
1466                         }
1467                         ds_hardware_buffers[i].pdsb = NULL;
1468                 }
1469         }
1470 }
1471
1472 // ---------------------------------------------------------------------------------------
1473 // ds_close_buffers()
1474 //
1475 // Free the channel buffers
1476 //
1477 void ds_close_buffers()
1478 {
1479         ds_close_software_buffers();
1480         ds_close_hardware_buffers();
1481 }
1482
1483 // ---------------------------------------------------------------------------------------
1484 // ds_close()
1485 //
1486 // Close the DirectSound system
1487 //
1488 void ds_close()
1489 {
1490         ds_close_all_channels();
1491         ds_close_buffers();
1492
1493         if (pPropertySet != NULL) {
1494                 pPropertySet->Release();
1495                 pPropertySet = NULL;
1496         }
1497
1498         if (Ds_property_set_pdsb != NULL) {
1499                 Ds_property_set_pdsb->Release();
1500                 Ds_property_set_pdsb = NULL;
1501         }
1502
1503         if (Ds_property_set_pds3db != NULL) {
1504                 Ds_property_set_pds3db->Release();
1505                 Ds_property_set_pds3db = NULL;
1506         }
1507
1508         if (pPrimaryBuffer)     {
1509                 pPrimaryBuffer->Release();
1510                 pPrimaryBuffer = NULL;
1511         }
1512
1513         if ( pIA3d2 ) {
1514                 pIA3d2->Release();
1515                 pIA3d2 = NULL;
1516         }
1517
1518         if (pDirectSound)       {
1519                 pDirectSound->Release();
1520                 pDirectSound = NULL;
1521         }
1522
1523         if ( Ds_dll_loaded ) {
1524                 FreeLibrary(Ds_dll_handle);
1525                 Ds_dll_loaded=0;
1526         }
1527
1528         if (Ds_must_call_couninitialize == 1) {
1529                 CoUninitialize();
1530         }
1531
1532         // free the Channels[] array, since it was dynamically allocated
1533         free(Channels);
1534         Channels = NULL;
1535 }
1536
1537 // ---------------------------------------------------------------------------------------
1538 // ds_get_3d_interface()
1539 // 
1540 // Get the 3d interface for a secondary buffer. 
1541 //
1542 // If the secondary buffer wasn't created with a DSBCAPS_CTRL3D flag, then no 3d interface
1543 // exists
1544 //
1545 void ds_get_3d_interface(LPDIRECTSOUNDBUFFER pdsb, LPDIRECTSOUND3DBUFFER *ppds3db)
1546 {
1547         DSBCAPS                 dsbc;
1548         HRESULT                 DSResult;
1549
1550         dsbc.dwSize = sizeof(dsbc);
1551         DSResult = pdsb->GetCaps(&dsbc);
1552         if ( DSResult == DS_OK && dsbc.dwFlags & DSBCAPS_CTRL3D ) {
1553                 DSResult = pdsb->QueryInterface( IID_IDirectSound3DBuffer, (void**)ppds3db );
1554                 if ( DSResult != DS_OK ) {
1555                         nprintf(("SOUND","Could not obtain 3D interface for hardware buffer: %s\n", get_DSERR_text(DSResult) ));
1556                 }
1557         }
1558 }
1559
1560
1561 // ---------------------------------------------------------------------------------------
1562 // ds_get_free_channel()
1563 // 
1564 // Find a free channel to play a sound on.  If no free channels exists, free up one based
1565 // on volume levels.
1566 //
1567 //      input:          new_volume      =>              volume in DS units for sound to play at
1568 //                                      snd_id          =>              which kind of sound to play
1569 //                                      priority                =>              DS_MUST_PLAY
1570 //                                                                                      DS_LIMIT_ONE
1571 //                                                                                      DS_LIMIT_TWO
1572 //                                                                                      DS_LIMIT_THREE
1573 //
1574 //      returns:                channel number to play sound on
1575 //                                      -1 if no channel could be found
1576 //
1577 // NOTE:        snd_id is needed since we limit the number of concurrent samples
1578 //
1579 //
1580 #define DS_MAX_SOUND_INSTANCES 2
1581
1582 int ds_get_free_channel(int new_volume, int snd_id, int priority)
1583 {
1584         int                             i, first_free_channel, limit;
1585         int                             lowest_vol = 0, lowest_vol_index = -1;
1586         int                             instance_count; // number of instances of sound already playing
1587         int                             lowest_instance_vol, lowest_instance_vol_index;
1588         unsigned long   status;
1589         HRESULT                 hr;
1590         channel                 *chp;
1591
1592         instance_count = 0;
1593         lowest_instance_vol = 99;
1594         lowest_instance_vol_index = -1;
1595         first_free_channel = -1;
1596
1597         // Look for a channel to use to play this sample
1598         for ( i = 0; i < MAX_CHANNELS; i++ )    {
1599                 chp = &Channels[i];
1600                 if ( chp->pdsb == NULL ) {
1601                         if ( first_free_channel == -1 )
1602                                 first_free_channel = i;
1603                         continue;
1604                 }
1605
1606                 hr = chp->pdsb->GetStatus(&status);
1607                 if ( hr != DS_OK ) {
1608                         nprintf(("Sound", "SOUND ==> GetStatus failed with return value %s\n", get_DSERR_text(hr) ));
1609                         return -1;
1610                 }
1611                 if ( !(status & DSBSTATUS_PLAYING) ) {
1612                         if ( first_free_channel == -1 )
1613                                 first_free_channel = i;
1614                         ds_close_channel(i);
1615                         continue;
1616                 }
1617                 else {
1618                         if ( chp->snd_id == snd_id ) {
1619                                 instance_count++;
1620                                 if ( chp->vol < lowest_instance_vol && chp->looping == FALSE ) {
1621                                         lowest_instance_vol = chp->vol;
1622                                         lowest_instance_vol_index = i;
1623                                 }
1624                         }
1625
1626                         if ( chp->vol < lowest_vol && chp->looping == FALSE ) {
1627                                 lowest_vol_index = i;
1628                                 lowest_vol = chp->vol;
1629                         }
1630                 }
1631         }
1632
1633         // determine the limit of concurrent instances of this sound
1634         switch(priority) {
1635                 case DS_MUST_PLAY:
1636                         limit = 100;
1637                         break;
1638                 case DS_LIMIT_ONE:
1639                         limit = 1;
1640                         break;
1641                 case DS_LIMIT_TWO:
1642                         limit = 2;
1643                         break;
1644                 case DS_LIMIT_THREE:
1645                         limit = 3;
1646                         break;
1647                 default:
1648                         Int3();                 // get Alan
1649                         limit = 100;
1650                         break;
1651         }
1652
1653
1654         // If we've exceeded the limit, then maybe stop the duplicate if it is lower volume
1655         if ( instance_count >= limit ) {
1656                 // If there is a lower volume duplicate, stop it.... otherwise, don't play the sound
1657                 if ( lowest_instance_vol_index >= 0 && (Channels[lowest_instance_vol_index].vol <= new_volume) ) {
1658                         ds_close_channel(lowest_instance_vol_index);
1659                         first_free_channel = lowest_instance_vol_index;
1660                 } else {
1661                         first_free_channel = -1;
1662                 }
1663         } else {
1664                 // there is no limit barrier to play the sound, so see if we've ran out of channels
1665                 if ( first_free_channel == -1 ) {
1666                         // stop the lowest volume instance to play our sound if priority demands it
1667                         if ( lowest_vol_index != -1 && priority == DS_MUST_PLAY ) {
1668                                 // Check if the lowest volume playing is less than the volume of the requested sound.
1669                                 // If so, then we are going to trash the lowest volume sound.
1670                                 if ( Channels[lowest_vol_index].vol <= new_volume ) {
1671                                         ds_close_channel(lowest_vol_index);
1672                                         first_free_channel = lowest_vol_index;
1673                                 }
1674                         }
1675                 }
1676         }
1677
1678         return first_free_channel;
1679 }
1680
1681
1682 // ---------------------------------------------------------------------------------------
1683 // ds_channel_dup()
1684 // 
1685 // Find a free channel to play a sound on.  If no free channels exists, free up one based
1686 // on volume levels.
1687 //
1688 // returns:             0               =>              dup was successful
1689 //                                      -1              =>              dup failed (Channels[channel].pdsb will be NULL)
1690 //
1691 int ds_channel_dup(LPDIRECTSOUNDBUFFER pdsb, int channel, int use_ds3d)
1692 {
1693         HRESULT DSResult;
1694
1695         // Duplicate the master buffer into a channel buffer.
1696         DSResult = pDirectSound->DuplicateSoundBuffer(pdsb, &Channels[channel].pdsb );
1697         if ( DSResult != DS_OK ) {
1698                 nprintf(("Sound", "SOUND ==> DuplicateSoundBuffer failed with return value %s\n", get_DSERR_text(DSResult) ));
1699                 Channels[channel].pdsb = NULL;
1700                 return -1;
1701         }
1702
1703         // get the 3d interface for the buffer if it exists
1704         if ( use_ds3d ) {
1705                 if (Channels[channel].pds3db == NULL) {
1706                         ds_get_3d_interface(Channels[channel].pdsb, &Channels[channel].pds3db);
1707                 }
1708         }
1709         
1710         return 0;
1711 }
1712
1713
1714 // ---------------------------------------------------------------------------------------
1715 // ds_restore_buffer()
1716 // 
1717 //
1718 void ds_restore_buffer(LPDIRECTSOUNDBUFFER pdsb)
1719 {
1720         HRESULT hr;
1721         
1722         Int3(); // get Alan, he wants to see this
1723         hr = pdsb->Restore();
1724         if ( hr != DS_OK ) {
1725                 nprintf(("Sound", "Sound ==> Lost a buffer, tried restoring but got %s\n", get_DSERR_text(hr) ));
1726         }
1727 }
1728
1729 // Create a direct sound buffer in software, without locking any data in
1730 int ds_create_buffer(int frequency, int bits_per_sample, int nchannels, int nseconds)
1731 {
1732         HRESULT                 dsrval;
1733         DSBUFFERDESC    dsbd;
1734         WAVEFORMATEX    wfx;
1735         int                             sid;
1736
1737         if (!ds_initialized) {
1738                 return -1;
1739         }
1740
1741         sid = ds_get_sid();
1742         if ( sid == -1 ) {
1743                 nprintf(("Sound","SOUND ==> No more software secondary buffers available\n"));
1744                 return -1;
1745         }
1746
1747         // Set up buffer format
1748         wfx.wFormatTag = WAVE_FORMAT_PCM;
1749         wfx.nChannels = (unsigned short)nchannels;
1750         wfx.nSamplesPerSec = frequency;
1751         wfx.wBitsPerSample = (unsigned short)bits_per_sample;
1752         wfx.cbSize = 0;
1753         wfx.nBlockAlign = (unsigned short)(wfx.nChannels * (wfx.wBitsPerSample / 8));
1754         wfx.nAvgBytesPerSec = wfx.nBlockAlign * wfx.nSamplesPerSec;
1755
1756         memset(&dsbd, 0, sizeof(DSBUFFERDESC));
1757         dsbd.dwSize = sizeof(DSBUFFERDESC);
1758         dsbd.dwBufferBytes = wfx.nAvgBytesPerSec * nseconds;
1759         dsbd.lpwfxFormat = &wfx;
1760         dsbd.dwFlags = DSBCAPS_STATIC | DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRLDEFAULT | DSBCAPS_LOCSOFTWARE;
1761
1762         dsrval = pDirectSound->CreateSoundBuffer(&dsbd, &ds_software_buffers[sid].pdsb, NULL);
1763         if ( dsrval != DS_OK ) {
1764                 return -1;
1765         }
1766
1767         ds_software_buffers[sid].desc = dsbd;
1768         return sid;
1769 }
1770
1771 // Lock data into an existing buffer
1772 int ds_lock_data(int sid, unsigned char *data, int size)
1773 {
1774         HRESULT                                 dsrval;
1775         LPDIRECTSOUNDBUFFER     pdsb;
1776         DSBCAPS                                 caps;
1777         void                                            *buffer_data, *buffer_data2;
1778         DWORD                                           buffer_size, buffer_size2;
1779
1780         Assert(sid >= 0);
1781         pdsb = ds_software_buffers[sid].pdsb;
1782
1783         memset(&caps, 0, sizeof(DSBCAPS));
1784         caps.dwSize = sizeof(DSBCAPS);
1785         dsrval = pdsb->GetCaps(&caps);
1786         if ( dsrval != DS_OK ) {
1787                 return -1;
1788         }
1789
1790         pdsb->SetCurrentPosition(0);
1791
1792         // lock the entire buffer
1793         dsrval = pdsb->Lock(0, caps.dwBufferBytes, &buffer_data, &buffer_size, &buffer_data2, &buffer_size2, 0 );
1794         if ( dsrval != DS_OK ) {
1795                 return -1;
1796         }
1797
1798         // first clear it out with silence
1799         memset(buffer_data, 0x80, buffer_size);
1800         memcpy(buffer_data, data, size);
1801
1802         dsrval = pdsb->Unlock(buffer_data, buffer_size, 0, 0);
1803         if ( dsrval != DS_OK ) {
1804                 return -1;
1805         }
1806
1807         return 0;
1808 }
1809
1810 // Stop a buffer from playing directly
1811 void ds_stop_easy(int sid)
1812 {
1813         HRESULT                                 dsrval;
1814         LPDIRECTSOUNDBUFFER     pdsb;
1815
1816         Assert(sid >= 0);
1817         pdsb = ds_software_buffers[sid].pdsb;
1818         dsrval = pdsb->Stop();
1819 }
1820
1821 //      Play a sound without the usual baggage (used for playing back real-time voice)
1822 //
1823 // parameters:  
1824 //                                      sid                     => software id of sound
1825 //                                      volume      => volume of sound effect in DirectSound units
1826 int ds_play_easy(int sid, int volume)
1827 {
1828         HRESULT                                 dsrval;
1829         LPDIRECTSOUNDBUFFER     pdsb;
1830
1831         Assert(sid >= 0);
1832         pdsb = ds_software_buffers[sid].pdsb;
1833
1834         pdsb->SetVolume(volume);
1835         dsrval=pdsb->Play(0, 0, 0);
1836         if ( dsrval != DS_OK ) {
1837                 return -1;
1838         }
1839
1840         return 0;
1841 }
1842
1843 //extern void HUD_add_to_scrollback(char *text, int source);
1844 //extern void HUD_printf(char *format, ...);
1845
1846 // ---------------------------------------------------------------------------------------
1847 // Play a DirectSound secondary buffer.  
1848 // 
1849 //
1850 // parameters:  
1851 //                                      sid                     => software id of sound
1852 //                                      hid                     => hardware id of sound ( -1 if not in hardware )
1853 //                                      snd_id          =>      what kind of sound this is
1854 //                                      priority                =>              DS_MUST_PLAY
1855 //                                                                                      DS_LIMIT_ONE
1856 //                                                                                      DS_LIMIT_TWO
1857 //                                                                                      DS_LIMIT_THREE
1858 //                                      volume      => volume of sound effect in DirectSound units
1859 //                                      pan         => pan of sound in DirectSound units
1860 //             looping     => whether the sound effect is looping or not
1861 //
1862 // returns:    -1          => sound effect could not be started
1863 //              >=0        => sig for sound effect successfully started
1864 //
1865 int ds_play(int sid, int hid, int snd_id, int priority, int volume, int pan, int looping, bool is_voice_msg)
1866 {
1867         int                             channel;
1868         HRESULT                 DSResult;
1869
1870         if (!ds_initialized)
1871                 return -1;
1872
1873         channel = ds_get_free_channel(volume, snd_id, priority);
1874
1875         if (channel > -1)       {
1876                 if ( Channels[channel].pdsb != NULL ) {
1877                         return -1;
1878                 }
1879
1880                 // First check if the sound is in hardware, and try to duplicate from there
1881                 if ( hid != -1 ) {
1882                         Int3();
1883                         if ( ds_channel_dup(ds_hardware_buffers[hid].pdsb, channel, 0) == 0 ) {
1884 //                              nprintf(("Sound", "SOUND ==> Played sound in hardware..\n"));
1885                         }
1886                 }
1887
1888                 // Channel will be NULL if hardware dup failed, or there was no hardware dup attempted
1889                 if ( Channels[channel].pdsb == NULL ) {
1890                         if ( ds_channel_dup(ds_software_buffers[sid].pdsb, channel, 0) == 0 ) {
1891 //                              nprintf(("Sound", "SOUND ==> Played sound in software..\n"));
1892                         }
1893                 }
1894         
1895                 if ( Channels[channel].pdsb == NULL ) {
1896                         return -1;
1897                 }
1898
1899                 if ( ds_using_ds3d() ) {
1900                         if ( ds_is_3d_buffer(Channels[channel].pdsb) ) {
1901                                 if (Channels[channel].pds3db == NULL) {
1902                                         ds_get_3d_interface(Channels[channel].pdsb, &Channels[channel].pds3db);
1903                                 }
1904                                 if ( Channels[channel].pds3db ) {
1905                                         Channels[channel].pds3db->SetMode(DS3DMODE_DISABLE,DS3D_IMMEDIATE);
1906                                 }
1907                         }
1908                 }
1909
1910                 // Actually play it
1911                 Channels[channel].vol = volume;
1912                 Channels[channel].looping = looping;
1913                 Channels[channel].priority = priority;
1914         Channels[channel].pdsb->SetPan(pan);
1915                 Channels[channel].pdsb->SetVolume(volume);
1916                 Channels[channel].is_voice_msg = is_voice_msg;
1917
1918                 int ds_flags = 0;
1919                 if ( looping )
1920                         ds_flags |= DSBPLAY_LOOPING;
1921                 
1922                 DSResult = Channels[channel].pdsb->Play(0, 0, ds_flags );
1923
1924                 /*
1925                 if (Stop_logging_sounds == false) {
1926                         char buf[256];
1927                         sprintf(buf, "channel %d, address: %x, ds_flags: %d", channel, Channels[channel].pdsb, ds_flags);
1928                         HUD_add_to_scrollback(buf, 3);
1929                 }
1930                 */
1931
1932                 if ( DSResult == DSERR_BUFFERLOST ) {
1933                         ds_restore_buffer(Channels[channel].pdsb);
1934                         DSResult = Channels[channel].pdsb->Play(0, 0, ds_flags );
1935                 }
1936
1937                 if ( DSResult != DS_OK ) {
1938                         nprintf(("Sound", "Sound ==> Play failed with return value %s\n", get_DSERR_text(DSResult) ));
1939                         return -1;
1940                 }
1941         }
1942         else {
1943 //              nprintf(( "Sound", "SOUND ==> Not playing sound requested at volume %.2f\n", ds_get_percentage_vol(volume) ));
1944                 return -1;
1945         }
1946
1947         Channels[channel].snd_id = snd_id;
1948         Channels[channel].sig = channel_next_sig++;
1949         if (channel_next_sig < 0 ) {
1950                 channel_next_sig = 1;
1951         }
1952
1953         /*
1954         if (Stop_logging_sounds == false) {
1955                 if (is_voice_msg) {
1956                         char buf[256];
1957                         sprintf(buf, "VOICE sig: %d, sid: %d, snd_id: %d, ch: %d", Channels[channel].sig, sid, snd_id, channel);
1958                         HUD_add_to_scrollback(buf, 3);
1959                 }
1960         }
1961         */
1962
1963         Channels[channel].last_position = 0;
1964
1965         // make sure there aren't any looping voice messages
1966         for (int i=0; i<MAX_CHANNELS; i++) {
1967                 if (Channels[i].is_voice_msg == true) {
1968                         if (Channels[i].pdsb == NULL) {
1969                                 continue;
1970                         }
1971
1972                         DWORD current_position = ds_get_play_position(i);
1973                         if (current_position != 0) {
1974                                 if (current_position < Channels[i].last_position) {
1975                                         ds_close_channel(i);
1976                                 } else {
1977                                         Channels[i].last_position = current_position;
1978                                 }
1979                         }
1980                 }
1981         }
1982
1983         return Channels[channel].sig;
1984 }
1985
1986
1987 // ---------------------------------------------------------------------------------------
1988 // ds_get_channel()
1989 //
1990 // Return the channel number that is playing the sound identified by sig.  If that sound is
1991 // not playing, return -1.
1992 //
1993 int ds_get_channel(int sig)
1994 {
1995         int i;
1996
1997         for ( i = 0; i < MAX_CHANNELS; i++ ) {
1998                 if ( Channels[i].pdsb && Channels[i].sig == sig ) {
1999                         if ( ds_is_channel_playing(i) == TRUE ) {
2000                                 return i;
2001                         }
2002                 }
2003         }
2004         return -1;
2005 }
2006
2007 // ---------------------------------------------------------------------------------------
2008 // ds_is_channel_playing()
2009 //
2010 //
2011 int ds_is_channel_playing(int channel)
2012 {
2013         HRESULT                 hr;
2014         unsigned long   status;         
2015
2016         if ( !Channels[channel].pdsb ) {
2017                 return 0;
2018         }
2019
2020         hr = Channels[channel].pdsb->GetStatus(&status);
2021         if ( hr != DS_OK ) {
2022                 nprintf(("Sound", "SOUND ==> GetStatus failed with return value %s\n", get_DSERR_text(hr) ));
2023                 return 0;
2024         }
2025
2026         if ( status & DSBSTATUS_PLAYING )
2027                 return TRUE;
2028         else
2029                 return FALSE;
2030 }
2031
2032 // ---------------------------------------------------------------------------------------
2033 // ds_stop_channel()
2034 //
2035 //
2036 void ds_stop_channel(int channel)
2037 {
2038         ds_close_channel(channel);
2039 }
2040
2041 // ---------------------------------------------------------------------------------------
2042 // ds_stop_channel_all()
2043 //
2044 //      
2045 void ds_stop_channel_all()
2046 {
2047         int i;
2048
2049         for ( i=0; i<MAX_CHANNELS; i++ )        {
2050                 if ( Channels[i].pdsb != NULL ) {
2051                         ds_stop_channel(i);
2052                 }
2053         }
2054 }
2055
2056 // ---------------------------------------------------------------------------------------
2057 // ds_set_volume()
2058 //
2059 //      Set the volume for a channel.  The volume is expected to be in DirectSound units
2060 //
2061 //      If the sound is a 3D sound buffer, this is like re-establishing the maximum 
2062 // volume.
2063 //
2064 void ds_set_volume( int channel, int vol )
2065 {
2066         HRESULT                 hr;
2067         unsigned long   status;         
2068
2069         hr = Channels[channel].pdsb->GetStatus(&status);
2070         if ( hr != DS_OK ) {
2071                 nprintf(("Sound", "SOUND ==> GetStatus failed with return value %s\n", get_DSERR_text(hr) ));
2072                 return;
2073         }
2074
2075         if ( status & DSBSTATUS_PLAYING ) {
2076                 Channels[channel].pdsb->SetVolume(vol);
2077         }
2078 }
2079
2080 // ---------------------------------------------------------------------------------------
2081 // ds_set_pan()
2082 //
2083 //      Set the pan for a channel.  The pan is expected to be in DirectSound units
2084 //
2085 void ds_set_pan( int channel, int pan )
2086 {
2087         HRESULT                 hr;
2088         unsigned long   status;         
2089
2090         hr = Channels[channel].pdsb->GetStatus(&status);
2091         if ( hr != DS_OK ) {
2092                 nprintf(("Sound", "SOUND ==> GetStatus failed with return value %s\n", get_DSERR_text(hr) ));
2093                 return;
2094         }
2095
2096         if ( status & DSBSTATUS_PLAYING ) {
2097                 Channels[channel].pdsb->SetPan(pan);
2098         }
2099 }
2100
2101 // ---------------------------------------------------------------------------------------
2102 // ds_get_pitch()
2103 //
2104 //      Get the pitch of a channel
2105 //
2106 int ds_get_pitch(int channel)
2107 {
2108         unsigned long   status, pitch = 0;
2109         HRESULT                 hr;
2110
2111         hr = Channels[channel].pdsb->GetStatus(&status);
2112
2113         if ( hr != DS_OK ) {
2114                 nprintf(("Sound", "SOUND ==> GetStatus failed with return value %s\n", get_DSERR_text(hr) ));
2115                 return -1;
2116         }
2117
2118         if ( status & DSBSTATUS_PLAYING )       {
2119                 hr = Channels[channel].pdsb->GetFrequency(&pitch);
2120                 if ( hr != DS_OK ) {
2121                         nprintf(("Sound", "SOUND ==> GetFrequency failed with return value %s\n", get_DSERR_text(hr) ));
2122                         return -1;
2123                 }
2124         }
2125
2126         return (int)pitch;
2127 }
2128
2129 // ---------------------------------------------------------------------------------------
2130 // ds_set_pitch()
2131 //
2132 //      Set the pitch of a channel
2133 //
2134 void ds_set_pitch(int channel, int pitch)
2135 {
2136         unsigned long   status;
2137         HRESULT                 hr;
2138
2139         hr = Channels[channel].pdsb->GetStatus(&status);
2140         if ( hr != DS_OK ) {
2141                 nprintf(("Sound", "SOUND ==> GetStatus failed with return value %s\n", get_DSERR_text(hr) ));
2142                 return;
2143         }
2144
2145         if ( pitch < MIN_PITCH )
2146                 pitch = MIN_PITCH;
2147
2148         if ( pitch > MAX_PITCH )
2149                 pitch = MAX_PITCH;
2150
2151         if ( status & DSBSTATUS_PLAYING )       {
2152                 Channels[channel].pdsb->SetFrequency((unsigned long)pitch);
2153         }
2154 }
2155
2156 // ---------------------------------------------------------------------------------------
2157 // ds_chg_loop_status()
2158 //
2159 //      
2160 void ds_chg_loop_status(int channel, int loop)
2161 {
2162         unsigned long   status;
2163         HRESULT                 hr;
2164
2165         hr = Channels[channel].pdsb->GetStatus(&status);
2166         if ( hr != DS_OK ) {
2167                 nprintf(("Sound", "SOUND ==> GetStatus failed with return value %s\n", get_DSERR_text(hr) ));
2168                 return;
2169         }
2170         
2171         if ( !(status & DSBSTATUS_PLAYING) )
2172                 return;         // sound is not playing anymore
2173
2174         if ( status & DSBSTATUS_LOOPING ) {
2175                 if ( loop )
2176                         return; // we are already looping
2177                 else {
2178                         // stop the sound from looping
2179                         hr = Channels[channel].pdsb->Play(0,0,0);
2180                 }
2181         }
2182         else {
2183                 if ( !loop )
2184                         return; // the sound is already not looping
2185                 else {
2186                         // start the sound looping
2187                         hr = Channels[channel].pdsb->Play(0,0,DSBPLAY_LOOPING);
2188                 }
2189         }
2190 }
2191
2192 // ---------------------------------------------------------------------------------------
2193 // ds3d_play()
2194 //
2195 // Starts a ds3d sound playing
2196 // 
2197 //      input:
2198 //
2199 //                                      sid                             =>      software id for sound to play
2200 //                                      hid                             =>      hardware id for sound to play (-1 if not in hardware)
2201 //                                      snd_id                  => identifies what type of sound is playing
2202 //                                      pos                             =>      world pos of sound
2203 //                                      vel                             =>      velocity of object emitting sound
2204 //                                      min                             =>      distance at which sound doesn't get any louder
2205 //                                      max                             =>      distance at which sound becomes inaudible
2206 //                                      looping                 =>      boolean, whether to loop the sound or not
2207 //                                      max_volume              =>      volume (-10000 to 0) for 3d sound at maximum
2208 //                                      estimated_vol   =>      manual estimated volume
2209 //                                      priority                =>              DS_MUST_PLAY
2210 //                                                                                      DS_LIMIT_ONE
2211 //                                                                                      DS_LIMIT_TWO
2212 //                                                                                      DS_LIMIT_THREE
2213 //
2214 //      returns:                        0                               => sound started successfully
2215 //                                              -1                              => sound could not be played
2216 //
2217 int ds3d_play(int sid, int hid, int snd_id, vector *pos, vector *vel, int min, int max, int looping, int max_volume, int estimated_vol, int priority )
2218 {
2219         int                             channel;
2220         HRESULT                 hr;
2221
2222         if (!ds_initialized)
2223                 return -1;
2224
2225         channel = ds_get_free_channel(estimated_vol, snd_id, priority);
2226
2227         if (channel > -1)       {
2228                 Assert(Channels[channel].pdsb == NULL);
2229
2230                 // First check if the sound is in hardware, and try to duplicate from there
2231                 if ( hid != -1 ) {
2232                         Int3();
2233                         if ( ds_is_3d_buffer(ds_hardware_buffers[hid].pdsb) == FALSE ) {
2234                                 nprintf(("Sound", "SOUND ==> Tried to play non-3d buffer in ds3d_play()..\n"));
2235                                 return -1;
2236                         }
2237
2238                         if ( ds_channel_dup(ds_hardware_buffers[hid].pdsb, channel, 1) == 0 ) {
2239                                 nprintf(("Sound", "SOUND ==> Played sound using DirectSound3D in hardware..\n"));
2240                         }
2241                 }
2242
2243                 // Channel will be NULL if hardware dup failed, or there was no hardware dup attempted
2244                 if ( Channels[channel].pdsb == NULL ) {
2245
2246 /*
2247                         if ( ds_is_3d_buffer(ds_software_buffers[sid].pdsb) == FALSE ) {
2248                                 nprintf(("Sound", "SOUND ==> Tried to play non-3d buffer in ds3d_play()..\n"));
2249                                 return -1;
2250                         }
2251 */
2252
2253                         if ( ds_channel_dup(ds_software_buffers[sid].pdsb, channel, 1) == 0 ) {
2254 //                              nprintf(("Sound", "SOUND ==> Played sound using DirectSound3D \n"));
2255                         }
2256                 }
2257
2258                 if ( Channels[channel].pdsb == NULL ) {
2259                         return -1;
2260 /*
2261                         DSBUFFERDESC desc;
2262
2263                         desc = ds_software_buffers[sid].desc;
2264                         desc.lpwfxFormat = &ds_software_buffers[sid].wfx;
2265
2266                         // duplicate buffer failed, so call CreateBuffer instead
2267
2268                         hr = pDirectSound->CreateSoundBuffer(&desc, &Channels[channel].pdsb, NULL );
2269                         // lock the data in
2270                         if ( (hr == DS_OK) && (Channels[channel].pdsb) ) {
2271                                 BYTE    *pdest, *pdest2;
2272                                 BYTE    *psrc, *psrc2;
2273                                 DWORD   src_ds_size, dest_ds_size, not_used;
2274                                 int     src_size;
2275                         
2276                                 if ( ds_get_size(sid, &src_size) != 0 ) {
2277                                         Int3();
2278                                         Channels[channel].pdsb->Release();
2279                                         return -1;
2280                                 }
2281
2282                                 // lock the src buffer
2283                                 hr = ds_software_buffers[sid].pdsb->Lock(0, src_size, (void**)&psrc, &src_ds_size, (void**)&psrc2, &not_used, 0);
2284                                 if ( hr != DS_OK ) {
2285                                         mprintf(("err: %s\n", get_DSERR_text(hr)));
2286                                         Int3();
2287                                         Channels[channel].pdsb->Release();
2288                                         return -1;
2289                                 }
2290
2291                                 if ( Channels[channel].pdsb->Lock(0, src_ds_size, (void**)(&pdest), &dest_ds_size, (void**)&pdest2, &not_used, 0) == DS_OK)     {
2292                                         memcpy(pdest, psrc, src_ds_size);
2293                                         Channels[channel].pdsb->Unlock(pdest, dest_ds_size, 0, 0);
2294                                         ds_get_3d_interface(Channels[channel].pdsb, &Channels[channel].pds3db);
2295                                 } else {
2296                                         Channels[channel].pdsb->Release();
2297                                         return -1;
2298                                 }
2299                         }
2300 */
2301                 }
2302
2303                 Assert(Channels[channel].pds3db );
2304                 Channels[channel].pds3db->SetMode(DS3DMODE_NORMAL,DS3D_IMMEDIATE);
2305
2306                 // set up 3D sound data here
2307                 ds3d_update_buffer(channel, i2fl(min), i2fl(max), pos, vel);
2308
2309                 Channels[channel].vol = estimated_vol;
2310                 Channels[channel].looping = looping;
2311
2312                 // sets the maximum "inner cone" volume
2313                 Channels[channel].pdsb->SetVolume(max_volume);
2314
2315                 int ds_flags = 0;
2316                 if ( looping )
2317                         ds_flags |= DSBPLAY_LOOPING;
2318
2319                 // Actually play it
2320                 hr = Channels[channel].pdsb->Play(0, 0, ds_flags );
2321
2322                 if ( hr == DSERR_BUFFERLOST ) {
2323                         ds_restore_buffer(Channels[channel].pdsb);
2324                         hr = Channels[channel].pdsb->Play(0, 0, ds_flags );
2325                 }
2326
2327                 if ( hr != DS_OK ) {
2328                         nprintf(("Sound", "Sound ==> Play failed with return value %s\n", get_DSERR_text(hr) ));
2329                         if ( Channels[channel].pdsb ) {
2330                                 int attempts = 0;
2331                                 while(++attempts < 10) {
2332                                         hr = Channels[channel].pdsb->Release();
2333                                         if ( hr == DS_OK ) {
2334                                                 break;
2335                                         } else {
2336                                                 nprintf(("Sound","SOUND ==> DirectSound Release() failed with code %s\n.",get_DSERR_text(hr) ));
2337                                                 continue;
2338                                         }
2339                                 }
2340                                 Channels[channel].pdsb = NULL;
2341                         }
2342                         return -1;
2343                 }
2344         }
2345         else {
2346                 nprintf(( "Sound", "SOUND ==> Not playing requested 3D sound\n"));
2347                 return -1;
2348         }
2349
2350         Channels[channel].snd_id = snd_id;
2351         Channels[channel].sig = channel_next_sig++;
2352         if (channel_next_sig < 0 ) {
2353                 channel_next_sig = 1;
2354         }
2355         return Channels[channel].sig;
2356 }
2357
2358 void ds_set_position(int channel, DWORD offset)
2359 {
2360         // set the position of the sound buffer
2361         Channels[channel].pdsb->SetCurrentPosition(offset);
2362 }
2363
2364 DWORD ds_get_play_position(int channel)
2365 {
2366         DWORD play,write;       
2367         if ( Channels[channel].pdsb ) {
2368                 Channels[channel].pdsb->GetCurrentPosition((LPDWORD)&play,(LPDWORD)&write);
2369         } else {
2370                 play = 0;
2371         }
2372
2373         return play;
2374 }
2375
2376 DWORD ds_get_write_position(int channel)
2377 {
2378         DWORD play,write;       
2379         if ( Channels[channel].pdsb ) {
2380                 Channels[channel].pdsb->GetCurrentPosition((LPDWORD)&play,(LPDWORD)&write);
2381         } else {
2382                 write = 0;
2383         }
2384
2385         return write;
2386 }
2387
2388 int ds_get_channel_size(int channel)
2389 {
2390         int             size;
2391         DSBCAPS caps;
2392         HRESULT dsrval;
2393
2394         if ( Channels[channel].pdsb ) {
2395                 memset(&caps, 0, sizeof(DSBCAPS));
2396                 caps.dwSize = sizeof(DSBCAPS);
2397                 dsrval = Channels[channel].pdsb->GetCaps(&caps);
2398                 if ( dsrval != DS_OK ) {
2399                         return 0;
2400                 }
2401                 size = caps.dwBufferBytes;
2402         } else {
2403                 size = 0;
2404         }
2405
2406         return size;
2407 }
2408
2409 // Returns the number of channels that are actually playing
2410 int ds_get_number_channels()
2411 {
2412         int i,n;
2413
2414         n = 0;
2415         for ( i = 0; i < MAX_CHANNELS; i++ ) {
2416                 if ( Channels[i].pdsb ) {
2417                         if ( ds_is_channel_playing(i) == TRUE ) {
2418                                 n++;
2419                         }
2420                 }
2421         }
2422
2423         return n;
2424 }
2425
2426 // retreive raw data from a sound buffer
2427 int ds_get_data(int sid, char *data)
2428 {
2429         HRESULT                                 dsrval;
2430         LPDIRECTSOUNDBUFFER     pdsb;
2431         DSBCAPS                                 caps;
2432         void                                            *buffer_data;
2433         DWORD                                           buffer_size;
2434
2435         Assert(sid >= 0);
2436         pdsb = ds_software_buffers[sid].pdsb;
2437
2438         memset(&caps, 0, sizeof(DSBCAPS));
2439         caps.dwSize = sizeof(DSBCAPS);
2440         dsrval = pdsb->GetCaps(&caps);
2441         if ( dsrval != DS_OK ) {
2442                 return -1;
2443         }
2444
2445         // lock the entire buffer
2446         dsrval = pdsb->Lock(0, caps.dwBufferBytes, &buffer_data, &buffer_size, 0, 0, 0);
2447         if ( dsrval != DS_OK ) {
2448                 return -1;
2449         }
2450
2451         memcpy(data, buffer_data, buffer_size);
2452
2453         dsrval = pdsb->Unlock(buffer_data, buffer_size, 0, 0);
2454         if ( dsrval != DS_OK ) {
2455                 return -1;
2456         }
2457
2458         return 0;
2459 }
2460
2461 // return the size of the raw sound data
2462 int ds_get_size(int sid, int *size)
2463 {
2464         HRESULT                                 dsrval;
2465         LPDIRECTSOUNDBUFFER     pdsb;
2466         DSBCAPS                                 caps;
2467
2468         Assert(sid >= 0);
2469         pdsb = ds_software_buffers[sid].pdsb;
2470
2471         memset(&caps, 0, sizeof(DSBCAPS));
2472         caps.dwSize = sizeof(DSBCAPS);
2473         dsrval = pdsb->GetCaps(&caps);
2474         if ( dsrval != DS_OK ) {
2475                 return -1;
2476         }
2477
2478         *size = caps.dwBufferBytes;
2479         return 0;
2480 }
2481
2482 int ds_using_ds3d()
2483 {
2484         return Ds_use_ds3d;
2485 }
2486
2487 // Return the primary buffer interface.  Note that we cast to a uint to avoid
2488 // having to include dsound.h (and thus windows.h) in ds.h.
2489 //
2490 uint ds_get_primary_buffer_interface()
2491 {
2492         return (uint)pPrimaryBuffer;
2493 }
2494
2495 // Return the DirectSound Interface.
2496 //
2497 uint ds_get_dsound_interface()
2498 {
2499         return (uint)pDirectSound;
2500 }
2501
2502 uint ds_get_property_set_interface()
2503 {
2504         return (uint)pPropertySet;
2505 }
2506
2507 // --------------------
2508 //
2509 // EAX Functions below
2510 //
2511 // --------------------
2512
2513 // Set the master volume for the reverb added to all sound sources.
2514 //
2515 // volume: volume, range from 0 to 1.0
2516 //
2517 // returns: 0 if the volume is set successfully, otherwise return -1
2518 //
2519 int ds_eax_set_volume(float volume)
2520 {
2521         HRESULT hr;
2522
2523         if (Ds_eax_inited == 0) {
2524                 return -1;
2525         }
2526
2527         Assert(Ds_eax_reverb);
2528
2529         CAP(volume, 0.0f, 1.0f);
2530
2531         hr = Ds_eax_reverb->Set(DSPROPSETID_EAX_ReverbProperties_Def, DSPROPERTY_EAX_VOLUME, NULL, 0, &volume, sizeof(float));
2532         if (SUCCEEDED(hr)) {
2533                 return 0;
2534         } else {
2535                 return -1;
2536         }
2537 }
2538
2539 // Set the decay time for the EAX environment (ie all sound sources)
2540 //
2541 // seconds: decay time in seconds
2542 //
2543 // returns: 0 if decay time is successfully set, otherwise return -1
2544 //
2545 int ds_eax_set_decay_time(float seconds)
2546 {
2547         HRESULT hr;
2548
2549         if (Ds_eax_inited == 0) {
2550                 return -1;
2551         }
2552
2553         Assert(Ds_eax_reverb);
2554
2555         CAP(seconds, 0.1f, 20.0f);
2556
2557         hr = Ds_eax_reverb->Set(DSPROPSETID_EAX_ReverbProperties_Def, DSPROPERTY_EAX_DECAYTIME, NULL, 0, &seconds, sizeof(float));
2558         if (SUCCEEDED(hr)) {
2559                 return 0;
2560         } else {
2561                 return -1;
2562         }
2563 }
2564
2565 // Set the damping value for the EAX environment (ie all sound sources)
2566 //
2567 // damp: damp value from 0 to 2.0
2568 //
2569 // returns: 0 if the damp value is successfully set, otherwise return -1
2570 //
2571 int ds_eax_set_damping(float damp)
2572 {
2573         HRESULT hr;
2574
2575         if (Ds_eax_inited == 0) {
2576                 return -1;
2577         }
2578
2579         Assert(Ds_eax_reverb);
2580
2581         CAP(damp, 0.0f, 2.0f);
2582
2583         hr = Ds_eax_reverb->Set(DSPROPSETID_EAX_ReverbProperties_Def, DSPROPERTY_EAX_DAMPING, NULL, 0, &damp, sizeof(float));
2584         if (SUCCEEDED(hr)) {
2585                 return 0;
2586         } else {
2587                 return -1;
2588         }
2589 }
2590
2591 // Set up the environment type for all sound sources.
2592 //
2593 // envid: value from the EAX_ENVIRONMENT_* enumeration in ds_eax.h
2594 //
2595 // returns: 0 if the environment is set successfully, otherwise return -1
2596 //
2597 int ds_eax_set_environment(unsigned long envid)
2598 {
2599         HRESULT hr;
2600
2601         if (Ds_eax_inited == 0) {
2602                 return -1;
2603         }
2604
2605         Assert(Ds_eax_reverb);
2606
2607         hr = Ds_eax_reverb->Set(DSPROPSETID_EAX_ReverbProperties_Def, DSPROPERTY_EAX_ENVIRONMENT, NULL, 0, &envid, sizeof(unsigned long));
2608         if (SUCCEEDED(hr)) {
2609                 return 0;
2610         } else {
2611                 return -1;
2612         }
2613 }
2614
2615 // Set up a predefined environment for EAX
2616 //
2617 // envid: value from teh EAX_ENVIRONMENT_* enumeration
2618 //
2619 // returns: 0 if successful, otherwise return -1
2620 //
2621 int ds_eax_set_preset(unsigned long envid)
2622 {
2623         HRESULT hr;
2624
2625         if (Ds_eax_inited == 0) {
2626                 return -1;
2627         }
2628
2629         Assert(Ds_eax_reverb);
2630         Assert(envid < EAX_ENVIRONMENT_COUNT);
2631
2632         hr = Ds_eax_reverb->Set(DSPROPSETID_EAX_ReverbProperties_Def, DSPROPERTY_EAX_ALL, NULL, 0, &Ds_eax_presets[envid], sizeof(EAX_REVERBPROPERTIES));
2633         if (SUCCEEDED(hr)) {
2634                 return 0;
2635         } else {
2636                 return -1;
2637         }
2638 }
2639
2640
2641 // Set up all the parameters for an environment
2642 //
2643 // id: value from teh EAX_ENVIRONMENT_* enumeration
2644 // volume: volume for the environment (0 to 1.0)
2645 // damping: damp value for the environment (0 to 2.0)
2646 // decay: decay time in seconds (0.1 to 20.0)
2647 //
2648 // returns: 0 if successful, otherwise return -1
2649 //
2650 int ds_eax_set_all(unsigned long id, float vol, float damping, float decay)
2651 {
2652         HRESULT hr;
2653
2654         if (Ds_eax_inited == 0) {
2655                 return -1;
2656         }
2657
2658         Assert(Ds_eax_reverb);
2659         Assert(id < EAX_ENVIRONMENT_COUNT);
2660
2661         EAX_REVERBPROPERTIES er;
2662
2663         er.environment = id;
2664         er.fVolume = vol;
2665         er.fDecayTime_sec = decay;
2666         er.fDamping = damping;
2667
2668         hr = Ds_eax_reverb->Set(DSPROPSETID_EAX_ReverbProperties_Def, DSPROPERTY_EAX_ALL, NULL, 0, &er, sizeof(EAX_REVERBPROPERTIES));
2669         if (SUCCEEDED(hr)) {
2670                 return 0;
2671         } else {
2672                 return -1;
2673         }
2674 }
2675
2676 // Get up the parameters for the current environment
2677 //
2678 // er: (output) hold environment parameters
2679 //
2680 // returns: 0 if successful, otherwise return -1
2681 //
2682 int ds_eax_get_all(EAX_REVERBPROPERTIES *er)
2683 {
2684         HRESULT hr;
2685         unsigned long outsize;
2686
2687         if (Ds_eax_inited == 0) {
2688                 return -1;
2689         }
2690
2691         Assert(Ds_eax_reverb);
2692
2693         hr = Ds_eax_reverb->Get(DSPROPSETID_EAX_ReverbProperties_Def, DSPROPERTY_EAX_ALL, NULL, 0, er, sizeof(EAX_REVERBPROPERTIES), &outsize);
2694         if (SUCCEEDED(hr)) {
2695                 return 0;
2696         } else {
2697                 return -1;
2698         }
2699
2700 }
2701
2702 // Close down EAX, freeing any allocated resources
2703 //
2704 void ds_eax_close()
2705 {
2706         if (Ds_eax_inited == 0) {
2707                 return;
2708         }
2709
2710         Ds_eax_inited = 0;
2711 }
2712
2713 // Initialize EAX
2714 //
2715 // returns: 0 if initialization is successful, otherwise return -1
2716 //
2717 int ds_eax_init()
2718 {
2719         HRESULT hr;
2720         unsigned long driver_support = 0;
2721
2722         if (Ds_eax_inited) {
2723                 return 0;
2724         }
2725
2726         Assert(Ds_eax_reverb == NULL);
2727
2728         Ds_eax_reverb = (LPKSPROPERTYSET)ds_get_property_set_interface();
2729         if (Ds_eax_reverb == NULL) {
2730                 return -1;
2731         }
2732
2733         // check if the listener property is supported by the audio driver
2734         hr = Ds_eax_reverb->QuerySupport(DSPROPSETID_EAX_ReverbProperties_Def, DSPROPERTY_EAX_ALL, &driver_support);
2735         if (FAILED(hr)) {
2736                 nprintf(("Sound", "QuerySupport for the EAX Listener property set failed.. disabling EAX\n"));
2737                 goto ds_eax_init_failed;
2738         }
2739
2740         if ((driver_support & (KSPROPERTY_SUPPORT_GET | KSPROPERTY_SUPPORT_SET)) != (KSPROPERTY_SUPPORT_GET | KSPROPERTY_SUPPORT_SET)) {
2741                 goto ds_eax_init_failed;
2742         }
2743
2744         ds_eax_set_all(EAX_ENVIRONMENT_GENERIC, 0.0f, 0.0f, 0.0f);
2745
2746         Ds_eax_inited = 1;
2747         return 0;
2748
2749 ds_eax_init_failed:
2750         if (Ds_eax_reverb != NULL) {
2751                 Ds_eax_reverb->Release();
2752                 Ds_eax_reverb = NULL;
2753         }
2754
2755         Ds_eax_inited = 0;
2756
2757         return -1;
2758 }
2759
2760 int ds_eax_is_inited()
2761 {
2762         return Ds_eax_inited;
2763 }
2764
2765 bool ds_using_a3d()
2766 {
2767         if (Ds_use_a3d == 0) {
2768                 return false;
2769         } else {
2770                 return true;
2771         }
2772 }
2773
2774 // Called once per game frame to make sure voice messages aren't looping
2775 //
2776 void ds_do_frame()
2777 {
2778         channel *cp;
2779
2780         for (int i=0; i<MAX_CHANNELS; i++) {
2781                 cp = &Channels[i];
2782                 if (cp->is_voice_msg == true) {
2783                         if (cp->pdsb == NULL) {
2784                                 continue;
2785                         }
2786
2787                         DWORD current_position = ds_get_play_position(i);
2788                         if (current_position != 0) {
2789                                 if (current_position < cp->last_position) {
2790                                         ds_close_channel(i);
2791                                 } else {
2792                                         cp->last_position = current_position;
2793                                 }
2794                         }
2795                 }
2796         }
2797 }
2798