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