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