2 * Copyright (C) Volition, Inc. 1999. All rights reserved.
4 * All source code herein is the property of Volition, Inc. You may not sell
5 * or otherwise commercially exploit the source or things you created based on
10 * $Logfile: /Freespace2/code/Sound/ds.cpp $
15 * C file for interface to DirectSound
18 * Revision 1.20 2005/03/29 07:50:34 taylor
19 * Update to newest movie code with much better video support and audio support from
20 * Pierre Willenbrock. Movies are enabled always now (no longer a build option)
21 * and but can be skipped with the "--nomovies" or "-n" cmdline options.
23 * Revision 1.19 2004/07/04 11:39:06 taylor
24 * fix missing debrief text, crash on exit, path separator's, warning fixes, no GR_SOFT
26 * Revision 1.18 2004/06/11 02:07:01 tigital
27 * byte-swapping changes for bigendian systems
29 * Revision 1.17 2003/12/02 03:24:47 taylor
30 * MS-ADPCM support, fix file parser with OSX support
32 * Revision 1.16 2003/08/03 16:03:53 taylor
33 * working play position; 2D pan; pitch; cleanup
35 * Revision 1.15 2003/03/15 05:12:56 theoddone33
36 * Fix OpenAL cleanup (Taylor)
38 * Revision 1.14 2002/08/01 04:55:45 relnev
39 * experimenting with texture state
41 * Revision 1.13 2002/07/30 05:24:38 relnev
44 * Revision 1.12 2002/07/28 05:19:44 relnev
47 * Revision 1.11 2002/06/16 01:43:23 relnev
48 * fixed demo dogfight multiplayer mission
52 * Revision 1.10 2002/06/09 04:41:26 relnev
53 * added copyright header
55 * Revision 1.9 2002/06/05 08:05:29 relnev
56 * stub/warning removal.
58 * reworked the sound code.
60 * Revision 1.8 2002/06/05 04:03:33 relnev
61 * finished cfilesystem.
63 * removed some old code.
65 * fixed mouse save off-by-one.
69 * Revision 1.7 2002/06/02 22:31:37 cemason
72 * Revision 1.6 2002/06/02 21:11:12 cemason
75 * Revision 1.5 2002/06/02 09:50:42 relnev
78 * Revision 1.4 2002/06/02 07:17:44 cemason
79 * Added OpenAL support.
81 * Revision 1.3 2002/05/28 17:03:29 theoddone33
82 * fs2 gets to the main game loop now
84 * Revision 1.2 2002/05/27 21:35:50 theoddone33
85 * Stub out dsound backend
87 * Revision 1.1.1.1 2002/05/03 03:28:10 root
91 * 18 10/25/99 5:56p Jefff
92 * increase num software channels to the number the users hardware can
93 * handle. not less than 16, tho.
95 * 17 9/08/99 3:22p Dave
96 * Updated builtin mission list.
98 * 16 8/27/99 6:38p Alanl
99 * crush the blasted repeating messages bug
101 * 15 8/23/99 11:16p Danw
104 * 14 8/22/99 11:06p Alanl
105 * fix small bug in ds_close_channel
107 * 13 8/19/99 11:25a Alanl
108 * change format of secondary buffer from 44100 to 22050
110 * 12 8/17/99 4:11p Danw
111 * AL: temp fix for solving A3D crash
113 * 11 8/06/99 2:20p Jasonh
114 * AL: free 3D portion of buffer first
116 * 10 8/04/99 9:48p Alanl
117 * fix bug with setting 3D properties on a 2D sound buffer
119 * 9 8/04/99 11:42a Danw
120 * tone down EAX reverb
122 * 8 8/01/99 2:06p Alanl
123 * increase the rolloff for A3D
125 * 7 7/20/99 5:28p Dave
126 * Fixed debug build error.
128 * 6 7/20/99 1:49p Dave
129 * Peter Drake build. Fixed some release build warnings.
131 * 5 7/14/99 11:32a Danw
132 * AL: add some debug code to catch nefarious A3D problem
134 * 4 5/23/99 8:11p Alanl
135 * Added support for EAX
137 * 3 10/08/98 4:29p Dave
138 * Removed reference to osdefs.h
140 * 2 10/07/98 10:54a Dave
143 * 1 10/07/98 10:51a Dave
145 * 72 6/28/98 6:34p Lawrance
146 * add sanity check in while() loop for releasing channels
148 * 71 6/13/98 1:45p Sandeep
150 * 70 6/10/98 2:29p Lawrance
151 * don't use COM for initializing DirectSound... appears some machines
154 * 69 5/26/98 2:10a Lawrance
155 * make sure DirectSound pointer gets freed if Aureal resource manager
158 * 68 5/21/98 9:14p Lawrance
159 * remove obsolete registry setting
161 * 67 5/20/98 4:28p Allender
162 * upped sound buffers as per alan's request
164 * 66 5/15/98 3:36p John
165 * Fixed bug with new graphics window code and standalone server. Made
166 * hwndApp not be a global anymore.
168 * 65 5/06/98 3:37p Lawrance
169 * allow panned sounds geesh
171 * 64 5/05/98 4:49p Lawrance
172 * Put in code to authenticate A3D, improve A3D support
174 * 63 4/20/98 11:17p Lawrance
175 * fix bug with releasing channels
177 * 62 4/20/98 7:34p Lawrance
178 * take out obsolete directsound3d debug command
180 * 61 4/20/98 11:10a Lawrance
181 * put correct flags when creating sound buffer
183 * 60 4/20/98 12:03a Lawrance
184 * Allow prioritizing of CTRL3D buffers
186 * 59 4/19/98 9:31p Lawrance
187 * Use Aureal_enabled flag
189 * 58 4/19/98 9:39a Lawrance
190 * use DYNAMIC_LOOPERS for Aureal resource manager
192 * 57 4/19/98 4:13a Lawrance
193 * Improve how dsound is initialized
195 * 56 4/18/98 9:13p Lawrance
196 * Added Aureal support.
198 * 55 4/13/98 5:04p Lawrance
199 * Write functions to determine how many milliseconds are left in a sound
201 * 54 4/09/98 5:53p Lawrance
202 * Make DirectSound init more robust
204 * 53 4/01/98 9:21p John
205 * Made NDEBUG, optimized build with no warnings or errors.
207 * 52 3/31/98 5:19p John
208 * Removed demo/save/restore. Made NDEBUG defined compile. Removed a
209 * bunch of debug stuff out of player file. Made model code be able to
210 * unload models and malloc out only however many models are needed.
213 * 51 3/29/98 12:56a Lawrance
214 * preload the warp in and explosions sounds before a mission.
216 * 50 3/25/98 6:10p Lawrance
217 * Work on DirectSound3D
219 * 49 3/24/98 4:28p Lawrance
220 * Make DirectSound3D support more robust
222 * 48 3/24/98 11:49a Dave
223 * AL: Change way buffer gets locked.
225 * 47 3/24/98 11:27a Lawrance
226 * Use buffer_size for memcpy when locking buffer
228 * 46 3/23/98 10:32a Lawrance
229 * Add functions for extracting raw sound data
231 * 45 3/19/98 5:36p Lawrance
232 * Add some sound debug functions to see how many sounds are playing, and
233 * to start/stop random looping sounds.
235 * 44 3/07/98 3:35p Dave
236 * AL: check for ds being initialized in ds_create_buffer()
238 * 43 2/18/98 5:49p Lawrance
239 * Even if the ADPCM codec is unavailable, allow game to continue.
241 * 42 2/16/98 7:31p Lawrance
242 * get compression/decompression of voice working
244 * 41 2/15/98 11:10p Lawrance
245 * more work on real-time voice system
247 * 40 2/15/98 4:43p Lawrance
248 * work on real-time voice
250 * 39 2/06/98 7:30p John
251 * Added code to monitor the number of channels of sound actually playing.
253 * 38 2/06/98 8:56a Allender
254 * fixed calling convention problem with DLL handles
256 * 37 2/04/98 6:08p Lawrance
257 * Read function pointers from dsound.dll, further work on
258 * DirectSoundCapture.
260 * 36 2/03/98 11:53p Lawrance
261 * Adding support for DirectSoundCapture
263 * 35 1/31/98 5:48p Lawrance
264 * Start on real-time voice recording
266 * 34 1/10/98 1:14p John
267 * Added explanation to debug console commands
269 * 33 12/21/97 4:33p John
270 * Made debug console functions a class that registers itself
271 * automatically, so you don't need to add the function to
272 * debugfunctions.cpp.
274 * 32 12/08/97 12:24a Lawrance
275 * Allow duplicate sounds to be stopped if less than OR equal to new sound
278 * 31 12/05/97 5:19p Lawrance
279 * re-do sound priorities to make more general and extensible
281 * 30 11/28/97 2:09p Lawrance
282 * Overhaul how ADPCM conversion works... use much less memory... safer
285 * 29 11/22/97 11:32p Lawrance
286 * decompress ADPCM data into 8 bit (not 16bit) for regular sounds (ie not
289 * 28 11/20/97 5:36p Dave
290 * Hooked in a bunch of main hall changes (including sound). Made it
291 * possible to reposition (rewind/ffwd)
292 * sound buffer pointers. Fixed animation direction change framerate
295 * 27 10/13/97 7:41p Lawrance
296 * store duration of sound
298 * 26 10/11/97 6:39p Lawrance
299 * start playing primary buffer, to reduce latency on sounds starting
301 * 25 10/08/97 5:09p Lawrance
302 * limit player impact sounds so only one plays at a time
304 * 24 9/26/97 5:43p Lawrance
305 * fix a bug that was freeing memory early when playing compressed sound
308 * 23 9/09/97 3:39p Sandeep
309 * warning level 4 bugs
311 * 22 8/16/97 4:05p Lawrance
312 * don't load sounds into hardware if running Lean_and_mean
314 * 21 8/05/97 1:39p Lawrance
315 * support compressed stereo playback
317 * 20 7/31/97 10:38a Lawrance
318 * return old debug function for toggling DirectSound3D
320 * 19 7/29/97 3:27p Lawrance
321 * make console toggle for directsound3d work right
323 * 18 7/28/97 11:39a Lawrance
324 * allow individual volume scaling on 3D buffers
326 * 17 7/18/97 8:18p Lawrance
327 * fix bug in ds_get_free_channel() that caused sounds to not play when
330 * 16 7/17/97 8:04p Lawrance
331 * allow priority sounds to play if free channel, otherwise stop lowest
332 * volume priority sound of same type
334 * 15 7/17/97 5:57p John
335 * made directsound3d config value work
337 * 14 7/17/97 5:43p John
338 * added new config stuff
340 * 13 7/17/97 4:25p John
341 * First, broken, stage of changing config stuff
343 * 12 7/15/97 12:13p Lawrance
344 * don't stop sounds that have highest priority
346 * 11 7/15/97 11:15a Lawrance
347 * limit the max instances of simultaneous sound effects, implement
348 * priorities to force critical sounds
350 * 10 6/09/97 11:50p Lawrance
351 * integrating DirectSound3D
353 * 9 6/08/97 5:59p Lawrance
354 * integrate DirectSound3D into sound system
356 * 8 6/04/97 1:19p Lawrance
357 * made hardware mixing robust
359 * 7 6/03/97 1:56p Hoffoss
360 * Return correct error code when direct sound init fails.
362 * 6 6/03/97 12:07p Lawrance
363 * don't enable 3D sounds in Primary buffer
365 * 5 6/02/97 3:45p Dan
366 * temp disable of hardware mixing until problem solved with
367 * CreateBuffer() failing
369 * 4 6/02/97 1:45p Lawrance
370 * implementing hardware mixing
372 * 3 5/29/97 4:01p Lawrance
373 * let snd_init() have final say on initialization
375 * 2 5/29/97 12:04p Lawrance
376 * creation of file to hold DirectSound specific portions
395 #include <initguid.h>
401 #include <SDL_audio.h>
406 #include <SDL/SDL_audio.h>
411 // Pointers to functions contained in DSOUND.dll
412 HRESULT (__stdcall *pfn_DirectSoundCreate)(LPGUID lpGuid, LPDIRECTSOUND *ppDS, IUnknown FAR *pUnkOuter) = NULL;
413 HRESULT (__stdcall *pfn_DirectSoundCaptureCreate)(LPGUID lpGUID, LPDIRECTSOUNDCAPTURE *lplpDSC, LPUNKNOWN pUnkOuter) = NULL;
415 HINSTANCE Ds_dll_handle=NULL;
417 LPDIRECTSOUND pDirectSound = NULL;
418 LPDIRECTSOUNDBUFFER pPrimaryBuffer = NULL;
419 LPIA3D2 pIA3d2 = NULL;
421 static LPKSPROPERTYSET pPropertySet; // pointer to sound card property set
422 static LPDIRECTSOUNDBUFFER Ds_property_set_pdsb = NULL;
423 static LPDIRECTSOUND3DBUFFER Ds_property_set_pds3db = NULL;
425 static int Ds_must_call_couninitialize = 0;
427 channel* Channels; //[MAX_CHANNELS];
428 static int channel_next_sig = 1;
430 #define MAX_DS_SOFTWARE_BUFFERS 256
431 typedef struct ds_sound_buffer
433 LPDIRECTSOUNDBUFFER pdsb;
439 ds_sound_buffer ds_software_buffers[MAX_DS_SOFTWARE_BUFFERS];
441 #define MAX_DS_HARDWARE_BUFFERS 32
442 ds_sound_buffer ds_hardware_buffers[MAX_DS_HARDWARE_BUFFERS];
444 static DSCAPS Soundcard_caps; // current soundcard capabilities
446 extern int Snd_sram; // mem (in bytes) used up by storing sounds in system memory
447 extern int Snd_hram; // mem (in bytes) used up by storing sounds in soundcard memory
449 static int Ds_use_ds3d = 0;
450 static int Ds_use_a3d = 0;
451 static int Ds_use_eax = 0;
453 GUID IID_IA3d2_Def = {0xfb80d1e0, 0x98d3, 0x11d1, {0x90, 0xfb, 0x00, 0x60, 0x08, 0xa1, 0xf4, 0x41}};
454 GUID CLSID_A3d_Def = {0xd8f1eee0, 0xf634, 0x11cf, {0x87, 0x0, 0x0, 0xa0, 0x24, 0x5d, 0x91, 0x8b}};
456 static bool Stop_logging_sounds = false;
459 ///////////////////////////
463 ///////////////////////////
466 //#define EAX_PRESET_GENERIC EAX_ENVIRONMENT_GENERIC,0.5F,1.493F,0.5F
467 #define EAX_PRESET_GENERIC EAX_ENVIRONMENT_GENERIC,0.2F,0.2F,1.0F
468 #define EAX_PRESET_PADDEDCELL EAX_ENVIRONMENT_PADDEDCELL,0.25F,0.1F,0.0F
469 #define EAX_PRESET_ROOM EAX_ENVIRONMENT_ROOM,0.417F,0.4F,0.666F
470 #define EAX_PRESET_BATHROOM EAX_ENVIRONMENT_BATHROOM,0.653F,1.499F,0.166F
471 #define EAX_PRESET_LIVINGROOM EAX_ENVIRONMENT_LIVINGROOM,0.208F,0.478F,0.0F
472 #define EAX_PRESET_STONEROOM EAX_ENVIRONMENT_STONEROOM,0.5F,2.309F,0.888F
473 #define EAX_PRESET_AUDITORIUM EAX_ENVIRONMENT_AUDITORIUM,0.403F,4.279F,0.5F
474 #define EAX_PRESET_CONCERTHALL EAX_ENVIRONMENT_CONCERTHALL,0.5F,3.961F,0.5F
475 #define EAX_PRESET_CAVE EAX_ENVIRONMENT_CAVE,0.5F,2.886F,1.304F
476 #define EAX_PRESET_ARENA EAX_ENVIRONMENT_ARENA,0.361F,7.284F,0.332F
477 #define EAX_PRESET_HANGAR EAX_ENVIRONMENT_HANGAR,0.5F,10.0F,0.3F
478 #define EAX_PRESET_CARPETEDHALLWAY EAX_ENVIRONMENT_CARPETEDHALLWAY,0.153F,0.259F,2.0F
479 #define EAX_PRESET_HALLWAY EAX_ENVIRONMENT_HALLWAY,0.361F,1.493F,0.0F
480 #define EAX_PRESET_STONECORRIDOR EAX_ENVIRONMENT_STONECORRIDOR,0.444F,2.697F,0.638F
481 #define EAX_PRESET_ALLEY EAX_ENVIRONMENT_ALLEY,0.25F,1.752F,0.776F
482 #define EAX_PRESET_FOREST EAX_ENVIRONMENT_FOREST,0.111F,3.145F,0.472F
483 #define EAX_PRESET_CITY EAX_ENVIRONMENT_CITY,0.111F,2.767F,0.224F
484 #define EAX_PRESET_MOUNTAINS EAX_ENVIRONMENT_MOUNTAINS,0.194F,7.841F,0.472F
485 #define EAX_PRESET_QUARRY EAX_ENVIRONMENT_QUARRY,1.0F,1.499F,0.5F
486 #define EAX_PRESET_PLAIN EAX_ENVIRONMENT_PLAIN,0.097F,2.767F,0.224F
487 #define EAX_PRESET_PARKINGLOT EAX_ENVIRONMENT_PARKINGLOT,0.208F,1.652F,1.5F
488 #define EAX_PRESET_SEWERPIPE EAX_ENVIRONMENT_SEWERPIPE,0.652F,2.886F,0.25F
489 #define EAX_PRESET_UNDERWATER EAX_ENVIRONMENT_UNDERWATER,1.0F,1.499F,0.0F
490 #define EAX_PRESET_DRUGGED EAX_ENVIRONMENT_DRUGGED,0.875F,8.392F,1.388F
491 #define EAX_PRESET_DIZZY EAX_ENVIRONMENT_DIZZY,0.139F,17.234F,0.666F
492 #define EAX_PRESET_PSYCHOTIC EAX_ENVIRONMENT_PSYCHOTIC,0.486F,7.563F,0.806F
494 static LPKSPROPERTYSET Ds_eax_reverb = NULL;
496 static int Ds_eax_inited = 0;
498 EAX_REVERBPROPERTIES Ds_eax_presets[] =
500 {EAX_PRESET_GENERIC},
501 {EAX_PRESET_PADDEDCELL},
503 {EAX_PRESET_BATHROOM},
504 {EAX_PRESET_LIVINGROOM},
505 {EAX_PRESET_STONEROOM},
506 {EAX_PRESET_AUDITORIUM},
507 {EAX_PRESET_CONCERTHALL},
511 {EAX_PRESET_CARPETEDHALLWAY},
512 {EAX_PRESET_HALLWAY},
513 {EAX_PRESET_STONECORRIDOR},
517 {EAX_PRESET_MOUNTAINS},
520 {EAX_PRESET_PARKINGLOT},
521 {EAX_PRESET_SEWERPIPE},
522 {EAX_PRESET_UNDERWATER},
523 {EAX_PRESET_DRUGGED},
525 {EAX_PRESET_PSYCHOTIC},
528 GUID DSPROPSETID_EAX_ReverbProperties_Def = {0x4a4e6fc1, 0xc341, 0x11d1, {0xb7, 0x3a, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}};
529 GUID DSPROPSETID_EAXBUFFER_ReverbProperties_Def = {0x4a4e6fc0, 0xc341, 0x11d1, {0xb7, 0x3a, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}};
531 //----------------------------------------------------------------
533 void ds_get_soundcard_caps(DSCAPS *dscaps);
536 typedef struct channel
538 int sig; // uniquely identifies the sound playing on the channel
539 int snd_id; // identifies which kind of sound is playing
540 ALuint source_id; // OpenAL source id
541 int buf_id; // currently bound buffer index (-1 if none)
542 int looping; // flag to indicate that the sound is looping
544 int priority; // implementation dependant priority
549 typedef struct sound_buffer
551 ALuint buf_id; // OpenAL buffer id
552 int source_id; // source index this buffer is currently bound to
561 #define MAX_DS_SOFTWARE_BUFFERS 256
563 static int MAX_CHANNELS = 1000; // initialized properly in ds_init_channels()
565 static int channel_next_sig = 1;
567 sound_buffer sound_buffers[MAX_DS_SOFTWARE_BUFFERS];
569 static int Ds_use_ds3d = 0;
570 static int Ds_use_a3d = 0;
571 static int Ds_use_eax = 0;
573 static int AL_play_position = 0;
576 // in case it's not defined by older/other drivers
577 #define AL_BYTE_LOKI 0x100C
580 ALCdevice *ds_sound_device;
581 void *ds_sound_context = (void *)0;
584 #define OpenAL_ErrorCheck() do { \
585 int i = alGetError(); \
586 if (i != AL_NO_ERROR) { \
587 while(i != AL_NO_ERROR) { \
588 nprintf(("Warning", "%s/%s:%d - OpenAL error %s\n", __FUNCTION__, __FILE__, __LINE__, alGetString(i))); \
595 #define OpenAL_ErrorCheck()
600 int ds_vol_lookup[101]; // lookup table for direct sound volumes
601 int ds_initialized = FALSE;
604 //--------------------------------------------------------------------------
607 // Determine if a secondary buffer is a 3d secondary buffer.
610 int ds_is_3d_buffer(LPDIRECTSOUNDBUFFER pdsb)
615 dsbc.dwSize = sizeof(dsbc);
616 hr = pdsb->GetCaps(&dsbc);
617 if ( hr == DS_OK && dsbc.dwFlags & DSBCAPS_CTRL3D ) {
626 //--------------------------------------------------------------------------
629 // Determine if a secondary buffer is a 3d secondary buffer.
631 int ds_is_3d_buffer(int sid)
635 return ds_is_3d_buffer(ds_software_buffers[sid].pdsb);
647 //--------------------------------------------------------------------------
648 // ds_build_vol_lookup()
650 // Fills up the ds_vol_lookup[] tables that converts from a volume in the form
651 // 0.0 -> 1.0 to -10000 -> 0 (this is the DirectSound method, where units are
652 // hundredths of decibls)
654 void ds_build_vol_lookup()
659 ds_vol_lookup[0] = -10000;
660 for ( i = 1; i <= 100; i++ ) {
662 ds_vol_lookup[i] = fl2i( (log(vol) / log(2.0f)) * 1000.0f);
667 //--------------------------------------------------------------------------
668 // ds_convert_volume()
670 // Takes volume between 0.0f and 1.0f and converts into
671 // DirectSound style volumes between -10000 and 0.
672 int ds_convert_volume(float volume)
676 index = fl2i(volume * 100.0f);
682 return ds_vol_lookup[index];
685 //--------------------------------------------------------------------------
686 // ds_get_percentage_vol()
688 // Converts -10000 -> 0 range volume to 0 -> 1
689 float ds_get_percentage_vol(int ds_vol)
692 vol = pow(2.0, ds_vol/1000.0);
696 // ---------------------------------------------------------------------------------------
699 // Parse a wave file.
701 // parameters: filename => file of sound to parse
702 // dest => address of pointer of where to store raw sound data (output parm)
703 // dest_size => number of bytes of sound data stored (output parm)
704 // header => address of pointer to a WAVEFORMATEX struct (output parm)
706 // returns: 0 => wave file successfully parsed
709 // NOTE: memory is malloced for the header and dest in this function. It is the responsibility
710 // of the caller to free this memory later.
712 int ds_parse_wave(char *filename, ubyte **dest, uint *dest_size, WAVEFORMATEX **header)
715 PCMWAVEFORMAT PCM_header;
717 unsigned int tag, size, next_chunk;
719 fp = cfopen( filename, "rb" );
721 nprintf(("Error", "Couldn't open '%s'\n", filename ));
725 // Skip the "RIFF" tag and file size (8 bytes)
726 // Skip the "WAVE" tag (4 bytes)
727 cfseek( fp, 12, CF_SEEK_SET );
729 // Now read RIFF tags until the end of file
732 if ( cfread( &tag, sizeof(uint), 1, fp ) != 1 )
734 tag = INTEL_INT( tag );
736 if ( cfread( &size, sizeof(uint), 1, fp ) != 1 )
738 size = INTEL_INT( size );
740 next_chunk = cftell(fp) + size;
743 case 0x20746d66: // The 'fmt ' tag
744 //nprintf(("Sound", "SOUND => size of fmt block: %d\n", size));
745 PCM_header.wf.wFormatTag = cfread_ushort(fp);
746 PCM_header.wf.nChannels = cfread_ushort(fp);
747 PCM_header.wf.nSamplesPerSec = cfread_uint(fp);
748 PCM_header.wf.nAvgBytesPerSec = cfread_uint(fp);
749 PCM_header.wf.nBlockAlign = cfread_ushort(fp);
750 PCM_header.wBitsPerSample = cfread_ushort(fp);
752 if ( PCM_header.wf.wFormatTag != WAVE_FORMAT_PCM ) {
753 cbExtra = cfread_ushort(fp);
756 // Allocate memory for WAVEFORMATEX structure + extra bytes
757 if ( (*header = (WAVEFORMATEX *) malloc ( sizeof(WAVEFORMATEX)+cbExtra )) != NULL ){
758 // Copy bytes from temporary format structure
759 memcpy (*header, &PCM_header, sizeof(PCM_header));
760 (*header)->cbSize = cbExtra;
762 // Read those extra bytes, append to WAVEFORMATEX structure
764 cfread( ((ubyte *)(*header) + sizeof(WAVEFORMATEX)), cbExtra, 1, fp);
768 Assert(0); // malloc failed
772 case 0x61746164: // the 'data' tag
774 (*dest) = (ubyte *)malloc(size);
775 Assert( *dest != NULL );
776 cfread( *dest, size, 1, fp );
778 default: // unknown, skip it
781 cfseek( fp, next_chunk, CF_SEEK_SET );
788 // ---------------------------------------------------------------------------------------
797 for ( i = 0; i < MAX_DS_SOFTWARE_BUFFERS; i++ ) {
798 if ( sound_buffers[i].buf_id == 0 )
802 if ( i == MAX_DS_SOFTWARE_BUFFERS ) {
810 for ( i = 0; i < MAX_DS_SOFTWARE_BUFFERS; i++ ) {
811 if ( ds_software_buffers[i].pdsb == NULL )
815 if ( i == MAX_DS_SOFTWARE_BUFFERS ) {
823 // ---------------------------------------------------------------------------------------
834 for ( i = 0; i < MAX_DS_HARDWARE_BUFFERS; i++ ) {
835 if ( ds_hardware_buffers[i].pdsb == NULL )
839 if ( i == MAX_DS_HARDWARE_BUFFERS ) {
847 // ---------------------------------------------------------------------------------------
848 // Load a DirectSound secondary buffer with sound data. The sounds data for
849 // game sounds are stored in the DirectSound secondary buffers, and are
850 // duplicated as needed and placed in the Channels[] array to be played.
854 // sid => pointer to software id for sound ( output parm)
855 // hid => pointer to hardware id for sound ( output parm)
856 // final_size => pointer to storage to receive uncompressed sound size (output parm)
857 // header => pointer to a WAVEFORMATEX structure
858 // si => sound_info structure, contains details on the sound format
859 // flags => buffer properties ( DS_HARDWARE , DS_3D )
861 // returns: -1 => sound effect could not loaded into a secondary buffer
862 // 0 => sound effect successfully loaded into a secondary buffer
865 // NOTE: this function is slow, especially when sounds are loaded into hardware. Don't call this
866 // function from within gameplay.
869 int ds_load_buffer(int *sid, int *hid, int *final_size, void *header, sound_info *si, int flags)
872 Assert( final_size != NULL );
873 Assert( header != NULL );
874 Assert( si != NULL );
875 Assert( si->data != NULL );
877 // All sounds are required to have a software buffer
881 nprintf(("Sound","SOUND ==> No more sound buffers available\n"));
886 alGenBuffers (1, &pi);
897 // the below two covnert_ variables are only used when the wav format is not
898 // PCM. DirectSound only takes PCM sound data, so we must convert to PCM if required
899 ubyte *convert_buffer = NULL; // storage for converted wav file
900 int convert_len; // num bytes of converted wav file
901 uint src_bytes_used; // number of source bytes actually converted (should always be equal to original size)
903 WAVEFORMATEX *pwfx = (WAVEFORMATEX *)header;
905 switch (si->format) {
906 case WAVE_FORMAT_PCM:
908 bps = si->avg_bytes_per_sec;
913 for (i=0; i<(uint)size; i=i+2)
915 swap_tmp = (ushort*)(si->data+i);
916 *swap_tmp = INTEL_SHORT(*swap_tmp);
921 case WAVE_FORMAT_ADPCM:
922 // this ADPCM decoder decodes to 16-bit only so keep that in mind
923 nprintf(( "Sound", "SOUND ==> converting sound from ADPCM to PCM\n" ));
924 rc = ACM_convert_ADPCM_to_PCM(pwfx, si->data, si->size, &convert_buffer, 0, &convert_len, &src_bytes_used, 16);
930 if (src_bytes_used != si->size) {
931 return -1; // ACM conversion failed?
935 bps = (((si->n_channels * bits) / 8) * si->sample_rate);
937 data = convert_buffer;
939 nprintf(( "Sound", "SOUND ==> Coverted sound from ADPCM to PCM successfully\n" ));
946 /* format is now in pcm */
947 frequency = si->sample_rate;
950 if (si->n_channels == 2) {
951 format = AL_FORMAT_STEREO16;
952 } else if (si->n_channels == 1) {
953 format = AL_FORMAT_MONO16;
957 } else if (bits == 8) {
958 if (si->n_channels == 2) {
959 format = AL_FORMAT_STEREO8;
960 } else if (si->n_channels == 1) {
961 format = AL_FORMAT_MONO8;
971 alBufferData (pi, format, data, size, frequency);
973 sound_buffers[*sid].buf_id = pi;
974 sound_buffers[*sid].source_id = -1;
975 sound_buffers[*sid].frequency = frequency;
976 sound_buffers[*sid].bits_per_sample = bits;
977 sound_buffers[*sid].nchannels = si->n_channels;
978 sound_buffers[*sid].nseconds = size / bps;
979 sound_buffers[*sid].nbytes = size;
983 if ( convert_buffer )
984 free( convert_buffer );
989 Assert( final_size != NULL );
990 Assert( header != NULL );
991 Assert( si != NULL );
992 Assert( si->data != NULL );
993 Assert( si->size > 0 );
994 Assert( si->sample_rate > 0);
995 Assert( si->bits > 0 );
996 Assert( si->n_channels > 0 );
997 Assert( si->n_block_align >= 0 );
998 Assert( si->avg_bytes_per_sec > 0 );
1000 WAVEFORMATEX *pwfx = (WAVEFORMATEX *)header;
1001 DSBUFFERDESC BufferDesc;
1002 WAVEFORMATEX WaveFormat;
1004 int rc, final_sound_size, DSOUND_load_buffer_result = 0;
1005 BYTE *pData, *pData2;
1006 DWORD DataSize, DataSize2;
1008 // the below two covnert_ variables are only used when the wav format is not
1009 // PCM. DirectSound only takes PCM sound data, so we must convert to PCM if required
1010 ubyte *convert_buffer = NULL; // storage for converted wav file
1011 int convert_len; // num bytes of converted wav file
1012 uint src_bytes_used; // number of source bytes actually converted (should always be equal to original size)
1014 // Ensure DirectSound initialized
1015 if (!ds_initialized) {
1016 DSOUND_load_buffer_result = -1;
1017 goto DSOUND_load_buffer_done;
1020 // Set up buffer information
1021 WaveFormat.wFormatTag = (unsigned short)si->format;
1022 WaveFormat.nChannels = (unsigned short)si->n_channels;
1023 WaveFormat.nSamplesPerSec = si->sample_rate;
1024 WaveFormat.wBitsPerSample = (unsigned short)si->bits;
1025 WaveFormat.cbSize = 0;
1026 WaveFormat.nBlockAlign = (unsigned short)si->n_block_align;
1027 WaveFormat.nAvgBytesPerSec = si->avg_bytes_per_sec;
1029 final_sound_size = si->size; // assume this format will be used, may be over-ridded by convert_len
1031 // Assert(WaveFormat.nChannels == 1);
1033 switch ( si->format ) {
1034 case WAVE_FORMAT_PCM:
1037 case WAVE_FORMAT_ADPCM:
1039 nprintf(( "Sound", "SOUND ==> converting sound from ADPCM to PCM\n" ));
1040 rc = ACM_convert_ADPCM_to_PCM(pwfx, si->data, si->size, &convert_buffer, 0, &convert_len, &src_bytes_used, 8);
1042 DSOUND_load_buffer_result = -1;
1043 goto DSOUND_load_buffer_done;
1046 if (src_bytes_used != si->size) {
1047 Int3(); // ACM conversion failed?
1048 DSOUND_load_buffer_result = -1;
1049 goto DSOUND_load_buffer_done;
1052 final_sound_size = convert_len;
1054 // Set up the WAVEFORMATEX structure to have the right PCM characteristics
1055 WaveFormat.wFormatTag = WAVE_FORMAT_PCM;
1056 WaveFormat.nChannels = (unsigned short)si->n_channels;
1057 WaveFormat.nSamplesPerSec = si->sample_rate;
1058 WaveFormat.wBitsPerSample = 8;
1059 WaveFormat.cbSize = 0;
1060 WaveFormat.nBlockAlign = (unsigned short)(( WaveFormat.nChannels * WaveFormat.wBitsPerSample ) / 8);
1061 WaveFormat.nAvgBytesPerSec = WaveFormat.nBlockAlign * WaveFormat.nSamplesPerSec;
1063 nprintf(( "Sound", "SOUND ==> Coverted sound from ADPCM to PCM successfully\n" ));
1067 nprintf(( "Sound", "Unsupported sound encoding\n" ));
1068 DSOUND_load_buffer_result = -1;
1069 goto DSOUND_load_buffer_done;
1073 WaveFormat.wFormatTag = WAVE_FORMAT_PCM; // DirectSound only used PCM wave files
1075 // Set up a DirectSound buffer
1076 ZeroMemory(&BufferDesc, sizeof(BufferDesc));
1077 BufferDesc.dwSize = sizeof(BufferDesc);
1078 BufferDesc.dwBufferBytes = final_sound_size;
1079 BufferDesc.lpwfxFormat = &WaveFormat;
1081 // check if DirectSound3D is enabled and the sound is flagged for 3D
1082 if ((ds_using_ds3d()) && (flags & DS_USE_DS3D)) {
1083 // if (ds_using_ds3d()) {
1084 BufferDesc.dwFlags = DSBCAPS_STATIC | DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRLVOLUME | DSBCAPS_CTRL3D | DSBCAPS_MUTE3DATMAXDISTANCE;
1086 BufferDesc.dwFlags = DSBCAPS_STATIC | DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRLVOLUME | DSBCAPS_LOCSOFTWARE;
1089 // Create a new software buffer using the settings for this wave
1090 // All sounds are required to have a software buffer
1091 *sid = ds_get_sid();
1093 nprintf(("Sound","SOUND ==> No more software secondary buffers available\n"));
1096 DSReturn = pDirectSound->CreateSoundBuffer(&BufferDesc, &ds_software_buffers[*sid].pdsb, NULL );
1098 if ( DSReturn == DS_OK && ds_software_buffers[*sid].pdsb != NULL ) {
1100 ds_software_buffers[*sid].desc = BufferDesc;
1101 ds_software_buffers[*sid].wfx = *BufferDesc.lpwfxFormat;
1103 // Lock the buffer and copy in the data
1104 if ((ds_software_buffers[*sid].pdsb)->Lock(0, final_sound_size, (void**)(&pData), &DataSize, (void**)(&pData2), &DataSize2, 0) == DS_OK) {
1106 if ( convert_buffer )
1107 memcpy(pData, convert_buffer, final_sound_size); // use converted data (PCM format)
1109 memcpy(pData, si->data, final_sound_size);
1111 (ds_software_buffers[*sid].pdsb)->Unlock(pData, DataSize, 0, 0);
1113 DSOUND_load_buffer_result = 0;
1115 // update ram used for sound
1116 Snd_sram += final_sound_size;
1117 *final_size = final_sound_size;
1120 nprintf(("Sound","SOUND => fatal error in DSOUND_load_buffer\n"));
1122 DSOUND_load_buffer_result = -1;
1125 DSOUND_load_buffer_done:
1126 if ( convert_buffer )
1127 free( convert_buffer );
1128 return DSOUND_load_buffer_result;
1132 // ---------------------------------------------------------------------------------------
1133 // ds_init_channels()
1135 // init the Channels[] array
1137 void ds_init_channels()
1144 Channels = (channel*) malloc(sizeof(channel) * MAX_CHANNELS);
1145 if (Channels == NULL) {
1146 Error(LOCATION, "Unable to allocate %d bytes for %d audio channels.", sizeof(channel) * MAX_CHANNELS, MAX_CHANNELS);
1149 // init the channels
1150 for ( i = 0; i < MAX_CHANNELS; i++ ) {
1151 alGenSources(1, &Channels[i].source_id);
1152 Channels[i].buf_id = -1;
1153 Channels[i].vol = 0;
1158 // detect how many channels we can support
1160 ds_get_soundcard_caps(&caps);
1162 // caps.dwSize = sizeof(DSCAPS);
1163 // pDirectSound->GetCaps(&caps);
1165 // minimum 16 channels
1166 MAX_CHANNELS = caps.dwMaxHwMixingStaticBuffers;
1167 int dbg_channels = MAX_CHANNELS;
1168 if (MAX_CHANNELS < 16) {
1172 // allocate the channels array
1173 Channels = (channel*) malloc(sizeof(channel) * MAX_CHANNELS);
1174 if (Channels == NULL) {
1175 Error(LOCATION, "Unable to allocate %d bytes for %d audio channels.", sizeof(channel) * MAX_CHANNELS, MAX_CHANNELS);
1178 // init the channels
1179 for ( i = 0; i < MAX_CHANNELS; i++ ) {
1180 Channels[i].pdsb = NULL;
1181 Channels[i].pds3db = NULL;
1182 Channels[i].vol = 0;
1185 mprintf(("** MAX_CHANNELS set to %d. DS reported %d.\n", MAX_CHANNELS, dbg_channels));
1189 // ---------------------------------------------------------------------------------------
1190 // ds_init_software_buffers()
1192 // init the software buffers
1194 void ds_init_software_buffers()
1199 for ( i = 0; i < MAX_DS_SOFTWARE_BUFFERS; i++ ) {
1200 sound_buffers[i].buf_id = 0;
1201 sound_buffers[i].source_id = -1;
1206 for ( i = 0; i < MAX_DS_SOFTWARE_BUFFERS; i++ ) {
1207 ds_software_buffers[i].pdsb = NULL;
1212 // ---------------------------------------------------------------------------------------
1213 // ds_init_hardware_buffers()
1215 // init the hardware buffers
1217 void ds_init_hardware_buffers()
1220 // STUB_FUNCTION; // not needed with openal (CM)
1225 for ( i = 0; i < MAX_DS_HARDWARE_BUFFERS; i++ ) {
1226 ds_hardware_buffers[i].pdsb = NULL;
1231 // ---------------------------------------------------------------------------------------
1232 // ds_init_buffers()
1234 // init the both the software and hardware buffers
1236 void ds_init_buffers()
1238 ds_init_software_buffers();
1239 ds_init_hardware_buffers();
1242 // Get the current soundcard capabilities
1244 void ds_get_soundcard_caps(DSCAPS *dscaps)
1247 int n_hbuffers, hram;
1249 dscaps->dwSize = sizeof(DSCAPS);
1251 hr = pDirectSound->GetCaps(dscaps);
1253 nprintf(("Sound","SOUND ==> DirectSound GetCaps() failed with code %s\n.",get_DSERR_text(hr) ));
1257 n_hbuffers = dscaps->dwMaxHwMixingStaticBuffers;
1258 hram = dscaps->dwTotalHwMemBytes;
1260 if ( !(dscaps->dwFlags & DSCAPS_CERTIFIED) ) {
1261 nprintf(("Sound","SOUND ==> Warning: audio driver is not Microsoft certified.\n"));
1265 // ---------------------------------------------------------------------------------------
1268 // init the both the software and hardware buffers
1270 void ds_show_caps(DSCAPS *dscaps)
1272 nprintf(("Sound", "SOUND => Soundcard Capabilities:\n"));
1273 nprintf(("Sound", "================================\n"));
1274 nprintf(("Sound", "Number of primary buffers: %d\n", dscaps->dwPrimaryBuffers ));
1275 nprintf(("Sound", "Number of total hw mixing buffers: %d\n", dscaps->dwMaxHwMixingAllBuffers ));
1276 nprintf(("Sound", "Number of total hw mixing static buffers: %d\n", dscaps->dwMaxHwMixingStaticBuffers ));
1277 nprintf(("Sound", "Number of total hw mixing streaming buffers: %d\n", dscaps->dwMaxHwMixingStreamingBuffers ));
1278 nprintf(("Sound", "Number of free hw mixing buffers: %d\n", dscaps->dwFreeHwMixingAllBuffers ));
1279 nprintf(("Sound", "Number of free hw mixing static buffers: %d\n", dscaps->dwFreeHwMixingStaticBuffers ));
1280 nprintf(("Sound", "Number of free hw mixing streaming buffers: %d\n", dscaps->dwFreeHwMixingStreamingBuffers ));
1281 nprintf(("Sound", "Number of hw 3D buffers: %d\n", dscaps->dwMaxHw3DAllBuffers ));
1282 nprintf(("Sound", "Number of hw 3D static buffers: %d\n", dscaps->dwMaxHw3DStaticBuffers ));
1283 nprintf(("Sound", "Number of hw 3D streaming buffers: %d\n", dscaps->dwMaxHw3DStreamingBuffers ));
1284 nprintf(("Sound", "Number of free hw 3D buffers: %d\n", dscaps->dwFreeHw3DAllBuffers ));
1285 nprintf(("Sound", "Number of free hw static 3D buffers: %d\n", dscaps->dwFreeHw3DStaticBuffers ));
1286 nprintf(("Sound", "Number of free hw streaming 3D buffers: %d\n", dscaps->dwFreeHw3DStreamingBuffers ));
1287 nprintf(("Sound", "Number of total hw bytes: %d\n", dscaps->dwTotalHwMemBytes ));
1288 nprintf(("Sound", "Number of free hw bytes: %d\n", dscaps->dwFreeHwMemBytes ));
1289 nprintf(("Sound", "================================\n"));
1294 // Fill in the waveformat struct with the primary buffer characteristics.
1295 void ds_get_primary_format(WAVEFORMATEX *wfx)
1297 // Set 16 bit / 22KHz / mono
1298 wfx->wFormatTag = WAVE_FORMAT_PCM;
1300 wfx->nSamplesPerSec = 22050;
1301 wfx->wBitsPerSample = 16;
1303 wfx->nBlockAlign = (unsigned short)(wfx->nChannels * (wfx->wBitsPerSample / 8));
1304 wfx->nAvgBytesPerSec = wfx->nBlockAlign * wfx->nSamplesPerSec;
1308 // obtain the function pointers from the dsound.dll
1309 void ds_dll_get_functions()
1311 pfn_DirectSoundCreate = (HRESULT(__stdcall *)(LPGUID lpGuid, LPDIRECTSOUND *ppDS, IUnknown FAR *pUnkOuter))GetProcAddress(Ds_dll_handle,"DirectSoundCreate");
1312 pfn_DirectSoundCaptureCreate = (HRESULT(__stdcall *)(LPGUID lpGuid, LPDIRECTSOUNDCAPTURE *lplpDSC, IUnknown FAR *pUnkOuter))GetProcAddress(Ds_dll_handle,"DirectSoundCaptureCreate");
1316 // Load the dsound.dll, and get funtion pointers
1317 // exit: 0 -> dll loaded successfully
1318 // !0 -> dll could not be loaded
1324 if ( !Ds_dll_loaded ) {
1325 Ds_dll_handle = LoadLibrary("dsound.dll");
1326 if ( !Ds_dll_handle ) {
1329 ds_dll_get_functions();
1342 HINSTANCE a3d_handle;
1345 a3d_handle = LoadLibrary("a3d.dll");
1349 FreeLibrary(a3d_handle);
1353 Ds_must_call_couninitialize = 1;
1355 hr = CoCreateInstance(CLSID_A3d_Def, NULL, CLSCTX_INPROC_SERVER, IID_IDirectSound, (void**)&pDirectSound);
1360 Assert(pDirectSound != NULL);
1361 hr = pDirectSound->QueryInterface(IID_IA3d2_Def, (void**)&pIA3d2);
1366 A3DCAPS_SOFTWARE swCaps;
1368 // Get Dll Software CAP to get DLL version number
1369 ZeroMemory(&swCaps,sizeof(swCaps));
1371 swCaps.dwSize = sizeof(swCaps);
1372 pIA3d2->GetSoftwareCaps(&swCaps);
1374 // Compare version from a3d.dll to header version only return A3D_OK if dll version >= to header version
1375 if (swCaps.dwVersion < A3D_CURRENT_VERSION) {
1376 pDirectSound->Release();
1377 pDirectSound = NULL;
1382 // verify this is authentic A3D
1383 int aureal_verified;
1384 aureal_verified = VerifyAurealA3D();
1386 if (aureal_verified == FALSE) {
1387 // This is fake A3D!!! Ignore
1388 pDirectSound->Release();
1389 pDirectSound = NULL;
1393 // Register our version for backwards compatibility with newer A3d.dll
1394 pIA3d2->RegisterVersion(A3D_CURRENT_VERSION);
1396 hr = pDirectSound->Initialize(NULL);
1398 pDirectSound->Release();
1399 pDirectSound = NULL;
1403 pIA3d2->SetResourceManagerMode(A3D_RESOURCE_MODE_DYNAMIC_LOOPERS);
1409 // Initialize the property set interface.
1411 // returns: 0 if successful, otherwise -1. If successful, the global pPropertySet will
1412 // set to a non-NULL value.
1414 int ds_init_property_set()
1421 // Create the secondary buffer required for EAX initialization
1423 wf.wFormatTag = WAVE_FORMAT_PCM;
1425 wf.nSamplesPerSec = 22050;
1426 wf.wBitsPerSample = 16;
1428 wf.nBlockAlign = (unsigned short)(wf.nChannels * (wf.wBitsPerSample / 8));
1429 wf.nAvgBytesPerSec = wf.nBlockAlign * wf.nSamplesPerSec;
1432 ZeroMemory(&dsbd, sizeof(dsbd));
1433 dsbd.dwSize = sizeof(dsbd);
1434 dsbd.dwFlags = DSBCAPS_CTRLDEFAULT | DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_STATIC | DSBCAPS_CTRL3D | DSBCAPS_MUTE3DATMAXDISTANCE;
1435 dsbd.dwBufferBytes = 3 * wf.nAvgBytesPerSec;
1436 dsbd.lpwfxFormat = &wf;
1438 // Create a new buffer using the settings for this wave
1439 hr = pDirectSound->CreateSoundBuffer(&dsbd, &Ds_property_set_pdsb, NULL);
1441 pPropertySet = NULL;
1445 // Get the 3D interface from the secondary buffer, which is used to query the EAX interface
1446 hr = Ds_property_set_pdsb->QueryInterface(IID_IDirectSound3DBuffer, (void**)&Ds_property_set_pds3db);
1448 Ds_property_set_pds3db = NULL;
1452 Assert(Ds_property_set_pds3db != NULL);
1453 hr = Ds_property_set_pds3db->QueryInterface(IID_IKsPropertySet, (void**)&pPropertySet);
1454 if ((FAILED(hr)) || (pPropertySet == NULL)) {
1462 // ---------------------------------------------------------------------------------------
1465 // returns: -1 => init failed
1466 // 0 => init success
1467 int ds_init(int use_a3d, int use_eax)
1470 // NOTE: A3D and EAX are unused in OpenAL
1471 // changed from 22050 to 44100 so that movies don't sound like crap
1472 ALCubyte *initStr = (ubyte *)"\'( (sampling-rate 44100 ))";
1473 int attr[] = { ALC_FREQUENCY, 44100, ALC_SYNC, AL_FALSE, 0 };
1479 nprintf(( "Sound", "SOUND ==> Initializing OpenAL...\n" ));
1482 ds_sound_device = alcOpenDevice (initStr);
1484 // Create Sound Device
1485 ds_sound_context = alcCreateContext (ds_sound_device, attr);
1486 alcMakeContextCurrent (ds_sound_context);
1488 if (alcGetError(ds_sound_device) != ALC_NO_ERROR) {
1489 nprintf(("Sound", "SOUND ==> Couldn't initialize OpenAL\n"));
1493 OpenAL_ErrorCheck();
1495 // make sure we can actually use AL_BYTE_LOKI (Mac OpenAL doesn't have it)
1496 AL_play_position = alIsExtensionPresent( (ALubyte*)"AL_LOKI_play_position" );
1498 // Initialize DirectSound3D. Since software performance of DirectSound3D is unacceptably
1499 // slow, we require the voice manger (a DirectSound extension) to be present. The
1500 // exception is when A3D is being used, since A3D has a resource manager built in.
1501 // if (Ds_use_ds3d && ds3d_init(0) != 0)
1504 // setup default listener position/orientation
1505 // this is needed for 2D pan
1506 alListener3f(AL_POSITION, 0.0, 0.0, 0.0);
1508 ALfloat list_orien[] = { 0.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f };
1509 alListenerfv(AL_ORIENTATION, list_orien);
1511 ds_build_vol_lookup();
1517 WAVEFORMATEX wave_format;
1518 DSBUFFERDESC BufferDesc;
1520 nprintf(( "Sound", "SOUND ==> Initializing DirectSound...\n" ));
1522 hwnd = (HWND)os_get_window();
1523 if ( hwnd == NULL ) {
1524 nprintf(( "Sound", "SOUND ==> No window handle, so no sound...\n" ));
1528 if ( ds_dll_load() == -1 ) {
1532 pDirectSound = NULL;
1534 Ds_use_a3d = use_a3d;
1535 Ds_use_eax = use_eax;
1537 if (Ds_use_a3d || Ds_use_eax) {
1541 if (Ds_use_a3d && Ds_use_eax) {
1546 // If we want A3D, ensure a3d.dll exists
1547 if (Ds_use_a3d == 1) {
1548 if (ds_init_a3d() != 0) {
1555 if (Ds_use_a3d == 0) {
1556 if (!pfn_DirectSoundCreate) {
1557 nprintf(( "Sound", "SOUND ==> Could not get DirectSoundCreate function pointer\n" ));
1561 hr = pfn_DirectSoundCreate(NULL, &pDirectSound, NULL);
1567 // Set up DirectSound for exclusive mode, so we can change the primary buffer if we want to.
1568 hr = pDirectSound->SetCooperativeLevel(hwnd, DSSCL_EXCLUSIVE);
1570 nprintf(("Sound","SOUND ==> DirectSound pDirectSound->SetCooperativeLevel failed with code %s\n.",get_DSERR_text(hr) ));
1571 pDirectSound = NULL;
1575 // Create the primary buffer
1576 ZeroMemory(&BufferDesc, sizeof(BufferDesc));
1577 BufferDesc.dwSize = sizeof(BufferDesc);
1579 ds_get_soundcard_caps(&Soundcard_caps);
1582 BufferDesc.dwFlags = DSBCAPS_PRIMARYBUFFER | DSBCAPS_CTRL3D;
1584 hr = pDirectSound->CreateSoundBuffer(&BufferDesc, &pPrimaryBuffer, 0);
1586 nprintf(("Sound","SOUND ==> Primary Buffer create failed with DSBCAPS_CTRL3D property... disabling DirectSound3D\n"));
1591 nprintf(("Sound","SOUND ==> Primary Buffer created with DirectSound3D enabled\n"));
1595 // If not using DirectSound3D, then create a normal primary buffer
1596 if (Ds_use_ds3d == 0) {
1597 BufferDesc.dwFlags = DSBCAPS_PRIMARYBUFFER;
1598 hr = pDirectSound->CreateSoundBuffer(&BufferDesc, &pPrimaryBuffer, 0);
1600 nprintf(("Sound","SOUND ==> Primary Buffer create failed with error: %s\n",get_DSERR_text(hr) ));
1601 pDirectSound = NULL;
1605 nprintf(("Sound","SOUND ==> Primary Buffer created with without DirectSound3D enabled\n"));
1609 // Get the primary buffer format
1610 ds_get_primary_format(&wave_format);
1612 hr = pPrimaryBuffer->SetFormat(&wave_format);
1614 nprintf(("Sound","SOUND ==> pPrimaryBuffer->SetFormat() failed with code %s\n",get_DSERR_text(hr) ));
1617 pPrimaryBuffer->GetFormat(&wave_format, sizeof(wave_format), NULL);
1618 nprintf(("Sound","SOUND ==> Primary Buffer forced to: rate: %d Hz bits: %d n_channels: %d\n",
1619 wave_format.nSamplesPerSec, wave_format.wBitsPerSample, wave_format.nChannels));
1621 // start the primary buffer playing. This will reduce sound latency when playing a sound
1622 // if no other sounds are playing.
1623 hr = pPrimaryBuffer->Play(0, 0, DSBPLAY_LOOPING);
1625 nprintf(("Sound","SOUND ==> pPrimaryBuffer->Play() failed with code %s\n",get_DSERR_text(hr) ));
1628 // Initialize DirectSound3D. Since software performance of DirectSound3D is unacceptably
1629 // slow, we require the voice manger (a DirectSound extension) to be present. The
1630 // exception is when A3D is being used, since A3D has a resource manager built in.
1632 int vm_required = 1; // voice manager
1633 if (Ds_use_a3d == 1) {
1637 if (ds3d_init(vm_required) != 0) {
1643 if (Ds_use_eax == 1) {
1644 ds_init_property_set();
1645 if (ds_eax_init() != 0) {
1650 ds_build_vol_lookup();
1654 ds_show_caps(&Soundcard_caps);
1660 // ---------------------------------------------------------------------------------------
1663 // returns the text equivalent for the a DirectSound DSERR_ code
1665 char *get_DSERR_text(int DSResult)
1670 static char buf[20];
1671 snprintf(buf, 19, "unknown %d", DSResult);
1674 switch( DSResult ) {
1680 case DSERR_ALLOCATED:
1681 return "DSERR_ALLOCATED";
1684 case DSERR_ALREADYINITIALIZED:
1685 return "DSERR_ALREADYINITIALIZED";
1688 case DSERR_BADFORMAT:
1689 return "DSERR_BADFORMAT";
1692 case DSERR_BUFFERLOST:
1693 return "DSERR_BUFFERLOST";
1696 case DSERR_CONTROLUNAVAIL:
1697 return "DSERR_CONTROLUNAVAIL";
1701 return "DSERR_GENERIC";
1704 case DSERR_INVALIDCALL:
1705 return "DSERR_INVALIDCALL";
1708 case DSERR_INVALIDPARAM:
1709 return "DSERR_INVALIDPARAM";
1712 case DSERR_NOAGGREGATION:
1713 return "DSERR_NOAGGREGATION";
1716 case DSERR_NODRIVER:
1717 return "DSERR_NODRIVER";
1720 case DSERR_OUTOFMEMORY:
1721 return "DSERR_OUTOFMEMORY";
1724 case DSERR_OTHERAPPHASPRIO:
1725 return "DSERR_OTHERAPPHASPRIO";
1728 case DSERR_PRIOLEVELNEEDED:
1729 return "DSERR_PRIOLEVELNEEDED";
1732 case DSERR_UNINITIALIZED:
1733 return "DSERR_UNINITIALIZED";
1736 case DSERR_UNSUPPORTED:
1737 return "DSERR_UNSUPPORTED";
1748 // ---------------------------------------------------------------------------------------
1749 // ds_close_channel()
1751 // Free a single channel
1753 void ds_close_channel(int i)
1756 if(Channels[i].source_id != 0 && alIsSource (Channels[i].source_id)) {
1757 alSourceStop (Channels[i].source_id);
1758 alDeleteSources(1, &Channels[i].source_id);
1760 Channels[i].source_id = 0;
1767 // If a 3D interface exists, free it
1768 if ( Channels[i].pds3db != NULL ) {
1771 Channels[i].pds3db = NULL;
1774 while(++attempts < 10) {
1775 hr = Channels[i].pds3db->Release();
1776 if ( hr == DS_OK ) {
1779 // nprintf(("Sound", "SOUND ==> Channels[channel].pds3db->Release() failed with return value %s\n", get_DSERR_text(second_hr) ));
1783 Channels[i].pds3db = NULL;
1787 if ( Channels[i].pdsb != NULL ) {
1788 // If a 2D interface exists, free it
1789 if ( Channels[i].pdsb != NULL ) {
1791 while(++attempts < 10) {
1792 hr = Channels[i].pdsb->Release();
1793 if ( hr == DS_OK ) {
1796 nprintf(("Sound", "SOUND ==> Channels[channel].pdsb->Release() failed with return value %s\n", get_DSERR_text(hr) ));
1801 Channels[i].pdsb = NULL;
1808 // ---------------------------------------------------------------------------------------
1809 // ds_close_all_channels()
1811 // Free all the channel buffers
1813 void ds_close_all_channels()
1817 for (i = 0; i < MAX_CHANNELS; i++) {
1818 ds_close_channel(i);
1822 // ---------------------------------------------------------------------------------------
1823 // ds_unload_buffer()
1826 void ds_unload_buffer(int sid, int hid)
1830 ALuint buf_id = sound_buffers[sid].buf_id;
1832 if (buf_id != 0 && alIsBuffer(buf_id)) {
1833 alDeleteBuffers(1, &buf_id);
1836 sound_buffers[sid].buf_id = 0;
1846 if ( ds_software_buffers[sid].pdsb != NULL ) {
1847 hr = ds_software_buffers[sid].pdsb->Release();
1848 if ( hr != DS_OK ) {
1850 nprintf(("Sound", "SOUND ==> ds_software_buffers[sid]->Release() failed with return value %s\n", get_DSERR_text(hr) ));
1852 ds_software_buffers[sid].pdsb = NULL;
1857 if ( ds_hardware_buffers[hid].pdsb != NULL ) {
1858 hr = ds_hardware_buffers[hid].pdsb->Release();
1859 if ( hr != DS_OK ) {
1861 nprintf(("Sound", "SOUND ==> ds_hardware_buffers[hid]->Release() failed with return value %s\n", get_DSERR_text(hr) ));
1863 ds_hardware_buffers[hid].pdsb = NULL;
1869 // ---------------------------------------------------------------------------------------
1870 // ds_close_software_buffers()
1873 void ds_close_software_buffers()
1878 for (i = 0; i < MAX_DS_SOFTWARE_BUFFERS; i++) {
1879 ALuint buf_id = sound_buffers[i].buf_id;
1881 if (buf_id != 0 && alIsBuffer(buf_id)) {
1882 alDeleteBuffers(1, &buf_id);
1885 sound_buffers[i].buf_id = 0;
1891 for (i = 0; i < MAX_DS_SOFTWARE_BUFFERS; i++) {
1892 if ( ds_software_buffers[i].pdsb != NULL ) {
1893 hr = ds_software_buffers[i].pdsb->Release();
1894 if ( hr != DS_OK ) {
1896 nprintf(("Sound", "SOUND ==> ds_software_buffers[i]->Release() failed with return value %s\n", get_DSERR_text(hr) ));
1898 ds_software_buffers[i].pdsb = NULL;
1904 // ---------------------------------------------------------------------------------------
1905 // ds_close_hardware_buffers()
1908 void ds_close_hardware_buffers()
1916 for (i = 0; i < MAX_DS_HARDWARE_BUFFERS; i++) {
1917 if ( ds_hardware_buffers[i].pdsb != NULL ) {
1918 hr = ds_hardware_buffers[i].pdsb->Release();
1919 if ( hr != DS_OK ) {
1921 nprintf(("Sound", "SOUND ==> ds_hardware_buffers[i]->Release() failed with return value %s\n", get_DSERR_text(hr) ));
1923 ds_hardware_buffers[i].pdsb = NULL;
1929 // ---------------------------------------------------------------------------------------
1930 // ds_close_buffers()
1932 // Free the channel buffers
1934 void ds_close_buffers()
1936 ds_close_software_buffers();
1937 ds_close_hardware_buffers();
1940 // ---------------------------------------------------------------------------------------
1943 // Close the DirectSound system
1947 ds_close_all_channels();
1951 if (pPropertySet != NULL) {
1952 pPropertySet->Release();
1953 pPropertySet = NULL;
1956 if (Ds_property_set_pdsb != NULL) {
1957 Ds_property_set_pdsb->Release();
1958 Ds_property_set_pdsb = NULL;
1961 if (Ds_property_set_pds3db != NULL) {
1962 Ds_property_set_pds3db->Release();
1963 Ds_property_set_pds3db = NULL;
1966 if (pPrimaryBuffer) {
1967 pPrimaryBuffer->Release();
1968 pPrimaryBuffer = NULL;
1977 pDirectSound->Release();
1978 pDirectSound = NULL;
1981 if ( Ds_dll_loaded ) {
1982 FreeLibrary(Ds_dll_handle);
1986 if (Ds_must_call_couninitialize == 1) {
1991 // free the Channels[] array, since it was dynamically allocated
1996 ds_sound_context = alcGetCurrentContext();
1997 ds_sound_device = alcGetContextsDevice(ds_sound_context);
1998 alcDestroyContext(ds_sound_context);
1999 alcCloseDevice(ds_sound_device);
2003 // ---------------------------------------------------------------------------------------
2004 // ds_get_3d_interface()
2006 // Get the 3d interface for a secondary buffer.
2008 // If the secondary buffer wasn't created with a DSBCAPS_CTRL3D flag, then no 3d interface
2012 void ds_get_3d_interface(LPDIRECTSOUNDBUFFER pdsb, LPDIRECTSOUND3DBUFFER *ppds3db)
2017 dsbc.dwSize = sizeof(dsbc);
2018 DSResult = pdsb->GetCaps(&dsbc);
2019 if ( DSResult == DS_OK && dsbc.dwFlags & DSBCAPS_CTRL3D ) {
2020 DSResult = pdsb->QueryInterface( IID_IDirectSound3DBuffer, (void**)ppds3db );
2021 if ( DSResult != DS_OK ) {
2022 nprintf(("SOUND","Could not obtain 3D interface for hardware buffer: %s\n", get_DSERR_text(DSResult) ));
2029 // ---------------------------------------------------------------------------------------
2030 // ds_get_free_channel()
2032 // Find a free channel to play a sound on. If no free channels exists, free up one based
2033 // on volume levels.
2035 // input: new_volume => volume in DS units for sound to play at
2036 // snd_id => which kind of sound to play
2037 // priority => DS_MUST_PLAY
2042 // returns: channel number to play sound on
2043 // -1 if no channel could be found
2045 // NOTE: snd_id is needed since we limit the number of concurrent samples
2049 int ds_get_free_channel(int new_volume, int snd_id, int priority)
2052 int i, first_free_channel, limit;
2053 int lowest_vol = 0, lowest_vol_index = -1;
2054 int instance_count; // number of instances of sound already playing
2055 int lowest_instance_vol, lowest_instance_vol_index;
2060 lowest_instance_vol = 99;
2061 lowest_instance_vol_index = -1;
2062 first_free_channel = -1;
2064 // Look for a channel to use to play this sample
2065 for ( i = 0; i < MAX_CHANNELS; i++ ) {
2067 if ( chp->source_id == 0 ) {
2068 if ( first_free_channel == -1 )
2069 first_free_channel = i;
2073 alGetSourcei(chp->source_id, AL_SOURCE_STATE, &status);
2075 OpenAL_ErrorCheck();
2077 if ( status != AL_PLAYING ) {
2078 if ( first_free_channel == -1 )
2079 first_free_channel = i;
2083 if ( chp->snd_id == snd_id ) {
2085 if ( chp->vol < lowest_instance_vol && chp->looping == FALSE ) {
2086 lowest_instance_vol = chp->vol;
2087 lowest_instance_vol_index = i;
2091 if ( chp->vol < lowest_vol && chp->looping == FALSE ) {
2092 lowest_vol_index = i;
2093 lowest_vol = chp->vol;
2098 // determine the limit of concurrent instances of this sound
2109 case DS_LIMIT_THREE:
2119 // If we've exceeded the limit, then maybe stop the duplicate if it is lower volume
2120 if ( instance_count >= limit ) {
2121 // If there is a lower volume duplicate, stop it.... otherwise, don't play the sound
2122 if ( lowest_instance_vol_index >= 0 && (Channels[lowest_instance_vol_index].vol <= new_volume) ) {
2123 first_free_channel = lowest_instance_vol_index;
2125 first_free_channel = -1;
2128 // there is no limit barrier to play the sound, so see if we've ran out of channels
2129 if ( first_free_channel == -1 ) {
2130 // stop the lowest volume instance to play our sound if priority demands it
2131 if ( lowest_vol_index != -1 && priority == DS_MUST_PLAY ) {
2132 // Check if the lowest volume playing is less than the volume of the requested sound.
2133 // If so, then we are going to trash the lowest volume sound.
2134 if ( Channels[lowest_vol_index].vol <= new_volume ) {
2135 first_free_channel = lowest_vol_index;
2141 return first_free_channel;
2143 int i, first_free_channel, limit;
2144 int lowest_vol = 0, lowest_vol_index = -1;
2145 int instance_count; // number of instances of sound already playing
2146 int lowest_instance_vol, lowest_instance_vol_index;
2147 unsigned long status;
2152 lowest_instance_vol = 99;
2153 lowest_instance_vol_index = -1;
2154 first_free_channel = -1;
2156 // Look for a channel to use to play this sample
2157 for ( i = 0; i < MAX_CHANNELS; i++ ) {
2159 if ( chp->pdsb == NULL ) {
2160 if ( first_free_channel == -1 )
2161 first_free_channel = i;
2165 hr = chp->pdsb->GetStatus(&status);
2166 if ( hr != DS_OK ) {
2167 nprintf(("Sound", "SOUND ==> GetStatus failed with return value %s\n", get_DSERR_text(hr) ));
2170 if ( !(status & DSBSTATUS_PLAYING) ) {
2171 if ( first_free_channel == -1 )
2172 first_free_channel = i;
2173 ds_close_channel(i);
2177 if ( chp->snd_id == snd_id ) {
2179 if ( chp->vol < lowest_instance_vol && chp->looping == FALSE ) {
2180 lowest_instance_vol = chp->vol;
2181 lowest_instance_vol_index = i;
2185 if ( chp->vol < lowest_vol && chp->looping == FALSE ) {
2186 lowest_vol_index = i;
2187 lowest_vol = chp->vol;
2192 // determine the limit of concurrent instances of this sound
2203 case DS_LIMIT_THREE:
2213 // If we've exceeded the limit, then maybe stop the duplicate if it is lower volume
2214 if ( instance_count >= limit ) {
2215 // If there is a lower volume duplicate, stop it.... otherwise, don't play the sound
2216 if ( lowest_instance_vol_index >= 0 && (Channels[lowest_instance_vol_index].vol <= new_volume) ) {
2217 ds_close_channel(lowest_instance_vol_index);
2218 first_free_channel = lowest_instance_vol_index;
2220 first_free_channel = -1;
2223 // there is no limit barrier to play the sound, so see if we've ran out of channels
2224 if ( first_free_channel == -1 ) {
2225 // stop the lowest volume instance to play our sound if priority demands it
2226 if ( lowest_vol_index != -1 && priority == DS_MUST_PLAY ) {
2227 // Check if the lowest volume playing is less than the volume of the requested sound.
2228 // If so, then we are going to trash the lowest volume sound.
2229 if ( Channels[lowest_vol_index].vol <= new_volume ) {
2230 ds_close_channel(lowest_vol_index);
2231 first_free_channel = lowest_vol_index;
2237 return first_free_channel;
2242 // ---------------------------------------------------------------------------------------
2245 // Find a free channel to play a sound on. If no free channels exists, free up one based
2246 // on volume levels.
2248 // returns: 0 => dup was successful
2249 // -1 => dup failed (Channels[channel].pdsb will be NULL)
2252 int ds_channel_dup(LPDIRECTSOUNDBUFFER pdsb, int channel, int use_ds3d)
2256 // Duplicate the master buffer into a channel buffer.
2257 DSResult = pDirectSound->DuplicateSoundBuffer(pdsb, &Channels[channel].pdsb );
2258 if ( DSResult != DS_OK ) {
2259 nprintf(("Sound", "SOUND ==> DuplicateSoundBuffer failed with return value %s\n", get_DSERR_text(DSResult) ));
2260 Channels[channel].pdsb = NULL;
2264 // get the 3d interface for the buffer if it exists
2266 if (Channels[channel].pds3db == NULL) {
2267 ds_get_3d_interface(Channels[channel].pdsb, &Channels[channel].pds3db);
2275 // ---------------------------------------------------------------------------------------
2276 // ds_restore_buffer()
2279 void ds_restore_buffer(LPDIRECTSOUNDBUFFER pdsb)
2283 Int3(); // get Alan, he wants to see this
2284 hr = pdsb->Restore();
2285 if ( hr != DS_OK ) {
2286 nprintf(("Sound", "Sound ==> Lost a buffer, tried restoring but got %s\n", get_DSERR_text(hr) ));
2291 // Create a direct sound buffer in software, without locking any data in
2292 int ds_create_buffer(int frequency, int bits_per_sample, int nchannels, int nseconds)
2298 if (!ds_initialized) {
2304 nprintf(("Sound","SOUND ==> No more OpenAL buffers available\n"));
2308 alGenBuffers (1, &i);
2310 sound_buffers[sid].buf_id = i;
2311 sound_buffers[sid].source_id = -1;
2312 sound_buffers[sid].frequency = frequency;
2313 sound_buffers[sid].bits_per_sample = bits_per_sample;
2314 sound_buffers[sid].nchannels = nchannels;
2315 sound_buffers[sid].nseconds = nseconds;
2316 sound_buffers[sid].nbytes = nseconds * (bits_per_sample / 8) * nchannels * frequency;
2325 if (!ds_initialized) {
2331 nprintf(("Sound","SOUND ==> No more software secondary buffers available\n"));
2335 // Set up buffer format
2336 wfx.wFormatTag = WAVE_FORMAT_PCM;
2337 wfx.nChannels = (unsigned short)nchannels;
2338 wfx.nSamplesPerSec = frequency;
2339 wfx.wBitsPerSample = (unsigned short)bits_per_sample;
2341 wfx.nBlockAlign = (unsigned short)(wfx.nChannels * (wfx.wBitsPerSample / 8));
2342 wfx.nAvgBytesPerSec = wfx.nBlockAlign * wfx.nSamplesPerSec;
2344 memset(&dsbd, 0, sizeof(DSBUFFERDESC));
2345 dsbd.dwSize = sizeof(DSBUFFERDESC);
2346 dsbd.dwBufferBytes = wfx.nAvgBytesPerSec * nseconds;
2347 dsbd.lpwfxFormat = &wfx;
2348 dsbd.dwFlags = DSBCAPS_STATIC | DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRLDEFAULT | DSBCAPS_LOCSOFTWARE;
2350 dsrval = pDirectSound->CreateSoundBuffer(&dsbd, &ds_software_buffers[sid].pdsb, NULL);
2351 if ( dsrval != DS_OK ) {
2355 ds_software_buffers[sid].desc = dsbd;
2360 // Lock data into an existing buffer
2361 int ds_lock_data(int sid, unsigned char *data, int size)
2366 ALuint buf_id = sound_buffers[sid].buf_id;
2369 if (sound_buffers[sid].bits_per_sample == 16) {
2370 if (sound_buffers[sid].nchannels == 2) {
2371 format = AL_FORMAT_STEREO16;
2372 } else if (sound_buffers[sid].nchannels == 1) {
2373 format = AL_FORMAT_MONO16;
2377 } else if (sound_buffers[sid].bits_per_sample == 8) {
2378 if (sound_buffers[sid].nchannels == 2) {
2379 format = AL_FORMAT_STEREO8;
2380 } else if (sound_buffers[sid].nchannels == 1) {
2381 format = AL_FORMAT_MONO8;
2389 sound_buffers[sid].nbytes = size;
2391 alBufferData(buf_id, format, data, size, sound_buffers[sid].frequency);
2393 OpenAL_ErrorCheck();
2398 LPDIRECTSOUNDBUFFER pdsb;
2400 void *buffer_data, *buffer_data2;
2401 DWORD buffer_size, buffer_size2;
2404 pdsb = ds_software_buffers[sid].pdsb;
2406 memset(&caps, 0, sizeof(DSBCAPS));
2407 caps.dwSize = sizeof(DSBCAPS);
2408 dsrval = pdsb->GetCaps(&caps);
2409 if ( dsrval != DS_OK ) {
2413 pdsb->SetCurrentPosition(0);
2415 // lock the entire buffer
2416 dsrval = pdsb->Lock(0, caps.dwBufferBytes, &buffer_data, &buffer_size, &buffer_data2, &buffer_size2, 0 );
2417 if ( dsrval != DS_OK ) {
2421 // first clear it out with silence
2422 memset(buffer_data, 0x80, buffer_size);
2423 memcpy(buffer_data, data, size);
2425 dsrval = pdsb->Unlock(buffer_data, buffer_size, 0, 0);
2426 if ( dsrval != DS_OK ) {
2434 // Stop a buffer from playing directly
2435 void ds_stop_easy(int sid)
2440 int cid = sound_buffers[sid].source_id;
2443 ALuint source_id = Channels[cid].source_id;
2445 alSourceStop(source_id);
2449 LPDIRECTSOUNDBUFFER pdsb;
2452 pdsb = ds_software_buffers[sid].pdsb;
2453 dsrval = pdsb->Stop();
2457 // Play a sound without the usual baggage (used for playing back real-time voice)
2460 // sid => software id of sound
2461 // volume => volume of sound effect in DirectSound units
2462 int ds_play_easy(int sid, int volume)
2465 if (!ds_initialized)
2468 int channel = ds_get_free_channel(volume, -1, DS_MUST_PLAY);
2471 ALuint source_id = Channels[channel].source_id;
2473 alSourceStop(source_id);
2475 if (Channels[channel].buf_id != sid) {
2476 ALuint buffer_id = sound_buffers[sid].buf_id;
2478 alSourcei(source_id, AL_BUFFER, buffer_id);
2480 OpenAL_ErrorCheck();
2483 Channels[channel].buf_id = sid;
2485 ALfloat alvol = (volume != -10000) ? pow(10.0, (float)volume / (-600.0 / log10(.5))): 0.0;
2487 alSourcef(source_id, AL_GAIN, alvol);
2489 alSourcei(source_id, AL_LOOPING, AL_FALSE);
2490 alSourcePlay(source_id);
2492 OpenAL_ErrorCheck();
2500 LPDIRECTSOUNDBUFFER pdsb;
2503 pdsb = ds_software_buffers[sid].pdsb;
2505 pdsb->SetVolume(volume);
2506 dsrval=pdsb->Play(0, 0, 0);
2507 if ( dsrval != DS_OK ) {
2515 // ---------------------------------------------------------------------------------------
2516 // Play a DirectSound secondary buffer.
2520 // sid => software id of sound
2521 // hid => hardware id of sound ( -1 if not in hardware )
2522 // snd_id => what kind of sound this is
2523 // priority => DS_MUST_PLAY
2527 // volume => volume of sound effect in DirectSound units
2528 // pan => pan of sound in DirectSound units
2529 // looping => whether the sound effect is looping or not
2531 // returns: -1 => sound effect could not be started
2532 // >=0 => sig for sound effect successfully started
2534 int ds_play(int sid, int hid, int snd_id, int priority, int volume, int pan, int looping, bool is_voice_msg)
2539 if (!ds_initialized)
2542 channel = ds_get_free_channel(volume, snd_id, priority);
2545 if ( Channels[channel].source_id == 0 ) {
2549 if ( ds_using_ds3d() ) {
2553 Channels[channel].vol = volume;
2554 Channels[channel].looping = looping;
2555 Channels[channel].priority = priority;
2557 // set new position for pan or zero out if none
2558 ALfloat alpan = (float)pan / MAX_PAN;
2561 alSource3f(Channels[channel].source_id, AL_POSITION, alpan, 0.0, 1.0);
2563 alSource3f(Channels[channel].source_id, AL_POSITION, 0.0, 0.0, 0.0);
2566 OpenAL_ErrorCheck();
2568 alSource3f(Channels[channel].source_id, AL_VELOCITY, 0.0, 0.0, 0.0);
2570 OpenAL_ErrorCheck();
2572 alSourcef(Channels[channel].source_id, AL_PITCH, 1.0);
2574 OpenAL_ErrorCheck();
2576 ALfloat alvol = (volume != -10000) ? pow(10.0, (float)volume / (-600.0 / log10(.5))): 0.0;
2577 alSourcef(Channels[channel].source_id, AL_GAIN, alvol);
2579 Channels[channel].is_voice_msg = is_voice_msg;
2581 OpenAL_ErrorCheck();
2584 alGetSourcei(Channels[channel].source_id, AL_SOURCE_STATE, &status);
2586 OpenAL_ErrorCheck();
2588 if (status == AL_PLAYING)
2589 alSourceStop(Channels[channel].source_id);
2591 OpenAL_ErrorCheck();
2593 alSourcei (Channels[channel].source_id, AL_BUFFER, sound_buffers[sid].buf_id);
2595 OpenAL_ErrorCheck();
2597 alSourcei (Channels[channel].source_id, AL_LOOPING, (looping) ? AL_TRUE : AL_FALSE);
2599 OpenAL_ErrorCheck();
2601 alSourcePlay(Channels[channel].source_id);
2603 OpenAL_ErrorCheck();
2605 sound_buffers[sid].source_id = channel;
2606 Channels[channel].buf_id = sid;
2609 // nprintf(( "Sound", "SOUND ==> Not playing sound requested at volume %.2f\n", ds_get_percentage_vol(volume) ));
2613 Channels[channel].snd_id = snd_id;
2614 Channels[channel].sig = channel_next_sig++;
2615 if (channel_next_sig < 0 ) {
2616 channel_next_sig = 1;
2619 Channels[channel].last_position = 0;
2621 // make sure there aren't any looping voice messages
2622 for (int i=0; i<MAX_CHANNELS; i++) {
2623 if (Channels[i].is_voice_msg == true) {
2624 if (Channels[i].source_id == 0) {
2628 DWORD current_position = ds_get_play_position(i);
2629 if (current_position != 0) {
2630 if (current_position < (DWORD)Channels[i].last_position) {
2633 Channels[i].last_position = current_position;
2639 return Channels[channel].sig;
2644 if (!ds_initialized)
2647 channel = ds_get_free_channel(volume, snd_id, priority);
2650 if ( Channels[channel].pdsb != NULL ) {
2654 // First check if the sound is in hardware, and try to duplicate from there
2657 if ( ds_channel_dup(ds_hardware_buffers[hid].pdsb, channel, 0) == 0 ) {
2658 // nprintf(("Sound", "SOUND ==> Played sound in hardware..\n"));
2662 // Channel will be NULL if hardware dup failed, or there was no hardware dup attempted
2663 if ( Channels[channel].pdsb == NULL ) {
2664 if ( ds_channel_dup(ds_software_buffers[sid].pdsb, channel, 0) == 0 ) {
2665 // nprintf(("Sound", "SOUND ==> Played sound in software..\n"));
2669 if ( Channels[channel].pdsb == NULL ) {
2673 if ( ds_using_ds3d() ) {
2674 if ( ds_is_3d_buffer(Channels[channel].pdsb) ) {
2675 if (Channels[channel].pds3db == NULL) {
2676 ds_get_3d_interface(Channels[channel].pdsb, &Channels[channel].pds3db);
2678 if ( Channels[channel].pds3db ) {
2679 Channels[channel].pds3db->SetMode(DS3DMODE_DISABLE,DS3D_IMMEDIATE);
2685 Channels[channel].vol = volume;
2686 Channels[channel].looping = looping;
2687 Channels[channel].priority = priority;
2688 Channels[channel].pdsb->SetPan(pan);
2689 Channels[channel].pdsb->SetVolume(volume);
2690 Channels[channel].is_voice_msg = is_voice_msg;
2694 ds_flags |= DSBPLAY_LOOPING;
2696 DSResult = Channels[channel].pdsb->Play(0, 0, ds_flags );
2699 if (Stop_logging_sounds == false) {
2701 sprintf(buf, "channel %d, address: %x, ds_flags: %d", channel, Channels[channel].pdsb, ds_flags);
2702 HUD_add_to_scrollback(buf, 3);
2706 if ( DSResult == DSERR_BUFFERLOST ) {
2707 ds_restore_buffer(Channels[channel].pdsb);
2708 DSResult = Channels[channel].pdsb->Play(0, 0, ds_flags );
2711 if ( DSResult != DS_OK ) {
2712 nprintf(("Sound", "Sound ==> Play failed with return value %s\n", get_DSERR_text(DSResult) ));
2717 // nprintf(( "Sound", "SOUND ==> Not playing sound requested at volume %.2f\n", ds_get_percentage_vol(volume) ));
2721 Channels[channel].snd_id = snd_id;
2722 Channels[channel].sig = channel_next_sig++;
2723 if (channel_next_sig < 0 ) {
2724 channel_next_sig = 1;
2728 if (Stop_logging_sounds == false) {
2731 sprintf(buf, "VOICE sig: %d, sid: %d, snd_id: %d, ch: %d", Channels[channel].sig, sid, snd_id, channel);
2732 HUD_add_to_scrollback(buf, 3);
2737 Channels[channel].last_position = 0;
2739 // make sure there aren't any looping voice messages
2740 for (int i=0; i<MAX_CHANNELS; i++) {
2741 if (Channels[i].is_voice_msg == true) {
2742 if (Channels[i].pdsb == NULL) {
2746 DWORD current_position = ds_get_play_position(i);
2747 if (current_position != 0) {
2748 if (current_position < Channels[i].last_position) {
2749 ds_close_channel(i);
2751 Channels[i].last_position = current_position;
2757 return Channels[channel].sig;
2762 // ---------------------------------------------------------------------------------------
2765 // Return the channel number that is playing the sound identified by sig. If that sound is
2766 // not playing, return -1.
2768 int ds_get_channel(int sig)
2773 for ( i = 0; i < MAX_CHANNELS; i++ ) {
2774 if ( Channels[i].source_id && Channels[i].sig == sig ) {
2775 if ( ds_is_channel_playing(i) == TRUE ) {
2785 for ( i = 0; i < MAX_CHANNELS; i++ ) {
2786 if ( Channels[i].pdsb && Channels[i].sig == sig ) {
2787 if ( ds_is_channel_playing(i) == TRUE ) {
2796 // ---------------------------------------------------------------------------------------
2797 // ds_is_channel_playing()
2800 int ds_is_channel_playing(int channel)
2803 if ( Channels[channel].source_id != 0 ) {
2806 alGetSourcei(Channels[channel].source_id, AL_SOURCE_STATE, &status);
2807 OpenAL_ErrorCheck();
2809 return (status == AL_PLAYING);
2815 unsigned long status;
2817 if ( !Channels[channel].pdsb ) {
2821 hr = Channels[channel].pdsb->GetStatus(&status);
2822 if ( hr != DS_OK ) {
2823 nprintf(("Sound", "SOUND ==> GetStatus failed with return value %s\n", get_DSERR_text(hr) ));
2827 if ( status & DSBSTATUS_PLAYING )
2834 // ---------------------------------------------------------------------------------------
2835 // ds_stop_channel()
2838 void ds_stop_channel(int channel)
2841 if ( Channels[channel].source_id != 0 ) {
2842 alSourceStop(Channels[channel].source_id);
2845 ds_close_channel(channel);
2849 // ---------------------------------------------------------------------------------------
2850 // ds_stop_channel_all()
2853 void ds_stop_channel_all()
2858 for ( i=0; i<MAX_CHANNELS; i++ ) {
2859 if ( Channels[i].source_id != 0 ) {
2860 alSourceStop(Channels[i].source_id);
2866 for ( i=0; i<MAX_CHANNELS; i++ ) {
2867 if ( Channels[i].pdsb != NULL ) {
2874 // ---------------------------------------------------------------------------------------
2877 // Set the volume for a channel. The volume is expected to be in DirectSound units
2879 // If the sound is a 3D sound buffer, this is like re-establishing the maximum
2882 void ds_set_volume( int channel, int vol )
2885 ALuint source_id = Channels[channel].source_id;
2887 if (source_id != 0) {
2888 ALfloat alvol = (vol != -10000) ? pow(10.0, (float)vol / (-600.0 / log10(.5))): 0.0;
2890 alSourcef(source_id, AL_GAIN, alvol);
2894 unsigned long status;
2896 hr = Channels[channel].pdsb->GetStatus(&status);
2897 if ( hr != DS_OK ) {
2898 nprintf(("Sound", "SOUND ==> GetStatus failed with return value %s\n", get_DSERR_text(hr) ));
2902 if ( status & DSBSTATUS_PLAYING ) {
2903 Channels[channel].pdsb->SetVolume(vol);
2908 // ---------------------------------------------------------------------------------------
2911 // Set the pan for a channel. The pan is expected to be in DirectSound units
2913 void ds_set_pan( int channel, int pan )
2918 alGetSourcei(Channels[channel].source_id, AL_SOURCE_STATE, &state);
2920 if (state == AL_PLAYING) {
2921 ALfloat alpan = (pan != 0) ? ((float)pan / MAX_PAN) : 0.0;
2922 alSource3f(Channels[channel].source_id, AL_POSITION, alpan, 0.0, 1.0);
2926 unsigned long status;
2928 hr = Channels[channel].pdsb->GetStatus(&status);
2929 if ( hr != DS_OK ) {
2930 nprintf(("Sound", "SOUND ==> GetStatus failed with return value %s\n", get_DSERR_text(hr) ));
2934 if ( status & DSBSTATUS_PLAYING ) {
2935 Channels[channel].pdsb->SetPan(pan);
2940 // ---------------------------------------------------------------------------------------
2943 // Get the pitch of a channel
2945 int ds_get_pitch(int channel)
2949 ALfloat alpitch = 0;
2952 alGetSourcei(Channels[channel].source_id, AL_SOURCE_STATE, &status);
2954 if (status == AL_PLAYING)
2955 alGetSourcef(Channels[channel].source_id, AL_PITCH, &alpitch);
2957 // convert OpenAL values to DirectSound values and return
2958 pitch = fl2i( pow(10.0, (alpitch + 2.0)) );
2962 unsigned long status, pitch = 0;
2965 hr = Channels[channel].pdsb->GetStatus(&status);
2967 if ( hr != DS_OK ) {
2968 nprintf(("Sound", "SOUND ==> GetStatus failed with return value %s\n", get_DSERR_text(hr) ));
2972 if ( status & DSBSTATUS_PLAYING ) {
2973 hr = Channels[channel].pdsb->GetFrequency(&pitch);
2974 if ( hr != DS_OK ) {
2975 nprintf(("Sound", "SOUND ==> GetFrequency failed with return value %s\n", get_DSERR_text(hr) ));
2984 // ---------------------------------------------------------------------------------------
2987 // Set the pitch of a channel
2989 void ds_set_pitch(int channel, int pitch)
2994 if ( pitch < MIN_PITCH )
2997 if ( pitch > MAX_PITCH )
3000 alGetSourcei(Channels[channel].source_id, AL_SOURCE_STATE, &status);
3002 if (status == AL_PLAYING) {
3003 ALfloat alpitch = log10(pitch) - 2.0;
3004 alSourcef(Channels[channel].source_id, AL_PITCH, alpitch);
3007 unsigned long status;
3010 hr = Channels[channel].pdsb->GetStatus(&status);
3011 if ( hr != DS_OK ) {
3012 nprintf(("Sound", "SOUND ==> GetStatus failed with return value %s\n", get_DSERR_text(hr) ));
3016 if ( pitch < MIN_PITCH )
3019 if ( pitch > MAX_PITCH )
3022 if ( status & DSBSTATUS_PLAYING ) {
3023 Channels[channel].pdsb->SetFrequency((unsigned long)pitch);
3028 // ---------------------------------------------------------------------------------------
3029 // ds_chg_loop_status()
3032 void ds_chg_loop_status(int channel, int loop)
3035 ALuint source_id = Channels[channel].source_id;
3037 alSourcei(source_id, AL_LOOPING, loop ? AL_TRUE : AL_FALSE);
3039 unsigned long status;
3042 hr = Channels[channel].pdsb->GetStatus(&status);
3043 if ( hr != DS_OK ) {
3044 nprintf(("Sound", "SOUND ==> GetStatus failed with return value %s\n", get_DSERR_text(hr) ));
3048 if ( !(status & DSBSTATUS_PLAYING) )
3049 return; // sound is not playing anymore
3051 if ( status & DSBSTATUS_LOOPING ) {
3053 return; // we are already looping
3055 // stop the sound from looping
3056 hr = Channels[channel].pdsb->Play(0,0,0);
3061 return; // the sound is already not looping
3063 // start the sound looping
3064 hr = Channels[channel].pdsb->Play(0,0,DSBPLAY_LOOPING);
3070 // ---------------------------------------------------------------------------------------
3073 // Starts a ds3d sound playing
3077 // sid => software id for sound to play
3078 // hid => hardware id for sound to play (-1 if not in hardware)
3079 // snd_id => identifies what type of sound is playing
3080 // pos => world pos of sound
3081 // vel => velocity of object emitting sound
3082 // min => distance at which sound doesn't get any louder
3083 // max => distance at which sound becomes inaudible
3084 // looping => boolean, whether to loop the sound or not
3085 // max_volume => volume (-10000 to 0) for 3d sound at maximum
3086 // estimated_vol => manual estimated volume
3087 // priority => DS_MUST_PLAY
3092 // returns: 0 => sound started successfully
3093 // -1 => sound could not be played
3095 int ds3d_play(int sid, int hid, int snd_id, vector *pos, vector *vel, int min, int max, int looping, int max_volume, int estimated_vol, int priority )
3105 if (!ds_initialized)
3108 channel = ds_get_free_channel(estimated_vol, snd_id, priority);
3111 Assert(Channels[channel].pdsb == NULL);
3113 // First check if the sound is in hardware, and try to duplicate from there
3116 if ( ds_is_3d_buffer(ds_hardware_buffers[hid].pdsb) == FALSE ) {
3117 nprintf(("Sound", "SOUND ==> Tried to play non-3d buffer in ds3d_play()..\n"));
3121 if ( ds_channel_dup(ds_hardware_buffers[hid].pdsb, channel, 1) == 0 ) {
3122 nprintf(("Sound", "SOUND ==> Played sound using DirectSound3D in hardware..\n"));
3126 // Channel will be NULL if hardware dup failed, or there was no hardware dup attempted
3127 if ( Channels[channel].pdsb == NULL ) {
3130 if ( ds_is_3d_buffer(ds_software_buffers[sid].pdsb) == FALSE ) {
3131 nprintf(("Sound", "SOUND ==> Tried to play non-3d buffer in ds3d_play()..\n"));
3136 if ( ds_channel_dup(ds_software_buffers[sid].pdsb, channel, 1) == 0 ) {
3137 // nprintf(("Sound", "SOUND ==> Played sound using DirectSound3D \n"));
3141 if ( Channels[channel].pdsb == NULL ) {
3146 desc = ds_software_buffers[sid].desc;
3147 desc.lpwfxFormat = &ds_software_buffers[sid].wfx;
3149 // duplicate buffer failed, so call CreateBuffer instead
3151 hr = pDirectSound->CreateSoundBuffer(&desc, &Channels[channel].pdsb, NULL );
3153 if ( (hr == DS_OK) && (Channels[channel].pdsb) ) {
3154 BYTE *pdest, *pdest2;
3156 DWORD src_ds_size, dest_ds_size, not_used;
3159 if ( ds_get_size(sid, &src_size) != 0 ) {
3161 Channels[channel].pdsb->Release();
3165 // lock the src buffer
3166 hr = ds_software_buffers[sid].pdsb->Lock(0, src_size, (void**)&psrc, &src_ds_size, (void**)&psrc2, ¬_used, 0);
3167 if ( hr != DS_OK ) {
3168 mprintf(("err: %s\n", get_DSERR_text(hr)));
3170 Channels[channel].pdsb->Release();
3174 if ( Channels[channel].pdsb->Lock(0, src_ds_size, (void**)(&pdest), &dest_ds_size, (void**)&pdest2, ¬_used, 0) == DS_OK) {
3175 memcpy(pdest, psrc, src_ds_size);
3176 Channels[channel].pdsb->Unlock(pdest, dest_ds_size, 0, 0);
3177 ds_get_3d_interface(Channels[channel].pdsb, &Channels[channel].pds3db);
3179 Channels[channel].pdsb->Release();
3186 Assert(Channels[channel].pds3db );
3187 Channels[channel].pds3db->SetMode(DS3DMODE_NORMAL,DS3D_IMMEDIATE);
3189 // set up 3D sound data here
3190 ds3d_update_buffer(channel, i2fl(min), i2fl(max), pos, vel);
3192 Channels[channel].vol = estimated_vol;
3193 Channels[channel].looping = looping;
3195 // sets the maximum "inner cone" volume
3196 Channels[channel].pdsb->SetVolume(max_volume);
3200 ds_flags |= DSBPLAY_LOOPING;
3203 hr = Channels[channel].pdsb->Play(0, 0, ds_flags );
3205 if ( hr == DSERR_BUFFERLOST ) {
3206 ds_restore_buffer(Channels[channel].pdsb);
3207 hr = Channels[channel].pdsb->Play(0, 0, ds_flags );
3210 if ( hr != DS_OK ) {
3211 nprintf(("Sound", "Sound ==> Play failed with return value %s\n", get_DSERR_text(hr) ));
3212 if ( Channels[channel].pdsb ) {
3214 while(++attempts < 10) {
3215 hr = Channels[channel].pdsb->Release();
3216 if ( hr == DS_OK ) {
3219 nprintf(("Sound","SOUND ==> DirectSound Release() failed with code %s\n.",get_DSERR_text(hr) ));
3223 Channels[channel].pdsb = NULL;
3229 nprintf(( "Sound", "SOUND ==> Not playing requested 3D sound\n"));
3233 Channels[channel].snd_id = snd_id;
3234 Channels[channel].sig = channel_next_sig++;
3235 if (channel_next_sig < 0 ) {
3236 channel_next_sig = 1;
3238 return Channels[channel].sig;
3242 void ds_set_position(int channel, DWORD offset)
3247 // set the position of the sound buffer
3248 Channels[channel].pdsb->SetCurrentPosition(offset);
3252 DWORD ds_get_play_position(int channel)
3257 if (!AL_play_position)
3260 alGetSourcei(Channels[channel].source_id, AL_BYTE_LOKI, &pos);
3268 if ( Channels[channel].pdsb ) {
3269 Channels[channel].pdsb->GetCurrentPosition((LPDWORD)&play,(LPDWORD)&write);
3278 DWORD ds_get_write_position(int channel)
3286 if ( Channels[channel].pdsb ) {
3287 Channels[channel].pdsb->GetCurrentPosition((LPDWORD)&play,(LPDWORD)&write);
3296 int ds_get_channel_size(int channel)
3299 int buf_id = Channels[channel].buf_id;
3302 return sound_buffers[buf_id].nbytes;
3311 if ( Channels[channel].pdsb ) {
3312 memset(&caps, 0, sizeof(DSBCAPS));
3313 caps.dwSize = sizeof(DSBCAPS);
3314 dsrval = Channels[channel].pdsb->GetCaps(&caps);
3315 if ( dsrval != DS_OK ) {
3318 size = caps.dwBufferBytes;
3327 // Returns the number of channels that are actually playing
3328 int ds_get_number_channels()
3333 if (!ds_initialized) {
3338 for ( i = 0; i < MAX_CHANNELS; i++ ) {
3339 if ( Channels[i].source_id ) {
3340 if ( ds_is_channel_playing(i) == TRUE ) {
3351 for ( i = 0; i < MAX_CHANNELS; i++ ) {
3352 if ( Channels[i].pdsb ) {
3353 if ( ds_is_channel_playing(i) == TRUE ) {
3363 // retreive raw data from a sound buffer
3364 int ds_get_data(int sid, char *data)
3372 LPDIRECTSOUNDBUFFER pdsb;
3378 pdsb = ds_software_buffers[sid].pdsb;
3380 memset(&caps, 0, sizeof(DSBCAPS));
3381 caps.dwSize = sizeof(DSBCAPS);
3382 dsrval = pdsb->GetCaps(&caps);
3383 if ( dsrval != DS_OK ) {
3387 // lock the entire buffer
3388 dsrval = pdsb->Lock(0, caps.dwBufferBytes, &buffer_data, &buffer_size, 0, 0, 0);
3389 if ( dsrval != DS_OK ) {
3393 memcpy(data, buffer_data, buffer_size);
3395 dsrval = pdsb->Unlock(buffer_data, buffer_size, 0, 0);
3396 if ( dsrval != DS_OK ) {
3404 // return the size of the raw sound data
3405 int ds_get_size(int sid, int *size)
3415 LPDIRECTSOUNDBUFFER pdsb;
3419 pdsb = ds_software_buffers[sid].pdsb;
3421 memset(&caps, 0, sizeof(DSBCAPS));
3422 caps.dwSize = sizeof(DSBCAPS);
3423 dsrval = pdsb->GetCaps(&caps);
3424 if ( dsrval != DS_OK ) {
3428 *size = caps.dwBufferBytes;
3437 // Return the primary buffer interface. Note that we cast to a uint to avoid
3438 // having to include dsound.h (and thus windows.h) in ds.h.
3440 uint ds_get_primary_buffer_interface()
3446 return (uint)pPrimaryBuffer;
3450 // Return the DirectSound Interface.
3452 uint ds_get_dsound_interface()
3458 return (uint)pDirectSound;
3462 uint ds_get_property_set_interface()
3467 return (uint)pPropertySet;
3471 // --------------------
3473 // EAX Functions below
3475 // --------------------
3477 // Set the master volume for the reverb added to all sound sources.
3479 // volume: volume, range from 0 to 1.0
3481 // returns: 0 if the volume is set successfully, otherwise return -1
3483 int ds_eax_set_volume(float volume)
3490 if (Ds_eax_inited == 0) {
3494 Assert(Ds_eax_reverb);
3496 CAP(volume, 0.0f, 1.0f);
3498 hr = Ds_eax_reverb->Set(DSPROPSETID_EAX_ReverbProperties_Def, DSPROPERTY_EAX_VOLUME, NULL, 0, &volume, sizeof(float));
3499 if (SUCCEEDED(hr)) {
3507 // Set the decay time for the EAX environment (ie all sound sources)
3509 // seconds: decay time in seconds
3511 // returns: 0 if decay time is successfully set, otherwise return -1
3513 int ds_eax_set_decay_time(float seconds)
3520 if (Ds_eax_inited == 0) {
3524 Assert(Ds_eax_reverb);
3526 CAP(seconds, 0.1f, 20.0f);
3528 hr = Ds_eax_reverb->Set(DSPROPSETID_EAX_ReverbProperties_Def, DSPROPERTY_EAX_DECAYTIME, NULL, 0, &seconds, sizeof(float));
3529 if (SUCCEEDED(hr)) {
3537 // Set the damping value for the EAX environment (ie all sound sources)
3539 // damp: damp value from 0 to 2.0
3541 // returns: 0 if the damp value is successfully set, otherwise return -1
3543 int ds_eax_set_damping(float damp)
3550 if (Ds_eax_inited == 0) {
3554 Assert(Ds_eax_reverb);
3556 CAP(damp, 0.0f, 2.0f);
3558 hr = Ds_eax_reverb->Set(DSPROPSETID_EAX_ReverbProperties_Def, DSPROPERTY_EAX_DAMPING, NULL, 0, &damp, sizeof(float));
3559 if (SUCCEEDED(hr)) {
3567 // Set up the environment type for all sound sources.
3569 // envid: value from the EAX_ENVIRONMENT_* enumeration in ds_eax.h
3571 // returns: 0 if the environment is set successfully, otherwise return -1
3573 int ds_eax_set_environment(unsigned long envid)
3580 if (Ds_eax_inited == 0) {
3584 Assert(Ds_eax_reverb);
3586 hr = Ds_eax_reverb->Set(DSPROPSETID_EAX_ReverbProperties_Def, DSPROPERTY_EAX_ENVIRONMENT, NULL, 0, &envid, sizeof(unsigned long));
3587 if (SUCCEEDED(hr)) {
3595 // Set up a predefined environment for EAX
3597 // envid: value from teh EAX_ENVIRONMENT_* enumeration
3599 // returns: 0 if successful, otherwise return -1
3601 int ds_eax_set_preset(unsigned long envid)
3608 if (Ds_eax_inited == 0) {
3612 Assert(Ds_eax_reverb);
3613 Assert(envid < EAX_ENVIRONMENT_COUNT);
3615 hr = Ds_eax_reverb->Set(DSPROPSETID_EAX_ReverbProperties_Def, DSPROPERTY_EAX_ALL, NULL, 0, &Ds_eax_presets[envid], sizeof(EAX_REVERBPROPERTIES));
3616 if (SUCCEEDED(hr)) {
3625 // Set up all the parameters for an environment
3627 // id: value from teh EAX_ENVIRONMENT_* enumeration
3628 // volume: volume for the environment (0 to 1.0)
3629 // damping: damp value for the environment (0 to 2.0)
3630 // decay: decay time in seconds (0.1 to 20.0)
3632 // returns: 0 if successful, otherwise return -1
3634 int ds_eax_set_all(unsigned long id, float vol, float damping, float decay)
3641 if (Ds_eax_inited == 0) {
3645 Assert(Ds_eax_reverb);
3646 Assert(id < EAX_ENVIRONMENT_COUNT);
3648 EAX_REVERBPROPERTIES er;
3650 er.environment = id;
3652 er.fDecayTime_sec = decay;
3653 er.fDamping = damping;
3655 hr = Ds_eax_reverb->Set(DSPROPSETID_EAX_ReverbProperties_Def, DSPROPERTY_EAX_ALL, NULL, 0, &er, sizeof(EAX_REVERBPROPERTIES));
3656 if (SUCCEEDED(hr)) {
3664 // Get up the parameters for the current environment
3666 // er: (output) hold environment parameters
3668 // returns: 0 if successful, otherwise return -1
3670 int ds_eax_get_all(EAX_REVERBPROPERTIES *er)
3676 unsigned long outsize;
3678 if (Ds_eax_inited == 0) {
3682 Assert(Ds_eax_reverb);
3684 hr = Ds_eax_reverb->Get(DSPROPSETID_EAX_ReverbProperties_Def, DSPROPERTY_EAX_ALL, NULL, 0, er, sizeof(EAX_REVERBPROPERTIES), &outsize);
3685 if (SUCCEEDED(hr)) {
3693 // Close down EAX, freeing any allocated resources
3698 if (Ds_eax_inited == 0) {
3708 // returns: 0 if initialization is successful, otherwise return -1
3714 unsigned long driver_support = 0;
3716 if (Ds_eax_inited) {
3720 Assert(Ds_eax_reverb == NULL);
3722 Ds_eax_reverb = (LPKSPROPERTYSET)ds_get_property_set_interface();
3723 if (Ds_eax_reverb == NULL) {
3727 // check if the listener property is supported by the audio driver
3728 hr = Ds_eax_reverb->QuerySupport(DSPROPSETID_EAX_ReverbProperties_Def, DSPROPERTY_EAX_ALL, &driver_support);
3730 nprintf(("Sound", "QuerySupport for the EAX Listener property set failed.. disabling EAX\n"));
3731 goto ds_eax_init_failed;
3734 if ((driver_support & (KSPROPERTY_SUPPORT_GET | KSPROPERTY_SUPPORT_SET)) != (KSPROPERTY_SUPPORT_GET | KSPROPERTY_SUPPORT_SET)) {
3735 goto ds_eax_init_failed;
3738 ds_eax_set_all(EAX_ENVIRONMENT_GENERIC, 0.0f, 0.0f, 0.0f);
3744 if (Ds_eax_reverb != NULL) {
3745 Ds_eax_reverb->Release();
3746 Ds_eax_reverb = NULL;
3755 int ds_eax_is_inited()
3760 return Ds_eax_inited;
3769 if (Ds_use_a3d == 0) {
3777 // Called once per game frame to make sure voice messages aren't looping
3783 if (!ds_initialized) {
3787 for (int i=0; i<MAX_CHANNELS; i++) {
3789 if (cp->is_voice_msg == true) {
3790 if (cp->source_id == 0) {
3794 DWORD current_position = ds_get_play_position(i);
3795 if (current_position != 0) {
3796 if (current_position < (DWORD)cp->last_position) {
3800 ds_close_channel(i);
3803 cp->last_position = current_position;
3816 int ds3d_update_buffer(int channel, float min, float max, vector *pos, vector *vel)
3823 int ds3d_update_listener(vector *pos, vector *vel, matrix *orient)
3828 ALfloat posv[] = { pos->x, pos->y, pos->z };
3829 ALfloat velv[] = { vel->x, vel->y, vel->z };
3830 ALfloat oriv[] = { orient->a1d[0],
3831 orient->a1d[1], orient->a1d[2],
3832 orient->a1d[3], orient->a1d[4],
3834 alListenerfv(AL_POSITION, posv);
3835 alListenerfv(AL_VELOCITY, velv);
3836 alListenerfv(AL_ORIENTATION, oriv);
3842 int ds3d_init (int unused)
3847 ALfloat pos[] = { 0.0, 0.0, 0.0 },
3848 vel[] = { 0.0, 0.0, 0.0 },
3849 ori[] = { 0.0, 0.0, 1.0, 0.0, -1.0, 0.0 };
3851 alListenerfv (AL_POSITION, pos);
3852 alListenerfv (AL_VELOCITY, vel);
3853 alListenerfv (AL_ORIENTATION, ori);
3855 if(alGetError() != AL_NO_ERROR)
3869 int dscap_create_buffer(int freq, int bits_per_sample, int nchannels, int nseconds)
3876 int dscap_get_raw_data(unsigned char *outbuf, unsigned int max_size)
3883 int dscap_max_buffersize()
3890 void dscap_release_buffer()
3895 int dscap_start_record()
3902 int dscap_stop_record()
3909 int dscap_supported()