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