2 * $Logfile: /Freespace2/code/Sound/ds.cpp $
7 * C file for interface to DirectSound
10 * Revision 1.1 2002/05/03 03:28:10 root
14 * 18 10/25/99 5:56p Jefff
15 * increase num software channels to the number the users hardware can
16 * handle. not less than 16, tho.
18 * 17 9/08/99 3:22p Dave
19 * Updated builtin mission list.
21 * 16 8/27/99 6:38p Alanl
22 * crush the blasted repeating messages bug
24 * 15 8/23/99 11:16p Danw
27 * 14 8/22/99 11:06p Alanl
28 * fix small bug in ds_close_channel
30 * 13 8/19/99 11:25a Alanl
31 * change format of secondary buffer from 44100 to 22050
33 * 12 8/17/99 4:11p Danw
34 * AL: temp fix for solving A3D crash
36 * 11 8/06/99 2:20p Jasonh
37 * AL: free 3D portion of buffer first
39 * 10 8/04/99 9:48p Alanl
40 * fix bug with setting 3D properties on a 2D sound buffer
42 * 9 8/04/99 11:42a Danw
43 * tone down EAX reverb
45 * 8 8/01/99 2:06p Alanl
46 * increase the rolloff for A3D
48 * 7 7/20/99 5:28p Dave
49 * Fixed debug build error.
51 * 6 7/20/99 1:49p Dave
52 * Peter Drake build. Fixed some release build warnings.
54 * 5 7/14/99 11:32a Danw
55 * AL: add some debug code to catch nefarious A3D problem
57 * 4 5/23/99 8:11p Alanl
58 * Added support for EAX
60 * 3 10/08/98 4:29p Dave
61 * Removed reference to osdefs.h
63 * 2 10/07/98 10:54a Dave
66 * 1 10/07/98 10:51a Dave
68 * 72 6/28/98 6:34p Lawrance
69 * add sanity check in while() loop for releasing channels
71 * 71 6/13/98 1:45p Sandeep
73 * 70 6/10/98 2:29p Lawrance
74 * don't use COM for initializing DirectSound... appears some machines
77 * 69 5/26/98 2:10a Lawrance
78 * make sure DirectSound pointer gets freed if Aureal resource manager
81 * 68 5/21/98 9:14p Lawrance
82 * remove obsolete registry setting
84 * 67 5/20/98 4:28p Allender
85 * upped sound buffers as per alan's request
87 * 66 5/15/98 3:36p John
88 * Fixed bug with new graphics window code and standalone server. Made
89 * hwndApp not be a global anymore.
91 * 65 5/06/98 3:37p Lawrance
92 * allow panned sounds geesh
94 * 64 5/05/98 4:49p Lawrance
95 * Put in code to authenticate A3D, improve A3D support
97 * 63 4/20/98 11:17p Lawrance
98 * fix bug with releasing channels
100 * 62 4/20/98 7:34p Lawrance
101 * take out obsolete directsound3d debug command
103 * 61 4/20/98 11:10a Lawrance
104 * put correct flags when creating sound buffer
106 * 60 4/20/98 12:03a Lawrance
107 * Allow prioritizing of CTRL3D buffers
109 * 59 4/19/98 9:31p Lawrance
110 * Use Aureal_enabled flag
112 * 58 4/19/98 9:39a Lawrance
113 * use DYNAMIC_LOOPERS for Aureal resource manager
115 * 57 4/19/98 4:13a Lawrance
116 * Improve how dsound is initialized
118 * 56 4/18/98 9:13p Lawrance
119 * Added Aureal support.
121 * 55 4/13/98 5:04p Lawrance
122 * Write functions to determine how many milliseconds are left in a sound
124 * 54 4/09/98 5:53p Lawrance
125 * Make DirectSound init more robust
127 * 53 4/01/98 9:21p John
128 * Made NDEBUG, optimized build with no warnings or errors.
130 * 52 3/31/98 5:19p John
131 * Removed demo/save/restore. Made NDEBUG defined compile. Removed a
132 * bunch of debug stuff out of player file. Made model code be able to
133 * unload models and malloc out only however many models are needed.
136 * 51 3/29/98 12:56a Lawrance
137 * preload the warp in and explosions sounds before a mission.
139 * 50 3/25/98 6:10p Lawrance
140 * Work on DirectSound3D
142 * 49 3/24/98 4:28p Lawrance
143 * Make DirectSound3D support more robust
145 * 48 3/24/98 11:49a Dave
146 * AL: Change way buffer gets locked.
148 * 47 3/24/98 11:27a Lawrance
149 * Use buffer_size for memcpy when locking buffer
151 * 46 3/23/98 10:32a Lawrance
152 * Add functions for extracting raw sound data
154 * 45 3/19/98 5:36p Lawrance
155 * Add some sound debug functions to see how many sounds are playing, and
156 * to start/stop random looping sounds.
158 * 44 3/07/98 3:35p Dave
159 * AL: check for ds being initialized in ds_create_buffer()
161 * 43 2/18/98 5:49p Lawrance
162 * Even if the ADPCM codec is unavailable, allow game to continue.
164 * 42 2/16/98 7:31p Lawrance
165 * get compression/decompression of voice working
167 * 41 2/15/98 11:10p Lawrance
168 * more work on real-time voice system
170 * 40 2/15/98 4:43p Lawrance
171 * work on real-time voice
173 * 39 2/06/98 7:30p John
174 * Added code to monitor the number of channels of sound actually playing.
176 * 38 2/06/98 8:56a Allender
177 * fixed calling convention problem with DLL handles
179 * 37 2/04/98 6:08p Lawrance
180 * Read function pointers from dsound.dll, further work on
181 * DirectSoundCapture.
183 * 36 2/03/98 11:53p Lawrance
184 * Adding support for DirectSoundCapture
186 * 35 1/31/98 5:48p Lawrance
187 * Start on real-time voice recording
189 * 34 1/10/98 1:14p John
190 * Added explanation to debug console commands
192 * 33 12/21/97 4:33p John
193 * Made debug console functions a class that registers itself
194 * automatically, so you don't need to add the function to
195 * debugfunctions.cpp.
197 * 32 12/08/97 12:24a Lawrance
198 * Allow duplicate sounds to be stopped if less than OR equal to new sound
201 * 31 12/05/97 5:19p Lawrance
202 * re-do sound priorities to make more general and extensible
204 * 30 11/28/97 2:09p Lawrance
205 * Overhaul how ADPCM conversion works... use much less memory... safer
208 * 29 11/22/97 11:32p Lawrance
209 * decompress ADPCM data into 8 bit (not 16bit) for regular sounds (ie not
212 * 28 11/20/97 5:36p Dave
213 * Hooked in a bunch of main hall changes (including sound). Made it
214 * possible to reposition (rewind/ffwd)
215 * sound buffer pointers. Fixed animation direction change framerate
218 * 27 10/13/97 7:41p Lawrance
219 * store duration of sound
221 * 26 10/11/97 6:39p Lawrance
222 * start playing primary buffer, to reduce latency on sounds starting
224 * 25 10/08/97 5:09p Lawrance
225 * limit player impact sounds so only one plays at a time
227 * 24 9/26/97 5:43p Lawrance
228 * fix a bug that was freeing memory early when playing compressed sound
231 * 23 9/09/97 3:39p Sandeep
232 * warning level 4 bugs
234 * 22 8/16/97 4:05p Lawrance
235 * don't load sounds into hardware if running Lean_and_mean
237 * 21 8/05/97 1:39p Lawrance
238 * support compressed stereo playback
240 * 20 7/31/97 10:38a Lawrance
241 * return old debug function for toggling DirectSound3D
243 * 19 7/29/97 3:27p Lawrance
244 * make console toggle for directsound3d work right
246 * 18 7/28/97 11:39a Lawrance
247 * allow individual volume scaling on 3D buffers
249 * 17 7/18/97 8:18p Lawrance
250 * fix bug in ds_get_free_channel() that caused sounds to not play when
253 * 16 7/17/97 8:04p Lawrance
254 * allow priority sounds to play if free channel, otherwise stop lowest
255 * volume priority sound of same type
257 * 15 7/17/97 5:57p John
258 * made directsound3d config value work
260 * 14 7/17/97 5:43p John
261 * added new config stuff
263 * 13 7/17/97 4:25p John
264 * First, broken, stage of changing config stuff
266 * 12 7/15/97 12:13p Lawrance
267 * don't stop sounds that have highest priority
269 * 11 7/15/97 11:15a Lawrance
270 * limit the max instances of simultaneous sound effects, implement
271 * priorities to force critical sounds
273 * 10 6/09/97 11:50p Lawrance
274 * integrating DirectSound3D
276 * 9 6/08/97 5:59p Lawrance
277 * integrate DirectSound3D into sound system
279 * 8 6/04/97 1:19p Lawrance
280 * made hardware mixing robust
282 * 7 6/03/97 1:56p Hoffoss
283 * Return correct error code when direct sound init fails.
285 * 6 6/03/97 12:07p Lawrance
286 * don't enable 3D sounds in Primary buffer
288 * 5 6/02/97 3:45p Dan
289 * temp disable of hardware mixing until problem solved with
290 * CreateBuffer() failing
292 * 4 6/02/97 1:45p Lawrance
293 * implementing hardware mixing
295 * 3 5/29/97 4:01p Lawrance
296 * let snd_init() have final say on initialization
298 * 2 5/29/97 12:04p Lawrance
299 * creation of file to hold DirectSound specific portions
315 #include <initguid.h>
317 #include "verifya3d.h"
319 // Pointers to functions contained in DSOUND.dll
320 HRESULT (__stdcall *pfn_DirectSoundCreate)(LPGUID lpGuid, LPDIRECTSOUND *ppDS, IUnknown FAR *pUnkOuter) = NULL;
321 HRESULT (__stdcall *pfn_DirectSoundCaptureCreate)(LPGUID lpGUID, LPDIRECTSOUNDCAPTURE *lplpDSC, LPUNKNOWN pUnkOuter) = NULL;
323 HINSTANCE Ds_dll_handle=NULL;
325 LPDIRECTSOUND pDirectSound = NULL;
326 LPDIRECTSOUNDBUFFER pPrimaryBuffer = NULL;
327 LPIA3D2 pIA3d2 = NULL;
329 static LPKSPROPERTYSET pPropertySet; // pointer to sound card property set
330 static LPDIRECTSOUNDBUFFER Ds_property_set_pdsb = NULL;
331 static LPDIRECTSOUND3DBUFFER Ds_property_set_pds3db = NULL;
333 static int Ds_must_call_couninitialize = 0;
335 channel* Channels; //[MAX_CHANNELS];
336 static int channel_next_sig = 1;
338 #define MAX_DS_SOFTWARE_BUFFERS 256
339 typedef struct ds_sound_buffer
341 LPDIRECTSOUNDBUFFER pdsb;
347 ds_sound_buffer ds_software_buffers[MAX_DS_SOFTWARE_BUFFERS];
349 #define MAX_DS_HARDWARE_BUFFERS 32
350 ds_sound_buffer ds_hardware_buffers[MAX_DS_HARDWARE_BUFFERS];
352 int ds_vol_lookup[101]; // lookup table for direct sound volumes
353 int ds_initialized = FALSE;
355 static DSCAPS Soundcard_caps; // current soundcard capabilities
357 extern int Snd_sram; // mem (in bytes) used up by storing sounds in system memory
358 extern int Snd_hram; // mem (in bytes) used up by storing sounds in soundcard memory
360 static int Ds_use_ds3d = 0;
361 static int Ds_use_a3d = 0;
362 static int Ds_use_eax = 0;
364 GUID IID_IA3d2_Def = {0xfb80d1e0, 0x98d3, 0x11d1, {0x90, 0xfb, 0x00, 0x60, 0x08, 0xa1, 0xf4, 0x41}};
365 GUID CLSID_A3d_Def = {0xd8f1eee0, 0xf634, 0x11cf, {0x87, 0x0, 0x0, 0xa0, 0x24, 0x5d, 0x91, 0x8b}};
367 static bool Stop_logging_sounds = false;
369 static int MAX_CHANNELS = 0; // initialized properly in ds_init_channels()
371 ///////////////////////////
375 ///////////////////////////
378 //#define EAX_PRESET_GENERIC EAX_ENVIRONMENT_GENERIC,0.5F,1.493F,0.5F
379 #define EAX_PRESET_GENERIC EAX_ENVIRONMENT_GENERIC,0.2F,0.2F,1.0F
380 #define EAX_PRESET_PADDEDCELL EAX_ENVIRONMENT_PADDEDCELL,0.25F,0.1F,0.0F
381 #define EAX_PRESET_ROOM EAX_ENVIRONMENT_ROOM,0.417F,0.4F,0.666F
382 #define EAX_PRESET_BATHROOM EAX_ENVIRONMENT_BATHROOM,0.653F,1.499F,0.166F
383 #define EAX_PRESET_LIVINGROOM EAX_ENVIRONMENT_LIVINGROOM,0.208F,0.478F,0.0F
384 #define EAX_PRESET_STONEROOM EAX_ENVIRONMENT_STONEROOM,0.5F,2.309F,0.888F
385 #define EAX_PRESET_AUDITORIUM EAX_ENVIRONMENT_AUDITORIUM,0.403F,4.279F,0.5F
386 #define EAX_PRESET_CONCERTHALL EAX_ENVIRONMENT_CONCERTHALL,0.5F,3.961F,0.5F
387 #define EAX_PRESET_CAVE EAX_ENVIRONMENT_CAVE,0.5F,2.886F,1.304F
388 #define EAX_PRESET_ARENA EAX_ENVIRONMENT_ARENA,0.361F,7.284F,0.332F
389 #define EAX_PRESET_HANGAR EAX_ENVIRONMENT_HANGAR,0.5F,10.0F,0.3F
390 #define EAX_PRESET_CARPETEDHALLWAY EAX_ENVIRONMENT_CARPETEDHALLWAY,0.153F,0.259F,2.0F
391 #define EAX_PRESET_HALLWAY EAX_ENVIRONMENT_HALLWAY,0.361F,1.493F,0.0F
392 #define EAX_PRESET_STONECORRIDOR EAX_ENVIRONMENT_STONECORRIDOR,0.444F,2.697F,0.638F
393 #define EAX_PRESET_ALLEY EAX_ENVIRONMENT_ALLEY,0.25F,1.752F,0.776F
394 #define EAX_PRESET_FOREST EAX_ENVIRONMENT_FOREST,0.111F,3.145F,0.472F
395 #define EAX_PRESET_CITY EAX_ENVIRONMENT_CITY,0.111F,2.767F,0.224F
396 #define EAX_PRESET_MOUNTAINS EAX_ENVIRONMENT_MOUNTAINS,0.194F,7.841F,0.472F
397 #define EAX_PRESET_QUARRY EAX_ENVIRONMENT_QUARRY,1.0F,1.499F,0.5F
398 #define EAX_PRESET_PLAIN EAX_ENVIRONMENT_PLAIN,0.097F,2.767F,0.224F
399 #define EAX_PRESET_PARKINGLOT EAX_ENVIRONMENT_PARKINGLOT,0.208F,1.652F,1.5F
400 #define EAX_PRESET_SEWERPIPE EAX_ENVIRONMENT_SEWERPIPE,0.652F,2.886F,0.25F
401 #define EAX_PRESET_UNDERWATER EAX_ENVIRONMENT_UNDERWATER,1.0F,1.499F,0.0F
402 #define EAX_PRESET_DRUGGED EAX_ENVIRONMENT_DRUGGED,0.875F,8.392F,1.388F
403 #define EAX_PRESET_DIZZY EAX_ENVIRONMENT_DIZZY,0.139F,17.234F,0.666F
404 #define EAX_PRESET_PSYCHOTIC EAX_ENVIRONMENT_PSYCHOTIC,0.486F,7.563F,0.806F
406 static LPKSPROPERTYSET Ds_eax_reverb = NULL;
408 static int Ds_eax_inited = 0;
410 EAX_REVERBPROPERTIES Ds_eax_presets[] =
412 {EAX_PRESET_GENERIC},
413 {EAX_PRESET_PADDEDCELL},
415 {EAX_PRESET_BATHROOM},
416 {EAX_PRESET_LIVINGROOM},
417 {EAX_PRESET_STONEROOM},
418 {EAX_PRESET_AUDITORIUM},
419 {EAX_PRESET_CONCERTHALL},
423 {EAX_PRESET_CARPETEDHALLWAY},
424 {EAX_PRESET_HALLWAY},
425 {EAX_PRESET_STONECORRIDOR},
429 {EAX_PRESET_MOUNTAINS},
432 {EAX_PRESET_PARKINGLOT},
433 {EAX_PRESET_SEWERPIPE},
434 {EAX_PRESET_UNDERWATER},
435 {EAX_PRESET_DRUGGED},
437 {EAX_PRESET_PSYCHOTIC},
440 GUID DSPROPSETID_EAX_ReverbProperties_Def = {0x4a4e6fc1, 0xc341, 0x11d1, {0xb7, 0x3a, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}};
441 GUID DSPROPSETID_EAXBUFFER_ReverbProperties_Def = {0x4a4e6fc0, 0xc341, 0x11d1, {0xb7, 0x3a, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}};
443 //----------------------------------------------------------------
445 void ds_get_soundcard_caps(DSCAPS *dscaps);
450 //--------------------------------------------------------------------------
453 // Determine if a secondary buffer is a 3d secondary buffer.
455 int ds_is_3d_buffer(LPDIRECTSOUNDBUFFER pdsb)
460 dsbc.dwSize = sizeof(dsbc);
461 hr = pdsb->GetCaps(&dsbc);
462 if ( hr == DS_OK && dsbc.dwFlags & DSBCAPS_CTRL3D ) {
470 //--------------------------------------------------------------------------
473 // Determine if a secondary buffer is a 3d secondary buffer.
475 int ds_is_3d_buffer(int sid)
478 return ds_is_3d_buffer(ds_software_buffers[sid].pdsb);
484 //--------------------------------------------------------------------------
485 // ds_build_vol_lookup()
487 // Fills up the ds_vol_lookup[] tables that converts from a volume in the form
488 // 0.0 -> 1.0 to -10000 -> 0 (this is the DirectSound method, where units are
489 // hundredths of decibls)
491 void ds_build_vol_lookup()
496 ds_vol_lookup[0] = -10000;
497 for ( i = 1; i <= 100; i++ ) {
499 ds_vol_lookup[i] = fl2i( (log(vol) / log(2.0f)) * 1000.0f);
504 //--------------------------------------------------------------------------
505 // ds_convert_volume()
507 // Takes volume between 0.0f and 1.0f and converts into
508 // DirectSound style volumes between -10000 and 0.
509 int ds_convert_volume(float volume)
513 index = fl2i(volume * 100.0f);
519 return ds_vol_lookup[index];
522 //--------------------------------------------------------------------------
523 // ds_get_percentage_vol()
525 // Converts -10000 -> 0 range volume to 0 -> 1
526 float ds_get_percentage_vol(int ds_vol)
529 vol = pow(2.0, ds_vol/1000.0);
533 // ---------------------------------------------------------------------------------------
536 // Parse a wave file.
538 // parameters: filename => file of sound to parse
539 // dest => address of pointer of where to store raw sound data (output parm)
540 // dest_size => number of bytes of sound data stored (output parm)
541 // header => address of pointer to a WAVEFORMATEX struct (output parm)
543 // returns: 0 => wave file successfully parsed
546 // NOTE: memory is malloced for the header and dest in this function. It is the responsibility
547 // of the caller to free this memory later.
549 int ds_parse_wave(char *filename, ubyte **dest, uint *dest_size, WAVEFORMATEX **header)
552 PCMWAVEFORMAT PCM_header;
554 unsigned int tag, size, next_chunk;
556 fp = cfopen( filename, "rb" );
558 nprintf(("Error", "Couldn't open '%s'\n", filename ));
562 // Skip the "RIFF" tag and file size (8 bytes)
563 // Skip the "WAVE" tag (4 bytes)
564 cfseek( fp, 12, CF_SEEK_SET );
566 // Now read RIFF tags until the end of file
569 if ( cfread( &tag, sizeof(uint), 1, fp ) != 1 )
572 if ( cfread( &size, sizeof(uint), 1, fp ) != 1 )
575 next_chunk = cftell(fp) + size;
578 case 0x20746d66: // The 'fmt ' tag
579 //nprintf(("Sound", "SOUND => size of fmt block: %d\n", size));
580 cfread( &PCM_header, sizeof(PCMWAVEFORMAT), 1, fp );
581 if ( PCM_header.wf.wFormatTag != WAVE_FORMAT_PCM ) {
582 cbExtra = cfread_short(fp);
585 // Allocate memory for WAVEFORMATEX structure + extra bytes
586 if ( (*header = (WAVEFORMATEX *) malloc ( sizeof(WAVEFORMATEX)+cbExtra )) != NULL ){
587 // Copy bytes from temporary format structure
588 memcpy (*header, &PCM_header, sizeof(PCM_header));
589 (*header)->cbSize = (unsigned short)cbExtra;
591 // Read those extra bytes, append to WAVEFORMATEX structure
593 cfread( ((ubyte *)(*header) + sizeof(WAVEFORMATEX)), cbExtra, 1, fp);
597 Assert(0); // malloc failed
601 case 0x61746164: // the 'data' tag
603 (*dest) = (ubyte *)malloc(size);
604 Assert( *dest != NULL );
605 cfread( *dest, size, 1, fp );
607 default: // unknown, skip it
610 cfseek( fp, next_chunk, CF_SEEK_SET );
618 // ---------------------------------------------------------------------------------------
626 for ( i = 0; i < MAX_DS_SOFTWARE_BUFFERS; i++ ) {
627 if ( ds_software_buffers[i].pdsb == NULL )
631 if ( i == MAX_DS_SOFTWARE_BUFFERS ) {
638 // ---------------------------------------------------------------------------------------
646 for ( i = 0; i < MAX_DS_HARDWARE_BUFFERS; i++ ) {
647 if ( ds_hardware_buffers[i].pdsb == NULL )
651 if ( i == MAX_DS_HARDWARE_BUFFERS ) {
658 // ---------------------------------------------------------------------------------------
659 // Load a DirectSound secondary buffer with sound data. The sounds data for
660 // game sounds are stored in the DirectSound secondary buffers, and are
661 // duplicated as needed and placed in the Channels[] array to be played.
665 // sid => pointer to software id for sound ( output parm)
666 // hid => pointer to hardware id for sound ( output parm)
667 // final_size => pointer to storage to receive uncompressed sound size (output parm)
668 // header => pointer to a WAVEFORMATEX structure
669 // si => sound_info structure, contains details on the sound format
670 // flags => buffer properties ( DS_HARDWARE , DS_3D )
672 // returns: -1 => sound effect could not loaded into a secondary buffer
673 // 0 => sound effect successfully loaded into a secondary buffer
676 // NOTE: this function is slow, especially when sounds are loaded into hardware. Don't call this
677 // function from within gameplay.
679 int ds_load_buffer(int *sid, int *hid, int *final_size, void *header, sound_info *si, int flags)
681 Assert( final_size != NULL );
682 Assert( header != NULL );
683 Assert( si != NULL );
684 Assert( si->data != NULL );
685 Assert( si->size > 0 );
686 Assert( si->sample_rate > 0);
687 Assert( si->bits > 0 );
688 Assert( si->n_channels > 0 );
689 Assert( si->n_block_align >= 0 );
690 Assert( si->avg_bytes_per_sec > 0 );
692 WAVEFORMATEX *pwfx = (WAVEFORMATEX *)header;
693 DSBUFFERDESC BufferDesc;
694 WAVEFORMATEX WaveFormat;
696 int rc, final_sound_size, DSOUND_load_buffer_result = 0;
697 BYTE *pData, *pData2;
698 DWORD DataSize, DataSize2;
700 // the below two covnert_ variables are only used when the wav format is not
701 // PCM. DirectSound only takes PCM sound data, so we must convert to PCM if required
702 ubyte *convert_buffer = NULL; // storage for converted wav file
703 int convert_len; // num bytes of converted wav file
704 uint src_bytes_used; // number of source bytes actually converted (should always be equal to original size)
706 // Ensure DirectSound initialized
707 if (!ds_initialized) {
708 DSOUND_load_buffer_result = -1;
709 goto DSOUND_load_buffer_done;
712 // Set up buffer information
713 WaveFormat.wFormatTag = (unsigned short)si->format;
714 WaveFormat.nChannels = (unsigned short)si->n_channels;
715 WaveFormat.nSamplesPerSec = si->sample_rate;
716 WaveFormat.wBitsPerSample = (unsigned short)si->bits;
717 WaveFormat.cbSize = 0;
718 WaveFormat.nBlockAlign = (unsigned short)si->n_block_align;
719 WaveFormat.nAvgBytesPerSec = si->avg_bytes_per_sec;
721 final_sound_size = si->size; // assume this format will be used, may be over-ridded by convert_len
723 // Assert(WaveFormat.nChannels == 1);
725 switch ( si->format ) {
726 case WAVE_FORMAT_PCM:
729 case WAVE_FORMAT_ADPCM:
731 nprintf(( "Sound", "SOUND ==> converting sound from ADPCM to PCM\n" ));
732 rc = ACM_convert_ADPCM_to_PCM(pwfx, si->data, si->size, &convert_buffer, 0, &convert_len, &src_bytes_used, 8);
734 DSOUND_load_buffer_result = -1;
735 goto DSOUND_load_buffer_done;
738 if (src_bytes_used != si->size) {
739 Int3(); // ACM conversion failed?
740 DSOUND_load_buffer_result = -1;
741 goto DSOUND_load_buffer_done;
744 final_sound_size = convert_len;
746 // Set up the WAVEFORMATEX structure to have the right PCM characteristics
747 WaveFormat.wFormatTag = WAVE_FORMAT_PCM;
748 WaveFormat.nChannels = (unsigned short)si->n_channels;
749 WaveFormat.nSamplesPerSec = si->sample_rate;
750 WaveFormat.wBitsPerSample = 8;
751 WaveFormat.cbSize = 0;
752 WaveFormat.nBlockAlign = (unsigned short)(( WaveFormat.nChannels * WaveFormat.wBitsPerSample ) / 8);
753 WaveFormat.nAvgBytesPerSec = WaveFormat.nBlockAlign * WaveFormat.nSamplesPerSec;
755 nprintf(( "Sound", "SOUND ==> Coverted sound from ADPCM to PCM successfully\n" ));
759 nprintf(( "Sound", "Unsupported sound encoding\n" ));
760 DSOUND_load_buffer_result = -1;
761 goto DSOUND_load_buffer_done;
765 WaveFormat.wFormatTag = WAVE_FORMAT_PCM; // DirectSound only used PCM wave files
767 // Set up a DirectSound buffer
768 ZeroMemory(&BufferDesc, sizeof(BufferDesc));
769 BufferDesc.dwSize = sizeof(BufferDesc);
770 BufferDesc.dwBufferBytes = final_sound_size;
771 BufferDesc.lpwfxFormat = &WaveFormat;
773 // check if DirectSound3D is enabled and the sound is flagged for 3D
774 if ((ds_using_ds3d()) && (flags & DS_USE_DS3D)) {
775 // if (ds_using_ds3d()) {
776 BufferDesc.dwFlags = DSBCAPS_STATIC | DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRLVOLUME | DSBCAPS_CTRL3D | DSBCAPS_MUTE3DATMAXDISTANCE;
778 BufferDesc.dwFlags = DSBCAPS_STATIC | DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRLVOLUME | DSBCAPS_LOCSOFTWARE;
781 // Create a new software buffer using the settings for this wave
782 // All sounds are required to have a software buffer
785 nprintf(("Sound","SOUND ==> No more software secondary buffers available\n"));
788 DSReturn = pDirectSound->CreateSoundBuffer(&BufferDesc, &ds_software_buffers[*sid].pdsb, NULL );
790 if ( DSReturn == DS_OK && ds_software_buffers[*sid].pdsb != NULL ) {
792 ds_software_buffers[*sid].desc = BufferDesc;
793 ds_software_buffers[*sid].wfx = *BufferDesc.lpwfxFormat;
795 // Lock the buffer and copy in the data
796 if ((ds_software_buffers[*sid].pdsb)->Lock(0, final_sound_size, (void**)(&pData), &DataSize, (void**)(&pData2), &DataSize2, 0) == DS_OK) {
798 if ( convert_buffer )
799 memcpy(pData, convert_buffer, final_sound_size); // use converted data (PCM format)
801 memcpy(pData, si->data, final_sound_size);
803 (ds_software_buffers[*sid].pdsb)->Unlock(pData, DataSize, 0, 0);
805 DSOUND_load_buffer_result = 0;
807 // update ram used for sound
808 Snd_sram += final_sound_size;
809 *final_size = final_sound_size;
812 nprintf(("Sound","SOUND => fatal error in DSOUND_load_buffer\n"));
814 DSOUND_load_buffer_result = -1;
817 DSOUND_load_buffer_done:
818 if ( convert_buffer )
819 free( convert_buffer );
820 return DSOUND_load_buffer_result;
823 // ---------------------------------------------------------------------------------------
824 // ds_init_channels()
826 // init the Channels[] array
828 void ds_init_channels()
832 // detect how many channels we can support
834 ds_get_soundcard_caps(&caps);
836 // caps.dwSize = sizeof(DSCAPS);
837 // pDirectSound->GetCaps(&caps);
839 // minimum 16 channels
840 MAX_CHANNELS = caps.dwMaxHwMixingStaticBuffers;
841 int dbg_channels = MAX_CHANNELS;
842 if (MAX_CHANNELS < 16) {
846 // allocate the channels array
847 Channels = (channel*) malloc(sizeof(channel) * MAX_CHANNELS);
848 if (Channels == NULL) {
849 Error(LOCATION, "Unable to allocate %d bytes for %d audio channels.", sizeof(channel) * MAX_CHANNELS, MAX_CHANNELS);
853 for ( i = 0; i < MAX_CHANNELS; i++ ) {
854 Channels[i].pdsb = NULL;
855 Channels[i].pds3db = NULL;
859 mprintf(("** MAX_CHANNELS set to %d. DS reported %d.\n", MAX_CHANNELS, dbg_channels));
862 // ---------------------------------------------------------------------------------------
863 // ds_init_software_buffers()
865 // init the software buffers
867 void ds_init_software_buffers()
871 for ( i = 0; i < MAX_DS_SOFTWARE_BUFFERS; i++ ) {
872 ds_software_buffers[i].pdsb = NULL;
876 // ---------------------------------------------------------------------------------------
877 // ds_init_hardware_buffers()
879 // init the hardware buffers
881 void ds_init_hardware_buffers()
885 for ( i = 0; i < MAX_DS_HARDWARE_BUFFERS; i++ ) {
886 ds_hardware_buffers[i].pdsb = NULL;
890 // ---------------------------------------------------------------------------------------
893 // init the both the software and hardware buffers
895 void ds_init_buffers()
897 ds_init_software_buffers();
898 ds_init_hardware_buffers();
901 // Get the current soundcard capabilities
902 void ds_get_soundcard_caps(DSCAPS *dscaps)
905 int n_hbuffers, hram;
907 dscaps->dwSize = sizeof(DSCAPS);
909 hr = pDirectSound->GetCaps(dscaps);
911 nprintf(("Sound","SOUND ==> DirectSound GetCaps() failed with code %s\n.",get_DSERR_text(hr) ));
915 n_hbuffers = dscaps->dwMaxHwMixingStaticBuffers;
916 hram = dscaps->dwTotalHwMemBytes;
918 if ( !(dscaps->dwFlags & DSCAPS_CERTIFIED) ) {
919 nprintf(("Sound","SOUND ==> Warning: audio driver is not Microsoft certified.\n"));
923 // ---------------------------------------------------------------------------------------
926 // init the both the software and hardware buffers
928 void ds_show_caps(DSCAPS *dscaps)
930 nprintf(("Sound", "SOUND => Soundcard Capabilities:\n"));
931 nprintf(("Sound", "================================\n"));
932 nprintf(("Sound", "Number of primary buffers: %d\n", dscaps->dwPrimaryBuffers ));
933 nprintf(("Sound", "Number of total hw mixing buffers: %d\n", dscaps->dwMaxHwMixingAllBuffers ));
934 nprintf(("Sound", "Number of total hw mixing static buffers: %d\n", dscaps->dwMaxHwMixingStaticBuffers ));
935 nprintf(("Sound", "Number of total hw mixing streaming buffers: %d\n", dscaps->dwMaxHwMixingStreamingBuffers ));
936 nprintf(("Sound", "Number of free hw mixing buffers: %d\n", dscaps->dwFreeHwMixingAllBuffers ));
937 nprintf(("Sound", "Number of free hw mixing static buffers: %d\n", dscaps->dwFreeHwMixingStaticBuffers ));
938 nprintf(("Sound", "Number of free hw mixing streaming buffers: %d\n", dscaps->dwFreeHwMixingStreamingBuffers ));
939 nprintf(("Sound", "Number of hw 3D buffers: %d\n", dscaps->dwMaxHw3DAllBuffers ));
940 nprintf(("Sound", "Number of hw 3D static buffers: %d\n", dscaps->dwMaxHw3DStaticBuffers ));
941 nprintf(("Sound", "Number of hw 3D streaming buffers: %d\n", dscaps->dwMaxHw3DStreamingBuffers ));
942 nprintf(("Sound", "Number of free hw 3D buffers: %d\n", dscaps->dwFreeHw3DAllBuffers ));
943 nprintf(("Sound", "Number of free hw static 3D buffers: %d\n", dscaps->dwFreeHw3DStaticBuffers ));
944 nprintf(("Sound", "Number of free hw streaming 3D buffers: %d\n", dscaps->dwFreeHw3DStreamingBuffers ));
945 nprintf(("Sound", "Number of total hw bytes: %d\n", dscaps->dwTotalHwMemBytes ));
946 nprintf(("Sound", "Number of free hw bytes: %d\n", dscaps->dwFreeHwMemBytes ));
947 nprintf(("Sound", "================================\n"));
950 // Fill in the waveformat struct with the primary buffer characteristics.
951 void ds_get_primary_format(WAVEFORMATEX *wfx)
953 // Set 16 bit / 22KHz / mono
954 wfx->wFormatTag = WAVE_FORMAT_PCM;
956 wfx->nSamplesPerSec = 22050;
957 wfx->wBitsPerSample = 16;
959 wfx->nBlockAlign = (unsigned short)(wfx->nChannels * (wfx->wBitsPerSample / 8));
960 wfx->nAvgBytesPerSec = wfx->nBlockAlign * wfx->nSamplesPerSec;
963 // obtain the function pointers from the dsound.dll
964 void ds_dll_get_functions()
966 pfn_DirectSoundCreate = (HRESULT(__stdcall *)(LPGUID lpGuid, LPDIRECTSOUND *ppDS, IUnknown FAR *pUnkOuter))GetProcAddress(Ds_dll_handle,"DirectSoundCreate");
967 pfn_DirectSoundCaptureCreate = (HRESULT(__stdcall *)(LPGUID lpGuid, LPDIRECTSOUNDCAPTURE *lplpDSC, IUnknown FAR *pUnkOuter))GetProcAddress(Ds_dll_handle,"DirectSoundCaptureCreate");
970 // Load the dsound.dll, and get funtion pointers
971 // exit: 0 -> dll loaded successfully
972 // !0 -> dll could not be loaded
975 if ( !Ds_dll_loaded ) {
976 Ds_dll_handle = LoadLibrary("dsound.dll");
977 if ( !Ds_dll_handle ) {
980 ds_dll_get_functions();
987 static int ds_init_a3d()
989 HINSTANCE a3d_handle;
992 a3d_handle = LoadLibrary("a3d.dll");
996 FreeLibrary(a3d_handle);
1000 Ds_must_call_couninitialize = 1;
1002 hr = CoCreateInstance(CLSID_A3d_Def, NULL, CLSCTX_INPROC_SERVER, IID_IDirectSound, (void**)&pDirectSound);
1007 Assert(pDirectSound != NULL);
1008 hr = pDirectSound->QueryInterface(IID_IA3d2_Def, (void**)&pIA3d2);
1013 A3DCAPS_SOFTWARE swCaps;
1015 // Get Dll Software CAP to get DLL version number
1016 ZeroMemory(&swCaps,sizeof(swCaps));
1018 swCaps.dwSize = sizeof(swCaps);
1019 pIA3d2->GetSoftwareCaps(&swCaps);
1021 // Compare version from a3d.dll to header version only return A3D_OK if dll version >= to header version
1022 if (swCaps.dwVersion < A3D_CURRENT_VERSION) {
1023 pDirectSound->Release();
1024 pDirectSound = NULL;
1029 // verify this is authentic A3D
1030 int aureal_verified;
1031 aureal_verified = VerifyAurealA3D();
1033 if (aureal_verified == FALSE) {
1034 // This is fake A3D!!! Ignore
1035 pDirectSound->Release();
1036 pDirectSound = NULL;
1040 // Register our version for backwards compatibility with newer A3d.dll
1041 pIA3d2->RegisterVersion(A3D_CURRENT_VERSION);
1043 hr = pDirectSound->Initialize(NULL);
1045 pDirectSound->Release();
1046 pDirectSound = NULL;
1050 pIA3d2->SetResourceManagerMode(A3D_RESOURCE_MODE_DYNAMIC_LOOPERS);
1056 // Initialize the property set interface.
1058 // returns: 0 if successful, otherwise -1. If successful, the global pPropertySet will
1059 // set to a non-NULL value.
1061 int ds_init_property_set()
1065 // Create the secondary buffer required for EAX initialization
1067 wf.wFormatTag = WAVE_FORMAT_PCM;
1069 wf.nSamplesPerSec = 22050;
1070 wf.wBitsPerSample = 16;
1072 wf.nBlockAlign = (unsigned short)(wf.nChannels * (wf.wBitsPerSample / 8));
1073 wf.nAvgBytesPerSec = wf.nBlockAlign * wf.nSamplesPerSec;
1076 ZeroMemory(&dsbd, sizeof(dsbd));
1077 dsbd.dwSize = sizeof(dsbd);
1078 dsbd.dwFlags = DSBCAPS_CTRLDEFAULT | DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_STATIC | DSBCAPS_CTRL3D | DSBCAPS_MUTE3DATMAXDISTANCE;
1079 dsbd.dwBufferBytes = 3 * wf.nAvgBytesPerSec;
1080 dsbd.lpwfxFormat = &wf;
1082 // Create a new buffer using the settings for this wave
1083 hr = pDirectSound->CreateSoundBuffer(&dsbd, &Ds_property_set_pdsb, NULL);
1085 pPropertySet = NULL;
1089 // Get the 3D interface from the secondary buffer, which is used to query the EAX interface
1090 hr = Ds_property_set_pdsb->QueryInterface(IID_IDirectSound3DBuffer, (void**)&Ds_property_set_pds3db);
1092 Ds_property_set_pds3db = NULL;
1096 Assert(Ds_property_set_pds3db != NULL);
1097 hr = Ds_property_set_pds3db->QueryInterface(IID_IKsPropertySet, (void**)&pPropertySet);
1098 if ((FAILED(hr)) || (pPropertySet == NULL)) {
1105 // ---------------------------------------------------------------------------------------
1108 // returns: -1 => init failed
1109 // 0 => init success
1110 int ds_init(int use_a3d, int use_eax)
1114 WAVEFORMATEX wave_format;
1115 DSBUFFERDESC BufferDesc;
1117 nprintf(( "Sound", "SOUND ==> Initializing DirectSound...\n" ));
1119 hwnd = (HWND)os_get_window();
1120 if ( hwnd == NULL ) {
1121 nprintf(( "Sound", "SOUND ==> No window handle, so no sound...\n" ));
1125 if ( ds_dll_load() == -1 ) {
1129 pDirectSound = NULL;
1131 Ds_use_a3d = use_a3d;
1132 Ds_use_eax = use_eax;
1134 if (Ds_use_a3d || Ds_use_eax) {
1138 if (Ds_use_a3d && Ds_use_eax) {
1143 // If we want A3D, ensure a3d.dll exists
1144 if (Ds_use_a3d == 1) {
1145 if (ds_init_a3d() != 0) {
1152 if (Ds_use_a3d == 0) {
1153 if (!pfn_DirectSoundCreate) {
1154 nprintf(( "Sound", "SOUND ==> Could not get DirectSoundCreate function pointer\n" ));
1158 hr = pfn_DirectSoundCreate(NULL, &pDirectSound, NULL);
1164 // Set up DirectSound for exclusive mode, so we can change the primary buffer if we want to.
1165 hr = pDirectSound->SetCooperativeLevel(hwnd, DSSCL_EXCLUSIVE);
1167 nprintf(("Sound","SOUND ==> DirectSound pDirectSound->SetCooperativeLevel failed with code %s\n.",get_DSERR_text(hr) ));
1168 pDirectSound = NULL;
1172 // Create the primary buffer
1173 ZeroMemory(&BufferDesc, sizeof(BufferDesc));
1174 BufferDesc.dwSize = sizeof(BufferDesc);
1176 ds_get_soundcard_caps(&Soundcard_caps);
1179 BufferDesc.dwFlags = DSBCAPS_PRIMARYBUFFER | DSBCAPS_CTRL3D;
1181 hr = pDirectSound->CreateSoundBuffer(&BufferDesc, &pPrimaryBuffer, 0);
1183 nprintf(("Sound","SOUND ==> Primary Buffer create failed with DSBCAPS_CTRL3D property... disabling DirectSound3D\n"));
1188 nprintf(("Sound","SOUND ==> Primary Buffer created with DirectSound3D enabled\n"));
1192 // If not using DirectSound3D, then create a normal primary buffer
1193 if (Ds_use_ds3d == 0) {
1194 BufferDesc.dwFlags = DSBCAPS_PRIMARYBUFFER;
1195 hr = pDirectSound->CreateSoundBuffer(&BufferDesc, &pPrimaryBuffer, 0);
1197 nprintf(("Sound","SOUND ==> Primary Buffer create failed with error: %s\n",get_DSERR_text(hr) ));
1198 pDirectSound = NULL;
1202 nprintf(("Sound","SOUND ==> Primary Buffer created with without DirectSound3D enabled\n"));
1206 // Get the primary buffer format
1207 ds_get_primary_format(&wave_format);
1209 hr = pPrimaryBuffer->SetFormat(&wave_format);
1211 nprintf(("Sound","SOUND ==> pPrimaryBuffer->SetFormat() failed with code %s\n",get_DSERR_text(hr) ));
1214 pPrimaryBuffer->GetFormat(&wave_format, sizeof(wave_format), NULL);
1215 nprintf(("Sound","SOUND ==> Primary Buffer forced to: rate: %d Hz bits: %d n_channels: %d\n",
1216 wave_format.nSamplesPerSec, wave_format.wBitsPerSample, wave_format.nChannels));
1218 // start the primary buffer playing. This will reduce sound latency when playing a sound
1219 // if no other sounds are playing.
1220 hr = pPrimaryBuffer->Play(0, 0, DSBPLAY_LOOPING);
1222 nprintf(("Sound","SOUND ==> pPrimaryBuffer->Play() failed with code %s\n",get_DSERR_text(hr) ));
1225 // Initialize DirectSound3D. Since software performance of DirectSound3D is unacceptably
1226 // slow, we require the voice manger (a DirectSound extension) to be present. The
1227 // exception is when A3D is being used, since A3D has a resource manager built in.
1229 int vm_required = 1; // voice manager
1230 if (Ds_use_a3d == 1) {
1234 if (ds3d_init(vm_required) != 0) {
1240 if (Ds_use_eax == 1) {
1241 ds_init_property_set();
1242 if (ds_eax_init() != 0) {
1247 ds_build_vol_lookup();
1251 ds_show_caps(&Soundcard_caps);
1256 // ---------------------------------------------------------------------------------------
1259 // returns the text equivalent for the a DirectSound DSERR_ code
1261 char *get_DSERR_text(int DSResult)
1263 switch( DSResult ) {
1269 case DSERR_ALLOCATED:
1270 return "DSERR_ALLOCATED";
1273 case DSERR_ALREADYINITIALIZED:
1274 return "DSERR_ALREADYINITIALIZED";
1277 case DSERR_BADFORMAT:
1278 return "DSERR_BADFORMAT";
1281 case DSERR_BUFFERLOST:
1282 return "DSERR_BUFFERLOST";
1285 case DSERR_CONTROLUNAVAIL:
1286 return "DSERR_CONTROLUNAVAIL";
1290 return "DSERR_GENERIC";
1293 case DSERR_INVALIDCALL:
1294 return "DSERR_INVALIDCALL";
1297 case DSERR_INVALIDPARAM:
1298 return "DSERR_INVALIDPARAM";
1301 case DSERR_NOAGGREGATION:
1302 return "DSERR_NOAGGREGATION";
1305 case DSERR_NODRIVER:
1306 return "DSERR_NODRIVER";
1309 case DSERR_OUTOFMEMORY:
1310 return "DSERR_OUTOFMEMORY";
1313 case DSERR_OTHERAPPHASPRIO:
1314 return "DSERR_OTHERAPPHASPRIO";
1317 case DSERR_PRIOLEVELNEEDED:
1318 return "DSERR_PRIOLEVELNEEDED";
1321 case DSERR_UNINITIALIZED:
1322 return "DSERR_UNINITIALIZED";
1325 case DSERR_UNSUPPORTED:
1326 return "DSERR_UNSUPPORTED";
1336 // ---------------------------------------------------------------------------------------
1337 // ds_close_channel()
1339 // Free a single channel
1341 void ds_close_channel(int i)
1345 // If a 3D interface exists, free it
1346 if ( Channels[i].pds3db != NULL ) {
1349 Channels[i].pds3db = NULL;
1352 while(++attempts < 10) {
1353 hr = Channels[i].pds3db->Release();
1354 if ( hr == DS_OK ) {
1357 // nprintf(("Sound", "SOUND ==> Channels[channel].pds3db->Release() failed with return value %s\n", get_DSERR_text(second_hr) ));
1361 Channels[i].pds3db = NULL;
1365 if ( Channels[i].pdsb != NULL ) {
1366 // If a 2D interface exists, free it
1367 if ( Channels[i].pdsb != NULL ) {
1369 while(++attempts < 10) {
1370 hr = Channels[i].pdsb->Release();
1371 if ( hr == DS_OK ) {
1374 nprintf(("Sound", "SOUND ==> Channels[channel].pdsb->Release() failed with return value %s\n", get_DSERR_text(hr) ));
1379 Channels[i].pdsb = NULL;
1385 // ---------------------------------------------------------------------------------------
1386 // ds_close_all_channels()
1388 // Free all the channel buffers
1390 void ds_close_all_channels()
1394 for (i = 0; i < MAX_CHANNELS; i++) {
1395 ds_close_channel(i);
1399 // ---------------------------------------------------------------------------------------
1400 // ds_unload_buffer()
1403 void ds_unload_buffer(int sid, int hid)
1408 if ( ds_software_buffers[sid].pdsb != NULL ) {
1409 hr = ds_software_buffers[sid].pdsb->Release();
1410 if ( hr != DS_OK ) {
1412 nprintf(("Sound", "SOUND ==> ds_software_buffers[sid]->Release() failed with return value %s\n", get_DSERR_text(hr) ));
1414 ds_software_buffers[sid].pdsb = NULL;
1419 if ( ds_hardware_buffers[hid].pdsb != NULL ) {
1420 hr = ds_hardware_buffers[hid].pdsb->Release();
1421 if ( hr != DS_OK ) {
1423 nprintf(("Sound", "SOUND ==> ds_hardware_buffers[hid]->Release() failed with return value %s\n", get_DSERR_text(hr) ));
1425 ds_hardware_buffers[hid].pdsb = NULL;
1430 // ---------------------------------------------------------------------------------------
1431 // ds_close_software_buffers()
1434 void ds_close_software_buffers()
1439 for (i = 0; i < MAX_DS_SOFTWARE_BUFFERS; i++) {
1440 if ( ds_software_buffers[i].pdsb != NULL ) {
1441 hr = ds_software_buffers[i].pdsb->Release();
1442 if ( hr != DS_OK ) {
1444 nprintf(("Sound", "SOUND ==> ds_software_buffers[i]->Release() failed with return value %s\n", get_DSERR_text(hr) ));
1446 ds_software_buffers[i].pdsb = NULL;
1451 // ---------------------------------------------------------------------------------------
1452 // ds_close_hardware_buffers()
1455 void ds_close_hardware_buffers()
1460 for (i = 0; i < MAX_DS_HARDWARE_BUFFERS; i++) {
1461 if ( ds_hardware_buffers[i].pdsb != NULL ) {
1462 hr = ds_hardware_buffers[i].pdsb->Release();
1463 if ( hr != DS_OK ) {
1465 nprintf(("Sound", "SOUND ==> ds_hardware_buffers[i]->Release() failed with return value %s\n", get_DSERR_text(hr) ));
1467 ds_hardware_buffers[i].pdsb = NULL;
1472 // ---------------------------------------------------------------------------------------
1473 // ds_close_buffers()
1475 // Free the channel buffers
1477 void ds_close_buffers()
1479 ds_close_software_buffers();
1480 ds_close_hardware_buffers();
1483 // ---------------------------------------------------------------------------------------
1486 // Close the DirectSound system
1490 ds_close_all_channels();
1493 if (pPropertySet != NULL) {
1494 pPropertySet->Release();
1495 pPropertySet = NULL;
1498 if (Ds_property_set_pdsb != NULL) {
1499 Ds_property_set_pdsb->Release();
1500 Ds_property_set_pdsb = NULL;
1503 if (Ds_property_set_pds3db != NULL) {
1504 Ds_property_set_pds3db->Release();
1505 Ds_property_set_pds3db = NULL;
1508 if (pPrimaryBuffer) {
1509 pPrimaryBuffer->Release();
1510 pPrimaryBuffer = NULL;
1519 pDirectSound->Release();
1520 pDirectSound = NULL;
1523 if ( Ds_dll_loaded ) {
1524 FreeLibrary(Ds_dll_handle);
1528 if (Ds_must_call_couninitialize == 1) {
1532 // free the Channels[] array, since it was dynamically allocated
1537 // ---------------------------------------------------------------------------------------
1538 // ds_get_3d_interface()
1540 // Get the 3d interface for a secondary buffer.
1542 // If the secondary buffer wasn't created with a DSBCAPS_CTRL3D flag, then no 3d interface
1545 void ds_get_3d_interface(LPDIRECTSOUNDBUFFER pdsb, LPDIRECTSOUND3DBUFFER *ppds3db)
1550 dsbc.dwSize = sizeof(dsbc);
1551 DSResult = pdsb->GetCaps(&dsbc);
1552 if ( DSResult == DS_OK && dsbc.dwFlags & DSBCAPS_CTRL3D ) {
1553 DSResult = pdsb->QueryInterface( IID_IDirectSound3DBuffer, (void**)ppds3db );
1554 if ( DSResult != DS_OK ) {
1555 nprintf(("SOUND","Could not obtain 3D interface for hardware buffer: %s\n", get_DSERR_text(DSResult) ));
1561 // ---------------------------------------------------------------------------------------
1562 // ds_get_free_channel()
1564 // Find a free channel to play a sound on. If no free channels exists, free up one based
1565 // on volume levels.
1567 // input: new_volume => volume in DS units for sound to play at
1568 // snd_id => which kind of sound to play
1569 // priority => DS_MUST_PLAY
1574 // returns: channel number to play sound on
1575 // -1 if no channel could be found
1577 // NOTE: snd_id is needed since we limit the number of concurrent samples
1580 #define DS_MAX_SOUND_INSTANCES 2
1582 int ds_get_free_channel(int new_volume, int snd_id, int priority)
1584 int i, first_free_channel, limit;
1585 int lowest_vol = 0, lowest_vol_index = -1;
1586 int instance_count; // number of instances of sound already playing
1587 int lowest_instance_vol, lowest_instance_vol_index;
1588 unsigned long status;
1593 lowest_instance_vol = 99;
1594 lowest_instance_vol_index = -1;
1595 first_free_channel = -1;
1597 // Look for a channel to use to play this sample
1598 for ( i = 0; i < MAX_CHANNELS; i++ ) {
1600 if ( chp->pdsb == NULL ) {
1601 if ( first_free_channel == -1 )
1602 first_free_channel = i;
1606 hr = chp->pdsb->GetStatus(&status);
1607 if ( hr != DS_OK ) {
1608 nprintf(("Sound", "SOUND ==> GetStatus failed with return value %s\n", get_DSERR_text(hr) ));
1611 if ( !(status & DSBSTATUS_PLAYING) ) {
1612 if ( first_free_channel == -1 )
1613 first_free_channel = i;
1614 ds_close_channel(i);
1618 if ( chp->snd_id == snd_id ) {
1620 if ( chp->vol < lowest_instance_vol && chp->looping == FALSE ) {
1621 lowest_instance_vol = chp->vol;
1622 lowest_instance_vol_index = i;
1626 if ( chp->vol < lowest_vol && chp->looping == FALSE ) {
1627 lowest_vol_index = i;
1628 lowest_vol = chp->vol;
1633 // determine the limit of concurrent instances of this sound
1644 case DS_LIMIT_THREE:
1654 // If we've exceeded the limit, then maybe stop the duplicate if it is lower volume
1655 if ( instance_count >= limit ) {
1656 // If there is a lower volume duplicate, stop it.... otherwise, don't play the sound
1657 if ( lowest_instance_vol_index >= 0 && (Channels[lowest_instance_vol_index].vol <= new_volume) ) {
1658 ds_close_channel(lowest_instance_vol_index);
1659 first_free_channel = lowest_instance_vol_index;
1661 first_free_channel = -1;
1664 // there is no limit barrier to play the sound, so see if we've ran out of channels
1665 if ( first_free_channel == -1 ) {
1666 // stop the lowest volume instance to play our sound if priority demands it
1667 if ( lowest_vol_index != -1 && priority == DS_MUST_PLAY ) {
1668 // Check if the lowest volume playing is less than the volume of the requested sound.
1669 // If so, then we are going to trash the lowest volume sound.
1670 if ( Channels[lowest_vol_index].vol <= new_volume ) {
1671 ds_close_channel(lowest_vol_index);
1672 first_free_channel = lowest_vol_index;
1678 return first_free_channel;
1682 // ---------------------------------------------------------------------------------------
1685 // Find a free channel to play a sound on. If no free channels exists, free up one based
1686 // on volume levels.
1688 // returns: 0 => dup was successful
1689 // -1 => dup failed (Channels[channel].pdsb will be NULL)
1691 int ds_channel_dup(LPDIRECTSOUNDBUFFER pdsb, int channel, int use_ds3d)
1695 // Duplicate the master buffer into a channel buffer.
1696 DSResult = pDirectSound->DuplicateSoundBuffer(pdsb, &Channels[channel].pdsb );
1697 if ( DSResult != DS_OK ) {
1698 nprintf(("Sound", "SOUND ==> DuplicateSoundBuffer failed with return value %s\n", get_DSERR_text(DSResult) ));
1699 Channels[channel].pdsb = NULL;
1703 // get the 3d interface for the buffer if it exists
1705 if (Channels[channel].pds3db == NULL) {
1706 ds_get_3d_interface(Channels[channel].pdsb, &Channels[channel].pds3db);
1714 // ---------------------------------------------------------------------------------------
1715 // ds_restore_buffer()
1718 void ds_restore_buffer(LPDIRECTSOUNDBUFFER pdsb)
1722 Int3(); // get Alan, he wants to see this
1723 hr = pdsb->Restore();
1724 if ( hr != DS_OK ) {
1725 nprintf(("Sound", "Sound ==> Lost a buffer, tried restoring but got %s\n", get_DSERR_text(hr) ));
1729 // Create a direct sound buffer in software, without locking any data in
1730 int ds_create_buffer(int frequency, int bits_per_sample, int nchannels, int nseconds)
1737 if (!ds_initialized) {
1743 nprintf(("Sound","SOUND ==> No more software secondary buffers available\n"));
1747 // Set up buffer format
1748 wfx.wFormatTag = WAVE_FORMAT_PCM;
1749 wfx.nChannels = (unsigned short)nchannels;
1750 wfx.nSamplesPerSec = frequency;
1751 wfx.wBitsPerSample = (unsigned short)bits_per_sample;
1753 wfx.nBlockAlign = (unsigned short)(wfx.nChannels * (wfx.wBitsPerSample / 8));
1754 wfx.nAvgBytesPerSec = wfx.nBlockAlign * wfx.nSamplesPerSec;
1756 memset(&dsbd, 0, sizeof(DSBUFFERDESC));
1757 dsbd.dwSize = sizeof(DSBUFFERDESC);
1758 dsbd.dwBufferBytes = wfx.nAvgBytesPerSec * nseconds;
1759 dsbd.lpwfxFormat = &wfx;
1760 dsbd.dwFlags = DSBCAPS_STATIC | DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRLDEFAULT | DSBCAPS_LOCSOFTWARE;
1762 dsrval = pDirectSound->CreateSoundBuffer(&dsbd, &ds_software_buffers[sid].pdsb, NULL);
1763 if ( dsrval != DS_OK ) {
1767 ds_software_buffers[sid].desc = dsbd;
1771 // Lock data into an existing buffer
1772 int ds_lock_data(int sid, unsigned char *data, int size)
1775 LPDIRECTSOUNDBUFFER pdsb;
1777 void *buffer_data, *buffer_data2;
1778 DWORD buffer_size, buffer_size2;
1781 pdsb = ds_software_buffers[sid].pdsb;
1783 memset(&caps, 0, sizeof(DSBCAPS));
1784 caps.dwSize = sizeof(DSBCAPS);
1785 dsrval = pdsb->GetCaps(&caps);
1786 if ( dsrval != DS_OK ) {
1790 pdsb->SetCurrentPosition(0);
1792 // lock the entire buffer
1793 dsrval = pdsb->Lock(0, caps.dwBufferBytes, &buffer_data, &buffer_size, &buffer_data2, &buffer_size2, 0 );
1794 if ( dsrval != DS_OK ) {
1798 // first clear it out with silence
1799 memset(buffer_data, 0x80, buffer_size);
1800 memcpy(buffer_data, data, size);
1802 dsrval = pdsb->Unlock(buffer_data, buffer_size, 0, 0);
1803 if ( dsrval != DS_OK ) {
1810 // Stop a buffer from playing directly
1811 void ds_stop_easy(int sid)
1814 LPDIRECTSOUNDBUFFER pdsb;
1817 pdsb = ds_software_buffers[sid].pdsb;
1818 dsrval = pdsb->Stop();
1821 // Play a sound without the usual baggage (used for playing back real-time voice)
1824 // sid => software id of sound
1825 // volume => volume of sound effect in DirectSound units
1826 int ds_play_easy(int sid, int volume)
1829 LPDIRECTSOUNDBUFFER pdsb;
1832 pdsb = ds_software_buffers[sid].pdsb;
1834 pdsb->SetVolume(volume);
1835 dsrval=pdsb->Play(0, 0, 0);
1836 if ( dsrval != DS_OK ) {
1843 //extern void HUD_add_to_scrollback(char *text, int source);
1844 //extern void HUD_printf(char *format, ...);
1846 // ---------------------------------------------------------------------------------------
1847 // Play a DirectSound secondary buffer.
1851 // sid => software id of sound
1852 // hid => hardware id of sound ( -1 if not in hardware )
1853 // snd_id => what kind of sound this is
1854 // priority => DS_MUST_PLAY
1858 // volume => volume of sound effect in DirectSound units
1859 // pan => pan of sound in DirectSound units
1860 // looping => whether the sound effect is looping or not
1862 // returns: -1 => sound effect could not be started
1863 // >=0 => sig for sound effect successfully started
1865 int ds_play(int sid, int hid, int snd_id, int priority, int volume, int pan, int looping, bool is_voice_msg)
1870 if (!ds_initialized)
1873 channel = ds_get_free_channel(volume, snd_id, priority);
1876 if ( Channels[channel].pdsb != NULL ) {
1880 // First check if the sound is in hardware, and try to duplicate from there
1883 if ( ds_channel_dup(ds_hardware_buffers[hid].pdsb, channel, 0) == 0 ) {
1884 // nprintf(("Sound", "SOUND ==> Played sound in hardware..\n"));
1888 // Channel will be NULL if hardware dup failed, or there was no hardware dup attempted
1889 if ( Channels[channel].pdsb == NULL ) {
1890 if ( ds_channel_dup(ds_software_buffers[sid].pdsb, channel, 0) == 0 ) {
1891 // nprintf(("Sound", "SOUND ==> Played sound in software..\n"));
1895 if ( Channels[channel].pdsb == NULL ) {
1899 if ( ds_using_ds3d() ) {
1900 if ( ds_is_3d_buffer(Channels[channel].pdsb) ) {
1901 if (Channels[channel].pds3db == NULL) {
1902 ds_get_3d_interface(Channels[channel].pdsb, &Channels[channel].pds3db);
1904 if ( Channels[channel].pds3db ) {
1905 Channels[channel].pds3db->SetMode(DS3DMODE_DISABLE,DS3D_IMMEDIATE);
1911 Channels[channel].vol = volume;
1912 Channels[channel].looping = looping;
1913 Channels[channel].priority = priority;
1914 Channels[channel].pdsb->SetPan(pan);
1915 Channels[channel].pdsb->SetVolume(volume);
1916 Channels[channel].is_voice_msg = is_voice_msg;
1920 ds_flags |= DSBPLAY_LOOPING;
1922 DSResult = Channels[channel].pdsb->Play(0, 0, ds_flags );
1925 if (Stop_logging_sounds == false) {
1927 sprintf(buf, "channel %d, address: %x, ds_flags: %d", channel, Channels[channel].pdsb, ds_flags);
1928 HUD_add_to_scrollback(buf, 3);
1932 if ( DSResult == DSERR_BUFFERLOST ) {
1933 ds_restore_buffer(Channels[channel].pdsb);
1934 DSResult = Channels[channel].pdsb->Play(0, 0, ds_flags );
1937 if ( DSResult != DS_OK ) {
1938 nprintf(("Sound", "Sound ==> Play failed with return value %s\n", get_DSERR_text(DSResult) ));
1943 // nprintf(( "Sound", "SOUND ==> Not playing sound requested at volume %.2f\n", ds_get_percentage_vol(volume) ));
1947 Channels[channel].snd_id = snd_id;
1948 Channels[channel].sig = channel_next_sig++;
1949 if (channel_next_sig < 0 ) {
1950 channel_next_sig = 1;
1954 if (Stop_logging_sounds == false) {
1957 sprintf(buf, "VOICE sig: %d, sid: %d, snd_id: %d, ch: %d", Channels[channel].sig, sid, snd_id, channel);
1958 HUD_add_to_scrollback(buf, 3);
1963 Channels[channel].last_position = 0;
1965 // make sure there aren't any looping voice messages
1966 for (int i=0; i<MAX_CHANNELS; i++) {
1967 if (Channels[i].is_voice_msg == true) {
1968 if (Channels[i].pdsb == NULL) {
1972 DWORD current_position = ds_get_play_position(i);
1973 if (current_position != 0) {
1974 if (current_position < Channels[i].last_position) {
1975 ds_close_channel(i);
1977 Channels[i].last_position = current_position;
1983 return Channels[channel].sig;
1987 // ---------------------------------------------------------------------------------------
1990 // Return the channel number that is playing the sound identified by sig. If that sound is
1991 // not playing, return -1.
1993 int ds_get_channel(int sig)
1997 for ( i = 0; i < MAX_CHANNELS; i++ ) {
1998 if ( Channels[i].pdsb && Channels[i].sig == sig ) {
1999 if ( ds_is_channel_playing(i) == TRUE ) {
2007 // ---------------------------------------------------------------------------------------
2008 // ds_is_channel_playing()
2011 int ds_is_channel_playing(int channel)
2014 unsigned long status;
2016 if ( !Channels[channel].pdsb ) {
2020 hr = Channels[channel].pdsb->GetStatus(&status);
2021 if ( hr != DS_OK ) {
2022 nprintf(("Sound", "SOUND ==> GetStatus failed with return value %s\n", get_DSERR_text(hr) ));
2026 if ( status & DSBSTATUS_PLAYING )
2032 // ---------------------------------------------------------------------------------------
2033 // ds_stop_channel()
2036 void ds_stop_channel(int channel)
2038 ds_close_channel(channel);
2041 // ---------------------------------------------------------------------------------------
2042 // ds_stop_channel_all()
2045 void ds_stop_channel_all()
2049 for ( i=0; i<MAX_CHANNELS; i++ ) {
2050 if ( Channels[i].pdsb != NULL ) {
2056 // ---------------------------------------------------------------------------------------
2059 // Set the volume for a channel. The volume is expected to be in DirectSound units
2061 // If the sound is a 3D sound buffer, this is like re-establishing the maximum
2064 void ds_set_volume( int channel, int vol )
2067 unsigned long status;
2069 hr = Channels[channel].pdsb->GetStatus(&status);
2070 if ( hr != DS_OK ) {
2071 nprintf(("Sound", "SOUND ==> GetStatus failed with return value %s\n", get_DSERR_text(hr) ));
2075 if ( status & DSBSTATUS_PLAYING ) {
2076 Channels[channel].pdsb->SetVolume(vol);
2080 // ---------------------------------------------------------------------------------------
2083 // Set the pan for a channel. The pan is expected to be in DirectSound units
2085 void ds_set_pan( int channel, int pan )
2088 unsigned long status;
2090 hr = Channels[channel].pdsb->GetStatus(&status);
2091 if ( hr != DS_OK ) {
2092 nprintf(("Sound", "SOUND ==> GetStatus failed with return value %s\n", get_DSERR_text(hr) ));
2096 if ( status & DSBSTATUS_PLAYING ) {
2097 Channels[channel].pdsb->SetPan(pan);
2101 // ---------------------------------------------------------------------------------------
2104 // Get the pitch of a channel
2106 int ds_get_pitch(int channel)
2108 unsigned long status, pitch = 0;
2111 hr = Channels[channel].pdsb->GetStatus(&status);
2113 if ( hr != DS_OK ) {
2114 nprintf(("Sound", "SOUND ==> GetStatus failed with return value %s\n", get_DSERR_text(hr) ));
2118 if ( status & DSBSTATUS_PLAYING ) {
2119 hr = Channels[channel].pdsb->GetFrequency(&pitch);
2120 if ( hr != DS_OK ) {
2121 nprintf(("Sound", "SOUND ==> GetFrequency failed with return value %s\n", get_DSERR_text(hr) ));
2129 // ---------------------------------------------------------------------------------------
2132 // Set the pitch of a channel
2134 void ds_set_pitch(int channel, int pitch)
2136 unsigned long status;
2139 hr = Channels[channel].pdsb->GetStatus(&status);
2140 if ( hr != DS_OK ) {
2141 nprintf(("Sound", "SOUND ==> GetStatus failed with return value %s\n", get_DSERR_text(hr) ));
2145 if ( pitch < MIN_PITCH )
2148 if ( pitch > MAX_PITCH )
2151 if ( status & DSBSTATUS_PLAYING ) {
2152 Channels[channel].pdsb->SetFrequency((unsigned long)pitch);
2156 // ---------------------------------------------------------------------------------------
2157 // ds_chg_loop_status()
2160 void ds_chg_loop_status(int channel, int loop)
2162 unsigned long status;
2165 hr = Channels[channel].pdsb->GetStatus(&status);
2166 if ( hr != DS_OK ) {
2167 nprintf(("Sound", "SOUND ==> GetStatus failed with return value %s\n", get_DSERR_text(hr) ));
2171 if ( !(status & DSBSTATUS_PLAYING) )
2172 return; // sound is not playing anymore
2174 if ( status & DSBSTATUS_LOOPING ) {
2176 return; // we are already looping
2178 // stop the sound from looping
2179 hr = Channels[channel].pdsb->Play(0,0,0);
2184 return; // the sound is already not looping
2186 // start the sound looping
2187 hr = Channels[channel].pdsb->Play(0,0,DSBPLAY_LOOPING);
2192 // ---------------------------------------------------------------------------------------
2195 // Starts a ds3d sound playing
2199 // sid => software id for sound to play
2200 // hid => hardware id for sound to play (-1 if not in hardware)
2201 // snd_id => identifies what type of sound is playing
2202 // pos => world pos of sound
2203 // vel => velocity of object emitting sound
2204 // min => distance at which sound doesn't get any louder
2205 // max => distance at which sound becomes inaudible
2206 // looping => boolean, whether to loop the sound or not
2207 // max_volume => volume (-10000 to 0) for 3d sound at maximum
2208 // estimated_vol => manual estimated volume
2209 // priority => DS_MUST_PLAY
2214 // returns: 0 => sound started successfully
2215 // -1 => sound could not be played
2217 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 )
2222 if (!ds_initialized)
2225 channel = ds_get_free_channel(estimated_vol, snd_id, priority);
2228 Assert(Channels[channel].pdsb == NULL);
2230 // First check if the sound is in hardware, and try to duplicate from there
2233 if ( ds_is_3d_buffer(ds_hardware_buffers[hid].pdsb) == FALSE ) {
2234 nprintf(("Sound", "SOUND ==> Tried to play non-3d buffer in ds3d_play()..\n"));
2238 if ( ds_channel_dup(ds_hardware_buffers[hid].pdsb, channel, 1) == 0 ) {
2239 nprintf(("Sound", "SOUND ==> Played sound using DirectSound3D in hardware..\n"));
2243 // Channel will be NULL if hardware dup failed, or there was no hardware dup attempted
2244 if ( Channels[channel].pdsb == NULL ) {
2247 if ( ds_is_3d_buffer(ds_software_buffers[sid].pdsb) == FALSE ) {
2248 nprintf(("Sound", "SOUND ==> Tried to play non-3d buffer in ds3d_play()..\n"));
2253 if ( ds_channel_dup(ds_software_buffers[sid].pdsb, channel, 1) == 0 ) {
2254 // nprintf(("Sound", "SOUND ==> Played sound using DirectSound3D \n"));
2258 if ( Channels[channel].pdsb == NULL ) {
2263 desc = ds_software_buffers[sid].desc;
2264 desc.lpwfxFormat = &ds_software_buffers[sid].wfx;
2266 // duplicate buffer failed, so call CreateBuffer instead
2268 hr = pDirectSound->CreateSoundBuffer(&desc, &Channels[channel].pdsb, NULL );
2270 if ( (hr == DS_OK) && (Channels[channel].pdsb) ) {
2271 BYTE *pdest, *pdest2;
2273 DWORD src_ds_size, dest_ds_size, not_used;
2276 if ( ds_get_size(sid, &src_size) != 0 ) {
2278 Channels[channel].pdsb->Release();
2282 // lock the src buffer
2283 hr = ds_software_buffers[sid].pdsb->Lock(0, src_size, (void**)&psrc, &src_ds_size, (void**)&psrc2, ¬_used, 0);
2284 if ( hr != DS_OK ) {
2285 mprintf(("err: %s\n", get_DSERR_text(hr)));
2287 Channels[channel].pdsb->Release();
2291 if ( Channels[channel].pdsb->Lock(0, src_ds_size, (void**)(&pdest), &dest_ds_size, (void**)&pdest2, ¬_used, 0) == DS_OK) {
2292 memcpy(pdest, psrc, src_ds_size);
2293 Channels[channel].pdsb->Unlock(pdest, dest_ds_size, 0, 0);
2294 ds_get_3d_interface(Channels[channel].pdsb, &Channels[channel].pds3db);
2296 Channels[channel].pdsb->Release();
2303 Assert(Channels[channel].pds3db );
2304 Channels[channel].pds3db->SetMode(DS3DMODE_NORMAL,DS3D_IMMEDIATE);
2306 // set up 3D sound data here
2307 ds3d_update_buffer(channel, i2fl(min), i2fl(max), pos, vel);
2309 Channels[channel].vol = estimated_vol;
2310 Channels[channel].looping = looping;
2312 // sets the maximum "inner cone" volume
2313 Channels[channel].pdsb->SetVolume(max_volume);
2317 ds_flags |= DSBPLAY_LOOPING;
2320 hr = Channels[channel].pdsb->Play(0, 0, ds_flags );
2322 if ( hr == DSERR_BUFFERLOST ) {
2323 ds_restore_buffer(Channels[channel].pdsb);
2324 hr = Channels[channel].pdsb->Play(0, 0, ds_flags );
2327 if ( hr != DS_OK ) {
2328 nprintf(("Sound", "Sound ==> Play failed with return value %s\n", get_DSERR_text(hr) ));
2329 if ( Channels[channel].pdsb ) {
2331 while(++attempts < 10) {
2332 hr = Channels[channel].pdsb->Release();
2333 if ( hr == DS_OK ) {
2336 nprintf(("Sound","SOUND ==> DirectSound Release() failed with code %s\n.",get_DSERR_text(hr) ));
2340 Channels[channel].pdsb = NULL;
2346 nprintf(( "Sound", "SOUND ==> Not playing requested 3D sound\n"));
2350 Channels[channel].snd_id = snd_id;
2351 Channels[channel].sig = channel_next_sig++;
2352 if (channel_next_sig < 0 ) {
2353 channel_next_sig = 1;
2355 return Channels[channel].sig;
2358 void ds_set_position(int channel, DWORD offset)
2360 // set the position of the sound buffer
2361 Channels[channel].pdsb->SetCurrentPosition(offset);
2364 DWORD ds_get_play_position(int channel)
2367 if ( Channels[channel].pdsb ) {
2368 Channels[channel].pdsb->GetCurrentPosition((LPDWORD)&play,(LPDWORD)&write);
2376 DWORD ds_get_write_position(int channel)
2379 if ( Channels[channel].pdsb ) {
2380 Channels[channel].pdsb->GetCurrentPosition((LPDWORD)&play,(LPDWORD)&write);
2388 int ds_get_channel_size(int channel)
2394 if ( Channels[channel].pdsb ) {
2395 memset(&caps, 0, sizeof(DSBCAPS));
2396 caps.dwSize = sizeof(DSBCAPS);
2397 dsrval = Channels[channel].pdsb->GetCaps(&caps);
2398 if ( dsrval != DS_OK ) {
2401 size = caps.dwBufferBytes;
2409 // Returns the number of channels that are actually playing
2410 int ds_get_number_channels()
2415 for ( i = 0; i < MAX_CHANNELS; i++ ) {
2416 if ( Channels[i].pdsb ) {
2417 if ( ds_is_channel_playing(i) == TRUE ) {
2426 // retreive raw data from a sound buffer
2427 int ds_get_data(int sid, char *data)
2430 LPDIRECTSOUNDBUFFER pdsb;
2436 pdsb = ds_software_buffers[sid].pdsb;
2438 memset(&caps, 0, sizeof(DSBCAPS));
2439 caps.dwSize = sizeof(DSBCAPS);
2440 dsrval = pdsb->GetCaps(&caps);
2441 if ( dsrval != DS_OK ) {
2445 // lock the entire buffer
2446 dsrval = pdsb->Lock(0, caps.dwBufferBytes, &buffer_data, &buffer_size, 0, 0, 0);
2447 if ( dsrval != DS_OK ) {
2451 memcpy(data, buffer_data, buffer_size);
2453 dsrval = pdsb->Unlock(buffer_data, buffer_size, 0, 0);
2454 if ( dsrval != DS_OK ) {
2461 // return the size of the raw sound data
2462 int ds_get_size(int sid, int *size)
2465 LPDIRECTSOUNDBUFFER pdsb;
2469 pdsb = ds_software_buffers[sid].pdsb;
2471 memset(&caps, 0, sizeof(DSBCAPS));
2472 caps.dwSize = sizeof(DSBCAPS);
2473 dsrval = pdsb->GetCaps(&caps);
2474 if ( dsrval != DS_OK ) {
2478 *size = caps.dwBufferBytes;
2487 // Return the primary buffer interface. Note that we cast to a uint to avoid
2488 // having to include dsound.h (and thus windows.h) in ds.h.
2490 uint ds_get_primary_buffer_interface()
2492 return (uint)pPrimaryBuffer;
2495 // Return the DirectSound Interface.
2497 uint ds_get_dsound_interface()
2499 return (uint)pDirectSound;
2502 uint ds_get_property_set_interface()
2504 return (uint)pPropertySet;
2507 // --------------------
2509 // EAX Functions below
2511 // --------------------
2513 // Set the master volume for the reverb added to all sound sources.
2515 // volume: volume, range from 0 to 1.0
2517 // returns: 0 if the volume is set successfully, otherwise return -1
2519 int ds_eax_set_volume(float volume)
2523 if (Ds_eax_inited == 0) {
2527 Assert(Ds_eax_reverb);
2529 CAP(volume, 0.0f, 1.0f);
2531 hr = Ds_eax_reverb->Set(DSPROPSETID_EAX_ReverbProperties_Def, DSPROPERTY_EAX_VOLUME, NULL, 0, &volume, sizeof(float));
2532 if (SUCCEEDED(hr)) {
2539 // Set the decay time for the EAX environment (ie all sound sources)
2541 // seconds: decay time in seconds
2543 // returns: 0 if decay time is successfully set, otherwise return -1
2545 int ds_eax_set_decay_time(float seconds)
2549 if (Ds_eax_inited == 0) {
2553 Assert(Ds_eax_reverb);
2555 CAP(seconds, 0.1f, 20.0f);
2557 hr = Ds_eax_reverb->Set(DSPROPSETID_EAX_ReverbProperties_Def, DSPROPERTY_EAX_DECAYTIME, NULL, 0, &seconds, sizeof(float));
2558 if (SUCCEEDED(hr)) {
2565 // Set the damping value for the EAX environment (ie all sound sources)
2567 // damp: damp value from 0 to 2.0
2569 // returns: 0 if the damp value is successfully set, otherwise return -1
2571 int ds_eax_set_damping(float damp)
2575 if (Ds_eax_inited == 0) {
2579 Assert(Ds_eax_reverb);
2581 CAP(damp, 0.0f, 2.0f);
2583 hr = Ds_eax_reverb->Set(DSPROPSETID_EAX_ReverbProperties_Def, DSPROPERTY_EAX_DAMPING, NULL, 0, &damp, sizeof(float));
2584 if (SUCCEEDED(hr)) {
2591 // Set up the environment type for all sound sources.
2593 // envid: value from the EAX_ENVIRONMENT_* enumeration in ds_eax.h
2595 // returns: 0 if the environment is set successfully, otherwise return -1
2597 int ds_eax_set_environment(unsigned long envid)
2601 if (Ds_eax_inited == 0) {
2605 Assert(Ds_eax_reverb);
2607 hr = Ds_eax_reverb->Set(DSPROPSETID_EAX_ReverbProperties_Def, DSPROPERTY_EAX_ENVIRONMENT, NULL, 0, &envid, sizeof(unsigned long));
2608 if (SUCCEEDED(hr)) {
2615 // Set up a predefined environment for EAX
2617 // envid: value from teh EAX_ENVIRONMENT_* enumeration
2619 // returns: 0 if successful, otherwise return -1
2621 int ds_eax_set_preset(unsigned long envid)
2625 if (Ds_eax_inited == 0) {
2629 Assert(Ds_eax_reverb);
2630 Assert(envid < EAX_ENVIRONMENT_COUNT);
2632 hr = Ds_eax_reverb->Set(DSPROPSETID_EAX_ReverbProperties_Def, DSPROPERTY_EAX_ALL, NULL, 0, &Ds_eax_presets[envid], sizeof(EAX_REVERBPROPERTIES));
2633 if (SUCCEEDED(hr)) {
2641 // Set up all the parameters for an environment
2643 // id: value from teh EAX_ENVIRONMENT_* enumeration
2644 // volume: volume for the environment (0 to 1.0)
2645 // damping: damp value for the environment (0 to 2.0)
2646 // decay: decay time in seconds (0.1 to 20.0)
2648 // returns: 0 if successful, otherwise return -1
2650 int ds_eax_set_all(unsigned long id, float vol, float damping, float decay)
2654 if (Ds_eax_inited == 0) {
2658 Assert(Ds_eax_reverb);
2659 Assert(id < EAX_ENVIRONMENT_COUNT);
2661 EAX_REVERBPROPERTIES er;
2663 er.environment = id;
2665 er.fDecayTime_sec = decay;
2666 er.fDamping = damping;
2668 hr = Ds_eax_reverb->Set(DSPROPSETID_EAX_ReverbProperties_Def, DSPROPERTY_EAX_ALL, NULL, 0, &er, sizeof(EAX_REVERBPROPERTIES));
2669 if (SUCCEEDED(hr)) {
2676 // Get up the parameters for the current environment
2678 // er: (output) hold environment parameters
2680 // returns: 0 if successful, otherwise return -1
2682 int ds_eax_get_all(EAX_REVERBPROPERTIES *er)
2685 unsigned long outsize;
2687 if (Ds_eax_inited == 0) {
2691 Assert(Ds_eax_reverb);
2693 hr = Ds_eax_reverb->Get(DSPROPSETID_EAX_ReverbProperties_Def, DSPROPERTY_EAX_ALL, NULL, 0, er, sizeof(EAX_REVERBPROPERTIES), &outsize);
2694 if (SUCCEEDED(hr)) {
2702 // Close down EAX, freeing any allocated resources
2706 if (Ds_eax_inited == 0) {
2715 // returns: 0 if initialization is successful, otherwise return -1
2720 unsigned long driver_support = 0;
2722 if (Ds_eax_inited) {
2726 Assert(Ds_eax_reverb == NULL);
2728 Ds_eax_reverb = (LPKSPROPERTYSET)ds_get_property_set_interface();
2729 if (Ds_eax_reverb == NULL) {
2733 // check if the listener property is supported by the audio driver
2734 hr = Ds_eax_reverb->QuerySupport(DSPROPSETID_EAX_ReverbProperties_Def, DSPROPERTY_EAX_ALL, &driver_support);
2736 nprintf(("Sound", "QuerySupport for the EAX Listener property set failed.. disabling EAX\n"));
2737 goto ds_eax_init_failed;
2740 if ((driver_support & (KSPROPERTY_SUPPORT_GET | KSPROPERTY_SUPPORT_SET)) != (KSPROPERTY_SUPPORT_GET | KSPROPERTY_SUPPORT_SET)) {
2741 goto ds_eax_init_failed;
2744 ds_eax_set_all(EAX_ENVIRONMENT_GENERIC, 0.0f, 0.0f, 0.0f);
2750 if (Ds_eax_reverb != NULL) {
2751 Ds_eax_reverb->Release();
2752 Ds_eax_reverb = NULL;
2760 int ds_eax_is_inited()
2762 return Ds_eax_inited;
2767 if (Ds_use_a3d == 0) {
2774 // Called once per game frame to make sure voice messages aren't looping
2780 for (int i=0; i<MAX_CHANNELS; i++) {
2782 if (cp->is_voice_msg == true) {
2783 if (cp->pdsb == NULL) {
2787 DWORD current_position = ds_get_play_position(i);
2788 if (current_position != 0) {
2789 if (current_position < cp->last_position) {
2790 ds_close_channel(i);
2792 cp->last_position = current_position;