2 * $Logfile: /Freespace2/code/Sound/ds.cpp $
7 * C file for interface to DirectSound
10 * Revision 1.8 2002/06/05 04:03:33 relnev
11 * finished cfilesystem.
13 * removed some old code.
15 * fixed mouse save off-by-one.
19 * Revision 1.7 2002/06/02 22:31:37 cemason
22 * Revision 1.6 2002/06/02 21:11:12 cemason
25 * Revision 1.5 2002/06/02 09:50:42 relnev
28 * Revision 1.4 2002/06/02 07:17:44 cemason
29 * Added OpenAL support.
31 * Revision 1.3 2002/05/28 17:03:29 theoddone33
32 * fs2 gets to the main game loop now
34 * Revision 1.2 2002/05/27 21:35:50 theoddone33
35 * Stub out dsound backend
37 * Revision 1.1.1.1 2002/05/03 03:28:10 root
41 * 18 10/25/99 5:56p Jefff
42 * increase num software channels to the number the users hardware can
43 * handle. not less than 16, tho.
45 * 17 9/08/99 3:22p Dave
46 * Updated builtin mission list.
48 * 16 8/27/99 6:38p Alanl
49 * crush the blasted repeating messages bug
51 * 15 8/23/99 11:16p Danw
54 * 14 8/22/99 11:06p Alanl
55 * fix small bug in ds_close_channel
57 * 13 8/19/99 11:25a Alanl
58 * change format of secondary buffer from 44100 to 22050
60 * 12 8/17/99 4:11p Danw
61 * AL: temp fix for solving A3D crash
63 * 11 8/06/99 2:20p Jasonh
64 * AL: free 3D portion of buffer first
66 * 10 8/04/99 9:48p Alanl
67 * fix bug with setting 3D properties on a 2D sound buffer
69 * 9 8/04/99 11:42a Danw
70 * tone down EAX reverb
72 * 8 8/01/99 2:06p Alanl
73 * increase the rolloff for A3D
75 * 7 7/20/99 5:28p Dave
76 * Fixed debug build error.
78 * 6 7/20/99 1:49p Dave
79 * Peter Drake build. Fixed some release build warnings.
81 * 5 7/14/99 11:32a Danw
82 * AL: add some debug code to catch nefarious A3D problem
84 * 4 5/23/99 8:11p Alanl
85 * Added support for EAX
87 * 3 10/08/98 4:29p Dave
88 * Removed reference to osdefs.h
90 * 2 10/07/98 10:54a Dave
93 * 1 10/07/98 10:51a Dave
95 * 72 6/28/98 6:34p Lawrance
96 * add sanity check in while() loop for releasing channels
98 * 71 6/13/98 1:45p Sandeep
100 * 70 6/10/98 2:29p Lawrance
101 * don't use COM for initializing DirectSound... appears some machines
104 * 69 5/26/98 2:10a Lawrance
105 * make sure DirectSound pointer gets freed if Aureal resource manager
108 * 68 5/21/98 9:14p Lawrance
109 * remove obsolete registry setting
111 * 67 5/20/98 4:28p Allender
112 * upped sound buffers as per alan's request
114 * 66 5/15/98 3:36p John
115 * Fixed bug with new graphics window code and standalone server. Made
116 * hwndApp not be a global anymore.
118 * 65 5/06/98 3:37p Lawrance
119 * allow panned sounds geesh
121 * 64 5/05/98 4:49p Lawrance
122 * Put in code to authenticate A3D, improve A3D support
124 * 63 4/20/98 11:17p Lawrance
125 * fix bug with releasing channels
127 * 62 4/20/98 7:34p Lawrance
128 * take out obsolete directsound3d debug command
130 * 61 4/20/98 11:10a Lawrance
131 * put correct flags when creating sound buffer
133 * 60 4/20/98 12:03a Lawrance
134 * Allow prioritizing of CTRL3D buffers
136 * 59 4/19/98 9:31p Lawrance
137 * Use Aureal_enabled flag
139 * 58 4/19/98 9:39a Lawrance
140 * use DYNAMIC_LOOPERS for Aureal resource manager
142 * 57 4/19/98 4:13a Lawrance
143 * Improve how dsound is initialized
145 * 56 4/18/98 9:13p Lawrance
146 * Added Aureal support.
148 * 55 4/13/98 5:04p Lawrance
149 * Write functions to determine how many milliseconds are left in a sound
151 * 54 4/09/98 5:53p Lawrance
152 * Make DirectSound init more robust
154 * 53 4/01/98 9:21p John
155 * Made NDEBUG, optimized build with no warnings or errors.
157 * 52 3/31/98 5:19p John
158 * Removed demo/save/restore. Made NDEBUG defined compile. Removed a
159 * bunch of debug stuff out of player file. Made model code be able to
160 * unload models and malloc out only however many models are needed.
163 * 51 3/29/98 12:56a Lawrance
164 * preload the warp in and explosions sounds before a mission.
166 * 50 3/25/98 6:10p Lawrance
167 * Work on DirectSound3D
169 * 49 3/24/98 4:28p Lawrance
170 * Make DirectSound3D support more robust
172 * 48 3/24/98 11:49a Dave
173 * AL: Change way buffer gets locked.
175 * 47 3/24/98 11:27a Lawrance
176 * Use buffer_size for memcpy when locking buffer
178 * 46 3/23/98 10:32a Lawrance
179 * Add functions for extracting raw sound data
181 * 45 3/19/98 5:36p Lawrance
182 * Add some sound debug functions to see how many sounds are playing, and
183 * to start/stop random looping sounds.
185 * 44 3/07/98 3:35p Dave
186 * AL: check for ds being initialized in ds_create_buffer()
188 * 43 2/18/98 5:49p Lawrance
189 * Even if the ADPCM codec is unavailable, allow game to continue.
191 * 42 2/16/98 7:31p Lawrance
192 * get compression/decompression of voice working
194 * 41 2/15/98 11:10p Lawrance
195 * more work on real-time voice system
197 * 40 2/15/98 4:43p Lawrance
198 * work on real-time voice
200 * 39 2/06/98 7:30p John
201 * Added code to monitor the number of channels of sound actually playing.
203 * 38 2/06/98 8:56a Allender
204 * fixed calling convention problem with DLL handles
206 * 37 2/04/98 6:08p Lawrance
207 * Read function pointers from dsound.dll, further work on
208 * DirectSoundCapture.
210 * 36 2/03/98 11:53p Lawrance
211 * Adding support for DirectSoundCapture
213 * 35 1/31/98 5:48p Lawrance
214 * Start on real-time voice recording
216 * 34 1/10/98 1:14p John
217 * Added explanation to debug console commands
219 * 33 12/21/97 4:33p John
220 * Made debug console functions a class that registers itself
221 * automatically, so you don't need to add the function to
222 * debugfunctions.cpp.
224 * 32 12/08/97 12:24a Lawrance
225 * Allow duplicate sounds to be stopped if less than OR equal to new sound
228 * 31 12/05/97 5:19p Lawrance
229 * re-do sound priorities to make more general and extensible
231 * 30 11/28/97 2:09p Lawrance
232 * Overhaul how ADPCM conversion works... use much less memory... safer
235 * 29 11/22/97 11:32p Lawrance
236 * decompress ADPCM data into 8 bit (not 16bit) for regular sounds (ie not
239 * 28 11/20/97 5:36p Dave
240 * Hooked in a bunch of main hall changes (including sound). Made it
241 * possible to reposition (rewind/ffwd)
242 * sound buffer pointers. Fixed animation direction change framerate
245 * 27 10/13/97 7:41p Lawrance
246 * store duration of sound
248 * 26 10/11/97 6:39p Lawrance
249 * start playing primary buffer, to reduce latency on sounds starting
251 * 25 10/08/97 5:09p Lawrance
252 * limit player impact sounds so only one plays at a time
254 * 24 9/26/97 5:43p Lawrance
255 * fix a bug that was freeing memory early when playing compressed sound
258 * 23 9/09/97 3:39p Sandeep
259 * warning level 4 bugs
261 * 22 8/16/97 4:05p Lawrance
262 * don't load sounds into hardware if running Lean_and_mean
264 * 21 8/05/97 1:39p Lawrance
265 * support compressed stereo playback
267 * 20 7/31/97 10:38a Lawrance
268 * return old debug function for toggling DirectSound3D
270 * 19 7/29/97 3:27p Lawrance
271 * make console toggle for directsound3d work right
273 * 18 7/28/97 11:39a Lawrance
274 * allow individual volume scaling on 3D buffers
276 * 17 7/18/97 8:18p Lawrance
277 * fix bug in ds_get_free_channel() that caused sounds to not play when
280 * 16 7/17/97 8:04p Lawrance
281 * allow priority sounds to play if free channel, otherwise stop lowest
282 * volume priority sound of same type
284 * 15 7/17/97 5:57p John
285 * made directsound3d config value work
287 * 14 7/17/97 5:43p John
288 * added new config stuff
290 * 13 7/17/97 4:25p John
291 * First, broken, stage of changing config stuff
293 * 12 7/15/97 12:13p Lawrance
294 * don't stop sounds that have highest priority
296 * 11 7/15/97 11:15a Lawrance
297 * limit the max instances of simultaneous sound effects, implement
298 * priorities to force critical sounds
300 * 10 6/09/97 11:50p Lawrance
301 * integrating DirectSound3D
303 * 9 6/08/97 5:59p Lawrance
304 * integrate DirectSound3D into sound system
306 * 8 6/04/97 1:19p Lawrance
307 * made hardware mixing robust
309 * 7 6/03/97 1:56p Hoffoss
310 * Return correct error code when direct sound init fails.
312 * 6 6/03/97 12:07p Lawrance
313 * don't enable 3D sounds in Primary buffer
315 * 5 6/02/97 3:45p Dan
316 * temp disable of hardware mixing until problem solved with
317 * CreateBuffer() failing
319 * 4 6/02/97 1:45p Lawrance
320 * implementing hardware mixing
322 * 3 5/29/97 4:01p Lawrance
323 * let snd_init() have final say on initialization
325 * 2 5/29/97 12:04p Lawrance
326 * creation of file to hold DirectSound specific portions
345 #include <initguid.h>
347 #include "verifya3d.h"
352 #include <SDL/SDL_audio.h>
356 // Pointers to functions contained in DSOUND.dll
357 HRESULT (__stdcall *pfn_DirectSoundCreate)(LPGUID lpGuid, LPDIRECTSOUND *ppDS, IUnknown FAR *pUnkOuter) = NULL;
358 HRESULT (__stdcall *pfn_DirectSoundCaptureCreate)(LPGUID lpGUID, LPDIRECTSOUNDCAPTURE *lplpDSC, LPUNKNOWN pUnkOuter) = NULL;
360 HINSTANCE Ds_dll_handle=NULL;
362 LPDIRECTSOUND pDirectSound = NULL;
363 LPDIRECTSOUNDBUFFER pPrimaryBuffer = NULL;
364 LPIA3D2 pIA3d2 = NULL;
366 static LPKSPROPERTYSET pPropertySet; // pointer to sound card property set
367 static LPDIRECTSOUNDBUFFER Ds_property_set_pdsb = NULL;
368 static LPDIRECTSOUND3DBUFFER Ds_property_set_pds3db = NULL;
370 static int Ds_must_call_couninitialize = 0;
372 channel* Channels; //[MAX_CHANNELS];
373 static int channel_next_sig = 1;
375 #define MAX_DS_SOFTWARE_BUFFERS 256
376 typedef struct ds_sound_buffer
378 LPDIRECTSOUNDBUFFER pdsb;
384 ds_sound_buffer ds_software_buffers[MAX_DS_SOFTWARE_BUFFERS];
386 #define MAX_DS_HARDWARE_BUFFERS 32
387 ds_sound_buffer ds_hardware_buffers[MAX_DS_HARDWARE_BUFFERS];
389 static DSCAPS Soundcard_caps; // current soundcard capabilities
391 extern int Snd_sram; // mem (in bytes) used up by storing sounds in system memory
392 extern int Snd_hram; // mem (in bytes) used up by storing sounds in soundcard memory
394 static int Ds_use_ds3d = 0;
395 static int Ds_use_a3d = 0;
396 static int Ds_use_eax = 0;
398 GUID IID_IA3d2_Def = {0xfb80d1e0, 0x98d3, 0x11d1, {0x90, 0xfb, 0x00, 0x60, 0x08, 0xa1, 0xf4, 0x41}};
399 GUID CLSID_A3d_Def = {0xd8f1eee0, 0xf634, 0x11cf, {0x87, 0x0, 0x0, 0xa0, 0x24, 0x5d, 0x91, 0x8b}};
401 static bool Stop_logging_sounds = false;
404 ///////////////////////////
408 ///////////////////////////
411 //#define EAX_PRESET_GENERIC EAX_ENVIRONMENT_GENERIC,0.5F,1.493F,0.5F
412 #define EAX_PRESET_GENERIC EAX_ENVIRONMENT_GENERIC,0.2F,0.2F,1.0F
413 #define EAX_PRESET_PADDEDCELL EAX_ENVIRONMENT_PADDEDCELL,0.25F,0.1F,0.0F
414 #define EAX_PRESET_ROOM EAX_ENVIRONMENT_ROOM,0.417F,0.4F,0.666F
415 #define EAX_PRESET_BATHROOM EAX_ENVIRONMENT_BATHROOM,0.653F,1.499F,0.166F
416 #define EAX_PRESET_LIVINGROOM EAX_ENVIRONMENT_LIVINGROOM,0.208F,0.478F,0.0F
417 #define EAX_PRESET_STONEROOM EAX_ENVIRONMENT_STONEROOM,0.5F,2.309F,0.888F
418 #define EAX_PRESET_AUDITORIUM EAX_ENVIRONMENT_AUDITORIUM,0.403F,4.279F,0.5F
419 #define EAX_PRESET_CONCERTHALL EAX_ENVIRONMENT_CONCERTHALL,0.5F,3.961F,0.5F
420 #define EAX_PRESET_CAVE EAX_ENVIRONMENT_CAVE,0.5F,2.886F,1.304F
421 #define EAX_PRESET_ARENA EAX_ENVIRONMENT_ARENA,0.361F,7.284F,0.332F
422 #define EAX_PRESET_HANGAR EAX_ENVIRONMENT_HANGAR,0.5F,10.0F,0.3F
423 #define EAX_PRESET_CARPETEDHALLWAY EAX_ENVIRONMENT_CARPETEDHALLWAY,0.153F,0.259F,2.0F
424 #define EAX_PRESET_HALLWAY EAX_ENVIRONMENT_HALLWAY,0.361F,1.493F,0.0F
425 #define EAX_PRESET_STONECORRIDOR EAX_ENVIRONMENT_STONECORRIDOR,0.444F,2.697F,0.638F
426 #define EAX_PRESET_ALLEY EAX_ENVIRONMENT_ALLEY,0.25F,1.752F,0.776F
427 #define EAX_PRESET_FOREST EAX_ENVIRONMENT_FOREST,0.111F,3.145F,0.472F
428 #define EAX_PRESET_CITY EAX_ENVIRONMENT_CITY,0.111F,2.767F,0.224F
429 #define EAX_PRESET_MOUNTAINS EAX_ENVIRONMENT_MOUNTAINS,0.194F,7.841F,0.472F
430 #define EAX_PRESET_QUARRY EAX_ENVIRONMENT_QUARRY,1.0F,1.499F,0.5F
431 #define EAX_PRESET_PLAIN EAX_ENVIRONMENT_PLAIN,0.097F,2.767F,0.224F
432 #define EAX_PRESET_PARKINGLOT EAX_ENVIRONMENT_PARKINGLOT,0.208F,1.652F,1.5F
433 #define EAX_PRESET_SEWERPIPE EAX_ENVIRONMENT_SEWERPIPE,0.652F,2.886F,0.25F
434 #define EAX_PRESET_UNDERWATER EAX_ENVIRONMENT_UNDERWATER,1.0F,1.499F,0.0F
435 #define EAX_PRESET_DRUGGED EAX_ENVIRONMENT_DRUGGED,0.875F,8.392F,1.388F
436 #define EAX_PRESET_DIZZY EAX_ENVIRONMENT_DIZZY,0.139F,17.234F,0.666F
437 #define EAX_PRESET_PSYCHOTIC EAX_ENVIRONMENT_PSYCHOTIC,0.486F,7.563F,0.806F
439 static LPKSPROPERTYSET Ds_eax_reverb = NULL;
441 static int Ds_eax_inited = 0;
443 EAX_REVERBPROPERTIES Ds_eax_presets[] =
445 {EAX_PRESET_GENERIC},
446 {EAX_PRESET_PADDEDCELL},
448 {EAX_PRESET_BATHROOM},
449 {EAX_PRESET_LIVINGROOM},
450 {EAX_PRESET_STONEROOM},
451 {EAX_PRESET_AUDITORIUM},
452 {EAX_PRESET_CONCERTHALL},
456 {EAX_PRESET_CARPETEDHALLWAY},
457 {EAX_PRESET_HALLWAY},
458 {EAX_PRESET_STONECORRIDOR},
462 {EAX_PRESET_MOUNTAINS},
465 {EAX_PRESET_PARKINGLOT},
466 {EAX_PRESET_SEWERPIPE},
467 {EAX_PRESET_UNDERWATER},
468 {EAX_PRESET_DRUGGED},
470 {EAX_PRESET_PSYCHOTIC},
473 GUID DSPROPSETID_EAX_ReverbProperties_Def = {0x4a4e6fc1, 0xc341, 0x11d1, {0xb7, 0x3a, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}};
474 GUID DSPROPSETID_EAXBUFFER_ReverbProperties_Def = {0x4a4e6fc0, 0xc341, 0x11d1, {0xb7, 0x3a, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}};
476 //----------------------------------------------------------------
478 void ds_get_soundcard_caps(DSCAPS *dscaps);
480 static int Ds_use_ds3d = 0;
481 static int Ds_use_a3d = 0;
482 static int Ds_use_eax = 0;
484 ALCdevice *ds_sound_device;
485 void *ds_sound_context = (void *)0;
487 static int MAX_CHANNELS = 1000; // initialized properly in ds_init_channels()
488 channel Channels[100];
492 int ds_vol_lookup[101]; // lookup table for direct sound volumes
493 int ds_initialized = FALSE;
496 //--------------------------------------------------------------------------
499 // Determine if a secondary buffer is a 3d secondary buffer.
502 int ds_is_3d_buffer(LPDIRECTSOUNDBUFFER pdsb)
507 dsbc.dwSize = sizeof(dsbc);
508 hr = pdsb->GetCaps(&dsbc);
509 if ( hr == DS_OK && dsbc.dwFlags & DSBCAPS_CTRL3D ) {
518 //--------------------------------------------------------------------------
521 // Determine if a secondary buffer is a 3d secondary buffer.
523 int ds_is_3d_buffer(int sid)
527 return ds_is_3d_buffer(ds_software_buffers[sid].pdsb);
535 //--------------------------------------------------------------------------
536 // ds_build_vol_lookup()
538 // Fills up the ds_vol_lookup[] tables that converts from a volume in the form
539 // 0.0 -> 1.0 to -10000 -> 0 (this is the DirectSound method, where units are
540 // hundredths of decibls)
542 void ds_build_vol_lookup()
547 ds_vol_lookup[0] = -10000;
548 for ( i = 1; i <= 100; i++ ) {
550 ds_vol_lookup[i] = fl2i( (log(vol) / log(2.0f)) * 1000.0f);
555 //--------------------------------------------------------------------------
556 // ds_convert_volume()
558 // Takes volume between 0.0f and 1.0f and converts into
559 // DirectSound style volumes between -10000 and 0.
560 int ds_convert_volume(float volume)
564 index = fl2i(volume * 100.0f);
570 return ds_vol_lookup[index];
573 //--------------------------------------------------------------------------
574 // ds_get_percentage_vol()
576 // Converts -10000 -> 0 range volume to 0 -> 1
577 float ds_get_percentage_vol(int ds_vol)
580 vol = pow(2.0, ds_vol/1000.0);
584 // ---------------------------------------------------------------------------------------
587 // Parse a wave file.
589 // parameters: filename => file of sound to parse
590 // dest => address of pointer of where to store raw sound data (output parm)
591 // dest_size => number of bytes of sound data stored (output parm)
592 // header => address of pointer to a WAVEFORMATEX struct (output parm)
594 // returns: 0 => wave file successfully parsed
597 // NOTE: memory is malloced for the header and dest in this function. It is the responsibility
598 // of the caller to free this memory later.
600 int ds_parse_wave(char *filename, ubyte **dest, uint *dest_size, WAVEFORMATEX **header)
603 PCMWAVEFORMAT PCM_header;
605 unsigned int tag, size, next_chunk;
607 fp = cfopen( filename, "rb" );
609 nprintf(("Error", "Couldn't open '%s'\n", filename ));
613 // Skip the "RIFF" tag and file size (8 bytes)
614 // Skip the "WAVE" tag (4 bytes)
615 cfseek( fp, 12, CF_SEEK_SET );
617 // Now read RIFF tags until the end of file
620 if ( cfread( &tag, sizeof(uint), 1, fp ) != 1 )
623 if ( cfread( &size, sizeof(uint), 1, fp ) != 1 )
626 next_chunk = cftell(fp) + size;
629 case 0x20746d66: // The 'fmt ' tag
630 //nprintf(("Sound", "SOUND => size of fmt block: %d\n", size));
631 cfread( &PCM_header, sizeof(PCMWAVEFORMAT), 1, fp );
632 if ( PCM_header.wf.wFormatTag != WAVE_FORMAT_PCM ) {
633 cbExtra = cfread_short(fp);
636 // Allocate memory for WAVEFORMATEX structure + extra bytes
637 if ( (*header = (WAVEFORMATEX *) malloc ( sizeof(WAVEFORMATEX)+cbExtra )) != NULL ){
638 // Copy bytes from temporary format structure
639 memcpy (*header, &PCM_header, sizeof(PCM_header));
640 (*header)->cbSize = (unsigned short)cbExtra;
642 // Read those extra bytes, append to WAVEFORMATEX structure
644 cfread( ((ubyte *)(*header) + sizeof(WAVEFORMATEX)), cbExtra, 1, fp);
648 Assert(0); // malloc failed
652 case 0x61746164: // the 'data' tag
654 (*dest) = (ubyte *)malloc(size);
655 Assert( *dest != NULL );
656 cfread( *dest, size, 1, fp );
658 default: // unknown, skip it
661 cfseek( fp, next_chunk, CF_SEEK_SET );
669 // ---------------------------------------------------------------------------------------
676 // this function is unused in linux.
682 for ( i = 0; i < MAX_DS_SOFTWARE_BUFFERS; i++ ) {
683 if ( ds_software_buffers[i].pdsb == NULL )
687 if ( i == MAX_DS_SOFTWARE_BUFFERS ) {
695 // ---------------------------------------------------------------------------------------
708 for ( i = 0; i < MAX_DS_HARDWARE_BUFFERS; i++ ) {
709 if ( ds_hardware_buffers[i].pdsb == NULL )
713 if ( i == MAX_DS_HARDWARE_BUFFERS ) {
721 // ---------------------------------------------------------------------------------------
722 // Load a DirectSound secondary buffer with sound data. The sounds data for
723 // game sounds are stored in the DirectSound secondary buffers, and are
724 // duplicated as needed and placed in the Channels[] array to be played.
728 // sid => pointer to software id for sound ( output parm)
729 // hid => pointer to hardware id for sound ( output parm)
730 // final_size => pointer to storage to receive uncompressed sound size (output parm)
731 // header => pointer to a WAVEFORMATEX structure
732 // si => sound_info structure, contains details on the sound format
733 // flags => buffer properties ( DS_HARDWARE , DS_3D )
735 // returns: -1 => sound effect could not loaded into a secondary buffer
736 // 0 => sound effect successfully loaded into a secondary buffer
739 // NOTE: this function is slow, especially when sounds are loaded into hardware. Don't call this
740 // function from within gameplay.
742 int ds_get_free_channel(int new_volume, int snd_id, int priority);
744 int ds_load_buffer(int *sid, int *hid, int *final_size, void *header, sound_info *si, int flags)
747 int channel = ds_get_free_channel(0,0,0);
749 Assert( final_size != NULL );
750 Assert( header != NULL );
751 Assert( si != NULL );
752 Assert( si->data != NULL );
754 // All sounds are required to have a software buffer
758 alGenBuffers (1, &pi);
765 switch (si->format) {
766 case WAVE_FORMAT_PCM:
774 /* format is now in pcm */
775 frequency = si->sample_rate;
777 if (si->bits == 16) {
778 if (si->n_channels == 2) {
779 format = AL_FORMAT_STEREO16;
780 } else if (si->n_channels == 1) {
781 format = AL_FORMAT_MONO16;
785 } else if (si->bits == 8) {
786 if (si->n_channels == 2) {
787 format = AL_FORMAT_STEREO8;
788 } else if (si->n_channels == 1) {
789 format = AL_FORMAT_MONO8;
799 alBufferData (pi, format, data, size, frequency);
801 (*sid) = Channels[channel].pds3db = (int)pi;
804 nprintf(("Sound","SOUND ==> Weird!\n"));
808 ALfloat pos[] = { 0, 0, 0 };
809 ALfloat vel[] = { 0, 0, 0 };
811 alGenSources (1, (ALuint*)hid);
812 Channels[channel].pdsb = (int)*hid;
815 alSourcef(*((ALuint*)hid), AL_PITCH, 1.0f);
816 alSourcef(*((ALuint*)hid), AL_GAIN, 1.0f);
817 alSourcefv(*((ALuint*)hid), AL_POSITION, pos);
818 alSourcefv(*((ALuint*)hid), AL_VELOCITY, vel);
820 int i = alGetError();
821 if(i != AL_NO_ERROR) {
822 printf("%s|||errorC!\n", alGetString(i));
828 Assert( final_size != NULL );
829 Assert( header != NULL );
830 Assert( si != NULL );
831 Assert( si->data != NULL );
832 Assert( si->size > 0 );
833 Assert( si->sample_rate > 0);
834 Assert( si->bits > 0 );
835 Assert( si->n_channels > 0 );
836 Assert( si->n_block_align >= 0 );
837 Assert( si->avg_bytes_per_sec > 0 );
839 WAVEFORMATEX *pwfx = (WAVEFORMATEX *)header;
840 DSBUFFERDESC BufferDesc;
841 WAVEFORMATEX WaveFormat;
843 int rc, final_sound_size, DSOUND_load_buffer_result = 0;
844 BYTE *pData, *pData2;
845 DWORD DataSize, DataSize2;
847 // the below two covnert_ variables are only used when the wav format is not
848 // PCM. DirectSound only takes PCM sound data, so we must convert to PCM if required
849 ubyte *convert_buffer = NULL; // storage for converted wav file
850 int convert_len; // num bytes of converted wav file
851 uint src_bytes_used; // number of source bytes actually converted (should always be equal to original size)
853 // Ensure DirectSound initialized
854 if (!ds_initialized) {
855 DSOUND_load_buffer_result = -1;
856 goto DSOUND_load_buffer_done;
859 // Set up buffer information
860 WaveFormat.wFormatTag = (unsigned short)si->format;
861 WaveFormat.nChannels = (unsigned short)si->n_channels;
862 WaveFormat.nSamplesPerSec = si->sample_rate;
863 WaveFormat.wBitsPerSample = (unsigned short)si->bits;
864 WaveFormat.cbSize = 0;
865 WaveFormat.nBlockAlign = (unsigned short)si->n_block_align;
866 WaveFormat.nAvgBytesPerSec = si->avg_bytes_per_sec;
868 final_sound_size = si->size; // assume this format will be used, may be over-ridded by convert_len
870 // Assert(WaveFormat.nChannels == 1);
872 switch ( si->format ) {
873 case WAVE_FORMAT_PCM:
876 case WAVE_FORMAT_ADPCM:
878 nprintf(( "Sound", "SOUND ==> converting sound from ADPCM to PCM\n" ));
879 rc = ACM_convert_ADPCM_to_PCM(pwfx, si->data, si->size, &convert_buffer, 0, &convert_len, &src_bytes_used, 8);
881 DSOUND_load_buffer_result = -1;
882 goto DSOUND_load_buffer_done;
885 if (src_bytes_used != si->size) {
886 Int3(); // ACM conversion failed?
887 DSOUND_load_buffer_result = -1;
888 goto DSOUND_load_buffer_done;
891 final_sound_size = convert_len;
893 // Set up the WAVEFORMATEX structure to have the right PCM characteristics
894 WaveFormat.wFormatTag = WAVE_FORMAT_PCM;
895 WaveFormat.nChannels = (unsigned short)si->n_channels;
896 WaveFormat.nSamplesPerSec = si->sample_rate;
897 WaveFormat.wBitsPerSample = 8;
898 WaveFormat.cbSize = 0;
899 WaveFormat.nBlockAlign = (unsigned short)(( WaveFormat.nChannels * WaveFormat.wBitsPerSample ) / 8);
900 WaveFormat.nAvgBytesPerSec = WaveFormat.nBlockAlign * WaveFormat.nSamplesPerSec;
902 nprintf(( "Sound", "SOUND ==> Coverted sound from ADPCM to PCM successfully\n" ));
906 nprintf(( "Sound", "Unsupported sound encoding\n" ));
907 DSOUND_load_buffer_result = -1;
908 goto DSOUND_load_buffer_done;
912 WaveFormat.wFormatTag = WAVE_FORMAT_PCM; // DirectSound only used PCM wave files
914 // Set up a DirectSound buffer
915 ZeroMemory(&BufferDesc, sizeof(BufferDesc));
916 BufferDesc.dwSize = sizeof(BufferDesc);
917 BufferDesc.dwBufferBytes = final_sound_size;
918 BufferDesc.lpwfxFormat = &WaveFormat;
920 // check if DirectSound3D is enabled and the sound is flagged for 3D
921 if ((ds_using_ds3d()) && (flags & DS_USE_DS3D)) {
922 // if (ds_using_ds3d()) {
923 BufferDesc.dwFlags = DSBCAPS_STATIC | DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRLVOLUME | DSBCAPS_CTRL3D | DSBCAPS_MUTE3DATMAXDISTANCE;
925 BufferDesc.dwFlags = DSBCAPS_STATIC | DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRLVOLUME | DSBCAPS_LOCSOFTWARE;
928 // Create a new software buffer using the settings for this wave
929 // All sounds are required to have a software buffer
932 nprintf(("Sound","SOUND ==> No more software secondary buffers available\n"));
935 DSReturn = pDirectSound->CreateSoundBuffer(&BufferDesc, &ds_software_buffers[*sid].pdsb, NULL );
937 if ( DSReturn == DS_OK && ds_software_buffers[*sid].pdsb != NULL ) {
939 ds_software_buffers[*sid].desc = BufferDesc;
940 ds_software_buffers[*sid].wfx = *BufferDesc.lpwfxFormat;
942 // Lock the buffer and copy in the data
943 if ((ds_software_buffers[*sid].pdsb)->Lock(0, final_sound_size, (void**)(&pData), &DataSize, (void**)(&pData2), &DataSize2, 0) == DS_OK) {
945 if ( convert_buffer )
946 memcpy(pData, convert_buffer, final_sound_size); // use converted data (PCM format)
948 memcpy(pData, si->data, final_sound_size);
950 (ds_software_buffers[*sid].pdsb)->Unlock(pData, DataSize, 0, 0);
952 DSOUND_load_buffer_result = 0;
954 // update ram used for sound
955 Snd_sram += final_sound_size;
956 *final_size = final_sound_size;
959 nprintf(("Sound","SOUND => fatal error in DSOUND_load_buffer\n"));
961 DSOUND_load_buffer_result = -1;
964 DSOUND_load_buffer_done:
965 if ( convert_buffer )
966 free( convert_buffer );
967 return DSOUND_load_buffer_result;
971 // ---------------------------------------------------------------------------------------
972 // ds_init_channels()
974 // init the Channels[] array
976 void ds_init_channels()
979 // STUB_FUNCTION; // not needed with openal (CM)
980 for(int i = 0; i < MAX_CHANNELS; i++) {
981 Channels[i].pdsb = 0; // source
982 Channels[i].pds3db = 0; // buffer
983 Channels[i].vol = 0; // volume;
989 // detect how many channels we can support
991 ds_get_soundcard_caps(&caps);
993 // caps.dwSize = sizeof(DSCAPS);
994 // pDirectSound->GetCaps(&caps);
996 // minimum 16 channels
997 MAX_CHANNELS = caps.dwMaxHwMixingStaticBuffers;
998 int dbg_channels = MAX_CHANNELS;
999 if (MAX_CHANNELS < 16) {
1003 // allocate the channels array
1004 Channels = (channel*) malloc(sizeof(channel) * MAX_CHANNELS);
1005 if (Channels == NULL) {
1006 Error(LOCATION, "Unable to allocate %d bytes for %d audio channels.", sizeof(channel) * MAX_CHANNELS, MAX_CHANNELS);
1009 // init the channels
1010 for ( i = 0; i < MAX_CHANNELS; i++ ) {
1011 Channels[i].pdsb = NULL;
1012 Channels[i].pds3db = NULL;
1013 Channels[i].vol = 0;
1016 mprintf(("** MAX_CHANNELS set to %d. DS reported %d.\n", MAX_CHANNELS, dbg_channels));
1020 // ---------------------------------------------------------------------------------------
1021 // ds_init_software_buffers()
1023 // init the software buffers
1025 void ds_init_software_buffers()
1028 // STUB_FUNCTION; // not needed with openal (CM)
1033 for ( i = 0; i < MAX_DS_SOFTWARE_BUFFERS; i++ ) {
1034 ds_software_buffers[i].pdsb = NULL;
1039 // ---------------------------------------------------------------------------------------
1040 // ds_init_hardware_buffers()
1042 // init the hardware buffers
1044 void ds_init_hardware_buffers()
1047 // STUB_FUNCTION; // not needed with openal (CM)
1052 for ( i = 0; i < MAX_DS_HARDWARE_BUFFERS; i++ ) {
1053 ds_hardware_buffers[i].pdsb = NULL;
1058 // ---------------------------------------------------------------------------------------
1059 // ds_init_buffers()
1061 // init the both the software and hardware buffers
1063 void ds_init_buffers()
1065 ds_init_software_buffers();
1066 ds_init_hardware_buffers();
1069 // Get the current soundcard capabilities
1071 void ds_get_soundcard_caps(DSCAPS *dscaps)
1074 int n_hbuffers, hram;
1076 dscaps->dwSize = sizeof(DSCAPS);
1078 hr = pDirectSound->GetCaps(dscaps);
1080 nprintf(("Sound","SOUND ==> DirectSound GetCaps() failed with code %s\n.",get_DSERR_text(hr) ));
1084 n_hbuffers = dscaps->dwMaxHwMixingStaticBuffers;
1085 hram = dscaps->dwTotalHwMemBytes;
1087 if ( !(dscaps->dwFlags & DSCAPS_CERTIFIED) ) {
1088 nprintf(("Sound","SOUND ==> Warning: audio driver is not Microsoft certified.\n"));
1092 // ---------------------------------------------------------------------------------------
1095 // init the both the software and hardware buffers
1097 void ds_show_caps(DSCAPS *dscaps)
1099 nprintf(("Sound", "SOUND => Soundcard Capabilities:\n"));
1100 nprintf(("Sound", "================================\n"));
1101 nprintf(("Sound", "Number of primary buffers: %d\n", dscaps->dwPrimaryBuffers ));
1102 nprintf(("Sound", "Number of total hw mixing buffers: %d\n", dscaps->dwMaxHwMixingAllBuffers ));
1103 nprintf(("Sound", "Number of total hw mixing static buffers: %d\n", dscaps->dwMaxHwMixingStaticBuffers ));
1104 nprintf(("Sound", "Number of total hw mixing streaming buffers: %d\n", dscaps->dwMaxHwMixingStreamingBuffers ));
1105 nprintf(("Sound", "Number of free hw mixing buffers: %d\n", dscaps->dwFreeHwMixingAllBuffers ));
1106 nprintf(("Sound", "Number of free hw mixing static buffers: %d\n", dscaps->dwFreeHwMixingStaticBuffers ));
1107 nprintf(("Sound", "Number of free hw mixing streaming buffers: %d\n", dscaps->dwFreeHwMixingStreamingBuffers ));
1108 nprintf(("Sound", "Number of hw 3D buffers: %d\n", dscaps->dwMaxHw3DAllBuffers ));
1109 nprintf(("Sound", "Number of hw 3D static buffers: %d\n", dscaps->dwMaxHw3DStaticBuffers ));
1110 nprintf(("Sound", "Number of hw 3D streaming buffers: %d\n", dscaps->dwMaxHw3DStreamingBuffers ));
1111 nprintf(("Sound", "Number of free hw 3D buffers: %d\n", dscaps->dwFreeHw3DAllBuffers ));
1112 nprintf(("Sound", "Number of free hw static 3D buffers: %d\n", dscaps->dwFreeHw3DStaticBuffers ));
1113 nprintf(("Sound", "Number of free hw streaming 3D buffers: %d\n", dscaps->dwFreeHw3DStreamingBuffers ));
1114 nprintf(("Sound", "Number of total hw bytes: %d\n", dscaps->dwTotalHwMemBytes ));
1115 nprintf(("Sound", "Number of free hw bytes: %d\n", dscaps->dwFreeHwMemBytes ));
1116 nprintf(("Sound", "================================\n"));
1120 // Fill in the waveformat struct with the primary buffer characteristics.
1121 void ds_get_primary_format(WAVEFORMATEX *wfx)
1127 // Set 16 bit / 22KHz / mono
1128 wfx->wFormatTag = WAVE_FORMAT_PCM;
1130 wfx->nSamplesPerSec = 22050;
1131 wfx->wBitsPerSample = 16;
1133 wfx->nBlockAlign = (unsigned short)(wfx->nChannels * (wfx->wBitsPerSample / 8));
1134 wfx->nAvgBytesPerSec = wfx->nBlockAlign * wfx->nSamplesPerSec;
1137 // obtain the function pointers from the dsound.dll
1138 void ds_dll_get_functions()
1140 pfn_DirectSoundCreate = (HRESULT(__stdcall *)(LPGUID lpGuid, LPDIRECTSOUND *ppDS, IUnknown FAR *pUnkOuter))GetProcAddress(Ds_dll_handle,"DirectSoundCreate");
1141 pfn_DirectSoundCaptureCreate = (HRESULT(__stdcall *)(LPGUID lpGuid, LPDIRECTSOUNDCAPTURE *lplpDSC, IUnknown FAR *pUnkOuter))GetProcAddress(Ds_dll_handle,"DirectSoundCaptureCreate");
1145 // Load the dsound.dll, and get funtion pointers
1146 // exit: 0 -> dll loaded successfully
1147 // !0 -> dll could not be loaded
1154 if ( !Ds_dll_loaded ) {
1155 Ds_dll_handle = LoadLibrary("dsound.dll");
1156 if ( !Ds_dll_handle ) {
1159 ds_dll_get_functions();
1173 HINSTANCE a3d_handle;
1176 a3d_handle = LoadLibrary("a3d.dll");
1180 FreeLibrary(a3d_handle);
1184 Ds_must_call_couninitialize = 1;
1186 hr = CoCreateInstance(CLSID_A3d_Def, NULL, CLSCTX_INPROC_SERVER, IID_IDirectSound, (void**)&pDirectSound);
1191 Assert(pDirectSound != NULL);
1192 hr = pDirectSound->QueryInterface(IID_IA3d2_Def, (void**)&pIA3d2);
1197 A3DCAPS_SOFTWARE swCaps;
1199 // Get Dll Software CAP to get DLL version number
1200 ZeroMemory(&swCaps,sizeof(swCaps));
1202 swCaps.dwSize = sizeof(swCaps);
1203 pIA3d2->GetSoftwareCaps(&swCaps);
1205 // Compare version from a3d.dll to header version only return A3D_OK if dll version >= to header version
1206 if (swCaps.dwVersion < A3D_CURRENT_VERSION) {
1207 pDirectSound->Release();
1208 pDirectSound = NULL;
1213 // verify this is authentic A3D
1214 int aureal_verified;
1215 aureal_verified = VerifyAurealA3D();
1217 if (aureal_verified == FALSE) {
1218 // This is fake A3D!!! Ignore
1219 pDirectSound->Release();
1220 pDirectSound = NULL;
1224 // Register our version for backwards compatibility with newer A3d.dll
1225 pIA3d2->RegisterVersion(A3D_CURRENT_VERSION);
1227 hr = pDirectSound->Initialize(NULL);
1229 pDirectSound->Release();
1230 pDirectSound = NULL;
1234 pIA3d2->SetResourceManagerMode(A3D_RESOURCE_MODE_DYNAMIC_LOOPERS);
1240 // Initialize the property set interface.
1242 // returns: 0 if successful, otherwise -1. If successful, the global pPropertySet will
1243 // set to a non-NULL value.
1245 int ds_init_property_set()
1253 // Create the secondary buffer required for EAX initialization
1255 wf.wFormatTag = WAVE_FORMAT_PCM;
1257 wf.nSamplesPerSec = 22050;
1258 wf.wBitsPerSample = 16;
1260 wf.nBlockAlign = (unsigned short)(wf.nChannels * (wf.wBitsPerSample / 8));
1261 wf.nAvgBytesPerSec = wf.nBlockAlign * wf.nSamplesPerSec;
1264 ZeroMemory(&dsbd, sizeof(dsbd));
1265 dsbd.dwSize = sizeof(dsbd);
1266 dsbd.dwFlags = DSBCAPS_CTRLDEFAULT | DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_STATIC | DSBCAPS_CTRL3D | DSBCAPS_MUTE3DATMAXDISTANCE;
1267 dsbd.dwBufferBytes = 3 * wf.nAvgBytesPerSec;
1268 dsbd.lpwfxFormat = &wf;
1270 // Create a new buffer using the settings for this wave
1271 hr = pDirectSound->CreateSoundBuffer(&dsbd, &Ds_property_set_pdsb, NULL);
1273 pPropertySet = NULL;
1277 // Get the 3D interface from the secondary buffer, which is used to query the EAX interface
1278 hr = Ds_property_set_pdsb->QueryInterface(IID_IDirectSound3DBuffer, (void**)&Ds_property_set_pds3db);
1280 Ds_property_set_pds3db = NULL;
1284 Assert(Ds_property_set_pds3db != NULL);
1285 hr = Ds_property_set_pds3db->QueryInterface(IID_IKsPropertySet, (void**)&pPropertySet);
1286 if ((FAILED(hr)) || (pPropertySet == NULL)) {
1294 // ---------------------------------------------------------------------------------------
1297 // returns: -1 => init failed
1298 // 0 => init success
1299 int ds_init(int use_a3d, int use_eax)
1302 // NOTE: A3D and EAX are unused in OpenAL
1303 const ALubyte *initStr = (const ALubyte *)"\'( (sampling-rate 22050 ))";
1304 int attr[] = { ALC_FREQUENCY, 22050, ALC_SYNC, AL_FALSE, 0 };
1310 nprintf(( "Sound", "SOUND ==> Initializing DirectSound...\n" ));
1313 ds_sound_device = alcOpenDevice (initStr);
1315 // Create Sound Device
1316 ds_sound_context = alcCreateContext (ds_sound_device, attr);
1317 alcMakeContextCurrent (ds_sound_context);
1319 if (alGetError() != AL_NO_ERROR) {
1320 nprintf(("Sound", "SOUND ==> Cannot initiate OpenAL\n"));
1324 // Get the primary buffer format
1325 //ds_get_primary_format(&wave_format);
1327 // Initialize DirectSound3D. Since software performance of DirectSound3D is unacceptably
1328 // slow, we require the voice manger (a DirectSound extension) to be present. The
1329 // exception is when A3D is being used, since A3D has a resource manager built in.
1330 // if (Ds_use_ds3d && ds3d_init(0) != 0)
1333 ds_build_vol_lookup();
1339 WAVEFORMATEX wave_format;
1340 DSBUFFERDESC BufferDesc;
1342 nprintf(( "Sound", "SOUND ==> Initializing DirectSound...\n" ));
1344 hwnd = (HWND)os_get_window();
1345 if ( hwnd == NULL ) {
1346 nprintf(( "Sound", "SOUND ==> No window handle, so no sound...\n" ));
1350 if ( ds_dll_load() == -1 ) {
1354 pDirectSound = NULL;
1356 Ds_use_a3d = use_a3d;
1357 Ds_use_eax = use_eax;
1359 if (Ds_use_a3d || Ds_use_eax) {
1363 if (Ds_use_a3d && Ds_use_eax) {
1368 // If we want A3D, ensure a3d.dll exists
1369 if (Ds_use_a3d == 1) {
1370 if (ds_init_a3d() != 0) {
1377 if (Ds_use_a3d == 0) {
1378 if (!pfn_DirectSoundCreate) {
1379 nprintf(( "Sound", "SOUND ==> Could not get DirectSoundCreate function pointer\n" ));
1383 hr = pfn_DirectSoundCreate(NULL, &pDirectSound, NULL);
1389 // Set up DirectSound for exclusive mode, so we can change the primary buffer if we want to.
1390 hr = pDirectSound->SetCooperativeLevel(hwnd, DSSCL_EXCLUSIVE);
1392 nprintf(("Sound","SOUND ==> DirectSound pDirectSound->SetCooperativeLevel failed with code %s\n.",get_DSERR_text(hr) ));
1393 pDirectSound = NULL;
1397 // Create the primary buffer
1398 ZeroMemory(&BufferDesc, sizeof(BufferDesc));
1399 BufferDesc.dwSize = sizeof(BufferDesc);
1401 ds_get_soundcard_caps(&Soundcard_caps);
1404 BufferDesc.dwFlags = DSBCAPS_PRIMARYBUFFER | DSBCAPS_CTRL3D;
1406 hr = pDirectSound->CreateSoundBuffer(&BufferDesc, &pPrimaryBuffer, 0);
1408 nprintf(("Sound","SOUND ==> Primary Buffer create failed with DSBCAPS_CTRL3D property... disabling DirectSound3D\n"));
1413 nprintf(("Sound","SOUND ==> Primary Buffer created with DirectSound3D enabled\n"));
1417 // If not using DirectSound3D, then create a normal primary buffer
1418 if (Ds_use_ds3d == 0) {
1419 BufferDesc.dwFlags = DSBCAPS_PRIMARYBUFFER;
1420 hr = pDirectSound->CreateSoundBuffer(&BufferDesc, &pPrimaryBuffer, 0);
1422 nprintf(("Sound","SOUND ==> Primary Buffer create failed with error: %s\n",get_DSERR_text(hr) ));
1423 pDirectSound = NULL;
1427 nprintf(("Sound","SOUND ==> Primary Buffer created with without DirectSound3D enabled\n"));
1431 // Get the primary buffer format
1432 ds_get_primary_format(&wave_format);
1434 hr = pPrimaryBuffer->SetFormat(&wave_format);
1436 nprintf(("Sound","SOUND ==> pPrimaryBuffer->SetFormat() failed with code %s\n",get_DSERR_text(hr) ));
1439 pPrimaryBuffer->GetFormat(&wave_format, sizeof(wave_format), NULL);
1440 nprintf(("Sound","SOUND ==> Primary Buffer forced to: rate: %d Hz bits: %d n_channels: %d\n",
1441 wave_format.nSamplesPerSec, wave_format.wBitsPerSample, wave_format.nChannels));
1443 // start the primary buffer playing. This will reduce sound latency when playing a sound
1444 // if no other sounds are playing.
1445 hr = pPrimaryBuffer->Play(0, 0, DSBPLAY_LOOPING);
1447 nprintf(("Sound","SOUND ==> pPrimaryBuffer->Play() failed with code %s\n",get_DSERR_text(hr) ));
1450 // Initialize DirectSound3D. Since software performance of DirectSound3D is unacceptably
1451 // slow, we require the voice manger (a DirectSound extension) to be present. The
1452 // exception is when A3D is being used, since A3D has a resource manager built in.
1454 int vm_required = 1; // voice manager
1455 if (Ds_use_a3d == 1) {
1459 if (ds3d_init(vm_required) != 0) {
1465 if (Ds_use_eax == 1) {
1466 ds_init_property_set();
1467 if (ds_eax_init() != 0) {
1472 ds_build_vol_lookup();
1476 ds_show_caps(&Soundcard_caps);
1482 // ---------------------------------------------------------------------------------------
1485 // returns the text equivalent for the a DirectSound DSERR_ code
1487 char *get_DSERR_text(int DSResult)
1492 static char buf[20];
1493 snprintf(buf, 19, "unknown %d", DSResult);
1496 switch( DSResult ) {
1502 case DSERR_ALLOCATED:
1503 return "DSERR_ALLOCATED";
1506 case DSERR_ALREADYINITIALIZED:
1507 return "DSERR_ALREADYINITIALIZED";
1510 case DSERR_BADFORMAT:
1511 return "DSERR_BADFORMAT";
1514 case DSERR_BUFFERLOST:
1515 return "DSERR_BUFFERLOST";
1518 case DSERR_CONTROLUNAVAIL:
1519 return "DSERR_CONTROLUNAVAIL";
1523 return "DSERR_GENERIC";
1526 case DSERR_INVALIDCALL:
1527 return "DSERR_INVALIDCALL";
1530 case DSERR_INVALIDPARAM:
1531 return "DSERR_INVALIDPARAM";
1534 case DSERR_NOAGGREGATION:
1535 return "DSERR_NOAGGREGATION";
1538 case DSERR_NODRIVER:
1539 return "DSERR_NODRIVER";
1542 case DSERR_OUTOFMEMORY:
1543 return "DSERR_OUTOFMEMORY";
1546 case DSERR_OTHERAPPHASPRIO:
1547 return "DSERR_OTHERAPPHASPRIO";
1550 case DSERR_PRIOLEVELNEEDED:
1551 return "DSERR_PRIOLEVELNEEDED";
1554 case DSERR_UNINITIALIZED:
1555 return "DSERR_UNINITIALIZED";
1558 case DSERR_UNSUPPORTED:
1559 return "DSERR_UNSUPPORTED";
1570 // ---------------------------------------------------------------------------------------
1571 // ds_close_channel()
1573 // Free a single channel
1575 void ds_close_channel(int i)
1579 if(Channels[i].pdsb != 0 && alIsSource (Channels[i].pdsb)) {
1580 alSourceStop (Channels[i].pdsb);
1581 Channels[i].pdsb = 0;
1587 // If a 3D interface exists, free it
1588 if ( Channels[i].pds3db != NULL ) {
1591 Channels[i].pds3db = NULL;
1594 while(++attempts < 10) {
1595 hr = Channels[i].pds3db->Release();
1596 if ( hr == DS_OK ) {
1599 // nprintf(("Sound", "SOUND ==> Channels[channel].pds3db->Release() failed with return value %s\n", get_DSERR_text(second_hr) ));
1603 Channels[i].pds3db = NULL;
1607 if ( Channels[i].pdsb != NULL ) {
1608 // If a 2D interface exists, free it
1609 if ( Channels[i].pdsb != NULL ) {
1611 while(++attempts < 10) {
1612 hr = Channels[i].pdsb->Release();
1613 if ( hr == DS_OK ) {
1616 nprintf(("Sound", "SOUND ==> Channels[channel].pdsb->Release() failed with return value %s\n", get_DSERR_text(hr) ));
1621 Channels[i].pdsb = NULL;
1628 // ---------------------------------------------------------------------------------------
1629 // ds_close_all_channels()
1631 // Free all the channel buffers
1633 void ds_close_all_channels()
1637 for (i = 0; i < MAX_CHANNELS; i++) {
1638 ds_close_channel(i);
1642 // ---------------------------------------------------------------------------------------
1643 // ds_unload_buffer()
1646 void ds_unload_buffer(int sid, int hid)
1651 if(alIsSource (hid)) {
1652 alSourceStop ((ALuint)hid);
1653 alDeleteSources(1, (ALuint*)&hid);
1655 if(alIsBuffer (sid)) {
1656 alDeleteBuffers(1, (ALuint*)&sid);
1663 if ( ds_software_buffers[sid].pdsb != NULL ) {
1664 hr = ds_software_buffers[sid].pdsb->Release();
1665 if ( hr != DS_OK ) {
1667 nprintf(("Sound", "SOUND ==> ds_software_buffers[sid]->Release() failed with return value %s\n", get_DSERR_text(hr) ));
1669 ds_software_buffers[sid].pdsb = NULL;
1674 if ( ds_hardware_buffers[hid].pdsb != NULL ) {
1675 hr = ds_hardware_buffers[hid].pdsb->Release();
1676 if ( hr != DS_OK ) {
1678 nprintf(("Sound", "SOUND ==> ds_hardware_buffers[hid]->Release() failed with return value %s\n", get_DSERR_text(hr) ));
1680 ds_hardware_buffers[hid].pdsb = NULL;
1686 // ---------------------------------------------------------------------------------------
1687 // ds_close_software_buffers()
1690 void ds_close_software_buffers()
1698 for (i = 0; i < MAX_DS_SOFTWARE_BUFFERS; i++) {
1699 if ( ds_software_buffers[i].pdsb != NULL ) {
1700 hr = ds_software_buffers[i].pdsb->Release();
1701 if ( hr != DS_OK ) {
1703 nprintf(("Sound", "SOUND ==> ds_software_buffers[i]->Release() failed with return value %s\n", get_DSERR_text(hr) ));
1705 ds_software_buffers[i].pdsb = NULL;
1711 // ---------------------------------------------------------------------------------------
1712 // ds_close_hardware_buffers()
1715 void ds_close_hardware_buffers()
1723 for (i = 0; i < MAX_DS_HARDWARE_BUFFERS; i++) {
1724 if ( ds_hardware_buffers[i].pdsb != NULL ) {
1725 hr = ds_hardware_buffers[i].pdsb->Release();
1726 if ( hr != DS_OK ) {
1728 nprintf(("Sound", "SOUND ==> ds_hardware_buffers[i]->Release() failed with return value %s\n", get_DSERR_text(hr) ));
1730 ds_hardware_buffers[i].pdsb = NULL;
1736 // ---------------------------------------------------------------------------------------
1737 // ds_close_buffers()
1739 // Free the channel buffers
1741 void ds_close_buffers()
1743 ds_close_software_buffers();
1744 ds_close_hardware_buffers();
1747 // ---------------------------------------------------------------------------------------
1750 // Close the DirectSound system
1754 ds_close_all_channels();
1760 if (pPropertySet != NULL) {
1761 pPropertySet->Release();
1762 pPropertySet = NULL;
1765 if (Ds_property_set_pdsb != NULL) {
1766 Ds_property_set_pdsb->Release();
1767 Ds_property_set_pdsb = NULL;
1770 if (Ds_property_set_pds3db != NULL) {
1771 Ds_property_set_pds3db->Release();
1772 Ds_property_set_pds3db = NULL;
1775 if (pPrimaryBuffer) {
1776 pPrimaryBuffer->Release();
1777 pPrimaryBuffer = NULL;
1786 pDirectSound->Release();
1787 pDirectSound = NULL;
1790 if ( Ds_dll_loaded ) {
1791 FreeLibrary(Ds_dll_handle);
1795 if (Ds_must_call_couninitialize == 1) {
1799 // free the Channels[] array, since it was dynamically allocated
1805 // ---------------------------------------------------------------------------------------
1806 // ds_get_3d_interface()
1808 // Get the 3d interface for a secondary buffer.
1810 // If the secondary buffer wasn't created with a DSBCAPS_CTRL3D flag, then no 3d interface
1814 void ds_get_3d_interface(LPDIRECTSOUNDBUFFER pdsb, LPDIRECTSOUND3DBUFFER *ppds3db)
1819 dsbc.dwSize = sizeof(dsbc);
1820 DSResult = pdsb->GetCaps(&dsbc);
1821 if ( DSResult == DS_OK && dsbc.dwFlags & DSBCAPS_CTRL3D ) {
1822 DSResult = pdsb->QueryInterface( IID_IDirectSound3DBuffer, (void**)ppds3db );
1823 if ( DSResult != DS_OK ) {
1824 nprintf(("SOUND","Could not obtain 3D interface for hardware buffer: %s\n", get_DSERR_text(DSResult) ));
1831 // ---------------------------------------------------------------------------------------
1832 // ds_get_free_channel()
1834 // Find a free channel to play a sound on. If no free channels exists, free up one based
1835 // on volume levels.
1837 // input: new_volume => volume in DS units for sound to play at
1838 // snd_id => which kind of sound to play
1839 // priority => DS_MUST_PLAY
1844 // returns: channel number to play sound on
1845 // -1 if no channel could be found
1847 // NOTE: snd_id is needed since we limit the number of concurrent samples
1850 #define DS_MAX_SOUND_INSTANCES 2
1852 int ds_get_free_channel(int new_volume, int snd_id, int priority)
1856 for(int i = 0; i < MAX_CHANNELS; i++) {
1857 if(Channels[i].pdsb == 0) {
1858 Channels[i].snd_id = snd_id;
1859 Channels[i].vol = new_volume;
1865 int i, first_free_channel, limit;
1866 int lowest_vol = 0, lowest_vol_index = -1;
1867 int instance_count; // number of instances of sound already playing
1868 int lowest_instance_vol, lowest_instance_vol_index;
1869 unsigned long status;
1874 lowest_instance_vol = 99;
1875 lowest_instance_vol_index = -1;
1876 first_free_channel = -1;
1878 // Look for a channel to use to play this sample
1879 for ( i = 0; i < MAX_CHANNELS; i++ ) {
1881 if ( chp->pdsb == NULL ) {
1882 if ( first_free_channel == -1 )
1883 first_free_channel = i;
1887 hr = chp->pdsb->GetStatus(&status);
1888 if ( hr != DS_OK ) {
1889 nprintf(("Sound", "SOUND ==> GetStatus failed with return value %s\n", get_DSERR_text(hr) ));
1892 if ( !(status & DSBSTATUS_PLAYING) ) {
1893 if ( first_free_channel == -1 )
1894 first_free_channel = i;
1895 ds_close_channel(i);
1899 if ( chp->snd_id == snd_id ) {
1901 if ( chp->vol < lowest_instance_vol && chp->looping == FALSE ) {
1902 lowest_instance_vol = chp->vol;
1903 lowest_instance_vol_index = i;
1907 if ( chp->vol < lowest_vol && chp->looping == FALSE ) {
1908 lowest_vol_index = i;
1909 lowest_vol = chp->vol;
1914 // determine the limit of concurrent instances of this sound
1925 case DS_LIMIT_THREE:
1935 // If we've exceeded the limit, then maybe stop the duplicate if it is lower volume
1936 if ( instance_count >= limit ) {
1937 // If there is a lower volume duplicate, stop it.... otherwise, don't play the sound
1938 if ( lowest_instance_vol_index >= 0 && (Channels[lowest_instance_vol_index].vol <= new_volume) ) {
1939 ds_close_channel(lowest_instance_vol_index);
1940 first_free_channel = lowest_instance_vol_index;
1942 first_free_channel = -1;
1945 // there is no limit barrier to play the sound, so see if we've ran out of channels
1946 if ( first_free_channel == -1 ) {
1947 // stop the lowest volume instance to play our sound if priority demands it
1948 if ( lowest_vol_index != -1 && priority == DS_MUST_PLAY ) {
1949 // Check if the lowest volume playing is less than the volume of the requested sound.
1950 // If so, then we are going to trash the lowest volume sound.
1951 if ( Channels[lowest_vol_index].vol <= new_volume ) {
1952 ds_close_channel(lowest_vol_index);
1953 first_free_channel = lowest_vol_index;
1959 return first_free_channel;
1964 // ---------------------------------------------------------------------------------------
1967 // Find a free channel to play a sound on. If no free channels exists, free up one based
1968 // on volume levels.
1970 // returns: 0 => dup was successful
1971 // -1 => dup failed (Channels[channel].pdsb will be NULL)
1974 int ds_channel_dup(LPDIRECTSOUNDBUFFER pdsb, int channel, int use_ds3d)
1978 // Duplicate the master buffer into a channel buffer.
1979 DSResult = pDirectSound->DuplicateSoundBuffer(pdsb, &Channels[channel].pdsb );
1980 if ( DSResult != DS_OK ) {
1981 nprintf(("Sound", "SOUND ==> DuplicateSoundBuffer failed with return value %s\n", get_DSERR_text(DSResult) ));
1982 Channels[channel].pdsb = NULL;
1986 // get the 3d interface for the buffer if it exists
1988 if (Channels[channel].pds3db == NULL) {
1989 ds_get_3d_interface(Channels[channel].pdsb, &Channels[channel].pds3db);
1997 // ---------------------------------------------------------------------------------------
1998 // ds_restore_buffer()
2001 void ds_restore_buffer(LPDIRECTSOUNDBUFFER pdsb)
2005 Int3(); // get Alan, he wants to see this
2006 hr = pdsb->Restore();
2007 if ( hr != DS_OK ) {
2008 nprintf(("Sound", "Sound ==> Lost a buffer, tried restoring but got %s\n", get_DSERR_text(hr) ));
2013 // Create a direct sound buffer in software, without locking any data in
2014 int ds_create_buffer(int frequency, int bits_per_sample, int nchannels, int nseconds)
2019 alGenBuffers (1, &i);
2027 if (!ds_initialized) {
2033 nprintf(("Sound","SOUND ==> No more software secondary buffers available\n"));
2037 // Set up buffer format
2038 wfx.wFormatTag = WAVE_FORMAT_PCM;
2039 wfx.nChannels = (unsigned short)nchannels;
2040 wfx.nSamplesPerSec = frequency;
2041 wfx.wBitsPerSample = (unsigned short)bits_per_sample;
2043 wfx.nBlockAlign = (unsigned short)(wfx.nChannels * (wfx.wBitsPerSample / 8));
2044 wfx.nAvgBytesPerSec = wfx.nBlockAlign * wfx.nSamplesPerSec;
2046 memset(&dsbd, 0, sizeof(DSBUFFERDESC));
2047 dsbd.dwSize = sizeof(DSBUFFERDESC);
2048 dsbd.dwBufferBytes = wfx.nAvgBytesPerSec * nseconds;
2049 dsbd.lpwfxFormat = &wfx;
2050 dsbd.dwFlags = DSBCAPS_STATIC | DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRLDEFAULT | DSBCAPS_LOCSOFTWARE;
2052 dsrval = pDirectSound->CreateSoundBuffer(&dsbd, &ds_software_buffers[sid].pdsb, NULL);
2053 if ( dsrval != DS_OK ) {
2057 ds_software_buffers[sid].desc = dsbd;
2062 // Lock data into an existing buffer
2063 int ds_lock_data(int sid, unsigned char *data, int size)
2069 LPDIRECTSOUNDBUFFER pdsb;
2071 void *buffer_data, *buffer_data2;
2072 DWORD buffer_size, buffer_size2;
2075 pdsb = ds_software_buffers[sid].pdsb;
2077 memset(&caps, 0, sizeof(DSBCAPS));
2078 caps.dwSize = sizeof(DSBCAPS);
2079 dsrval = pdsb->GetCaps(&caps);
2080 if ( dsrval != DS_OK ) {
2084 pdsb->SetCurrentPosition(0);
2086 // lock the entire buffer
2087 dsrval = pdsb->Lock(0, caps.dwBufferBytes, &buffer_data, &buffer_size, &buffer_data2, &buffer_size2, 0 );
2088 if ( dsrval != DS_OK ) {
2092 // first clear it out with silence
2093 memset(buffer_data, 0x80, buffer_size);
2094 memcpy(buffer_data, data, size);
2096 dsrval = pdsb->Unlock(buffer_data, buffer_size, 0, 0);
2097 if ( dsrval != DS_OK ) {
2105 // Stop a buffer from playing directly
2106 void ds_stop_easy(int sid)
2112 LPDIRECTSOUNDBUFFER pdsb;
2115 pdsb = ds_software_buffers[sid].pdsb;
2116 dsrval = pdsb->Stop();
2120 // Play a sound without the usual baggage (used for playing back real-time voice)
2123 // sid => software id of sound
2124 // volume => volume of sound effect in DirectSound units
2125 int ds_play_easy(int sid, int volume)
2131 LPDIRECTSOUNDBUFFER pdsb;
2134 pdsb = ds_software_buffers[sid].pdsb;
2136 pdsb->SetVolume(volume);
2137 dsrval=pdsb->Play(0, 0, 0);
2138 if ( dsrval != DS_OK ) {
2146 //extern void HUD_add_to_scrollback(char *text, int source);
2147 //extern void HUD_printf(char *format, ...);
2149 // ---------------------------------------------------------------------------------------
2150 // Play a DirectSound secondary buffer.
2154 // sid => software id of sound
2155 // hid => hardware id of sound ( -1 if not in hardware )
2156 // snd_id => what kind of sound this is
2157 // priority => DS_MUST_PLAY
2161 // volume => volume of sound effect in DirectSound units
2162 // pan => pan of sound in DirectSound units
2163 // looping => whether the sound effect is looping or not
2165 // returns: -1 => sound effect could not be started
2166 // >=0 => sig for sound effect successfully started
2168 int ds_play(int sid, int hid, int snd_id, int priority, int volume, int pan, int looping, bool is_voice_msg)
2175 printf("hid = %d | sid = %d | looping = %d\n", Channels[sid].pdsb,
2176 Channels[sid].pds3db, looping);
2179 hid = Channels[sid].pdsb;
2180 Channels[sid].is_voice_msg = is_voice_msg;
2181 Channels[sid].snd_id = snd_id;
2182 Channels[sid].priority = priority;
2183 Channels[sid].last_position = 1;
2185 alGetSourceiv(hid, AL_SOURCE_STATE, &value);
2186 if(value & AL_PLAYING)
2189 sid = Channels[sid].pds3db;
2190 if (!alIsBuffer (sid)) {
2191 nprintf (("Error", "SOUND ==> %d is not a buffer!\n", sid));
2195 alSourcei (hid, AL_BUFFER, sid);
2196 alSourcei (hid, AL_LOOPING, (looping) ? AL_TRUE : AL_FALSE);
2197 alSourcei (hid, AL_SOURCE_RELATIVE, AL_TRUE);
2199 // set pan, volume, etc
2203 nprintf(("Sound","SOUND ==> Playing sound %d looping\n", sid));
2204 } else nprintf(("Sound", "SOUND ==> Playing sound %d not looping\n", sid));
2206 int i = alGetError();
2207 if(i != AL_NO_ERROR) {
2208 printf("OpenAL ==> %s!\n", alGetString(i));
2217 if (!ds_initialized)
2220 channel = ds_get_free_channel(volume, snd_id, priority);
2223 if ( Channels[channel].pdsb != NULL ) {
2227 // First check if the sound is in hardware, and try to duplicate from there
2230 if ( ds_channel_dup(ds_hardware_buffers[hid].pdsb, channel, 0) == 0 ) {
2231 // nprintf(("Sound", "SOUND ==> Played sound in hardware..\n"));
2235 // Channel will be NULL if hardware dup failed, or there was no hardware dup attempted
2236 if ( Channels[channel].pdsb == NULL ) {
2237 if ( ds_channel_dup(ds_software_buffers[sid].pdsb, channel, 0) == 0 ) {
2238 // nprintf(("Sound", "SOUND ==> Played sound in software..\n"));
2242 if ( Channels[channel].pdsb == NULL ) {
2246 if ( ds_using_ds3d() ) {
2247 if ( ds_is_3d_buffer(Channels[channel].pdsb) ) {
2248 if (Channels[channel].pds3db == NULL) {
2249 ds_get_3d_interface(Channels[channel].pdsb, &Channels[channel].pds3db);
2251 if ( Channels[channel].pds3db ) {
2252 Channels[channel].pds3db->SetMode(DS3DMODE_DISABLE,DS3D_IMMEDIATE);
2258 Channels[channel].vol = volume;
2259 Channels[channel].looping = looping;
2260 Channels[channel].priority = priority;
2261 Channels[channel].pdsb->SetPan(pan);
2262 Channels[channel].pdsb->SetVolume(volume);
2263 Channels[channel].is_voice_msg = is_voice_msg;
2267 ds_flags |= DSBPLAY_LOOPING;
2269 DSResult = Channels[channel].pdsb->Play(0, 0, ds_flags );
2272 if (Stop_logging_sounds == false) {
2274 sprintf(buf, "channel %d, address: %x, ds_flags: %d", channel, Channels[channel].pdsb, ds_flags);
2275 HUD_add_to_scrollback(buf, 3);
2279 if ( DSResult == DSERR_BUFFERLOST ) {
2280 ds_restore_buffer(Channels[channel].pdsb);
2281 DSResult = Channels[channel].pdsb->Play(0, 0, ds_flags );
2284 if ( DSResult != DS_OK ) {
2285 nprintf(("Sound", "Sound ==> Play failed with return value %s\n", get_DSERR_text(DSResult) ));
2290 // nprintf(( "Sound", "SOUND ==> Not playing sound requested at volume %.2f\n", ds_get_percentage_vol(volume) ));
2294 Channels[channel].snd_id = snd_id;
2295 Channels[channel].sig = channel_next_sig++;
2296 if (channel_next_sig < 0 ) {
2297 channel_next_sig = 1;
2301 if (Stop_logging_sounds == false) {
2304 sprintf(buf, "VOICE sig: %d, sid: %d, snd_id: %d, ch: %d", Channels[channel].sig, sid, snd_id, channel);
2305 HUD_add_to_scrollback(buf, 3);
2310 Channels[channel].last_position = 0;
2312 // make sure there aren't any looping voice messages
2313 for (int i=0; i<MAX_CHANNELS; i++) {
2314 if (Channels[i].is_voice_msg == true) {
2315 if (Channels[i].pdsb == NULL) {
2319 DWORD current_position = ds_get_play_position(i);
2320 if (current_position != 0) {
2321 if (current_position < Channels[i].last_position) {
2322 ds_close_channel(i);
2324 Channels[i].last_position = current_position;
2330 return Channels[channel].sig;
2335 // ---------------------------------------------------------------------------------------
2338 // Return the channel number that is playing the sound identified by sig. If that sound is
2339 // not playing, return -1.
2341 int ds_get_channel(int sig)
2348 for ( i = 0; i < MAX_CHANNELS; i++ ) {
2349 if ( Channels[i].pdsb && Channels[i].sig == sig ) {
2350 if ( ds_is_channel_playing(i) == TRUE ) {
2359 // ---------------------------------------------------------------------------------------
2360 // ds_is_channel_playing()
2363 int ds_is_channel_playing(int channel)
2370 unsigned long status;
2372 if ( !Channels[channel].pdsb ) {
2376 hr = Channels[channel].pdsb->GetStatus(&status);
2377 if ( hr != DS_OK ) {
2378 nprintf(("Sound", "SOUND ==> GetStatus failed with return value %s\n", get_DSERR_text(hr) ));
2382 if ( status & DSBSTATUS_PLAYING )
2389 // ---------------------------------------------------------------------------------------
2390 // ds_stop_channel()
2393 void ds_stop_channel(int channel)
2395 ds_close_channel(channel);
2398 // ---------------------------------------------------------------------------------------
2399 // ds_stop_channel_all()
2402 void ds_stop_channel_all()
2409 for ( i=0; i<MAX_CHANNELS; i++ ) {
2410 // if ( Channels[i].pdsb != NULL ) {
2417 // ---------------------------------------------------------------------------------------
2420 // Set the volume for a channel. The volume is expected to be in DirectSound units
2422 // If the sound is a 3D sound buffer, this is like re-establishing the maximum
2425 void ds_set_volume( int channel, int vol )
2431 unsigned long status;
2433 hr = Channels[channel].pdsb->GetStatus(&status);
2434 if ( hr != DS_OK ) {
2435 nprintf(("Sound", "SOUND ==> GetStatus failed with return value %s\n", get_DSERR_text(hr) ));
2439 if ( status & DSBSTATUS_PLAYING ) {
2440 Channels[channel].pdsb->SetVolume(vol);
2445 // ---------------------------------------------------------------------------------------
2448 // Set the pan for a channel. The pan is expected to be in DirectSound units
2450 void ds_set_pan( int channel, int pan )
2456 unsigned long status;
2458 hr = Channels[channel].pdsb->GetStatus(&status);
2459 if ( hr != DS_OK ) {
2460 nprintf(("Sound", "SOUND ==> GetStatus failed with return value %s\n", get_DSERR_text(hr) ));
2464 if ( status & DSBSTATUS_PLAYING ) {
2465 Channels[channel].pdsb->SetPan(pan);
2470 // ---------------------------------------------------------------------------------------
2473 // Get the pitch of a channel
2475 int ds_get_pitch(int channel)
2481 unsigned long status, pitch = 0;
2484 hr = Channels[channel].pdsb->GetStatus(&status);
2486 if ( hr != DS_OK ) {
2487 nprintf(("Sound", "SOUND ==> GetStatus failed with return value %s\n", get_DSERR_text(hr) ));
2491 if ( status & DSBSTATUS_PLAYING ) {
2492 hr = Channels[channel].pdsb->GetFrequency(&pitch);
2493 if ( hr != DS_OK ) {
2494 nprintf(("Sound", "SOUND ==> GetFrequency failed with return value %s\n", get_DSERR_text(hr) ));
2503 // ---------------------------------------------------------------------------------------
2506 // Set the pitch of a channel
2508 void ds_set_pitch(int channel, int pitch)
2513 unsigned long status;
2516 hr = Channels[channel].pdsb->GetStatus(&status);
2517 if ( hr != DS_OK ) {
2518 nprintf(("Sound", "SOUND ==> GetStatus failed with return value %s\n", get_DSERR_text(hr) ));
2522 if ( pitch < MIN_PITCH )
2525 if ( pitch > MAX_PITCH )
2528 if ( status & DSBSTATUS_PLAYING ) {
2529 Channels[channel].pdsb->SetFrequency((unsigned long)pitch);
2534 // ---------------------------------------------------------------------------------------
2535 // ds_chg_loop_status()
2538 void ds_chg_loop_status(int channel, int loop)
2543 unsigned long status;
2546 hr = Channels[channel].pdsb->GetStatus(&status);
2547 if ( hr != DS_OK ) {
2548 nprintf(("Sound", "SOUND ==> GetStatus failed with return value %s\n", get_DSERR_text(hr) ));
2552 if ( !(status & DSBSTATUS_PLAYING) )
2553 return; // sound is not playing anymore
2555 if ( status & DSBSTATUS_LOOPING ) {
2557 return; // we are already looping
2559 // stop the sound from looping
2560 hr = Channels[channel].pdsb->Play(0,0,0);
2565 return; // the sound is already not looping
2567 // start the sound looping
2568 hr = Channels[channel].pdsb->Play(0,0,DSBPLAY_LOOPING);
2574 // ---------------------------------------------------------------------------------------
2577 // Starts a ds3d sound playing
2581 // sid => software id for sound to play
2582 // hid => hardware id for sound to play (-1 if not in hardware)
2583 // snd_id => identifies what type of sound is playing
2584 // pos => world pos of sound
2585 // vel => velocity of object emitting sound
2586 // min => distance at which sound doesn't get any louder
2587 // max => distance at which sound becomes inaudible
2588 // looping => boolean, whether to loop the sound or not
2589 // max_volume => volume (-10000 to 0) for 3d sound at maximum
2590 // estimated_vol => manual estimated volume
2591 // priority => DS_MUST_PLAY
2596 // returns: 0 => sound started successfully
2597 // -1 => sound could not be played
2599 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 )
2608 if (!ds_initialized)
2611 channel = ds_get_free_channel(estimated_vol, snd_id, priority);
2614 Assert(Channels[channel].pdsb == NULL);
2616 // First check if the sound is in hardware, and try to duplicate from there
2619 if ( ds_is_3d_buffer(ds_hardware_buffers[hid].pdsb) == FALSE ) {
2620 nprintf(("Sound", "SOUND ==> Tried to play non-3d buffer in ds3d_play()..\n"));
2624 if ( ds_channel_dup(ds_hardware_buffers[hid].pdsb, channel, 1) == 0 ) {
2625 nprintf(("Sound", "SOUND ==> Played sound using DirectSound3D in hardware..\n"));
2629 // Channel will be NULL if hardware dup failed, or there was no hardware dup attempted
2630 if ( Channels[channel].pdsb == NULL ) {
2633 if ( ds_is_3d_buffer(ds_software_buffers[sid].pdsb) == FALSE ) {
2634 nprintf(("Sound", "SOUND ==> Tried to play non-3d buffer in ds3d_play()..\n"));
2639 if ( ds_channel_dup(ds_software_buffers[sid].pdsb, channel, 1) == 0 ) {
2640 // nprintf(("Sound", "SOUND ==> Played sound using DirectSound3D \n"));
2644 if ( Channels[channel].pdsb == NULL ) {
2649 desc = ds_software_buffers[sid].desc;
2650 desc.lpwfxFormat = &ds_software_buffers[sid].wfx;
2652 // duplicate buffer failed, so call CreateBuffer instead
2654 hr = pDirectSound->CreateSoundBuffer(&desc, &Channels[channel].pdsb, NULL );
2656 if ( (hr == DS_OK) && (Channels[channel].pdsb) ) {
2657 BYTE *pdest, *pdest2;
2659 DWORD src_ds_size, dest_ds_size, not_used;
2662 if ( ds_get_size(sid, &src_size) != 0 ) {
2664 Channels[channel].pdsb->Release();
2668 // lock the src buffer
2669 hr = ds_software_buffers[sid].pdsb->Lock(0, src_size, (void**)&psrc, &src_ds_size, (void**)&psrc2, ¬_used, 0);
2670 if ( hr != DS_OK ) {
2671 mprintf(("err: %s\n", get_DSERR_text(hr)));
2673 Channels[channel].pdsb->Release();
2677 if ( Channels[channel].pdsb->Lock(0, src_ds_size, (void**)(&pdest), &dest_ds_size, (void**)&pdest2, ¬_used, 0) == DS_OK) {
2678 memcpy(pdest, psrc, src_ds_size);
2679 Channels[channel].pdsb->Unlock(pdest, dest_ds_size, 0, 0);
2680 ds_get_3d_interface(Channels[channel].pdsb, &Channels[channel].pds3db);
2682 Channels[channel].pdsb->Release();
2689 Assert(Channels[channel].pds3db );
2690 Channels[channel].pds3db->SetMode(DS3DMODE_NORMAL,DS3D_IMMEDIATE);
2692 // set up 3D sound data here
2693 ds3d_update_buffer(channel, i2fl(min), i2fl(max), pos, vel);
2695 Channels[channel].vol = estimated_vol;
2696 Channels[channel].looping = looping;
2698 // sets the maximum "inner cone" volume
2699 Channels[channel].pdsb->SetVolume(max_volume);
2703 ds_flags |= DSBPLAY_LOOPING;
2706 hr = Channels[channel].pdsb->Play(0, 0, ds_flags );
2708 if ( hr == DSERR_BUFFERLOST ) {
2709 ds_restore_buffer(Channels[channel].pdsb);
2710 hr = Channels[channel].pdsb->Play(0, 0, ds_flags );
2713 if ( hr != DS_OK ) {
2714 nprintf(("Sound", "Sound ==> Play failed with return value %s\n", get_DSERR_text(hr) ));
2715 if ( Channels[channel].pdsb ) {
2717 while(++attempts < 10) {
2718 hr = Channels[channel].pdsb->Release();
2719 if ( hr == DS_OK ) {
2722 nprintf(("Sound","SOUND ==> DirectSound Release() failed with code %s\n.",get_DSERR_text(hr) ));
2726 Channels[channel].pdsb = NULL;
2732 nprintf(( "Sound", "SOUND ==> Not playing requested 3D sound\n"));
2736 Channels[channel].snd_id = snd_id;
2737 Channels[channel].sig = channel_next_sig++;
2738 if (channel_next_sig < 0 ) {
2739 channel_next_sig = 1;
2741 return Channels[channel].sig;
2745 void ds_set_position(int channel, DWORD offset)
2750 // set the position of the sound buffer
2751 Channels[channel].pdsb->SetCurrentPosition(offset);
2755 DWORD ds_get_play_position(int channel)
2761 if( Channels[channel].pdsb ) {
2762 // get source position
2763 alGetSourceiv(Channels[channel].pdsb, AL_SOURCE_STATE, &value);
2765 play = (value == AL_PLAYING) ? 1 : 0;
2773 if ( Channels[channel].pdsb ) {
2774 Channels[channel].pdsb->GetCurrentPosition((LPDWORD)&play,(LPDWORD)&write);
2783 DWORD ds_get_write_position(int channel)
2790 if ( Channels[channel].pdsb ) {
2791 Channels[channel].pdsb->GetCurrentPosition((LPDWORD)&play,(LPDWORD)&write);
2800 int ds_get_channel_size(int channel)
2810 if ( Channels[channel].pdsb ) {
2811 memset(&caps, 0, sizeof(DSBCAPS));
2812 caps.dwSize = sizeof(DSBCAPS);
2813 dsrval = Channels[channel].pdsb->GetCaps(&caps);
2814 if ( dsrval != DS_OK ) {
2817 size = caps.dwBufferBytes;
2826 // Returns the number of channels that are actually playing
2827 int ds_get_number_channels()
2836 for ( i = 0; i < MAX_CHANNELS; i++ ) {
2837 if ( Channels[i].pdsb ) {
2838 if ( ds_is_channel_playing(i) == TRUE ) {
2848 // retreive raw data from a sound buffer
2849 int ds_get_data(int sid, char *data)
2855 LPDIRECTSOUNDBUFFER pdsb;
2861 pdsb = ds_software_buffers[sid].pdsb;
2863 memset(&caps, 0, sizeof(DSBCAPS));
2864 caps.dwSize = sizeof(DSBCAPS);
2865 dsrval = pdsb->GetCaps(&caps);
2866 if ( dsrval != DS_OK ) {
2870 // lock the entire buffer
2871 dsrval = pdsb->Lock(0, caps.dwBufferBytes, &buffer_data, &buffer_size, 0, 0, 0);
2872 if ( dsrval != DS_OK ) {
2876 memcpy(data, buffer_data, buffer_size);
2878 dsrval = pdsb->Unlock(buffer_data, buffer_size, 0, 0);
2879 if ( dsrval != DS_OK ) {
2887 // return the size of the raw sound data
2888 int ds_get_size(int sid, int *size)
2894 LPDIRECTSOUNDBUFFER pdsb;
2898 pdsb = ds_software_buffers[sid].pdsb;
2900 memset(&caps, 0, sizeof(DSBCAPS));
2901 caps.dwSize = sizeof(DSBCAPS);
2902 dsrval = pdsb->GetCaps(&caps);
2903 if ( dsrval != DS_OK ) {
2907 *size = caps.dwBufferBytes;
2917 // Return the primary buffer interface. Note that we cast to a uint to avoid
2918 // having to include dsound.h (and thus windows.h) in ds.h.
2920 uint ds_get_primary_buffer_interface()
2926 return (uint)pPrimaryBuffer;
2930 // Return the DirectSound Interface.
2932 uint ds_get_dsound_interface()
2938 return (uint)pDirectSound;
2942 uint ds_get_property_set_interface()
2948 return (uint)pPropertySet;
2952 // --------------------
2954 // EAX Functions below
2956 // --------------------
2958 // Set the master volume for the reverb added to all sound sources.
2960 // volume: volume, range from 0 to 1.0
2962 // returns: 0 if the volume is set successfully, otherwise return -1
2964 int ds_eax_set_volume(float volume)
2972 if (Ds_eax_inited == 0) {
2976 Assert(Ds_eax_reverb);
2978 CAP(volume, 0.0f, 1.0f);
2980 hr = Ds_eax_reverb->Set(DSPROPSETID_EAX_ReverbProperties_Def, DSPROPERTY_EAX_VOLUME, NULL, 0, &volume, sizeof(float));
2981 if (SUCCEEDED(hr)) {
2989 // Set the decay time for the EAX environment (ie all sound sources)
2991 // seconds: decay time in seconds
2993 // returns: 0 if decay time is successfully set, otherwise return -1
2995 int ds_eax_set_decay_time(float seconds)
3003 if (Ds_eax_inited == 0) {
3007 Assert(Ds_eax_reverb);
3009 CAP(seconds, 0.1f, 20.0f);
3011 hr = Ds_eax_reverb->Set(DSPROPSETID_EAX_ReverbProperties_Def, DSPROPERTY_EAX_DECAYTIME, NULL, 0, &seconds, sizeof(float));
3012 if (SUCCEEDED(hr)) {
3020 // Set the damping value for the EAX environment (ie all sound sources)
3022 // damp: damp value from 0 to 2.0
3024 // returns: 0 if the damp value is successfully set, otherwise return -1
3026 int ds_eax_set_damping(float damp)
3034 if (Ds_eax_inited == 0) {
3038 Assert(Ds_eax_reverb);
3040 CAP(damp, 0.0f, 2.0f);
3042 hr = Ds_eax_reverb->Set(DSPROPSETID_EAX_ReverbProperties_Def, DSPROPERTY_EAX_DAMPING, NULL, 0, &damp, sizeof(float));
3043 if (SUCCEEDED(hr)) {
3051 // Set up the environment type for all sound sources.
3053 // envid: value from the EAX_ENVIRONMENT_* enumeration in ds_eax.h
3055 // returns: 0 if the environment is set successfully, otherwise return -1
3057 int ds_eax_set_environment(unsigned long envid)
3065 if (Ds_eax_inited == 0) {
3069 Assert(Ds_eax_reverb);
3071 hr = Ds_eax_reverb->Set(DSPROPSETID_EAX_ReverbProperties_Def, DSPROPERTY_EAX_ENVIRONMENT, NULL, 0, &envid, sizeof(unsigned long));
3072 if (SUCCEEDED(hr)) {
3080 // Set up a predefined environment for EAX
3082 // envid: value from teh EAX_ENVIRONMENT_* enumeration
3084 // returns: 0 if successful, otherwise return -1
3086 int ds_eax_set_preset(unsigned long envid)
3094 if (Ds_eax_inited == 0) {
3098 Assert(Ds_eax_reverb);
3099 Assert(envid < EAX_ENVIRONMENT_COUNT);
3101 hr = Ds_eax_reverb->Set(DSPROPSETID_EAX_ReverbProperties_Def, DSPROPERTY_EAX_ALL, NULL, 0, &Ds_eax_presets[envid], sizeof(EAX_REVERBPROPERTIES));
3102 if (SUCCEEDED(hr)) {
3111 // Set up all the parameters for an environment
3113 // id: value from teh EAX_ENVIRONMENT_* enumeration
3114 // volume: volume for the environment (0 to 1.0)
3115 // damping: damp value for the environment (0 to 2.0)
3116 // decay: decay time in seconds (0.1 to 20.0)
3118 // returns: 0 if successful, otherwise return -1
3120 int ds_eax_set_all(unsigned long id, float vol, float damping, float decay)
3128 if (Ds_eax_inited == 0) {
3132 Assert(Ds_eax_reverb);
3133 Assert(id < EAX_ENVIRONMENT_COUNT);
3135 EAX_REVERBPROPERTIES er;
3137 er.environment = id;
3139 er.fDecayTime_sec = decay;
3140 er.fDamping = damping;
3142 hr = Ds_eax_reverb->Set(DSPROPSETID_EAX_ReverbProperties_Def, DSPROPERTY_EAX_ALL, NULL, 0, &er, sizeof(EAX_REVERBPROPERTIES));
3143 if (SUCCEEDED(hr)) {
3151 // Get up the parameters for the current environment
3153 // er: (output) hold environment parameters
3155 // returns: 0 if successful, otherwise return -1
3157 int ds_eax_get_all(EAX_REVERBPROPERTIES *er)
3164 unsigned long outsize;
3166 if (Ds_eax_inited == 0) {
3170 Assert(Ds_eax_reverb);
3172 hr = Ds_eax_reverb->Get(DSPROPSETID_EAX_ReverbProperties_Def, DSPROPERTY_EAX_ALL, NULL, 0, er, sizeof(EAX_REVERBPROPERTIES), &outsize);
3173 if (SUCCEEDED(hr)) {
3181 // Close down EAX, freeing any allocated resources
3188 if (Ds_eax_inited == 0) {
3198 // returns: 0 if initialization is successful, otherwise return -1
3206 unsigned long driver_support = 0;
3208 if (Ds_eax_inited) {
3212 Assert(Ds_eax_reverb == NULL);
3214 Ds_eax_reverb = (LPKSPROPERTYSET)ds_get_property_set_interface();
3215 if (Ds_eax_reverb == NULL) {
3219 // check if the listener property is supported by the audio driver
3220 hr = Ds_eax_reverb->QuerySupport(DSPROPSETID_EAX_ReverbProperties_Def, DSPROPERTY_EAX_ALL, &driver_support);
3222 nprintf(("Sound", "QuerySupport for the EAX Listener property set failed.. disabling EAX\n"));
3223 goto ds_eax_init_failed;
3226 if ((driver_support & (KSPROPERTY_SUPPORT_GET | KSPROPERTY_SUPPORT_SET)) != (KSPROPERTY_SUPPORT_GET | KSPROPERTY_SUPPORT_SET)) {
3227 goto ds_eax_init_failed;
3230 ds_eax_set_all(EAX_ENVIRONMENT_GENERIC, 0.0f, 0.0f, 0.0f);
3236 if (Ds_eax_reverb != NULL) {
3237 Ds_eax_reverb->Release();
3238 Ds_eax_reverb = NULL;
3247 int ds_eax_is_inited()
3253 return Ds_eax_inited;
3263 if (Ds_use_a3d == 0) {
3271 // Called once per game frame to make sure voice messages aren't looping
3277 for (int i=0; i<MAX_CHANNELS; i++) {
3279 if (cp->is_voice_msg) {
3280 if (cp->pdsb == 0) {
3284 int current_position = ds_get_play_position(i);
3285 if (current_position != 0) {
3286 if (current_position < cp->last_position) {
3287 ds_close_channel(i);
3289 cp->last_position = current_position;