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