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