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