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