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