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