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.27 2005/11/18 09:36:13 taylor
19 * gah, should have been paying more attention there
21 * Revision 1.26 2005/11/14 05:22:08 taylor
22 * patch from mailing list (courtesy of fatty) to allow compling with both OpenAL 1.0 and 1.1
24 * Revision 1.25 2005/10/01 21:53:06 taylor
25 * include file cleanup
26 * byte-swap streaming PCM to avoid the endless, loud, static
28 * Revision 1.24 2005/08/13 17:01:34 taylor
29 * gah, fix stupid commit message
31 * Revision 1.23 2005/08/12 20:21:06 taylor
34 * Revision 1.22 2005/08/12 08:47:24 taylor
35 * use new audiostr code rather than old windows and *nix version
36 * update all OpenAL commands with new error checking macros
37 * fix play_position to properly account for real position, fixes the talking heads and message text cutting out early
38 * movies will now use better filtering when scaled
40 * Revision 1.21 2005/04/02 18:57:01 taylor
41 * little better error handling, debug output of OpenAL info
43 * Revision 1.20 2005/03/29 07:50:34 taylor
44 * Update to newest movie code with much better video support and audio support from
45 * Pierre Willenbrock. Movies are enabled always now (no longer a build option)
46 * and but can be skipped with the "--nomovies" or "-n" cmdline options.
48 * Revision 1.19 2004/07/04 11:39:06 taylor
49 * fix missing debrief text, crash on exit, path separator's, warning fixes, no GR_SOFT
51 * Revision 1.18 2004/06/11 02:07:01 tigital
52 * byte-swapping changes for bigendian systems
54 * Revision 1.17 2003/12/02 03:24:47 taylor
55 * MS-ADPCM support, fix file parser with OSX support
57 * Revision 1.16 2003/08/03 16:03:53 taylor
58 * working play position; 2D pan; pitch; cleanup
60 * Revision 1.15 2003/03/15 05:12:56 theoddone33
61 * Fix OpenAL cleanup (Taylor)
63 * Revision 1.14 2002/08/01 04:55:45 relnev
64 * experimenting with texture state
66 * Revision 1.13 2002/07/30 05:24:38 relnev
69 * Revision 1.12 2002/07/28 05:19:44 relnev
72 * Revision 1.11 2002/06/16 01:43:23 relnev
73 * fixed demo dogfight multiplayer mission
77 * Revision 1.10 2002/06/09 04:41:26 relnev
78 * added copyright header
80 * Revision 1.9 2002/06/05 08:05:29 relnev
81 * stub/warning removal.
83 * reworked the sound code.
85 * Revision 1.8 2002/06/05 04:03:33 relnev
86 * finished cfilesystem.
88 * removed some old code.
90 * fixed mouse save off-by-one.
94 * Revision 1.7 2002/06/02 22:31:37 cemason
97 * Revision 1.6 2002/06/02 21:11:12 cemason
100 * Revision 1.5 2002/06/02 09:50:42 relnev
103 * Revision 1.4 2002/06/02 07:17:44 cemason
104 * Added OpenAL support.
106 * Revision 1.3 2002/05/28 17:03:29 theoddone33
107 * fs2 gets to the main game loop now
109 * Revision 1.2 2002/05/27 21:35:50 theoddone33
110 * Stub out dsound backend
112 * Revision 1.1.1.1 2002/05/03 03:28:10 root
116 * 18 10/25/99 5:56p Jefff
117 * increase num software channels to the number the users hardware can
118 * handle. not less than 16, tho.
120 * 17 9/08/99 3:22p Dave
121 * Updated builtin mission list.
123 * 16 8/27/99 6:38p Alanl
124 * crush the blasted repeating messages bug
126 * 15 8/23/99 11:16p Danw
129 * 14 8/22/99 11:06p Alanl
130 * fix small bug in ds_close_channel
132 * 13 8/19/99 11:25a Alanl
133 * change format of secondary buffer from 44100 to 22050
135 * 12 8/17/99 4:11p Danw
136 * AL: temp fix for solving A3D crash
138 * 11 8/06/99 2:20p Jasonh
139 * AL: free 3D portion of buffer first
141 * 10 8/04/99 9:48p Alanl
142 * fix bug with setting 3D properties on a 2D sound buffer
144 * 9 8/04/99 11:42a Danw
145 * tone down EAX reverb
147 * 8 8/01/99 2:06p Alanl
148 * increase the rolloff for A3D
150 * 7 7/20/99 5:28p Dave
151 * Fixed debug build error.
153 * 6 7/20/99 1:49p Dave
154 * Peter Drake build. Fixed some release build warnings.
156 * 5 7/14/99 11:32a Danw
157 * AL: add some debug code to catch nefarious A3D problem
159 * 4 5/23/99 8:11p Alanl
160 * Added support for EAX
162 * 3 10/08/98 4:29p Dave
163 * Removed reference to osdefs.h
165 * 2 10/07/98 10:54a Dave
168 * 1 10/07/98 10:51a Dave
170 * 72 6/28/98 6:34p Lawrance
171 * add sanity check in while() loop for releasing channels
173 * 71 6/13/98 1:45p Sandeep
175 * 70 6/10/98 2:29p Lawrance
176 * don't use COM for initializing DirectSound... appears some machines
179 * 69 5/26/98 2:10a Lawrance
180 * make sure DirectSound pointer gets freed if Aureal resource manager
183 * 68 5/21/98 9:14p Lawrance
184 * remove obsolete registry setting
186 * 67 5/20/98 4:28p Allender
187 * upped sound buffers as per alan's request
189 * 66 5/15/98 3:36p John
190 * Fixed bug with new graphics window code and standalone server. Made
191 * hwndApp not be a global anymore.
193 * 65 5/06/98 3:37p Lawrance
194 * allow panned sounds geesh
196 * 64 5/05/98 4:49p Lawrance
197 * Put in code to authenticate A3D, improve A3D support
199 * 63 4/20/98 11:17p Lawrance
200 * fix bug with releasing channels
202 * 62 4/20/98 7:34p Lawrance
203 * take out obsolete directsound3d debug command
205 * 61 4/20/98 11:10a Lawrance
206 * put correct flags when creating sound buffer
208 * 60 4/20/98 12:03a Lawrance
209 * Allow prioritizing of CTRL3D buffers
211 * 59 4/19/98 9:31p Lawrance
212 * Use Aureal_enabled flag
214 * 58 4/19/98 9:39a Lawrance
215 * use DYNAMIC_LOOPERS for Aureal resource manager
217 * 57 4/19/98 4:13a Lawrance
218 * Improve how dsound is initialized
220 * 56 4/18/98 9:13p Lawrance
221 * Added Aureal support.
223 * 55 4/13/98 5:04p Lawrance
224 * Write functions to determine how many milliseconds are left in a sound
226 * 54 4/09/98 5:53p Lawrance
227 * Make DirectSound init more robust
229 * 53 4/01/98 9:21p John
230 * Made NDEBUG, optimized build with no warnings or errors.
232 * 52 3/31/98 5:19p John
233 * Removed demo/save/restore. Made NDEBUG defined compile. Removed a
234 * bunch of debug stuff out of player file. Made model code be able to
235 * unload models and malloc out only however many models are needed.
238 * 51 3/29/98 12:56a Lawrance
239 * preload the warp in and explosions sounds before a mission.
241 * 50 3/25/98 6:10p Lawrance
242 * Work on DirectSound3D
244 * 49 3/24/98 4:28p Lawrance
245 * Make DirectSound3D support more robust
247 * 48 3/24/98 11:49a Dave
248 * AL: Change way buffer gets locked.
250 * 47 3/24/98 11:27a Lawrance
251 * Use buffer_size for memcpy when locking buffer
253 * 46 3/23/98 10:32a Lawrance
254 * Add functions for extracting raw sound data
256 * 45 3/19/98 5:36p Lawrance
257 * Add some sound debug functions to see how many sounds are playing, and
258 * to start/stop random looping sounds.
260 * 44 3/07/98 3:35p Dave
261 * AL: check for ds being initialized in ds_create_buffer()
263 * 43 2/18/98 5:49p Lawrance
264 * Even if the ADPCM codec is unavailable, allow game to continue.
266 * 42 2/16/98 7:31p Lawrance
267 * get compression/decompression of voice working
269 * 41 2/15/98 11:10p Lawrance
270 * more work on real-time voice system
272 * 40 2/15/98 4:43p Lawrance
273 * work on real-time voice
275 * 39 2/06/98 7:30p John
276 * Added code to monitor the number of channels of sound actually playing.
278 * 38 2/06/98 8:56a Allender
279 * fixed calling convention problem with DLL handles
281 * 37 2/04/98 6:08p Lawrance
282 * Read function pointers from dsound.dll, further work on
283 * DirectSoundCapture.
285 * 36 2/03/98 11:53p Lawrance
286 * Adding support for DirectSoundCapture
288 * 35 1/31/98 5:48p Lawrance
289 * Start on real-time voice recording
291 * 34 1/10/98 1:14p John
292 * Added explanation to debug console commands
294 * 33 12/21/97 4:33p John
295 * Made debug console functions a class that registers itself
296 * automatically, so you don't need to add the function to
297 * debugfunctions.cpp.
299 * 32 12/08/97 12:24a Lawrance
300 * Allow duplicate sounds to be stopped if less than OR equal to new sound
303 * 31 12/05/97 5:19p Lawrance
304 * re-do sound priorities to make more general and extensible
306 * 30 11/28/97 2:09p Lawrance
307 * Overhaul how ADPCM conversion works... use much less memory... safer
310 * 29 11/22/97 11:32p Lawrance
311 * decompress ADPCM data into 8 bit (not 16bit) for regular sounds (ie not
314 * 28 11/20/97 5:36p Dave
315 * Hooked in a bunch of main hall changes (including sound). Made it
316 * possible to reposition (rewind/ffwd)
317 * sound buffer pointers. Fixed animation direction change framerate
320 * 27 10/13/97 7:41p Lawrance
321 * store duration of sound
323 * 26 10/11/97 6:39p Lawrance
324 * start playing primary buffer, to reduce latency on sounds starting
326 * 25 10/08/97 5:09p Lawrance
327 * limit player impact sounds so only one plays at a time
329 * 24 9/26/97 5:43p Lawrance
330 * fix a bug that was freeing memory early when playing compressed sound
333 * 23 9/09/97 3:39p Sandeep
334 * warning level 4 bugs
336 * 22 8/16/97 4:05p Lawrance
337 * don't load sounds into hardware if running Lean_and_mean
339 * 21 8/05/97 1:39p Lawrance
340 * support compressed stereo playback
342 * 20 7/31/97 10:38a Lawrance
343 * return old debug function for toggling DirectSound3D
345 * 19 7/29/97 3:27p Lawrance
346 * make console toggle for directsound3d work right
348 * 18 7/28/97 11:39a Lawrance
349 * allow individual volume scaling on 3D buffers
351 * 17 7/18/97 8:18p Lawrance
352 * fix bug in ds_get_free_channel() that caused sounds to not play when
355 * 16 7/17/97 8:04p Lawrance
356 * allow priority sounds to play if free channel, otherwise stop lowest
357 * volume priority sound of same type
359 * 15 7/17/97 5:57p John
360 * made directsound3d config value work
362 * 14 7/17/97 5:43p John
363 * added new config stuff
365 * 13 7/17/97 4:25p John
366 * First, broken, stage of changing config stuff
368 * 12 7/15/97 12:13p Lawrance
369 * don't stop sounds that have highest priority
371 * 11 7/15/97 11:15a Lawrance
372 * limit the max instances of simultaneous sound effects, implement
373 * priorities to force critical sounds
375 * 10 6/09/97 11:50p Lawrance
376 * integrating DirectSound3D
378 * 9 6/08/97 5:59p Lawrance
379 * integrate DirectSound3D into sound system
381 * 8 6/04/97 1:19p Lawrance
382 * made hardware mixing robust
384 * 7 6/03/97 1:56p Hoffoss
385 * Return correct error code when direct sound init fails.
387 * 6 6/03/97 12:07p Lawrance
388 * don't enable 3D sounds in Primary buffer
390 * 5 6/02/97 3:45p Dan
391 * temp disable of hardware mixing until problem solved with
392 * CreateBuffer() failing
394 * 4 6/02/97 1:45p Lawrance
395 * implementing hardware mixing
397 * 3 5/29/97 4:01p Lawrance
398 * let snd_init() have final say on initialization
400 * 2 5/29/97 12:04p Lawrance
401 * creation of file to hold DirectSound specific portions
420 #include <initguid.h>
424 // Pointers to functions contained in DSOUND.dll
425 HRESULT (__stdcall *pfn_DirectSoundCreate)(LPGUID lpGuid, LPDIRECTSOUND *ppDS, IUnknown FAR *pUnkOuter) = NULL;
426 HRESULT (__stdcall *pfn_DirectSoundCaptureCreate)(LPGUID lpGUID, LPDIRECTSOUNDCAPTURE *lplpDSC, LPUNKNOWN pUnkOuter) = NULL;
428 HINSTANCE Ds_dll_handle=NULL;
430 LPDIRECTSOUND pDirectSound = NULL;
431 LPDIRECTSOUNDBUFFER pPrimaryBuffer = NULL;
432 LPIA3D2 pIA3d2 = NULL;
434 static LPKSPROPERTYSET pPropertySet; // pointer to sound card property set
435 static LPDIRECTSOUNDBUFFER Ds_property_set_pdsb = NULL;
436 static LPDIRECTSOUND3DBUFFER Ds_property_set_pds3db = NULL;
438 static int Ds_must_call_couninitialize = 0;
440 channel* Channels; //[MAX_CHANNELS];
441 static int channel_next_sig = 1;
443 #define MAX_DS_SOFTWARE_BUFFERS 256
444 typedef struct ds_sound_buffer
446 LPDIRECTSOUNDBUFFER pdsb;
452 ds_sound_buffer ds_software_buffers[MAX_DS_SOFTWARE_BUFFERS];
454 #define MAX_DS_HARDWARE_BUFFERS 32
455 ds_sound_buffer ds_hardware_buffers[MAX_DS_HARDWARE_BUFFERS];
457 static DSCAPS Soundcard_caps; // current soundcard capabilities
459 extern int Snd_sram; // mem (in bytes) used up by storing sounds in system memory
460 extern int Snd_hram; // mem (in bytes) used up by storing sounds in soundcard memory
462 static int Ds_use_ds3d = 0;
463 static int Ds_use_a3d = 0;
464 static int Ds_use_eax = 0;
466 GUID IID_IA3d2_Def = {0xfb80d1e0, 0x98d3, 0x11d1, {0x90, 0xfb, 0x00, 0x60, 0x08, 0xa1, 0xf4, 0x41}};
467 GUID CLSID_A3d_Def = {0xd8f1eee0, 0xf634, 0x11cf, {0x87, 0x0, 0x0, 0xa0, 0x24, 0x5d, 0x91, 0x8b}};
469 static bool Stop_logging_sounds = false;
472 ///////////////////////////
476 ///////////////////////////
479 //#define EAX_PRESET_GENERIC EAX_ENVIRONMENT_GENERIC,0.5F,1.493F,0.5F
480 #define EAX_PRESET_GENERIC EAX_ENVIRONMENT_GENERIC,0.2F,0.2F,1.0F
481 #define EAX_PRESET_PADDEDCELL EAX_ENVIRONMENT_PADDEDCELL,0.25F,0.1F,0.0F
482 #define EAX_PRESET_ROOM EAX_ENVIRONMENT_ROOM,0.417F,0.4F,0.666F
483 #define EAX_PRESET_BATHROOM EAX_ENVIRONMENT_BATHROOM,0.653F,1.499F,0.166F
484 #define EAX_PRESET_LIVINGROOM EAX_ENVIRONMENT_LIVINGROOM,0.208F,0.478F,0.0F
485 #define EAX_PRESET_STONEROOM EAX_ENVIRONMENT_STONEROOM,0.5F,2.309F,0.888F
486 #define EAX_PRESET_AUDITORIUM EAX_ENVIRONMENT_AUDITORIUM,0.403F,4.279F,0.5F
487 #define EAX_PRESET_CONCERTHALL EAX_ENVIRONMENT_CONCERTHALL,0.5F,3.961F,0.5F
488 #define EAX_PRESET_CAVE EAX_ENVIRONMENT_CAVE,0.5F,2.886F,1.304F
489 #define EAX_PRESET_ARENA EAX_ENVIRONMENT_ARENA,0.361F,7.284F,0.332F
490 #define EAX_PRESET_HANGAR EAX_ENVIRONMENT_HANGAR,0.5F,10.0F,0.3F
491 #define EAX_PRESET_CARPETEDHALLWAY EAX_ENVIRONMENT_CARPETEDHALLWAY,0.153F,0.259F,2.0F
492 #define EAX_PRESET_HALLWAY EAX_ENVIRONMENT_HALLWAY,0.361F,1.493F,0.0F
493 #define EAX_PRESET_STONECORRIDOR EAX_ENVIRONMENT_STONECORRIDOR,0.444F,2.697F,0.638F
494 #define EAX_PRESET_ALLEY EAX_ENVIRONMENT_ALLEY,0.25F,1.752F,0.776F
495 #define EAX_PRESET_FOREST EAX_ENVIRONMENT_FOREST,0.111F,3.145F,0.472F
496 #define EAX_PRESET_CITY EAX_ENVIRONMENT_CITY,0.111F,2.767F,0.224F
497 #define EAX_PRESET_MOUNTAINS EAX_ENVIRONMENT_MOUNTAINS,0.194F,7.841F,0.472F
498 #define EAX_PRESET_QUARRY EAX_ENVIRONMENT_QUARRY,1.0F,1.499F,0.5F
499 #define EAX_PRESET_PLAIN EAX_ENVIRONMENT_PLAIN,0.097F,2.767F,0.224F
500 #define EAX_PRESET_PARKINGLOT EAX_ENVIRONMENT_PARKINGLOT,0.208F,1.652F,1.5F
501 #define EAX_PRESET_SEWERPIPE EAX_ENVIRONMENT_SEWERPIPE,0.652F,2.886F,0.25F
502 #define EAX_PRESET_UNDERWATER EAX_ENVIRONMENT_UNDERWATER,1.0F,1.499F,0.0F
503 #define EAX_PRESET_DRUGGED EAX_ENVIRONMENT_DRUGGED,0.875F,8.392F,1.388F
504 #define EAX_PRESET_DIZZY EAX_ENVIRONMENT_DIZZY,0.139F,17.234F,0.666F
505 #define EAX_PRESET_PSYCHOTIC EAX_ENVIRONMENT_PSYCHOTIC,0.486F,7.563F,0.806F
507 static LPKSPROPERTYSET Ds_eax_reverb = NULL;
509 static int Ds_eax_inited = 0;
511 EAX_REVERBPROPERTIES Ds_eax_presets[] =
513 {EAX_PRESET_GENERIC},
514 {EAX_PRESET_PADDEDCELL},
516 {EAX_PRESET_BATHROOM},
517 {EAX_PRESET_LIVINGROOM},
518 {EAX_PRESET_STONEROOM},
519 {EAX_PRESET_AUDITORIUM},
520 {EAX_PRESET_CONCERTHALL},
524 {EAX_PRESET_CARPETEDHALLWAY},
525 {EAX_PRESET_HALLWAY},
526 {EAX_PRESET_STONECORRIDOR},
530 {EAX_PRESET_MOUNTAINS},
533 {EAX_PRESET_PARKINGLOT},
534 {EAX_PRESET_SEWERPIPE},
535 {EAX_PRESET_UNDERWATER},
536 {EAX_PRESET_DRUGGED},
538 {EAX_PRESET_PSYCHOTIC},
541 GUID DSPROPSETID_EAX_ReverbProperties_Def = {0x4a4e6fc1, 0xc341, 0x11d1, {0xb7, 0x3a, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}};
542 GUID DSPROPSETID_EAXBUFFER_ReverbProperties_Def = {0x4a4e6fc0, 0xc341, 0x11d1, {0xb7, 0x3a, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}};
544 //----------------------------------------------------------------
546 void ds_get_soundcard_caps(DSCAPS *dscaps);
549 typedef struct channel
551 int sig; // uniquely identifies the sound playing on the channel
552 int snd_id; // identifies which kind of sound is playing
553 ALuint source_id; // OpenAL source id
554 int buf_id; // currently bound buffer index (-1 if none)
555 int looping; // flag to indicate that the sound is looping
557 int priority; // implementation dependant priority
562 typedef struct sound_buffer
564 ALuint buf_id; // OpenAL buffer id
565 int source_id; // source index this buffer is currently bound to
574 #define MAX_DS_SOFTWARE_BUFFERS 256
576 static int MAX_CHANNELS = 1000; // initialized properly in ds_init_channels()
578 static int channel_next_sig = 1;
580 sound_buffer sound_buffers[MAX_DS_SOFTWARE_BUFFERS];
582 extern int Snd_sram; // mem (in bytes) used up by storing sounds in system memory
584 static int Ds_use_ds3d = 0;
585 static int Ds_use_a3d = 0;
586 static int Ds_use_eax = 0;
588 static int AL_play_position = 0;
591 // in case it's not defined by older/other drivers
592 #define AL_BYTE_LOKI 0x100C
595 ALCdevice *ds_sound_device = NULL;
596 ALCcontext *ds_sound_context = NULL;
599 //--------------------------------------------------------------------------
600 // openal_error_string()
602 // Returns the human readable error string if there is an error or NULL if not
604 const char* openal_error_string()
610 if ( i != AL_NO_ERROR )
611 return (const char*)alGetString(i);
618 int ds_vol_lookup[101]; // lookup table for direct sound volumes
619 int ds_initialized = FALSE;
622 //--------------------------------------------------------------------------
625 // Determine if a secondary buffer is a 3d secondary buffer.
628 int ds_is_3d_buffer(LPDIRECTSOUNDBUFFER pdsb)
633 dsbc.dwSize = sizeof(dsbc);
634 hr = pdsb->GetCaps(&dsbc);
635 if ( hr == DS_OK && dsbc.dwFlags & DSBCAPS_CTRL3D ) {
644 //--------------------------------------------------------------------------
647 // Determine if a secondary buffer is a 3d secondary buffer.
649 int ds_is_3d_buffer(int sid)
653 return ds_is_3d_buffer(ds_software_buffers[sid].pdsb);
665 //--------------------------------------------------------------------------
666 // ds_build_vol_lookup()
668 // Fills up the ds_vol_lookup[] tables that converts from a volume in the form
669 // 0.0 -> 1.0 to -10000 -> 0 (this is the DirectSound method, where units are
670 // hundredths of decibls)
672 void ds_build_vol_lookup()
677 ds_vol_lookup[0] = -10000;
678 for ( i = 1; i <= 100; i++ ) {
680 ds_vol_lookup[i] = fl2i( (log(vol) / log(2.0f)) * 1000.0f);
685 //--------------------------------------------------------------------------
686 // ds_convert_volume()
688 // Takes volume between 0.0f and 1.0f and converts into
689 // DirectSound style volumes between -10000 and 0.
690 int ds_convert_volume(float volume)
694 index = fl2i(volume * 100.0f);
700 return ds_vol_lookup[index];
703 //--------------------------------------------------------------------------
704 // ds_get_percentage_vol()
706 // Converts -10000 -> 0 range volume to 0 -> 1
707 float ds_get_percentage_vol(int ds_vol)
710 vol = pow(2.0, ds_vol/1000.0);
714 // ---------------------------------------------------------------------------------------
717 // Parse a wave file.
719 // parameters: filename => file of sound to parse
720 // dest => address of pointer of where to store raw sound data (output parm)
721 // dest_size => number of bytes of sound data stored (output parm)
722 // header => address of pointer to a WAVEFORMATEX struct (output parm)
724 // returns: 0 => wave file successfully parsed
727 // NOTE: memory is malloced for the header and dest in this function. It is the responsibility
728 // of the caller to free this memory later.
730 int ds_parse_wave(char *filename, ubyte **dest, uint *dest_size, WAVEFORMATEX **header)
733 PCMWAVEFORMAT PCM_header;
735 unsigned int tag, size, next_chunk;
737 fp = cfopen( filename, "rb" );
739 nprintf(("Error", "Couldn't open '%s'\n", filename ));
743 // Skip the "RIFF" tag and file size (8 bytes)
744 // Skip the "WAVE" tag (4 bytes)
745 cfseek( fp, 12, CF_SEEK_SET );
747 // Now read RIFF tags until the end of file
750 if ( cfread( &tag, sizeof(uint), 1, fp ) != 1 )
752 tag = INTEL_INT( tag );
754 if ( cfread( &size, sizeof(uint), 1, fp ) != 1 )
756 size = INTEL_INT( size );
758 next_chunk = cftell(fp) + size;
761 case 0x20746d66: // The 'fmt ' tag
762 //nprintf(("Sound", "SOUND => size of fmt block: %d\n", size));
763 PCM_header.wf.wFormatTag = cfread_ushort(fp);
764 PCM_header.wf.nChannels = cfread_ushort(fp);
765 PCM_header.wf.nSamplesPerSec = cfread_uint(fp);
766 PCM_header.wf.nAvgBytesPerSec = cfread_uint(fp);
767 PCM_header.wf.nBlockAlign = cfread_ushort(fp);
768 PCM_header.wBitsPerSample = cfread_ushort(fp);
770 if ( PCM_header.wf.wFormatTag != WAVE_FORMAT_PCM ) {
771 cbExtra = cfread_ushort(fp);
774 // Allocate memory for WAVEFORMATEX structure + extra bytes
775 if ( (*header = (WAVEFORMATEX *) malloc ( sizeof(WAVEFORMATEX)+cbExtra )) != NULL ){
776 // Copy bytes from temporary format structure
777 memcpy (*header, &PCM_header, sizeof(PCM_header));
778 (*header)->cbSize = cbExtra;
780 // Read those extra bytes, append to WAVEFORMATEX structure
782 cfread( ((ubyte *)(*header) + sizeof(WAVEFORMATEX)), cbExtra, 1, fp);
786 Assert(0); // malloc failed
790 case 0x61746164: // the 'data' tag
792 (*dest) = (ubyte *)malloc(size);
793 Assert( *dest != NULL );
794 cfread( *dest, size, 1, fp );
796 default: // unknown, skip it
799 cfseek( fp, next_chunk, CF_SEEK_SET );
806 // ---------------------------------------------------------------------------------------
815 for ( i = 0; i < MAX_DS_SOFTWARE_BUFFERS; i++ ) {
816 if ( sound_buffers[i].buf_id == 0 )
820 if ( i == MAX_DS_SOFTWARE_BUFFERS ) {
828 for ( i = 0; i < MAX_DS_SOFTWARE_BUFFERS; i++ ) {
829 if ( ds_software_buffers[i].pdsb == NULL )
833 if ( i == MAX_DS_SOFTWARE_BUFFERS ) {
841 // ---------------------------------------------------------------------------------------
852 for ( i = 0; i < MAX_DS_HARDWARE_BUFFERS; i++ ) {
853 if ( ds_hardware_buffers[i].pdsb == NULL )
857 if ( i == MAX_DS_HARDWARE_BUFFERS ) {
865 // ---------------------------------------------------------------------------------------
866 // Load a DirectSound secondary buffer with sound data. The sounds data for
867 // game sounds are stored in the DirectSound secondary buffers, and are
868 // duplicated as needed and placed in the Channels[] array to be played.
872 // sid => pointer to software id for sound ( output parm)
873 // hid => pointer to hardware id for sound ( output parm)
874 // final_size => pointer to storage to receive uncompressed sound size (output parm)
875 // header => pointer to a WAVEFORMATEX structure
876 // si => sound_info structure, contains details on the sound format
877 // flags => buffer properties ( DS_HARDWARE , DS_3D )
879 // returns: -1 => sound effect could not loaded into a secondary buffer
880 // 0 => sound effect successfully loaded into a secondary buffer
883 // NOTE: this function is slow, especially when sounds are loaded into hardware. Don't call this
884 // function from within gameplay.
887 int ds_load_buffer(int *sid, int *hid, int *final_size, void *header, sound_info *si, int flags)
890 Assert( final_size != NULL );
891 Assert( header != NULL );
892 Assert( si != NULL );
894 // All sounds are required to have a software buffer
898 nprintf(("Sound","SOUND ==> No more sound buffers available\n"));
903 OpenAL_ErrorCheck( alGenBuffers (1, &pi), return -1 );
911 // the below two covnert_ variables are only used when the wav format is not
912 // PCM. DirectSound only takes PCM sound data, so we must convert to PCM if required
913 ubyte *convert_buffer = NULL; // storage for converted wav file
914 int convert_len; // num bytes of converted wav file
915 uint src_bytes_used; // number of source bytes actually converted (should always be equal to original size)
917 WAVEFORMATEX *pwfx = (WAVEFORMATEX *)header;
920 switch (si->format) {
921 case WAVE_FORMAT_PCM:
922 Assert( si->data != NULL );
924 bps = si->avg_bytes_per_sec;
926 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
927 // swap 16-bit sound data
931 for (uint i=0; i<size; i=i+2) {
932 swap_tmp = (ushort*)(si->data + i);
933 *swap_tmp = INTEL_SHORT(*swap_tmp);
940 case WAVE_FORMAT_ADPCM:
941 Assert( si->data != NULL );
942 // this ADPCM decoder decodes to 16-bit only so keep that in mind
943 nprintf(( "Sound", "SOUND ==> converting sound from ADPCM to PCM\n" ));
944 rc = ACM_convert_ADPCM_to_PCM(pwfx, si->data, si->size, &convert_buffer, 0, &convert_len, &src_bytes_used, 16);
950 if (src_bytes_used != si->size) {
951 return -1; // ACM conversion failed?
955 bps = (((si->n_channels * bits) / 8) * si->sample_rate);
957 data = convert_buffer;
959 nprintf(( "Sound", "SOUND ==> Coverted sound from ADPCM to PCM successfully\n" ));
967 /* format is now in pcm */
968 frequency = si->sample_rate;
971 if (si->n_channels == 2) {
972 format = AL_FORMAT_STEREO16;
973 } else if (si->n_channels == 1) {
974 format = AL_FORMAT_MONO16;
978 } else if (bits == 8) {
979 if (si->n_channels == 2) {
980 format = AL_FORMAT_STEREO8;
981 } else if (si->n_channels == 1) {
982 format = AL_FORMAT_MONO8;
993 OpenAL_ErrorCheck( alBufferData (pi, format, data, size, frequency), return -1 );
995 sound_buffers[*sid].buf_id = pi;
996 sound_buffers[*sid].source_id = -1;
997 sound_buffers[*sid].frequency = frequency;
998 sound_buffers[*sid].bits_per_sample = bits;
999 sound_buffers[*sid].nchannels = si->n_channels;
1000 sound_buffers[*sid].nseconds = size / bps;
1001 sound_buffers[*sid].nbytes = size;
1003 if ( convert_buffer )
1004 free( convert_buffer );
1009 Assert( final_size != NULL );
1010 Assert( header != NULL );
1011 Assert( si != NULL );
1012 Assert( si->data != NULL );
1013 Assert( si->size > 0 );
1014 Assert( si->sample_rate > 0);
1015 Assert( si->bits > 0 );
1016 Assert( si->n_channels > 0 );
1017 Assert( si->n_block_align >= 0 );
1018 Assert( si->avg_bytes_per_sec > 0 );
1020 WAVEFORMATEX *pwfx = (WAVEFORMATEX *)header;
1021 DSBUFFERDESC BufferDesc;
1022 WAVEFORMATEX WaveFormat;
1024 int rc, final_sound_size, DSOUND_load_buffer_result = 0;
1025 BYTE *pData, *pData2;
1026 DWORD DataSize, DataSize2;
1028 // the below two covnert_ variables are only used when the wav format is not
1029 // PCM. DirectSound only takes PCM sound data, so we must convert to PCM if required
1030 ubyte *convert_buffer = NULL; // storage for converted wav file
1031 int convert_len; // num bytes of converted wav file
1032 uint src_bytes_used; // number of source bytes actually converted (should always be equal to original size)
1034 // Ensure DirectSound initialized
1035 if (!ds_initialized) {
1036 DSOUND_load_buffer_result = -1;
1037 goto DSOUND_load_buffer_done;
1040 // Set up buffer information
1041 WaveFormat.wFormatTag = (unsigned short)si->format;
1042 WaveFormat.nChannels = (unsigned short)si->n_channels;
1043 WaveFormat.nSamplesPerSec = si->sample_rate;
1044 WaveFormat.wBitsPerSample = (unsigned short)si->bits;
1045 WaveFormat.cbSize = 0;
1046 WaveFormat.nBlockAlign = (unsigned short)si->n_block_align;
1047 WaveFormat.nAvgBytesPerSec = si->avg_bytes_per_sec;
1049 final_sound_size = si->size; // assume this format will be used, may be over-ridded by convert_len
1051 // Assert(WaveFormat.nChannels == 1);
1053 switch ( si->format ) {
1054 case WAVE_FORMAT_PCM:
1057 case WAVE_FORMAT_ADPCM:
1059 nprintf(( "Sound", "SOUND ==> converting sound from ADPCM to PCM\n" ));
1060 rc = ACM_convert_ADPCM_to_PCM(pwfx, si->data, si->size, &convert_buffer, 0, &convert_len, &src_bytes_used, 8);
1062 DSOUND_load_buffer_result = -1;
1063 goto DSOUND_load_buffer_done;
1066 if (src_bytes_used != si->size) {
1067 Int3(); // ACM conversion failed?
1068 DSOUND_load_buffer_result = -1;
1069 goto DSOUND_load_buffer_done;
1072 final_sound_size = convert_len;
1074 // Set up the WAVEFORMATEX structure to have the right PCM characteristics
1075 WaveFormat.wFormatTag = WAVE_FORMAT_PCM;
1076 WaveFormat.nChannels = (unsigned short)si->n_channels;
1077 WaveFormat.nSamplesPerSec = si->sample_rate;
1078 WaveFormat.wBitsPerSample = 8;
1079 WaveFormat.cbSize = 0;
1080 WaveFormat.nBlockAlign = (unsigned short)(( WaveFormat.nChannels * WaveFormat.wBitsPerSample ) / 8);
1081 WaveFormat.nAvgBytesPerSec = WaveFormat.nBlockAlign * WaveFormat.nSamplesPerSec;
1083 nprintf(( "Sound", "SOUND ==> Coverted sound from ADPCM to PCM successfully\n" ));
1087 nprintf(( "Sound", "Unsupported sound encoding\n" ));
1088 DSOUND_load_buffer_result = -1;
1089 goto DSOUND_load_buffer_done;
1093 WaveFormat.wFormatTag = WAVE_FORMAT_PCM; // DirectSound only used PCM wave files
1095 // Set up a DirectSound buffer
1096 ZeroMemory(&BufferDesc, sizeof(BufferDesc));
1097 BufferDesc.dwSize = sizeof(BufferDesc);
1098 BufferDesc.dwBufferBytes = final_sound_size;
1099 BufferDesc.lpwfxFormat = &WaveFormat;
1101 // check if DirectSound3D is enabled and the sound is flagged for 3D
1102 if ((ds_using_ds3d()) && (flags & DS_USE_DS3D)) {
1103 // if (ds_using_ds3d()) {
1104 BufferDesc.dwFlags = DSBCAPS_STATIC | DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRLVOLUME | DSBCAPS_CTRL3D | DSBCAPS_MUTE3DATMAXDISTANCE;
1106 BufferDesc.dwFlags = DSBCAPS_STATIC | DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRLVOLUME | DSBCAPS_LOCSOFTWARE;
1109 // Create a new software buffer using the settings for this wave
1110 // All sounds are required to have a software buffer
1111 *sid = ds_get_sid();
1113 nprintf(("Sound","SOUND ==> No more software secondary buffers available\n"));
1116 DSReturn = pDirectSound->CreateSoundBuffer(&BufferDesc, &ds_software_buffers[*sid].pdsb, NULL );
1118 if ( DSReturn == DS_OK && ds_software_buffers[*sid].pdsb != NULL ) {
1120 ds_software_buffers[*sid].desc = BufferDesc;
1121 ds_software_buffers[*sid].wfx = *BufferDesc.lpwfxFormat;
1123 // Lock the buffer and copy in the data
1124 if ((ds_software_buffers[*sid].pdsb)->Lock(0, final_sound_size, (void**)(&pData), &DataSize, (void**)(&pData2), &DataSize2, 0) == DS_OK) {
1126 if ( convert_buffer )
1127 memcpy(pData, convert_buffer, final_sound_size); // use converted data (PCM format)
1129 memcpy(pData, si->data, final_sound_size);
1131 (ds_software_buffers[*sid].pdsb)->Unlock(pData, DataSize, 0, 0);
1133 DSOUND_load_buffer_result = 0;
1135 // update ram used for sound
1136 Snd_sram += final_sound_size;
1137 *final_size = final_sound_size;
1140 nprintf(("Sound","SOUND => fatal error in DSOUND_load_buffer\n"));
1142 DSOUND_load_buffer_result = -1;
1145 DSOUND_load_buffer_done:
1146 if ( convert_buffer )
1147 free( convert_buffer );
1148 return DSOUND_load_buffer_result;
1152 // ---------------------------------------------------------------------------------------
1153 // ds_init_channels()
1155 // init the Channels[] array
1157 void ds_init_channels()
1164 Channels = (channel*) malloc(sizeof(channel) * MAX_CHANNELS);
1165 if (Channels == NULL) {
1166 Error(LOCATION, "Unable to allocate %d bytes for %d audio channels.", sizeof(channel) * MAX_CHANNELS, MAX_CHANNELS);
1169 // init the channels
1170 for ( i = 0; i < MAX_CHANNELS; i++ ) {
1171 OpenAL_ErrorPrint( alGenSources(1, &Channels[i].source_id) );
1172 Channels[i].buf_id = -1;
1173 Channels[i].vol = 0;
1178 // detect how many channels we can support
1180 ds_get_soundcard_caps(&caps);
1182 // caps.dwSize = sizeof(DSCAPS);
1183 // pDirectSound->GetCaps(&caps);
1185 // minimum 16 channels
1186 MAX_CHANNELS = caps.dwMaxHwMixingStaticBuffers;
1187 int dbg_channels = MAX_CHANNELS;
1188 if (MAX_CHANNELS < 16) {
1192 // allocate the channels array
1193 Channels = (channel*) malloc(sizeof(channel) * MAX_CHANNELS);
1194 if (Channels == NULL) {
1195 Error(LOCATION, "Unable to allocate %d bytes for %d audio channels.", sizeof(channel) * MAX_CHANNELS, MAX_CHANNELS);
1198 // init the channels
1199 for ( i = 0; i < MAX_CHANNELS; i++ ) {
1200 Channels[i].pdsb = NULL;
1201 Channels[i].pds3db = NULL;
1202 Channels[i].vol = 0;
1205 mprintf(("** MAX_CHANNELS set to %d. DS reported %d.\n", MAX_CHANNELS, dbg_channels));
1209 // ---------------------------------------------------------------------------------------
1210 // ds_init_software_buffers()
1212 // init the software buffers
1214 void ds_init_software_buffers()
1219 for ( i = 0; i < MAX_DS_SOFTWARE_BUFFERS; i++ ) {
1220 sound_buffers[i].buf_id = 0;
1221 sound_buffers[i].source_id = -1;
1226 for ( i = 0; i < MAX_DS_SOFTWARE_BUFFERS; i++ ) {
1227 ds_software_buffers[i].pdsb = NULL;
1232 // ---------------------------------------------------------------------------------------
1233 // ds_init_hardware_buffers()
1235 // init the hardware buffers
1237 void ds_init_hardware_buffers()
1240 // STUB_FUNCTION; // not needed with openal (CM)
1245 for ( i = 0; i < MAX_DS_HARDWARE_BUFFERS; i++ ) {
1246 ds_hardware_buffers[i].pdsb = NULL;
1251 // ---------------------------------------------------------------------------------------
1252 // ds_init_buffers()
1254 // init the both the software and hardware buffers
1256 void ds_init_buffers()
1258 ds_init_software_buffers();
1259 ds_init_hardware_buffers();
1262 // Get the current soundcard capabilities
1264 void ds_get_soundcard_caps(DSCAPS *dscaps)
1267 int n_hbuffers, hram;
1269 dscaps->dwSize = sizeof(DSCAPS);
1271 hr = pDirectSound->GetCaps(dscaps);
1273 nprintf(("Sound","SOUND ==> DirectSound GetCaps() failed with code %s\n.",get_DSERR_text(hr) ));
1277 n_hbuffers = dscaps->dwMaxHwMixingStaticBuffers;
1278 hram = dscaps->dwTotalHwMemBytes;
1280 if ( !(dscaps->dwFlags & DSCAPS_CERTIFIED) ) {
1281 nprintf(("Sound","SOUND ==> Warning: audio driver is not Microsoft certified.\n"));
1285 // ---------------------------------------------------------------------------------------
1288 // init the both the software and hardware buffers
1290 void ds_show_caps(DSCAPS *dscaps)
1292 nprintf(("Sound", "SOUND => Soundcard Capabilities:\n"));
1293 nprintf(("Sound", "================================\n"));
1294 nprintf(("Sound", "Number of primary buffers: %d\n", dscaps->dwPrimaryBuffers ));
1295 nprintf(("Sound", "Number of total hw mixing buffers: %d\n", dscaps->dwMaxHwMixingAllBuffers ));
1296 nprintf(("Sound", "Number of total hw mixing static buffers: %d\n", dscaps->dwMaxHwMixingStaticBuffers ));
1297 nprintf(("Sound", "Number of total hw mixing streaming buffers: %d\n", dscaps->dwMaxHwMixingStreamingBuffers ));
1298 nprintf(("Sound", "Number of free hw mixing buffers: %d\n", dscaps->dwFreeHwMixingAllBuffers ));
1299 nprintf(("Sound", "Number of free hw mixing static buffers: %d\n", dscaps->dwFreeHwMixingStaticBuffers ));
1300 nprintf(("Sound", "Number of free hw mixing streaming buffers: %d\n", dscaps->dwFreeHwMixingStreamingBuffers ));
1301 nprintf(("Sound", "Number of hw 3D buffers: %d\n", dscaps->dwMaxHw3DAllBuffers ));
1302 nprintf(("Sound", "Number of hw 3D static buffers: %d\n", dscaps->dwMaxHw3DStaticBuffers ));
1303 nprintf(("Sound", "Number of hw 3D streaming buffers: %d\n", dscaps->dwMaxHw3DStreamingBuffers ));
1304 nprintf(("Sound", "Number of free hw 3D buffers: %d\n", dscaps->dwFreeHw3DAllBuffers ));
1305 nprintf(("Sound", "Number of free hw static 3D buffers: %d\n", dscaps->dwFreeHw3DStaticBuffers ));
1306 nprintf(("Sound", "Number of free hw streaming 3D buffers: %d\n", dscaps->dwFreeHw3DStreamingBuffers ));
1307 nprintf(("Sound", "Number of total hw bytes: %d\n", dscaps->dwTotalHwMemBytes ));
1308 nprintf(("Sound", "Number of free hw bytes: %d\n", dscaps->dwFreeHwMemBytes ));
1309 nprintf(("Sound", "================================\n"));
1314 // Fill in the waveformat struct with the primary buffer characteristics.
1315 void ds_get_primary_format(WAVEFORMATEX *wfx)
1317 // Set 16 bit / 22KHz / mono
1318 wfx->wFormatTag = WAVE_FORMAT_PCM;
1320 wfx->nSamplesPerSec = 22050;
1321 wfx->wBitsPerSample = 16;
1323 wfx->nBlockAlign = (unsigned short)(wfx->nChannels * (wfx->wBitsPerSample / 8));
1324 wfx->nAvgBytesPerSec = wfx->nBlockAlign * wfx->nSamplesPerSec;
1328 // obtain the function pointers from the dsound.dll
1329 void ds_dll_get_functions()
1331 pfn_DirectSoundCreate = (HRESULT(__stdcall *)(LPGUID lpGuid, LPDIRECTSOUND *ppDS, IUnknown FAR *pUnkOuter))GetProcAddress(Ds_dll_handle,"DirectSoundCreate");
1332 pfn_DirectSoundCaptureCreate = (HRESULT(__stdcall *)(LPGUID lpGuid, LPDIRECTSOUNDCAPTURE *lplpDSC, IUnknown FAR *pUnkOuter))GetProcAddress(Ds_dll_handle,"DirectSoundCaptureCreate");
1336 // Load the dsound.dll, and get funtion pointers
1337 // exit: 0 -> dll loaded successfully
1338 // !0 -> dll could not be loaded
1344 if ( !Ds_dll_loaded ) {
1345 Ds_dll_handle = LoadLibrary("dsound.dll");
1346 if ( !Ds_dll_handle ) {
1349 ds_dll_get_functions();
1362 HINSTANCE a3d_handle;
1365 a3d_handle = LoadLibrary("a3d.dll");
1369 FreeLibrary(a3d_handle);
1373 Ds_must_call_couninitialize = 1;
1375 hr = CoCreateInstance(CLSID_A3d_Def, NULL, CLSCTX_INPROC_SERVER, IID_IDirectSound, (void**)&pDirectSound);
1380 Assert(pDirectSound != NULL);
1381 hr = pDirectSound->QueryInterface(IID_IA3d2_Def, (void**)&pIA3d2);
1386 A3DCAPS_SOFTWARE swCaps;
1388 // Get Dll Software CAP to get DLL version number
1389 ZeroMemory(&swCaps,sizeof(swCaps));
1391 swCaps.dwSize = sizeof(swCaps);
1392 pIA3d2->GetSoftwareCaps(&swCaps);
1394 // Compare version from a3d.dll to header version only return A3D_OK if dll version >= to header version
1395 if (swCaps.dwVersion < A3D_CURRENT_VERSION) {
1396 pDirectSound->Release();
1397 pDirectSound = NULL;
1402 // verify this is authentic A3D
1403 int aureal_verified;
1404 aureal_verified = VerifyAurealA3D();
1406 if (aureal_verified == FALSE) {
1407 // This is fake A3D!!! Ignore
1408 pDirectSound->Release();
1409 pDirectSound = NULL;
1413 // Register our version for backwards compatibility with newer A3d.dll
1414 pIA3d2->RegisterVersion(A3D_CURRENT_VERSION);
1416 hr = pDirectSound->Initialize(NULL);
1418 pDirectSound->Release();
1419 pDirectSound = NULL;
1423 pIA3d2->SetResourceManagerMode(A3D_RESOURCE_MODE_DYNAMIC_LOOPERS);
1429 // Initialize the property set interface.
1431 // returns: 0 if successful, otherwise -1. If successful, the global pPropertySet will
1432 // set to a non-NULL value.
1434 int ds_init_property_set()
1441 // Create the secondary buffer required for EAX initialization
1443 wf.wFormatTag = WAVE_FORMAT_PCM;
1445 wf.nSamplesPerSec = 22050;
1446 wf.wBitsPerSample = 16;
1448 wf.nBlockAlign = (unsigned short)(wf.nChannels * (wf.wBitsPerSample / 8));
1449 wf.nAvgBytesPerSec = wf.nBlockAlign * wf.nSamplesPerSec;
1452 ZeroMemory(&dsbd, sizeof(dsbd));
1453 dsbd.dwSize = sizeof(dsbd);
1454 dsbd.dwFlags = DSBCAPS_CTRLDEFAULT | DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_STATIC | DSBCAPS_CTRL3D | DSBCAPS_MUTE3DATMAXDISTANCE;
1455 dsbd.dwBufferBytes = 3 * wf.nAvgBytesPerSec;
1456 dsbd.lpwfxFormat = &wf;
1458 // Create a new buffer using the settings for this wave
1459 hr = pDirectSound->CreateSoundBuffer(&dsbd, &Ds_property_set_pdsb, NULL);
1461 pPropertySet = NULL;
1465 // Get the 3D interface from the secondary buffer, which is used to query the EAX interface
1466 hr = Ds_property_set_pdsb->QueryInterface(IID_IDirectSound3DBuffer, (void**)&Ds_property_set_pds3db);
1468 Ds_property_set_pds3db = NULL;
1472 Assert(Ds_property_set_pds3db != NULL);
1473 hr = Ds_property_set_pds3db->QueryInterface(IID_IKsPropertySet, (void**)&pPropertySet);
1474 if ((FAILED(hr)) || (pPropertySet == NULL)) {
1482 // ---------------------------------------------------------------------------------------
1485 // returns: -1 => init failed
1486 // 0 => init success
1487 int ds_init(int use_a3d, int use_eax)
1490 // NOTE: A3D and EAX are unused in OpenAL
1491 // changed from 22050 to 44100 so that movies don't sound like crap
1492 #ifdef AL_VERSION_1_1
1493 const ALCchar *initStr = (ALCchar *)"\'( (sampling-rate 44100 ))";
1495 ALCubyte *initStr = (ALCubyte *)"\'( (sampling-rate 44100 ))";
1497 int attr[] = { ALC_FREQUENCY, 44100, ALC_SYNC, AL_FALSE, 0 };
1503 nprintf(( "Sound", "SOUND ==> Initializing OpenAL...\n" ));
1506 ds_sound_device = alcOpenDevice( initStr );
1508 if (ds_sound_device == NULL) {
1509 nprintf(("Sound", "SOUND ==> Couldn't open OpenAL device\n"));
1513 // Create Sound Device
1514 ds_sound_context = alcCreateContext( ds_sound_device, attr );
1516 if (ds_sound_context == NULL) {
1517 nprintf(("Sound", "SOUND ==> Couldn't create OpenAL context\n"));
1518 alcCloseDevice( ds_sound_device );
1522 alcMakeContextCurrent( ds_sound_context );
1524 if (alcGetError( ds_sound_device ) != ALC_NO_ERROR) {
1525 nprintf(("Sound", "SOUND ==> Couldn't initialize OpenAL\n"));
1531 mprintf(( "OpenAL INITED!\n" ));
1533 mprintf(( "Vendor : %s\n", alGetString( AL_VENDOR ) ));
1534 mprintf(( "Renderer : %s\n", alGetString( AL_RENDERER ) ));
1535 mprintf(( "Version : %s\n", alGetString( AL_VERSION ) ));
1536 mprintf(( "Extensions : \n" ));
1538 // print out OpenAL extensions
1539 static const char *OAL_extensions=(const char*)alGetString( AL_EXTENSIONS );
1541 // we use the "+1" here to have an extra NULL char on the end (with the memset())
1542 // this is to fix memory errors when the last char in extlist is the same as the token
1543 // we are looking for and ultra evil strtok() may still return non-NULL at EOS
1544 char *extlist = (char*)malloc( strlen(OAL_extensions) + 1 );
1545 memset( extlist, 0, strlen(OAL_extensions) + 1);
1547 if (extlist != NULL) {
1548 memcpy(extlist, OAL_extensions, strlen(OAL_extensions));
1550 char *curext = strtok(extlist, " ");
1553 mprintf(( " %s\n", curext ));
1554 curext = strtok(NULL, " ");
1564 // make sure we can actually use AL_BYTE_LOKI (Mac OpenAL doesn't have it)
1565 #ifdef AL_VERSION_1_1
1566 AL_play_position = alIsExtensionPresent( (const ALchar*)"AL_LOKI_play_position" );
1568 AL_play_position = alIsExtensionPresent( (ALubyte*)"AL_LOKI_play_position" );
1571 // Initialize DirectSound3D. Since software performance of DirectSound3D is unacceptably
1572 // slow, we require the voice manger (a DirectSound extension) to be present. The
1573 // exception is when A3D is being used, since A3D has a resource manager built in.
1574 // if (Ds_use_ds3d && ds3d_init(0) != 0)
1577 // setup default listener position/orientation
1578 // this is needed for 2D pan
1579 OpenAL_ErrorPrint( alListener3f(AL_POSITION, 0.0, 0.0, 0.0) );
1581 ALfloat list_orien[] = { 0.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f };
1582 OpenAL_ErrorPrint( alListenerfv(AL_ORIENTATION, list_orien) );
1584 ds_build_vol_lookup();
1590 WAVEFORMATEX wave_format;
1591 DSBUFFERDESC BufferDesc;
1593 nprintf(( "Sound", "SOUND ==> Initializing DirectSound...\n" ));
1595 hwnd = (HWND)os_get_window();
1596 if ( hwnd == NULL ) {
1597 nprintf(( "Sound", "SOUND ==> No window handle, so no sound...\n" ));
1601 if ( ds_dll_load() == -1 ) {
1605 pDirectSound = NULL;
1607 Ds_use_a3d = use_a3d;
1608 Ds_use_eax = use_eax;
1610 if (Ds_use_a3d || Ds_use_eax) {
1614 if (Ds_use_a3d && Ds_use_eax) {
1619 // If we want A3D, ensure a3d.dll exists
1620 if (Ds_use_a3d == 1) {
1621 if (ds_init_a3d() != 0) {
1628 if (Ds_use_a3d == 0) {
1629 if (!pfn_DirectSoundCreate) {
1630 nprintf(( "Sound", "SOUND ==> Could not get DirectSoundCreate function pointer\n" ));
1634 hr = pfn_DirectSoundCreate(NULL, &pDirectSound, NULL);
1640 // Set up DirectSound for exclusive mode, so we can change the primary buffer if we want to.
1641 hr = pDirectSound->SetCooperativeLevel(hwnd, DSSCL_EXCLUSIVE);
1643 nprintf(("Sound","SOUND ==> DirectSound pDirectSound->SetCooperativeLevel failed with code %s\n.",get_DSERR_text(hr) ));
1644 pDirectSound = NULL;
1648 // Create the primary buffer
1649 ZeroMemory(&BufferDesc, sizeof(BufferDesc));
1650 BufferDesc.dwSize = sizeof(BufferDesc);
1652 ds_get_soundcard_caps(&Soundcard_caps);
1655 BufferDesc.dwFlags = DSBCAPS_PRIMARYBUFFER | DSBCAPS_CTRL3D;
1657 hr = pDirectSound->CreateSoundBuffer(&BufferDesc, &pPrimaryBuffer, 0);
1659 nprintf(("Sound","SOUND ==> Primary Buffer create failed with DSBCAPS_CTRL3D property... disabling DirectSound3D\n"));
1664 nprintf(("Sound","SOUND ==> Primary Buffer created with DirectSound3D enabled\n"));
1668 // If not using DirectSound3D, then create a normal primary buffer
1669 if (Ds_use_ds3d == 0) {
1670 BufferDesc.dwFlags = DSBCAPS_PRIMARYBUFFER;
1671 hr = pDirectSound->CreateSoundBuffer(&BufferDesc, &pPrimaryBuffer, 0);
1673 nprintf(("Sound","SOUND ==> Primary Buffer create failed with error: %s\n",get_DSERR_text(hr) ));
1674 pDirectSound = NULL;
1678 nprintf(("Sound","SOUND ==> Primary Buffer created with without DirectSound3D enabled\n"));
1682 // Get the primary buffer format
1683 ds_get_primary_format(&wave_format);
1685 hr = pPrimaryBuffer->SetFormat(&wave_format);
1687 nprintf(("Sound","SOUND ==> pPrimaryBuffer->SetFormat() failed with code %s\n",get_DSERR_text(hr) ));
1690 pPrimaryBuffer->GetFormat(&wave_format, sizeof(wave_format), NULL);
1691 nprintf(("Sound","SOUND ==> Primary Buffer forced to: rate: %d Hz bits: %d n_channels: %d\n",
1692 wave_format.nSamplesPerSec, wave_format.wBitsPerSample, wave_format.nChannels));
1694 // start the primary buffer playing. This will reduce sound latency when playing a sound
1695 // if no other sounds are playing.
1696 hr = pPrimaryBuffer->Play(0, 0, DSBPLAY_LOOPING);
1698 nprintf(("Sound","SOUND ==> pPrimaryBuffer->Play() failed with code %s\n",get_DSERR_text(hr) ));
1701 // Initialize DirectSound3D. Since software performance of DirectSound3D is unacceptably
1702 // slow, we require the voice manger (a DirectSound extension) to be present. The
1703 // exception is when A3D is being used, since A3D has a resource manager built in.
1705 int vm_required = 1; // voice manager
1706 if (Ds_use_a3d == 1) {
1710 if (ds3d_init(vm_required) != 0) {
1716 if (Ds_use_eax == 1) {
1717 ds_init_property_set();
1718 if (ds_eax_init() != 0) {
1723 ds_build_vol_lookup();
1727 ds_show_caps(&Soundcard_caps);
1733 // ---------------------------------------------------------------------------------------
1736 // returns the text equivalent for the a DirectSound DSERR_ code
1738 char *get_DSERR_text(int DSResult)
1743 static char buf[20];
1744 snprintf(buf, 19, "unknown %d", DSResult);
1747 switch( DSResult ) {
1753 case DSERR_ALLOCATED:
1754 return "DSERR_ALLOCATED";
1757 case DSERR_ALREADYINITIALIZED:
1758 return "DSERR_ALREADYINITIALIZED";
1761 case DSERR_BADFORMAT:
1762 return "DSERR_BADFORMAT";
1765 case DSERR_BUFFERLOST:
1766 return "DSERR_BUFFERLOST";
1769 case DSERR_CONTROLUNAVAIL:
1770 return "DSERR_CONTROLUNAVAIL";
1774 return "DSERR_GENERIC";
1777 case DSERR_INVALIDCALL:
1778 return "DSERR_INVALIDCALL";
1781 case DSERR_INVALIDPARAM:
1782 return "DSERR_INVALIDPARAM";
1785 case DSERR_NOAGGREGATION:
1786 return "DSERR_NOAGGREGATION";
1789 case DSERR_NODRIVER:
1790 return "DSERR_NODRIVER";
1793 case DSERR_OUTOFMEMORY:
1794 return "DSERR_OUTOFMEMORY";
1797 case DSERR_OTHERAPPHASPRIO:
1798 return "DSERR_OTHERAPPHASPRIO";
1801 case DSERR_PRIOLEVELNEEDED:
1802 return "DSERR_PRIOLEVELNEEDED";
1805 case DSERR_UNINITIALIZED:
1806 return "DSERR_UNINITIALIZED";
1809 case DSERR_UNSUPPORTED:
1810 return "DSERR_UNSUPPORTED";
1821 // ---------------------------------------------------------------------------------------
1822 // ds_close_channel()
1824 // Free a single channel
1826 void ds_close_channel(int i)
1829 if(Channels[i].source_id != 0 && alIsSource (Channels[i].source_id)) {
1830 OpenAL_ErrorPrint( alSourceStop (Channels[i].source_id) );
1832 OpenAL_ErrorPrint( alDeleteSources(1, &Channels[i].source_id) );
1834 Channels[i].source_id = 0;
1841 // If a 3D interface exists, free it
1842 if ( Channels[i].pds3db != NULL ) {
1845 Channels[i].pds3db = NULL;
1848 while(++attempts < 10) {
1849 hr = Channels[i].pds3db->Release();
1850 if ( hr == DS_OK ) {
1853 // nprintf(("Sound", "SOUND ==> Channels[channel].pds3db->Release() failed with return value %s\n", get_DSERR_text(second_hr) ));
1857 Channels[i].pds3db = NULL;
1861 if ( Channels[i].pdsb != NULL ) {
1862 // If a 2D interface exists, free it
1863 if ( Channels[i].pdsb != NULL ) {
1865 while(++attempts < 10) {
1866 hr = Channels[i].pdsb->Release();
1867 if ( hr == DS_OK ) {
1870 nprintf(("Sound", "SOUND ==> Channels[channel].pdsb->Release() failed with return value %s\n", get_DSERR_text(hr) ));
1875 Channels[i].pdsb = NULL;
1882 // ---------------------------------------------------------------------------------------
1883 // ds_close_all_channels()
1885 // Free all the channel buffers
1887 void ds_close_all_channels()
1891 for (i = 0; i < MAX_CHANNELS; i++) {
1892 ds_close_channel(i);
1896 // ---------------------------------------------------------------------------------------
1897 // ds_unload_buffer()
1900 void ds_unload_buffer(int sid, int hid)
1904 ALuint buf_id = sound_buffers[sid].buf_id;
1906 if (buf_id != 0 && alIsBuffer(buf_id)) {
1907 OpenAL_ErrorPrint( alDeleteBuffers(1, &buf_id) );
1910 sound_buffers[sid].buf_id = 0;
1920 if ( ds_software_buffers[sid].pdsb != NULL ) {
1921 hr = ds_software_buffers[sid].pdsb->Release();
1922 if ( hr != DS_OK ) {
1924 nprintf(("Sound", "SOUND ==> ds_software_buffers[sid]->Release() failed with return value %s\n", get_DSERR_text(hr) ));
1926 ds_software_buffers[sid].pdsb = NULL;
1931 if ( ds_hardware_buffers[hid].pdsb != NULL ) {
1932 hr = ds_hardware_buffers[hid].pdsb->Release();
1933 if ( hr != DS_OK ) {
1935 nprintf(("Sound", "SOUND ==> ds_hardware_buffers[hid]->Release() failed with return value %s\n", get_DSERR_text(hr) ));
1937 ds_hardware_buffers[hid].pdsb = NULL;
1943 // ---------------------------------------------------------------------------------------
1944 // ds_close_software_buffers()
1947 void ds_close_software_buffers()
1952 for (i = 0; i < MAX_DS_SOFTWARE_BUFFERS; i++) {
1953 ALuint buf_id = sound_buffers[i].buf_id;
1955 if (buf_id != 0 && alIsBuffer(buf_id)) {
1956 OpenAL_ErrorPrint( alDeleteBuffers(1, &buf_id) );
1959 sound_buffers[i].buf_id = 0;
1965 for (i = 0; i < MAX_DS_SOFTWARE_BUFFERS; i++) {
1966 if ( ds_software_buffers[i].pdsb != NULL ) {
1967 hr = ds_software_buffers[i].pdsb->Release();
1968 if ( hr != DS_OK ) {
1970 nprintf(("Sound", "SOUND ==> ds_software_buffers[i]->Release() failed with return value %s\n", get_DSERR_text(hr) ));
1972 ds_software_buffers[i].pdsb = NULL;
1978 // ---------------------------------------------------------------------------------------
1979 // ds_close_hardware_buffers()
1982 void ds_close_hardware_buffers()
1990 for (i = 0; i < MAX_DS_HARDWARE_BUFFERS; i++) {
1991 if ( ds_hardware_buffers[i].pdsb != NULL ) {
1992 hr = ds_hardware_buffers[i].pdsb->Release();
1993 if ( hr != DS_OK ) {
1995 nprintf(("Sound", "SOUND ==> ds_hardware_buffers[i]->Release() failed with return value %s\n", get_DSERR_text(hr) ));
1997 ds_hardware_buffers[i].pdsb = NULL;
2003 // ---------------------------------------------------------------------------------------
2004 // ds_close_buffers()
2006 // Free the channel buffers
2008 void ds_close_buffers()
2010 ds_close_software_buffers();
2011 ds_close_hardware_buffers();
2014 // ---------------------------------------------------------------------------------------
2017 // Close the DirectSound system
2021 ds_close_all_channels();
2025 if (pPropertySet != NULL) {
2026 pPropertySet->Release();
2027 pPropertySet = NULL;
2030 if (Ds_property_set_pdsb != NULL) {
2031 Ds_property_set_pdsb->Release();
2032 Ds_property_set_pdsb = NULL;
2035 if (Ds_property_set_pds3db != NULL) {
2036 Ds_property_set_pds3db->Release();
2037 Ds_property_set_pds3db = NULL;
2040 if (pPrimaryBuffer) {
2041 pPrimaryBuffer->Release();
2042 pPrimaryBuffer = NULL;
2051 pDirectSound->Release();
2052 pDirectSound = NULL;
2055 if ( Ds_dll_loaded ) {
2056 FreeLibrary(Ds_dll_handle);
2060 if (Ds_must_call_couninitialize == 1) {
2065 // free the Channels[] array, since it was dynamically allocated
2070 if (ds_sound_context != NULL)
2071 alcDestroyContext(ds_sound_context);
2073 if (ds_sound_device != NULL)
2074 alcCloseDevice(ds_sound_device);
2078 // ---------------------------------------------------------------------------------------
2079 // ds_get_3d_interface()
2081 // Get the 3d interface for a secondary buffer.
2083 // If the secondary buffer wasn't created with a DSBCAPS_CTRL3D flag, then no 3d interface
2087 void ds_get_3d_interface(LPDIRECTSOUNDBUFFER pdsb, LPDIRECTSOUND3DBUFFER *ppds3db)
2092 dsbc.dwSize = sizeof(dsbc);
2093 DSResult = pdsb->GetCaps(&dsbc);
2094 if ( DSResult == DS_OK && dsbc.dwFlags & DSBCAPS_CTRL3D ) {
2095 DSResult = pdsb->QueryInterface( IID_IDirectSound3DBuffer, (void**)ppds3db );
2096 if ( DSResult != DS_OK ) {
2097 nprintf(("SOUND","Could not obtain 3D interface for hardware buffer: %s\n", get_DSERR_text(DSResult) ));
2104 // ---------------------------------------------------------------------------------------
2105 // ds_get_free_channel()
2107 // Find a free channel to play a sound on. If no free channels exists, free up one based
2108 // on volume levels.
2110 // input: new_volume => volume in DS units for sound to play at
2111 // snd_id => which kind of sound to play
2112 // priority => DS_MUST_PLAY
2117 // returns: channel number to play sound on
2118 // -1 if no channel could be found
2120 // NOTE: snd_id is needed since we limit the number of concurrent samples
2124 int ds_get_free_channel(int new_volume, int snd_id, int priority)
2127 int i, first_free_channel, limit;
2128 int lowest_vol = 0, lowest_vol_index = -1;
2129 int instance_count; // number of instances of sound already playing
2130 int lowest_instance_vol, lowest_instance_vol_index;
2135 lowest_instance_vol = 99;
2136 lowest_instance_vol_index = -1;
2137 first_free_channel = -1;
2139 // Look for a channel to use to play this sample
2140 for ( i = 0; i < MAX_CHANNELS; i++ ) {
2142 if ( chp->source_id == 0 ) {
2143 if ( first_free_channel == -1 )
2144 first_free_channel = i;
2148 OpenAL_ErrorCheck( alGetSourcei(chp->source_id, AL_SOURCE_STATE, &status), return -1 );
2150 if ( status != AL_PLAYING ) {
2151 if ( first_free_channel == -1 )
2152 first_free_channel = i;
2156 if ( chp->snd_id == snd_id ) {
2158 if ( chp->vol < lowest_instance_vol && chp->looping == FALSE ) {
2159 lowest_instance_vol = chp->vol;
2160 lowest_instance_vol_index = i;
2164 if ( chp->vol < lowest_vol && chp->looping == FALSE ) {
2165 lowest_vol_index = i;
2166 lowest_vol = chp->vol;
2171 // determine the limit of concurrent instances of this sound
2182 case DS_LIMIT_THREE:
2192 // If we've exceeded the limit, then maybe stop the duplicate if it is lower volume
2193 if ( instance_count >= limit ) {
2194 // If there is a lower volume duplicate, stop it.... otherwise, don't play the sound
2195 if ( lowest_instance_vol_index >= 0 && (Channels[lowest_instance_vol_index].vol <= new_volume) ) {
2196 first_free_channel = lowest_instance_vol_index;
2198 first_free_channel = -1;
2201 // there is no limit barrier to play the sound, so see if we've ran out of channels
2202 if ( first_free_channel == -1 ) {
2203 // stop the lowest volume instance to play our sound if priority demands it
2204 if ( lowest_vol_index != -1 && priority == DS_MUST_PLAY ) {
2205 // Check if the lowest volume playing is less than the volume of the requested sound.
2206 // If so, then we are going to trash the lowest volume sound.
2207 if ( Channels[lowest_vol_index].vol <= new_volume ) {
2208 first_free_channel = lowest_vol_index;
2214 return first_free_channel;
2216 int i, first_free_channel, limit;
2217 int lowest_vol = 0, lowest_vol_index = -1;
2218 int instance_count; // number of instances of sound already playing
2219 int lowest_instance_vol, lowest_instance_vol_index;
2220 unsigned long status;
2225 lowest_instance_vol = 99;
2226 lowest_instance_vol_index = -1;
2227 first_free_channel = -1;
2229 // Look for a channel to use to play this sample
2230 for ( i = 0; i < MAX_CHANNELS; i++ ) {
2232 if ( chp->pdsb == NULL ) {
2233 if ( first_free_channel == -1 )
2234 first_free_channel = i;
2238 hr = chp->pdsb->GetStatus(&status);
2239 if ( hr != DS_OK ) {
2240 nprintf(("Sound", "SOUND ==> GetStatus failed with return value %s\n", get_DSERR_text(hr) ));
2243 if ( !(status & DSBSTATUS_PLAYING) ) {
2244 if ( first_free_channel == -1 )
2245 first_free_channel = i;
2246 ds_close_channel(i);
2250 if ( chp->snd_id == snd_id ) {
2252 if ( chp->vol < lowest_instance_vol && chp->looping == FALSE ) {
2253 lowest_instance_vol = chp->vol;
2254 lowest_instance_vol_index = i;
2258 if ( chp->vol < lowest_vol && chp->looping == FALSE ) {
2259 lowest_vol_index = i;
2260 lowest_vol = chp->vol;
2265 // determine the limit of concurrent instances of this sound
2276 case DS_LIMIT_THREE:
2286 // If we've exceeded the limit, then maybe stop the duplicate if it is lower volume
2287 if ( instance_count >= limit ) {
2288 // If there is a lower volume duplicate, stop it.... otherwise, don't play the sound
2289 if ( lowest_instance_vol_index >= 0 && (Channels[lowest_instance_vol_index].vol <= new_volume) ) {
2290 ds_close_channel(lowest_instance_vol_index);
2291 first_free_channel = lowest_instance_vol_index;
2293 first_free_channel = -1;
2296 // there is no limit barrier to play the sound, so see if we've ran out of channels
2297 if ( first_free_channel == -1 ) {
2298 // stop the lowest volume instance to play our sound if priority demands it
2299 if ( lowest_vol_index != -1 && priority == DS_MUST_PLAY ) {
2300 // Check if the lowest volume playing is less than the volume of the requested sound.
2301 // If so, then we are going to trash the lowest volume sound.
2302 if ( Channels[lowest_vol_index].vol <= new_volume ) {
2303 ds_close_channel(lowest_vol_index);
2304 first_free_channel = lowest_vol_index;
2310 return first_free_channel;
2315 // ---------------------------------------------------------------------------------------
2318 // Find a free channel to play a sound on. If no free channels exists, free up one based
2319 // on volume levels.
2321 // returns: 0 => dup was successful
2322 // -1 => dup failed (Channels[channel].pdsb will be NULL)
2325 int ds_channel_dup(LPDIRECTSOUNDBUFFER pdsb, int channel, int use_ds3d)
2329 // Duplicate the master buffer into a channel buffer.
2330 DSResult = pDirectSound->DuplicateSoundBuffer(pdsb, &Channels[channel].pdsb );
2331 if ( DSResult != DS_OK ) {
2332 nprintf(("Sound", "SOUND ==> DuplicateSoundBuffer failed with return value %s\n", get_DSERR_text(DSResult) ));
2333 Channels[channel].pdsb = NULL;
2337 // get the 3d interface for the buffer if it exists
2339 if (Channels[channel].pds3db == NULL) {
2340 ds_get_3d_interface(Channels[channel].pdsb, &Channels[channel].pds3db);
2348 // ---------------------------------------------------------------------------------------
2349 // ds_restore_buffer()
2352 void ds_restore_buffer(LPDIRECTSOUNDBUFFER pdsb)
2356 Int3(); // get Alan, he wants to see this
2357 hr = pdsb->Restore();
2358 if ( hr != DS_OK ) {
2359 nprintf(("Sound", "Sound ==> Lost a buffer, tried restoring but got %s\n", get_DSERR_text(hr) ));
2364 // Create a direct sound buffer in software, without locking any data in
2365 int ds_create_buffer(int frequency, int bits_per_sample, int nchannels, int nseconds)
2371 if (!ds_initialized) {
2377 nprintf(("Sound","SOUND ==> No more OpenAL buffers available\n"));
2381 OpenAL_ErrorCheck( alGenBuffers (1, &i), return -1 );
2383 sound_buffers[sid].buf_id = i;
2384 sound_buffers[sid].source_id = -1;
2385 sound_buffers[sid].frequency = frequency;
2386 sound_buffers[sid].bits_per_sample = bits_per_sample;
2387 sound_buffers[sid].nchannels = nchannels;
2388 sound_buffers[sid].nseconds = nseconds;
2389 sound_buffers[sid].nbytes = nseconds * (bits_per_sample / 8) * nchannels * frequency;
2398 if (!ds_initialized) {
2404 nprintf(("Sound","SOUND ==> No more software secondary buffers available\n"));
2408 // Set up buffer format
2409 wfx.wFormatTag = WAVE_FORMAT_PCM;
2410 wfx.nChannels = (unsigned short)nchannels;
2411 wfx.nSamplesPerSec = frequency;
2412 wfx.wBitsPerSample = (unsigned short)bits_per_sample;
2414 wfx.nBlockAlign = (unsigned short)(wfx.nChannels * (wfx.wBitsPerSample / 8));
2415 wfx.nAvgBytesPerSec = wfx.nBlockAlign * wfx.nSamplesPerSec;
2417 memset(&dsbd, 0, sizeof(DSBUFFERDESC));
2418 dsbd.dwSize = sizeof(DSBUFFERDESC);
2419 dsbd.dwBufferBytes = wfx.nAvgBytesPerSec * nseconds;
2420 dsbd.lpwfxFormat = &wfx;
2421 dsbd.dwFlags = DSBCAPS_STATIC | DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRLDEFAULT | DSBCAPS_LOCSOFTWARE;
2423 dsrval = pDirectSound->CreateSoundBuffer(&dsbd, &ds_software_buffers[sid].pdsb, NULL);
2424 if ( dsrval != DS_OK ) {
2428 ds_software_buffers[sid].desc = dsbd;
2433 // Lock data into an existing buffer
2434 int ds_lock_data(int sid, unsigned char *data, int size)
2439 ALuint buf_id = sound_buffers[sid].buf_id;
2442 if (sound_buffers[sid].bits_per_sample == 16) {
2443 if (sound_buffers[sid].nchannels == 2) {
2444 format = AL_FORMAT_STEREO16;
2445 } else if (sound_buffers[sid].nchannels == 1) {
2446 format = AL_FORMAT_MONO16;
2450 } else if (sound_buffers[sid].bits_per_sample == 8) {
2451 if (sound_buffers[sid].nchannels == 2) {
2452 format = AL_FORMAT_STEREO8;
2453 } else if (sound_buffers[sid].nchannels == 1) {
2454 format = AL_FORMAT_MONO8;
2462 sound_buffers[sid].nbytes = size;
2464 OpenAL_ErrorCheck( alBufferData(buf_id, format, data, size, sound_buffers[sid].frequency), return -1 );
2469 LPDIRECTSOUNDBUFFER pdsb;
2471 void *buffer_data, *buffer_data2;
2472 DWORD buffer_size, buffer_size2;
2475 pdsb = ds_software_buffers[sid].pdsb;
2477 memset(&caps, 0, sizeof(DSBCAPS));
2478 caps.dwSize = sizeof(DSBCAPS);
2479 dsrval = pdsb->GetCaps(&caps);
2480 if ( dsrval != DS_OK ) {
2484 pdsb->SetCurrentPosition(0);
2486 // lock the entire buffer
2487 dsrval = pdsb->Lock(0, caps.dwBufferBytes, &buffer_data, &buffer_size, &buffer_data2, &buffer_size2, 0 );
2488 if ( dsrval != DS_OK ) {
2492 // first clear it out with silence
2493 memset(buffer_data, 0x80, buffer_size);
2494 memcpy(buffer_data, data, size);
2496 dsrval = pdsb->Unlock(buffer_data, buffer_size, 0, 0);
2497 if ( dsrval != DS_OK ) {
2505 // Stop a buffer from playing directly
2506 void ds_stop_easy(int sid)
2511 int cid = sound_buffers[sid].source_id;
2514 ALuint source_id = Channels[cid].source_id;
2516 OpenAL_ErrorPrint( alSourceStop(source_id) );
2520 LPDIRECTSOUNDBUFFER pdsb;
2523 pdsb = ds_software_buffers[sid].pdsb;
2524 dsrval = pdsb->Stop();
2528 // Play a sound without the usual baggage (used for playing back real-time voice)
2531 // sid => software id of sound
2532 // volume => volume of sound effect in DirectSound units
2533 int ds_play_easy(int sid, int volume)
2536 if (!ds_initialized)
2539 int channel = ds_get_free_channel(volume, -1, DS_MUST_PLAY);
2542 ALuint source_id = Channels[channel].source_id;
2544 OpenAL_ErrorPrint( alSourceStop(source_id) );
2546 if (Channels[channel].buf_id != sid) {
2547 ALuint buffer_id = sound_buffers[sid].buf_id;
2549 OpenAL_ErrorCheck( alSourcei(source_id, AL_BUFFER, buffer_id), return -1 );
2552 Channels[channel].buf_id = sid;
2554 ALfloat alvol = (volume != -10000) ? powf(10.0f, (float)volume / (-600.0f / log10f(.5f))): 0.0f;
2556 OpenAL_ErrorPrint( alSourcef(source_id, AL_GAIN, alvol) );
2558 OpenAL_ErrorPrint( alSourcei(source_id, AL_LOOPING, AL_FALSE) );
2560 OpenAL_ErrorPrint( alSourcePlay(source_id) );
2568 LPDIRECTSOUNDBUFFER pdsb;
2571 pdsb = ds_software_buffers[sid].pdsb;
2573 pdsb->SetVolume(volume);
2574 dsrval=pdsb->Play(0, 0, 0);
2575 if ( dsrval != DS_OK ) {
2583 // ---------------------------------------------------------------------------------------
2584 // Play a DirectSound secondary buffer.
2588 // sid => software id of sound
2589 // hid => hardware id of sound ( -1 if not in hardware )
2590 // snd_id => what kind of sound this is
2591 // priority => DS_MUST_PLAY
2595 // volume => volume of sound effect in DirectSound units
2596 // pan => pan of sound in DirectSound units
2597 // looping => whether the sound effect is looping or not
2599 // returns: -1 => sound effect could not be started
2600 // >=0 => sig for sound effect successfully started
2602 int ds_play(int sid, int hid, int snd_id, int priority, int volume, int pan, int looping, bool is_voice_msg)
2607 if (!ds_initialized)
2610 channel = ds_get_free_channel(volume, snd_id, priority);
2613 if ( Channels[channel].source_id == 0 ) {
2617 if ( ds_using_ds3d() ) {
2621 Channels[channel].vol = volume;
2622 Channels[channel].looping = looping;
2623 Channels[channel].priority = priority;
2625 // set new position for pan or zero out if none
2626 ALfloat alpan = (float)pan / MAX_PAN;
2629 OpenAL_ErrorPrint( alSource3f(Channels[channel].source_id, AL_POSITION, alpan, 0.0, 1.0) );
2631 OpenAL_ErrorPrint( alSource3f(Channels[channel].source_id, AL_POSITION, 0.0, 0.0, 0.0) );
2634 OpenAL_ErrorPrint( alSource3f(Channels[channel].source_id, AL_VELOCITY, 0.0, 0.0, 0.0) );
2636 OpenAL_ErrorPrint( alSourcef(Channels[channel].source_id, AL_PITCH, 1.0) );
2638 ALfloat alvol = (volume != -10000) ? powf(10.0f, (float)volume / (-600.0f / log10f(.5f))): 0.0f;
2639 OpenAL_ErrorPrint( alSourcef(Channels[channel].source_id, AL_GAIN, alvol) );
2641 Channels[channel].is_voice_msg = is_voice_msg;
2645 OpenAL_ErrorCheck( alGetSourcei(Channels[channel].source_id, AL_SOURCE_STATE, &status), return -1 );
2647 if (status == AL_PLAYING)
2648 OpenAL_ErrorPrint( alSourceStop(Channels[channel].source_id) );
2651 OpenAL_ErrorCheck( alSourcei(Channels[channel].source_id, AL_BUFFER, sound_buffers[sid].buf_id), return -1 );
2654 // setup default listener position/orientation
2655 // this is needed for 2D pan
2656 OpenAL_ErrorPrint( alListener3f(AL_POSITION, 0.0, 0.0, 0.0) );
2658 ALfloat list_orien[] = { 0.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f };
2659 OpenAL_ErrorPrint( alListenerfv(AL_ORIENTATION, list_orien) );
2661 OpenAL_ErrorPrint( alSourcei(Channels[channel].source_id, AL_SOURCE_RELATIVE, AL_FALSE) );
2663 OpenAL_ErrorPrint( alSourcei(Channels[channel].source_id, AL_LOOPING, (looping) ? AL_TRUE : AL_FALSE) );
2665 OpenAL_ErrorPrint( alSourcePlay(Channels[channel].source_id) );
2667 sound_buffers[sid].source_id = channel;
2668 Channels[channel].buf_id = sid;
2671 // nprintf(( "Sound", "SOUND ==> Not playing sound requested at volume %.2f\n", ds_get_percentage_vol(volume) ));
2675 Channels[channel].snd_id = snd_id;
2676 Channels[channel].sig = channel_next_sig++;
2677 if (channel_next_sig < 0 ) {
2678 channel_next_sig = 1;
2681 Channels[channel].last_position = 0;
2683 // make sure there aren't any looping voice messages
2684 for (int i=0; i<MAX_CHANNELS; i++) {
2685 if (Channels[i].is_voice_msg == true) {
2686 if (Channels[i].source_id == 0) {
2690 DWORD current_position = ds_get_play_position(i);
2691 if (current_position != 0) {
2692 if (current_position < Channels[i].last_position) {
2695 Channels[i].last_position = current_position;
2701 return Channels[channel].sig;
2706 if (!ds_initialized)
2709 channel = ds_get_free_channel(volume, snd_id, priority);
2712 if ( Channels[channel].pdsb != NULL ) {
2716 // First check if the sound is in hardware, and try to duplicate from there
2719 if ( ds_channel_dup(ds_hardware_buffers[hid].pdsb, channel, 0) == 0 ) {
2720 // nprintf(("Sound", "SOUND ==> Played sound in hardware..\n"));
2724 // Channel will be NULL if hardware dup failed, or there was no hardware dup attempted
2725 if ( Channels[channel].pdsb == NULL ) {
2726 if ( ds_channel_dup(ds_software_buffers[sid].pdsb, channel, 0) == 0 ) {
2727 // nprintf(("Sound", "SOUND ==> Played sound in software..\n"));
2731 if ( Channels[channel].pdsb == NULL ) {
2735 if ( ds_using_ds3d() ) {
2736 if ( ds_is_3d_buffer(Channels[channel].pdsb) ) {
2737 if (Channels[channel].pds3db == NULL) {
2738 ds_get_3d_interface(Channels[channel].pdsb, &Channels[channel].pds3db);
2740 if ( Channels[channel].pds3db ) {
2741 Channels[channel].pds3db->SetMode(DS3DMODE_DISABLE,DS3D_IMMEDIATE);
2747 Channels[channel].vol = volume;
2748 Channels[channel].looping = looping;
2749 Channels[channel].priority = priority;
2750 Channels[channel].pdsb->SetPan(pan);
2751 Channels[channel].pdsb->SetVolume(volume);
2752 Channels[channel].is_voice_msg = is_voice_msg;
2756 ds_flags |= DSBPLAY_LOOPING;
2758 DSResult = Channels[channel].pdsb->Play(0, 0, ds_flags );
2761 if (Stop_logging_sounds == false) {
2763 sprintf(buf, "channel %d, address: %x, ds_flags: %d", channel, Channels[channel].pdsb, ds_flags);
2764 HUD_add_to_scrollback(buf, 3);
2768 if ( DSResult == DSERR_BUFFERLOST ) {
2769 ds_restore_buffer(Channels[channel].pdsb);
2770 DSResult = Channels[channel].pdsb->Play(0, 0, ds_flags );
2773 if ( DSResult != DS_OK ) {
2774 nprintf(("Sound", "Sound ==> Play failed with return value %s\n", get_DSERR_text(DSResult) ));
2779 // nprintf(( "Sound", "SOUND ==> Not playing sound requested at volume %.2f\n", ds_get_percentage_vol(volume) ));
2783 Channels[channel].snd_id = snd_id;
2784 Channels[channel].sig = channel_next_sig++;
2785 if (channel_next_sig < 0 ) {
2786 channel_next_sig = 1;
2790 if (Stop_logging_sounds == false) {
2793 sprintf(buf, "VOICE sig: %d, sid: %d, snd_id: %d, ch: %d", Channels[channel].sig, sid, snd_id, channel);
2794 HUD_add_to_scrollback(buf, 3);
2799 Channels[channel].last_position = 0;
2801 // make sure there aren't any looping voice messages
2802 for (int i=0; i<MAX_CHANNELS; i++) {
2803 if (Channels[i].is_voice_msg == true) {
2804 if (Channels[i].pdsb == NULL) {
2808 DWORD current_position = ds_get_play_position(i);
2809 if (current_position != 0) {
2810 if (current_position < Channels[i].last_position) {
2811 ds_close_channel(i);
2813 Channels[i].last_position = current_position;
2819 return Channels[channel].sig;
2824 // ---------------------------------------------------------------------------------------
2827 // Return the channel number that is playing the sound identified by sig. If that sound is
2828 // not playing, return -1.
2830 int ds_get_channel(int sig)
2835 for ( i = 0; i < MAX_CHANNELS; i++ ) {
2836 if ( Channels[i].source_id && Channels[i].sig == sig ) {
2837 if ( ds_is_channel_playing(i) == TRUE ) {
2847 for ( i = 0; i < MAX_CHANNELS; i++ ) {
2848 if ( Channels[i].pdsb && Channels[i].sig == sig ) {
2849 if ( ds_is_channel_playing(i) == TRUE ) {
2858 // ---------------------------------------------------------------------------------------
2859 // ds_is_channel_playing()
2862 int ds_is_channel_playing(int channel)
2865 if ( Channels[channel].source_id != 0 ) {
2868 OpenAL_ErrorPrint( alGetSourcei(Channels[channel].source_id, AL_SOURCE_STATE, &status) );
2870 return (status == AL_PLAYING);
2876 unsigned long status;
2878 if ( !Channels[channel].pdsb ) {
2882 hr = Channels[channel].pdsb->GetStatus(&status);
2883 if ( hr != DS_OK ) {
2884 nprintf(("Sound", "SOUND ==> GetStatus failed with return value %s\n", get_DSERR_text(hr) ));
2888 if ( status & DSBSTATUS_PLAYING )
2895 // ---------------------------------------------------------------------------------------
2896 // ds_stop_channel()
2899 void ds_stop_channel(int channel)
2902 if ( Channels[channel].source_id != 0 ) {
2903 OpenAL_ErrorPrint( alSourceStop(Channels[channel].source_id) );
2906 ds_close_channel(channel);
2910 // ---------------------------------------------------------------------------------------
2911 // ds_stop_channel_all()
2914 void ds_stop_channel_all()
2919 for ( i=0; i<MAX_CHANNELS; i++ ) {
2920 if ( Channels[i].source_id != 0 ) {
2921 OpenAL_ErrorPrint( alSourceStop(Channels[i].source_id) );
2927 for ( i=0; i<MAX_CHANNELS; i++ ) {
2928 if ( Channels[i].pdsb != NULL ) {
2935 // ---------------------------------------------------------------------------------------
2938 // Set the volume for a channel. The volume is expected to be in DirectSound units
2940 // If the sound is a 3D sound buffer, this is like re-establishing the maximum
2943 void ds_set_volume( int channel, int vol )
2946 ALuint source_id = Channels[channel].source_id;
2948 if (source_id != 0) {
2949 ALfloat alvol = (vol != -10000) ? powf(10.0f, (float)vol / (-600.0f / log10f(.5f))): 0.0f;
2951 OpenAL_ErrorPrint( alSourcef(source_id, AL_GAIN, alvol) );
2955 unsigned long status;
2957 hr = Channels[channel].pdsb->GetStatus(&status);
2958 if ( hr != DS_OK ) {
2959 nprintf(("Sound", "SOUND ==> GetStatus failed with return value %s\n", get_DSERR_text(hr) ));
2963 if ( status & DSBSTATUS_PLAYING ) {
2964 Channels[channel].pdsb->SetVolume(vol);
2969 // ---------------------------------------------------------------------------------------
2972 // Set the pan for a channel. The pan is expected to be in DirectSound units
2974 void ds_set_pan( int channel, int pan )
2979 OpenAL_ErrorCheck( alGetSourcei(Channels[channel].source_id, AL_SOURCE_STATE, &state), return );
2981 if (state == AL_PLAYING) {
2982 ALfloat alpan = (pan != 0) ? ((float)pan / MAX_PAN) : 0.0f;
2983 OpenAL_ErrorPrint( alSource3f(Channels[channel].source_id, AL_POSITION, alpan, 0.0, 1.0) );
2987 unsigned long status;
2989 hr = Channels[channel].pdsb->GetStatus(&status);
2990 if ( hr != DS_OK ) {
2991 nprintf(("Sound", "SOUND ==> GetStatus failed with return value %s\n", get_DSERR_text(hr) ));
2995 if ( status & DSBSTATUS_PLAYING ) {
2996 Channels[channel].pdsb->SetPan(pan);
3001 // ---------------------------------------------------------------------------------------
3004 // Get the pitch of a channel
3006 int ds_get_pitch(int channel)
3010 ALfloat alpitch = 0;
3013 OpenAL_ErrorCheck( alGetSourcei(Channels[channel].source_id, AL_SOURCE_STATE, &status), return -1 );
3015 if (status == AL_PLAYING)
3016 OpenAL_ErrorPrint( alGetSourcef(Channels[channel].source_id, AL_PITCH, &alpitch) );
3018 // convert OpenAL values to DirectSound values and return
3019 pitch = fl2i( pow(10.0, (alpitch + 2.0)) );
3023 unsigned long status, pitch = 0;
3026 hr = Channels[channel].pdsb->GetStatus(&status);
3028 if ( hr != DS_OK ) {
3029 nprintf(("Sound", "SOUND ==> GetStatus failed with return value %s\n", get_DSERR_text(hr) ));
3033 if ( status & DSBSTATUS_PLAYING ) {
3034 hr = Channels[channel].pdsb->GetFrequency(&pitch);
3035 if ( hr != DS_OK ) {
3036 nprintf(("Sound", "SOUND ==> GetFrequency failed with return value %s\n", get_DSERR_text(hr) ));
3045 // ---------------------------------------------------------------------------------------
3048 // Set the pitch of a channel
3050 void ds_set_pitch(int channel, int pitch)
3055 if ( pitch < MIN_PITCH )
3058 if ( pitch > MAX_PITCH )
3061 OpenAL_ErrorCheck( alGetSourcei(Channels[channel].source_id, AL_SOURCE_STATE, &status), return );
3063 if (status == AL_PLAYING) {
3064 ALfloat alpitch = log10f((float)pitch) - 2.0f;
3065 OpenAL_ErrorPrint( alSourcef(Channels[channel].source_id, AL_PITCH, alpitch) );
3068 unsigned long status;
3071 hr = Channels[channel].pdsb->GetStatus(&status);
3072 if ( hr != DS_OK ) {
3073 nprintf(("Sound", "SOUND ==> GetStatus failed with return value %s\n", get_DSERR_text(hr) ));
3077 if ( pitch < MIN_PITCH )
3080 if ( pitch > MAX_PITCH )
3083 if ( status & DSBSTATUS_PLAYING ) {
3084 Channels[channel].pdsb->SetFrequency((unsigned long)pitch);
3089 // ---------------------------------------------------------------------------------------
3090 // ds_chg_loop_status()
3093 void ds_chg_loop_status(int channel, int loop)
3096 ALuint source_id = Channels[channel].source_id;
3098 OpenAL_ErrorPrint( alSourcei(source_id, AL_LOOPING, loop ? AL_TRUE : AL_FALSE) );
3100 unsigned long status;
3103 hr = Channels[channel].pdsb->GetStatus(&status);
3104 if ( hr != DS_OK ) {
3105 nprintf(("Sound", "SOUND ==> GetStatus failed with return value %s\n", get_DSERR_text(hr) ));
3109 if ( !(status & DSBSTATUS_PLAYING) )
3110 return; // sound is not playing anymore
3112 if ( status & DSBSTATUS_LOOPING ) {
3114 return; // we are already looping
3116 // stop the sound from looping
3117 hr = Channels[channel].pdsb->Play(0,0,0);
3122 return; // the sound is already not looping
3124 // start the sound looping
3125 hr = Channels[channel].pdsb->Play(0,0,DSBPLAY_LOOPING);
3131 // ---------------------------------------------------------------------------------------
3134 // Starts a ds3d sound playing
3138 // sid => software id for sound to play
3139 // hid => hardware id for sound to play (-1 if not in hardware)
3140 // snd_id => identifies what type of sound is playing
3141 // pos => world pos of sound
3142 // vel => velocity of object emitting sound
3143 // min => distance at which sound doesn't get any louder
3144 // max => distance at which sound becomes inaudible
3145 // looping => boolean, whether to loop the sound or not
3146 // max_volume => volume (-10000 to 0) for 3d sound at maximum
3147 // estimated_vol => manual estimated volume
3148 // priority => DS_MUST_PLAY
3153 // returns: 0 => sound started successfully
3154 // -1 => sound could not be played
3156 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 )
3166 if (!ds_initialized)
3169 channel = ds_get_free_channel(estimated_vol, snd_id, priority);
3172 Assert(Channels[channel].pdsb == NULL);
3174 // First check if the sound is in hardware, and try to duplicate from there
3177 if ( ds_is_3d_buffer(ds_hardware_buffers[hid].pdsb) == FALSE ) {
3178 nprintf(("Sound", "SOUND ==> Tried to play non-3d buffer in ds3d_play()..\n"));
3182 if ( ds_channel_dup(ds_hardware_buffers[hid].pdsb, channel, 1) == 0 ) {
3183 nprintf(("Sound", "SOUND ==> Played sound using DirectSound3D in hardware..\n"));
3187 // Channel will be NULL if hardware dup failed, or there was no hardware dup attempted
3188 if ( Channels[channel].pdsb == NULL ) {
3191 if ( ds_is_3d_buffer(ds_software_buffers[sid].pdsb) == FALSE ) {
3192 nprintf(("Sound", "SOUND ==> Tried to play non-3d buffer in ds3d_play()..\n"));
3197 if ( ds_channel_dup(ds_software_buffers[sid].pdsb, channel, 1) == 0 ) {
3198 // nprintf(("Sound", "SOUND ==> Played sound using DirectSound3D \n"));
3202 if ( Channels[channel].pdsb == NULL ) {
3207 desc = ds_software_buffers[sid].desc;
3208 desc.lpwfxFormat = &ds_software_buffers[sid].wfx;
3210 // duplicate buffer failed, so call CreateBuffer instead
3212 hr = pDirectSound->CreateSoundBuffer(&desc, &Channels[channel].pdsb, NULL );
3214 if ( (hr == DS_OK) && (Channels[channel].pdsb) ) {
3215 BYTE *pdest, *pdest2;
3217 DWORD src_ds_size, dest_ds_size, not_used;
3220 if ( ds_get_size(sid, &src_size) != 0 ) {
3222 Channels[channel].pdsb->Release();
3226 // lock the src buffer
3227 hr = ds_software_buffers[sid].pdsb->Lock(0, src_size, (void**)&psrc, &src_ds_size, (void**)&psrc2, ¬_used, 0);
3228 if ( hr != DS_OK ) {
3229 mprintf(("err: %s\n", get_DSERR_text(hr)));
3231 Channels[channel].pdsb->Release();
3235 if ( Channels[channel].pdsb->Lock(0, src_ds_size, (void**)(&pdest), &dest_ds_size, (void**)&pdest2, ¬_used, 0) == DS_OK) {
3236 memcpy(pdest, psrc, src_ds_size);
3237 Channels[channel].pdsb->Unlock(pdest, dest_ds_size, 0, 0);
3238 ds_get_3d_interface(Channels[channel].pdsb, &Channels[channel].pds3db);
3240 Channels[channel].pdsb->Release();
3247 Assert(Channels[channel].pds3db );
3248 Channels[channel].pds3db->SetMode(DS3DMODE_NORMAL,DS3D_IMMEDIATE);
3250 // set up 3D sound data here
3251 ds3d_update_buffer(channel, i2fl(min), i2fl(max), pos, vel);
3253 Channels[channel].vol = estimated_vol;
3254 Channels[channel].looping = looping;
3256 // sets the maximum "inner cone" volume
3257 Channels[channel].pdsb->SetVolume(max_volume);
3261 ds_flags |= DSBPLAY_LOOPING;
3264 hr = Channels[channel].pdsb->Play(0, 0, ds_flags );
3266 if ( hr == DSERR_BUFFERLOST ) {
3267 ds_restore_buffer(Channels[channel].pdsb);
3268 hr = Channels[channel].pdsb->Play(0, 0, ds_flags );
3271 if ( hr != DS_OK ) {
3272 nprintf(("Sound", "Sound ==> Play failed with return value %s\n", get_DSERR_text(hr) ));
3273 if ( Channels[channel].pdsb ) {
3275 while(++attempts < 10) {
3276 hr = Channels[channel].pdsb->Release();
3277 if ( hr == DS_OK ) {
3280 nprintf(("Sound","SOUND ==> DirectSound Release() failed with code %s\n.",get_DSERR_text(hr) ));
3284 Channels[channel].pdsb = NULL;
3290 nprintf(( "Sound", "SOUND ==> Not playing requested 3D sound\n"));
3294 Channels[channel].snd_id = snd_id;
3295 Channels[channel].sig = channel_next_sig++;
3296 if (channel_next_sig < 0 ) {
3297 channel_next_sig = 1;
3299 return Channels[channel].sig;
3303 void ds_set_position(int channel, DWORD offset)
3308 // set the position of the sound buffer
3309 Channels[channel].pdsb->SetCurrentPosition(offset);
3313 DWORD ds_get_play_position(int channel)
3319 if (!AL_play_position)
3322 buf_id = Channels[channel].buf_id;
3327 OpenAL_ErrorCheck( alGetSourcei( Channels[channel].source_id, AL_BYTE_LOKI, &pos), return 0 );
3332 } else if ( pos > 0 ) {
3333 // AL_BYTE_LOKI returns position in canon format which may differ
3334 // from our sample, so we may have to scale it
3335 ALuint buf = sound_buffers[buf_id].buf_id;
3338 OpenAL_ErrorCheck( alGetBufferi(buf, AL_SIZE, &size), return 0 );
3340 pos = (ALint)(pos * ((float)sound_buffers[buf_id].nbytes / size));
3346 if ( Channels[channel].pdsb ) {
3347 Channels[channel].pdsb->GetCurrentPosition((LPDWORD)&play,(LPDWORD)&write);
3356 DWORD ds_get_write_position(int channel)
3364 if ( Channels[channel].pdsb ) {
3365 Channels[channel].pdsb->GetCurrentPosition((LPDWORD)&play,(LPDWORD)&write);
3374 int ds_get_channel_size(int channel)
3377 int buf_id = Channels[channel].buf_id;
3380 return sound_buffers[buf_id].nbytes;
3389 if ( Channels[channel].pdsb ) {
3390 memset(&caps, 0, sizeof(DSBCAPS));
3391 caps.dwSize = sizeof(DSBCAPS);
3392 dsrval = Channels[channel].pdsb->GetCaps(&caps);
3393 if ( dsrval != DS_OK ) {
3396 size = caps.dwBufferBytes;
3405 // Returns the number of channels that are actually playing
3406 int ds_get_number_channels()
3411 if (!ds_initialized) {
3416 for ( i = 0; i < MAX_CHANNELS; i++ ) {
3417 if ( Channels[i].source_id ) {
3418 if ( ds_is_channel_playing(i) == TRUE ) {
3429 for ( i = 0; i < MAX_CHANNELS; i++ ) {
3430 if ( Channels[i].pdsb ) {
3431 if ( ds_is_channel_playing(i) == TRUE ) {
3441 // retreive raw data from a sound buffer
3442 int ds_get_data(int sid, char *data)
3450 LPDIRECTSOUNDBUFFER pdsb;
3456 pdsb = ds_software_buffers[sid].pdsb;
3458 memset(&caps, 0, sizeof(DSBCAPS));
3459 caps.dwSize = sizeof(DSBCAPS);
3460 dsrval = pdsb->GetCaps(&caps);
3461 if ( dsrval != DS_OK ) {
3465 // lock the entire buffer
3466 dsrval = pdsb->Lock(0, caps.dwBufferBytes, &buffer_data, &buffer_size, 0, 0, 0);
3467 if ( dsrval != DS_OK ) {
3471 memcpy(data, buffer_data, buffer_size);
3473 dsrval = pdsb->Unlock(buffer_data, buffer_size, 0, 0);
3474 if ( dsrval != DS_OK ) {
3482 // return the size of the raw sound data
3483 int ds_get_size(int sid, int *size)
3493 LPDIRECTSOUNDBUFFER pdsb;
3497 pdsb = ds_software_buffers[sid].pdsb;
3499 memset(&caps, 0, sizeof(DSBCAPS));
3500 caps.dwSize = sizeof(DSBCAPS);
3501 dsrval = pdsb->GetCaps(&caps);
3502 if ( dsrval != DS_OK ) {
3506 *size = caps.dwBufferBytes;
3515 // Return the primary buffer interface. Note that we cast to a uint to avoid
3516 // having to include dsound.h (and thus windows.h) in ds.h.
3518 uint ds_get_primary_buffer_interface()
3524 return (uint)pPrimaryBuffer;
3528 // Return the DirectSound Interface.
3530 uint ds_get_dsound_interface()
3536 return (uint)pDirectSound;
3540 uint ds_get_property_set_interface()
3545 return (uint)pPropertySet;
3549 // --------------------
3551 // EAX Functions below
3553 // --------------------
3555 // Set the master volume for the reverb added to all sound sources.
3557 // volume: volume, range from 0 to 1.0
3559 // returns: 0 if the volume is set successfully, otherwise return -1
3561 int ds_eax_set_volume(float volume)
3568 if (Ds_eax_inited == 0) {
3572 Assert(Ds_eax_reverb);
3574 CAP(volume, 0.0f, 1.0f);
3576 hr = Ds_eax_reverb->Set(DSPROPSETID_EAX_ReverbProperties_Def, DSPROPERTY_EAX_VOLUME, NULL, 0, &volume, sizeof(float));
3577 if (SUCCEEDED(hr)) {
3585 // Set the decay time for the EAX environment (ie all sound sources)
3587 // seconds: decay time in seconds
3589 // returns: 0 if decay time is successfully set, otherwise return -1
3591 int ds_eax_set_decay_time(float seconds)
3598 if (Ds_eax_inited == 0) {
3602 Assert(Ds_eax_reverb);
3604 CAP(seconds, 0.1f, 20.0f);
3606 hr = Ds_eax_reverb->Set(DSPROPSETID_EAX_ReverbProperties_Def, DSPROPERTY_EAX_DECAYTIME, NULL, 0, &seconds, sizeof(float));
3607 if (SUCCEEDED(hr)) {
3615 // Set the damping value for the EAX environment (ie all sound sources)
3617 // damp: damp value from 0 to 2.0
3619 // returns: 0 if the damp value is successfully set, otherwise return -1
3621 int ds_eax_set_damping(float damp)
3628 if (Ds_eax_inited == 0) {
3632 Assert(Ds_eax_reverb);
3634 CAP(damp, 0.0f, 2.0f);
3636 hr = Ds_eax_reverb->Set(DSPROPSETID_EAX_ReverbProperties_Def, DSPROPERTY_EAX_DAMPING, NULL, 0, &damp, sizeof(float));
3637 if (SUCCEEDED(hr)) {
3645 // Set up the environment type for all sound sources.
3647 // envid: value from the EAX_ENVIRONMENT_* enumeration in ds_eax.h
3649 // returns: 0 if the environment is set successfully, otherwise return -1
3651 int ds_eax_set_environment(unsigned long envid)
3658 if (Ds_eax_inited == 0) {
3662 Assert(Ds_eax_reverb);
3664 hr = Ds_eax_reverb->Set(DSPROPSETID_EAX_ReverbProperties_Def, DSPROPERTY_EAX_ENVIRONMENT, NULL, 0, &envid, sizeof(unsigned long));
3665 if (SUCCEEDED(hr)) {
3673 // Set up a predefined environment for EAX
3675 // envid: value from teh EAX_ENVIRONMENT_* enumeration
3677 // returns: 0 if successful, otherwise return -1
3679 int ds_eax_set_preset(unsigned long envid)
3686 if (Ds_eax_inited == 0) {
3690 Assert(Ds_eax_reverb);
3691 Assert(envid < EAX_ENVIRONMENT_COUNT);
3693 hr = Ds_eax_reverb->Set(DSPROPSETID_EAX_ReverbProperties_Def, DSPROPERTY_EAX_ALL, NULL, 0, &Ds_eax_presets[envid], sizeof(EAX_REVERBPROPERTIES));
3694 if (SUCCEEDED(hr)) {
3703 // Set up all the parameters for an environment
3705 // id: value from teh EAX_ENVIRONMENT_* enumeration
3706 // volume: volume for the environment (0 to 1.0)
3707 // damping: damp value for the environment (0 to 2.0)
3708 // decay: decay time in seconds (0.1 to 20.0)
3710 // returns: 0 if successful, otherwise return -1
3712 int ds_eax_set_all(unsigned long id, float vol, float damping, float decay)
3719 if (Ds_eax_inited == 0) {
3723 Assert(Ds_eax_reverb);
3724 Assert(id < EAX_ENVIRONMENT_COUNT);
3726 EAX_REVERBPROPERTIES er;
3728 er.environment = id;
3730 er.fDecayTime_sec = decay;
3731 er.fDamping = damping;
3733 hr = Ds_eax_reverb->Set(DSPROPSETID_EAX_ReverbProperties_Def, DSPROPERTY_EAX_ALL, NULL, 0, &er, sizeof(EAX_REVERBPROPERTIES));
3734 if (SUCCEEDED(hr)) {
3742 // Get up the parameters for the current environment
3744 // er: (output) hold environment parameters
3746 // returns: 0 if successful, otherwise return -1
3748 int ds_eax_get_all(EAX_REVERBPROPERTIES *er)
3754 unsigned long outsize;
3756 if (Ds_eax_inited == 0) {
3760 Assert(Ds_eax_reverb);
3762 hr = Ds_eax_reverb->Get(DSPROPSETID_EAX_ReverbProperties_Def, DSPROPERTY_EAX_ALL, NULL, 0, er, sizeof(EAX_REVERBPROPERTIES), &outsize);
3763 if (SUCCEEDED(hr)) {
3771 // Close down EAX, freeing any allocated resources
3776 if (Ds_eax_inited == 0) {
3786 // returns: 0 if initialization is successful, otherwise return -1
3792 unsigned long driver_support = 0;
3794 if (Ds_eax_inited) {
3798 Assert(Ds_eax_reverb == NULL);
3800 Ds_eax_reverb = (LPKSPROPERTYSET)ds_get_property_set_interface();
3801 if (Ds_eax_reverb == NULL) {
3805 // check if the listener property is supported by the audio driver
3806 hr = Ds_eax_reverb->QuerySupport(DSPROPSETID_EAX_ReverbProperties_Def, DSPROPERTY_EAX_ALL, &driver_support);
3808 nprintf(("Sound", "QuerySupport for the EAX Listener property set failed.. disabling EAX\n"));
3809 goto ds_eax_init_failed;
3812 if ((driver_support & (KSPROPERTY_SUPPORT_GET | KSPROPERTY_SUPPORT_SET)) != (KSPROPERTY_SUPPORT_GET | KSPROPERTY_SUPPORT_SET)) {
3813 goto ds_eax_init_failed;
3816 ds_eax_set_all(EAX_ENVIRONMENT_GENERIC, 0.0f, 0.0f, 0.0f);
3822 if (Ds_eax_reverb != NULL) {
3823 Ds_eax_reverb->Release();
3824 Ds_eax_reverb = NULL;
3833 int ds_eax_is_inited()
3838 return Ds_eax_inited;
3847 if (Ds_use_a3d == 0) {
3855 // Called once per game frame to make sure voice messages aren't looping
3861 if (!ds_initialized) {
3865 for (int i=0; i<MAX_CHANNELS; i++) {
3867 if (cp->is_voice_msg == true) {
3868 if (cp->source_id == 0) {
3872 DWORD current_position = ds_get_play_position(i);
3873 if (current_position != 0) {
3874 if (current_position < (DWORD)cp->last_position) {
3878 ds_close_channel(i);
3881 cp->last_position = current_position;
3894 int ds3d_update_buffer(int channel, float min, float max, vector *pos, vector *vel)
3901 int ds3d_update_listener(vector *pos, vector *vel, matrix *orient)
3906 ALfloat posv[] = { pos->x, pos->y, pos->z };
3907 ALfloat velv[] = { vel->x, vel->y, vel->z };
3908 ALfloat oriv[] = { orient->a1d[0],
3909 orient->a1d[1], orient->a1d[2],
3910 orient->a1d[3], orient->a1d[4],
3912 alListenerfv(AL_POSITION, posv);
3913 alListenerfv(AL_VELOCITY, velv);
3914 alListenerfv(AL_ORIENTATION, oriv);
3920 int ds3d_init (int unused)
3925 ALfloat pos[] = { 0.0, 0.0, 0.0 },
3926 vel[] = { 0.0, 0.0, 0.0 },
3927 ori[] = { 0.0, 0.0, 1.0, 0.0, -1.0, 0.0 };
3929 alListenerfv (AL_POSITION, pos);
3930 alListenerfv (AL_VELOCITY, vel);
3931 alListenerfv (AL_ORIENTATION, ori);
3933 if(alGetError() != AL_NO_ERROR)
3947 int dscap_create_buffer(int freq, int bits_per_sample, int nchannels, int nseconds)
3954 int dscap_get_raw_data(unsigned char *outbuf, unsigned int max_size)
3961 int dscap_max_buffersize()
3968 void dscap_release_buffer()
3973 int dscap_start_record()
3980 int dscap_stop_record()
3987 int dscap_supported()