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