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