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