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