2 * $Logfile: /Freespace2/code/Sound/ds.cpp $
7 * C file for interface to DirectSound
10 * Revision 1.9 2002/06/05 08:05:29 relnev
11 * stub/warning removal.
13 * reworked the sound code.
15 * Revision 1.8 2002/06/05 04:03:33 relnev
16 * finished cfilesystem.
18 * removed some old code.
20 * fixed mouse save off-by-one.
24 * Revision 1.7 2002/06/02 22:31:37 cemason
27 * Revision 1.6 2002/06/02 21:11:12 cemason
30 * Revision 1.5 2002/06/02 09:50:42 relnev
33 * Revision 1.4 2002/06/02 07:17:44 cemason
34 * Added OpenAL support.
36 * Revision 1.3 2002/05/28 17:03:29 theoddone33
37 * fs2 gets to the main game loop now
39 * Revision 1.2 2002/05/27 21:35:50 theoddone33
40 * Stub out dsound backend
42 * Revision 1.1.1.1 2002/05/03 03:28:10 root
46 * 18 10/25/99 5:56p Jefff
47 * increase num software channels to the number the users hardware can
48 * handle. not less than 16, tho.
50 * 17 9/08/99 3:22p Dave
51 * Updated builtin mission list.
53 * 16 8/27/99 6:38p Alanl
54 * crush the blasted repeating messages bug
56 * 15 8/23/99 11:16p Danw
59 * 14 8/22/99 11:06p Alanl
60 * fix small bug in ds_close_channel
62 * 13 8/19/99 11:25a Alanl
63 * change format of secondary buffer from 44100 to 22050
65 * 12 8/17/99 4:11p Danw
66 * AL: temp fix for solving A3D crash
68 * 11 8/06/99 2:20p Jasonh
69 * AL: free 3D portion of buffer first
71 * 10 8/04/99 9:48p Alanl
72 * fix bug with setting 3D properties on a 2D sound buffer
74 * 9 8/04/99 11:42a Danw
75 * tone down EAX reverb
77 * 8 8/01/99 2:06p Alanl
78 * increase the rolloff for A3D
80 * 7 7/20/99 5:28p Dave
81 * Fixed debug build error.
83 * 6 7/20/99 1:49p Dave
84 * Peter Drake build. Fixed some release build warnings.
86 * 5 7/14/99 11:32a Danw
87 * AL: add some debug code to catch nefarious A3D problem
89 * 4 5/23/99 8:11p Alanl
90 * Added support for EAX
92 * 3 10/08/98 4:29p Dave
93 * Removed reference to osdefs.h
95 * 2 10/07/98 10:54a Dave
98 * 1 10/07/98 10:51a Dave
100 * 72 6/28/98 6:34p Lawrance
101 * add sanity check in while() loop for releasing channels
103 * 71 6/13/98 1:45p Sandeep
105 * 70 6/10/98 2:29p Lawrance
106 * don't use COM for initializing DirectSound... appears some machines
109 * 69 5/26/98 2:10a Lawrance
110 * make sure DirectSound pointer gets freed if Aureal resource manager
113 * 68 5/21/98 9:14p Lawrance
114 * remove obsolete registry setting
116 * 67 5/20/98 4:28p Allender
117 * upped sound buffers as per alan's request
119 * 66 5/15/98 3:36p John
120 * Fixed bug with new graphics window code and standalone server. Made
121 * hwndApp not be a global anymore.
123 * 65 5/06/98 3:37p Lawrance
124 * allow panned sounds geesh
126 * 64 5/05/98 4:49p Lawrance
127 * Put in code to authenticate A3D, improve A3D support
129 * 63 4/20/98 11:17p Lawrance
130 * fix bug with releasing channels
132 * 62 4/20/98 7:34p Lawrance
133 * take out obsolete directsound3d debug command
135 * 61 4/20/98 11:10a Lawrance
136 * put correct flags when creating sound buffer
138 * 60 4/20/98 12:03a Lawrance
139 * Allow prioritizing of CTRL3D buffers
141 * 59 4/19/98 9:31p Lawrance
142 * Use Aureal_enabled flag
144 * 58 4/19/98 9:39a Lawrance
145 * use DYNAMIC_LOOPERS for Aureal resource manager
147 * 57 4/19/98 4:13a Lawrance
148 * Improve how dsound is initialized
150 * 56 4/18/98 9:13p Lawrance
151 * Added Aureal support.
153 * 55 4/13/98 5:04p Lawrance
154 * Write functions to determine how many milliseconds are left in a sound
156 * 54 4/09/98 5:53p Lawrance
157 * Make DirectSound init more robust
159 * 53 4/01/98 9:21p John
160 * Made NDEBUG, optimized build with no warnings or errors.
162 * 52 3/31/98 5:19p John
163 * Removed demo/save/restore. Made NDEBUG defined compile. Removed a
164 * bunch of debug stuff out of player file. Made model code be able to
165 * unload models and malloc out only however many models are needed.
168 * 51 3/29/98 12:56a Lawrance
169 * preload the warp in and explosions sounds before a mission.
171 * 50 3/25/98 6:10p Lawrance
172 * Work on DirectSound3D
174 * 49 3/24/98 4:28p Lawrance
175 * Make DirectSound3D support more robust
177 * 48 3/24/98 11:49a Dave
178 * AL: Change way buffer gets locked.
180 * 47 3/24/98 11:27a Lawrance
181 * Use buffer_size for memcpy when locking buffer
183 * 46 3/23/98 10:32a Lawrance
184 * Add functions for extracting raw sound data
186 * 45 3/19/98 5:36p Lawrance
187 * Add some sound debug functions to see how many sounds are playing, and
188 * to start/stop random looping sounds.
190 * 44 3/07/98 3:35p Dave
191 * AL: check for ds being initialized in ds_create_buffer()
193 * 43 2/18/98 5:49p Lawrance
194 * Even if the ADPCM codec is unavailable, allow game to continue.
196 * 42 2/16/98 7:31p Lawrance
197 * get compression/decompression of voice working
199 * 41 2/15/98 11:10p Lawrance
200 * more work on real-time voice system
202 * 40 2/15/98 4:43p Lawrance
203 * work on real-time voice
205 * 39 2/06/98 7:30p John
206 * Added code to monitor the number of channels of sound actually playing.
208 * 38 2/06/98 8:56a Allender
209 * fixed calling convention problem with DLL handles
211 * 37 2/04/98 6:08p Lawrance
212 * Read function pointers from dsound.dll, further work on
213 * DirectSoundCapture.
215 * 36 2/03/98 11:53p Lawrance
216 * Adding support for DirectSoundCapture
218 * 35 1/31/98 5:48p Lawrance
219 * Start on real-time voice recording
221 * 34 1/10/98 1:14p John
222 * Added explanation to debug console commands
224 * 33 12/21/97 4:33p John
225 * Made debug console functions a class that registers itself
226 * automatically, so you don't need to add the function to
227 * debugfunctions.cpp.
229 * 32 12/08/97 12:24a Lawrance
230 * Allow duplicate sounds to be stopped if less than OR equal to new sound
233 * 31 12/05/97 5:19p Lawrance
234 * re-do sound priorities to make more general and extensible
236 * 30 11/28/97 2:09p Lawrance
237 * Overhaul how ADPCM conversion works... use much less memory... safer
240 * 29 11/22/97 11:32p Lawrance
241 * decompress ADPCM data into 8 bit (not 16bit) for regular sounds (ie not
244 * 28 11/20/97 5:36p Dave
245 * Hooked in a bunch of main hall changes (including sound). Made it
246 * possible to reposition (rewind/ffwd)
247 * sound buffer pointers. Fixed animation direction change framerate
250 * 27 10/13/97 7:41p Lawrance
251 * store duration of sound
253 * 26 10/11/97 6:39p Lawrance
254 * start playing primary buffer, to reduce latency on sounds starting
256 * 25 10/08/97 5:09p Lawrance
257 * limit player impact sounds so only one plays at a time
259 * 24 9/26/97 5:43p Lawrance
260 * fix a bug that was freeing memory early when playing compressed sound
263 * 23 9/09/97 3:39p Sandeep
264 * warning level 4 bugs
266 * 22 8/16/97 4:05p Lawrance
267 * don't load sounds into hardware if running Lean_and_mean
269 * 21 8/05/97 1:39p Lawrance
270 * support compressed stereo playback
272 * 20 7/31/97 10:38a Lawrance
273 * return old debug function for toggling DirectSound3D
275 * 19 7/29/97 3:27p Lawrance
276 * make console toggle for directsound3d work right
278 * 18 7/28/97 11:39a Lawrance
279 * allow individual volume scaling on 3D buffers
281 * 17 7/18/97 8:18p Lawrance
282 * fix bug in ds_get_free_channel() that caused sounds to not play when
285 * 16 7/17/97 8:04p Lawrance
286 * allow priority sounds to play if free channel, otherwise stop lowest
287 * volume priority sound of same type
289 * 15 7/17/97 5:57p John
290 * made directsound3d config value work
292 * 14 7/17/97 5:43p John
293 * added new config stuff
295 * 13 7/17/97 4:25p John
296 * First, broken, stage of changing config stuff
298 * 12 7/15/97 12:13p Lawrance
299 * don't stop sounds that have highest priority
301 * 11 7/15/97 11:15a Lawrance
302 * limit the max instances of simultaneous sound effects, implement
303 * priorities to force critical sounds
305 * 10 6/09/97 11:50p Lawrance
306 * integrating DirectSound3D
308 * 9 6/08/97 5:59p Lawrance
309 * integrate DirectSound3D into sound system
311 * 8 6/04/97 1:19p Lawrance
312 * made hardware mixing robust
314 * 7 6/03/97 1:56p Hoffoss
315 * Return correct error code when direct sound init fails.
317 * 6 6/03/97 12:07p Lawrance
318 * don't enable 3D sounds in Primary buffer
320 * 5 6/02/97 3:45p Dan
321 * temp disable of hardware mixing until problem solved with
322 * CreateBuffer() failing
324 * 4 6/02/97 1:45p Lawrance
325 * implementing hardware mixing
327 * 3 5/29/97 4:01p Lawrance
328 * let snd_init() have final say on initialization
330 * 2 5/29/97 12:04p Lawrance
331 * creation of file to hold DirectSound specific portions
350 #include <initguid.h>
352 #include "verifya3d.h"
357 #include <SDL/SDL_audio.h>
361 // Pointers to functions contained in DSOUND.dll
362 HRESULT (__stdcall *pfn_DirectSoundCreate)(LPGUID lpGuid, LPDIRECTSOUND *ppDS, IUnknown FAR *pUnkOuter) = NULL;
363 HRESULT (__stdcall *pfn_DirectSoundCaptureCreate)(LPGUID lpGUID, LPDIRECTSOUNDCAPTURE *lplpDSC, LPUNKNOWN pUnkOuter) = NULL;
365 HINSTANCE Ds_dll_handle=NULL;
367 LPDIRECTSOUND pDirectSound = NULL;
368 LPDIRECTSOUNDBUFFER pPrimaryBuffer = NULL;
369 LPIA3D2 pIA3d2 = NULL;
371 static LPKSPROPERTYSET pPropertySet; // pointer to sound card property set
372 static LPDIRECTSOUNDBUFFER Ds_property_set_pdsb = NULL;
373 static LPDIRECTSOUND3DBUFFER Ds_property_set_pds3db = NULL;
375 static int Ds_must_call_couninitialize = 0;
377 channel* Channels; //[MAX_CHANNELS];
378 static int channel_next_sig = 1;
380 #define MAX_DS_SOFTWARE_BUFFERS 256
381 typedef struct ds_sound_buffer
383 LPDIRECTSOUNDBUFFER pdsb;
389 ds_sound_buffer ds_software_buffers[MAX_DS_SOFTWARE_BUFFERS];
391 #define MAX_DS_HARDWARE_BUFFERS 32
392 ds_sound_buffer ds_hardware_buffers[MAX_DS_HARDWARE_BUFFERS];
394 static DSCAPS Soundcard_caps; // current soundcard capabilities
396 extern int Snd_sram; // mem (in bytes) used up by storing sounds in system memory
397 extern int Snd_hram; // mem (in bytes) used up by storing sounds in soundcard memory
399 static int Ds_use_ds3d = 0;
400 static int Ds_use_a3d = 0;
401 static int Ds_use_eax = 0;
403 GUID IID_IA3d2_Def = {0xfb80d1e0, 0x98d3, 0x11d1, {0x90, 0xfb, 0x00, 0x60, 0x08, 0xa1, 0xf4, 0x41}};
404 GUID CLSID_A3d_Def = {0xd8f1eee0, 0xf634, 0x11cf, {0x87, 0x0, 0x0, 0xa0, 0x24, 0x5d, 0x91, 0x8b}};
406 static bool Stop_logging_sounds = false;
409 ///////////////////////////
413 ///////////////////////////
416 //#define EAX_PRESET_GENERIC EAX_ENVIRONMENT_GENERIC,0.5F,1.493F,0.5F
417 #define EAX_PRESET_GENERIC EAX_ENVIRONMENT_GENERIC,0.2F,0.2F,1.0F
418 #define EAX_PRESET_PADDEDCELL EAX_ENVIRONMENT_PADDEDCELL,0.25F,0.1F,0.0F
419 #define EAX_PRESET_ROOM EAX_ENVIRONMENT_ROOM,0.417F,0.4F,0.666F
420 #define EAX_PRESET_BATHROOM EAX_ENVIRONMENT_BATHROOM,0.653F,1.499F,0.166F
421 #define EAX_PRESET_LIVINGROOM EAX_ENVIRONMENT_LIVINGROOM,0.208F,0.478F,0.0F
422 #define EAX_PRESET_STONEROOM EAX_ENVIRONMENT_STONEROOM,0.5F,2.309F,0.888F
423 #define EAX_PRESET_AUDITORIUM EAX_ENVIRONMENT_AUDITORIUM,0.403F,4.279F,0.5F
424 #define EAX_PRESET_CONCERTHALL EAX_ENVIRONMENT_CONCERTHALL,0.5F,3.961F,0.5F
425 #define EAX_PRESET_CAVE EAX_ENVIRONMENT_CAVE,0.5F,2.886F,1.304F
426 #define EAX_PRESET_ARENA EAX_ENVIRONMENT_ARENA,0.361F,7.284F,0.332F
427 #define EAX_PRESET_HANGAR EAX_ENVIRONMENT_HANGAR,0.5F,10.0F,0.3F
428 #define EAX_PRESET_CARPETEDHALLWAY EAX_ENVIRONMENT_CARPETEDHALLWAY,0.153F,0.259F,2.0F
429 #define EAX_PRESET_HALLWAY EAX_ENVIRONMENT_HALLWAY,0.361F,1.493F,0.0F
430 #define EAX_PRESET_STONECORRIDOR EAX_ENVIRONMENT_STONECORRIDOR,0.444F,2.697F,0.638F
431 #define EAX_PRESET_ALLEY EAX_ENVIRONMENT_ALLEY,0.25F,1.752F,0.776F
432 #define EAX_PRESET_FOREST EAX_ENVIRONMENT_FOREST,0.111F,3.145F,0.472F
433 #define EAX_PRESET_CITY EAX_ENVIRONMENT_CITY,0.111F,2.767F,0.224F
434 #define EAX_PRESET_MOUNTAINS EAX_ENVIRONMENT_MOUNTAINS,0.194F,7.841F,0.472F
435 #define EAX_PRESET_QUARRY EAX_ENVIRONMENT_QUARRY,1.0F,1.499F,0.5F
436 #define EAX_PRESET_PLAIN EAX_ENVIRONMENT_PLAIN,0.097F,2.767F,0.224F
437 #define EAX_PRESET_PARKINGLOT EAX_ENVIRONMENT_PARKINGLOT,0.208F,1.652F,1.5F
438 #define EAX_PRESET_SEWERPIPE EAX_ENVIRONMENT_SEWERPIPE,0.652F,2.886F,0.25F
439 #define EAX_PRESET_UNDERWATER EAX_ENVIRONMENT_UNDERWATER,1.0F,1.499F,0.0F
440 #define EAX_PRESET_DRUGGED EAX_ENVIRONMENT_DRUGGED,0.875F,8.392F,1.388F
441 #define EAX_PRESET_DIZZY EAX_ENVIRONMENT_DIZZY,0.139F,17.234F,0.666F
442 #define EAX_PRESET_PSYCHOTIC EAX_ENVIRONMENT_PSYCHOTIC,0.486F,7.563F,0.806F
444 static LPKSPROPERTYSET Ds_eax_reverb = NULL;
446 static int Ds_eax_inited = 0;
448 EAX_REVERBPROPERTIES Ds_eax_presets[] =
450 {EAX_PRESET_GENERIC},
451 {EAX_PRESET_PADDEDCELL},
453 {EAX_PRESET_BATHROOM},
454 {EAX_PRESET_LIVINGROOM},
455 {EAX_PRESET_STONEROOM},
456 {EAX_PRESET_AUDITORIUM},
457 {EAX_PRESET_CONCERTHALL},
461 {EAX_PRESET_CARPETEDHALLWAY},
462 {EAX_PRESET_HALLWAY},
463 {EAX_PRESET_STONECORRIDOR},
467 {EAX_PRESET_MOUNTAINS},
470 {EAX_PRESET_PARKINGLOT},
471 {EAX_PRESET_SEWERPIPE},
472 {EAX_PRESET_UNDERWATER},
473 {EAX_PRESET_DRUGGED},
475 {EAX_PRESET_PSYCHOTIC},
478 GUID DSPROPSETID_EAX_ReverbProperties_Def = {0x4a4e6fc1, 0xc341, 0x11d1, {0xb7, 0x3a, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}};
479 GUID DSPROPSETID_EAXBUFFER_ReverbProperties_Def = {0x4a4e6fc0, 0xc341, 0x11d1, {0xb7, 0x3a, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}};
481 //----------------------------------------------------------------
483 void ds_get_soundcard_caps(DSCAPS *dscaps);
486 typedef struct channel
488 int sig; // uniquely identifies the sound playing on the channel
489 int snd_id; // identifies which kind of sound is playing
490 ALuint source_id; // OpenAL source id
491 int buf_id; // currently bound buffer index (-1 if none)
492 int looping; // flag to indicate that the sound is looping
494 int priority; // implementation dependant priority
499 typedef struct sound_buffer
501 ALuint buf_id; // OpenAL buffer id
502 int source_id; // source index this buffer is currently bound to
510 #define MAX_DS_SOFTWARE_BUFFERS 256
512 static int MAX_CHANNELS = 1000; // initialized properly in ds_init_channels()
514 static int channel_next_sig = 1;
516 sound_buffer sound_buffers[MAX_DS_SOFTWARE_BUFFERS];
518 static int Ds_use_ds3d = 0;
519 static int Ds_use_a3d = 0;
520 static int Ds_use_eax = 0;
522 ALCdevice *ds_sound_device;
523 void *ds_sound_context = (void *)0;
526 #define OpenAL_ErrorCheck() do { \
527 int i = alGetError(); \
528 if (i != AL_NO_ERROR) { \
529 while(i != AL_NO_ERROR) { \
530 nprintf(("Warning", "%s/%s:%d - OpenAL error %s\n", __FUNCTION__, __FILE__, __LINE__, alGetString(i))); \
537 #define OpenAL_ErrorCheck()
542 int ds_vol_lookup[101]; // lookup table for direct sound volumes
543 int ds_initialized = FALSE;
546 //--------------------------------------------------------------------------
549 // Determine if a secondary buffer is a 3d secondary buffer.
552 int ds_is_3d_buffer(LPDIRECTSOUNDBUFFER pdsb)
557 dsbc.dwSize = sizeof(dsbc);
558 hr = pdsb->GetCaps(&dsbc);
559 if ( hr == DS_OK && dsbc.dwFlags & DSBCAPS_CTRL3D ) {
568 //--------------------------------------------------------------------------
571 // Determine if a secondary buffer is a 3d secondary buffer.
573 int ds_is_3d_buffer(int sid)
577 return ds_is_3d_buffer(ds_software_buffers[sid].pdsb);
584 //--------------------------------------------------------------------------
585 // ds_build_vol_lookup()
587 // Fills up the ds_vol_lookup[] tables that converts from a volume in the form
588 // 0.0 -> 1.0 to -10000 -> 0 (this is the DirectSound method, where units are
589 // hundredths of decibls)
591 void ds_build_vol_lookup()
596 ds_vol_lookup[0] = -10000;
597 for ( i = 1; i <= 100; i++ ) {
599 ds_vol_lookup[i] = fl2i( (log(vol) / log(2.0f)) * 1000.0f);
604 //--------------------------------------------------------------------------
605 // ds_convert_volume()
607 // Takes volume between 0.0f and 1.0f and converts into
608 // DirectSound style volumes between -10000 and 0.
609 int ds_convert_volume(float volume)
613 index = fl2i(volume * 100.0f);
619 return ds_vol_lookup[index];
622 //--------------------------------------------------------------------------
623 // ds_get_percentage_vol()
625 // Converts -10000 -> 0 range volume to 0 -> 1
626 float ds_get_percentage_vol(int ds_vol)
629 vol = pow(2.0, ds_vol/1000.0);
633 // ---------------------------------------------------------------------------------------
636 // Parse a wave file.
638 // parameters: filename => file of sound to parse
639 // dest => address of pointer of where to store raw sound data (output parm)
640 // dest_size => number of bytes of sound data stored (output parm)
641 // header => address of pointer to a WAVEFORMATEX struct (output parm)
643 // returns: 0 => wave file successfully parsed
646 // NOTE: memory is malloced for the header and dest in this function. It is the responsibility
647 // of the caller to free this memory later.
649 int ds_parse_wave(char *filename, ubyte **dest, uint *dest_size, WAVEFORMATEX **header)
652 PCMWAVEFORMAT PCM_header;
654 unsigned int tag, size, next_chunk;
656 fp = cfopen( filename, "rb" );
658 nprintf(("Error", "Couldn't open '%s'\n", filename ));
662 // Skip the "RIFF" tag and file size (8 bytes)
663 // Skip the "WAVE" tag (4 bytes)
664 cfseek( fp, 12, CF_SEEK_SET );
666 // Now read RIFF tags until the end of file
669 if ( cfread( &tag, sizeof(uint), 1, fp ) != 1 )
672 if ( cfread( &size, sizeof(uint), 1, fp ) != 1 )
675 next_chunk = cftell(fp) + size;
678 case 0x20746d66: // The 'fmt ' tag
679 //nprintf(("Sound", "SOUND => size of fmt block: %d\n", size));
680 cfread( &PCM_header, sizeof(PCMWAVEFORMAT), 1, fp );
681 if ( PCM_header.wf.wFormatTag != WAVE_FORMAT_PCM ) {
682 cbExtra = cfread_short(fp);
685 // Allocate memory for WAVEFORMATEX structure + extra bytes
686 if ( (*header = (WAVEFORMATEX *) malloc ( sizeof(WAVEFORMATEX)+cbExtra )) != NULL ){
687 // Copy bytes from temporary format structure
688 memcpy (*header, &PCM_header, sizeof(PCM_header));
689 (*header)->cbSize = (unsigned short)cbExtra;
691 // Read those extra bytes, append to WAVEFORMATEX structure
693 cfread( ((ubyte *)(*header) + sizeof(WAVEFORMATEX)), cbExtra, 1, fp);
697 Assert(0); // malloc failed
701 case 0x61746164: // the 'data' tag
703 (*dest) = (ubyte *)malloc(size);
704 Assert( *dest != NULL );
705 cfread( *dest, size, 1, fp );
707 default: // unknown, skip it
710 cfseek( fp, next_chunk, CF_SEEK_SET );
717 // ---------------------------------------------------------------------------------------
726 for ( i = 0; i < MAX_DS_SOFTWARE_BUFFERS; i++ ) {
727 if ( sound_buffers[i].buf_id == 0 )
731 if ( i == MAX_DS_SOFTWARE_BUFFERS ) {
739 for ( i = 0; i < MAX_DS_SOFTWARE_BUFFERS; i++ ) {
740 if ( ds_software_buffers[i].pdsb == NULL )
744 if ( i == MAX_DS_SOFTWARE_BUFFERS ) {
752 // ---------------------------------------------------------------------------------------
763 for ( i = 0; i < MAX_DS_HARDWARE_BUFFERS; i++ ) {
764 if ( ds_hardware_buffers[i].pdsb == NULL )
768 if ( i == MAX_DS_HARDWARE_BUFFERS ) {
776 // ---------------------------------------------------------------------------------------
777 // Load a DirectSound secondary buffer with sound data. The sounds data for
778 // game sounds are stored in the DirectSound secondary buffers, and are
779 // duplicated as needed and placed in the Channels[] array to be played.
783 // sid => pointer to software id for sound ( output parm)
784 // hid => pointer to hardware id for sound ( output parm)
785 // final_size => pointer to storage to receive uncompressed sound size (output parm)
786 // header => pointer to a WAVEFORMATEX structure
787 // si => sound_info structure, contains details on the sound format
788 // flags => buffer properties ( DS_HARDWARE , DS_3D )
790 // returns: -1 => sound effect could not loaded into a secondary buffer
791 // 0 => sound effect successfully loaded into a secondary buffer
794 // NOTE: this function is slow, especially when sounds are loaded into hardware. Don't call this
795 // function from within gameplay.
798 int ds_load_buffer(int *sid, int *hid, int *final_size, void *header, sound_info *si, int flags)
801 Assert( final_size != NULL );
802 Assert( header != NULL );
803 Assert( si != NULL );
804 Assert( si->data != NULL );
806 // All sounds are required to have a software buffer
810 nprintf(("Sound","SOUND ==> No more sound buffers available\n"));
815 alGenBuffers (1, &pi);
824 switch (si->format) {
825 case WAVE_FORMAT_PCM:
834 /* format is now in pcm */
835 frequency = si->sample_rate;
837 if (si->bits == 16) {
838 if (si->n_channels == 2) {
839 format = AL_FORMAT_STEREO16;
840 } else if (si->n_channels == 1) {
841 format = AL_FORMAT_MONO16;
845 } else if (si->bits == 8) {
846 if (si->n_channels == 2) {
847 format = AL_FORMAT_STEREO8;
848 } else if (si->n_channels == 1) {
849 format = AL_FORMAT_MONO8;
859 alBufferData (pi, format, data, size, frequency);
861 sound_buffers[*sid].buf_id = pi;
862 sound_buffers[*sid].source_id = -1;
863 sound_buffers[*sid].frequency = frequency;
864 sound_buffers[*sid].bits_per_sample = si->bits;
865 sound_buffers[*sid].nchannels = si->n_channels;
866 sound_buffers[*sid].nseconds = si->size / si->avg_bytes_per_sec;
873 Assert( final_size != NULL );
874 Assert( header != NULL );
875 Assert( si != NULL );
876 Assert( si->data != NULL );
877 Assert( si->size > 0 );
878 Assert( si->sample_rate > 0);
879 Assert( si->bits > 0 );
880 Assert( si->n_channels > 0 );
881 Assert( si->n_block_align >= 0 );
882 Assert( si->avg_bytes_per_sec > 0 );
884 WAVEFORMATEX *pwfx = (WAVEFORMATEX *)header;
885 DSBUFFERDESC BufferDesc;
886 WAVEFORMATEX WaveFormat;
888 int rc, final_sound_size, DSOUND_load_buffer_result = 0;
889 BYTE *pData, *pData2;
890 DWORD DataSize, DataSize2;
892 // the below two covnert_ variables are only used when the wav format is not
893 // PCM. DirectSound only takes PCM sound data, so we must convert to PCM if required
894 ubyte *convert_buffer = NULL; // storage for converted wav file
895 int convert_len; // num bytes of converted wav file
896 uint src_bytes_used; // number of source bytes actually converted (should always be equal to original size)
898 // Ensure DirectSound initialized
899 if (!ds_initialized) {
900 DSOUND_load_buffer_result = -1;
901 goto DSOUND_load_buffer_done;
904 // Set up buffer information
905 WaveFormat.wFormatTag = (unsigned short)si->format;
906 WaveFormat.nChannels = (unsigned short)si->n_channels;
907 WaveFormat.nSamplesPerSec = si->sample_rate;
908 WaveFormat.wBitsPerSample = (unsigned short)si->bits;
909 WaveFormat.cbSize = 0;
910 WaveFormat.nBlockAlign = (unsigned short)si->n_block_align;
911 WaveFormat.nAvgBytesPerSec = si->avg_bytes_per_sec;
913 final_sound_size = si->size; // assume this format will be used, may be over-ridded by convert_len
915 // Assert(WaveFormat.nChannels == 1);
917 switch ( si->format ) {
918 case WAVE_FORMAT_PCM:
921 case WAVE_FORMAT_ADPCM:
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, 8);
926 DSOUND_load_buffer_result = -1;
927 goto DSOUND_load_buffer_done;
930 if (src_bytes_used != si->size) {
931 Int3(); // ACM conversion failed?
932 DSOUND_load_buffer_result = -1;
933 goto DSOUND_load_buffer_done;
936 final_sound_size = convert_len;
938 // Set up the WAVEFORMATEX structure to have the right PCM characteristics
939 WaveFormat.wFormatTag = WAVE_FORMAT_PCM;
940 WaveFormat.nChannels = (unsigned short)si->n_channels;
941 WaveFormat.nSamplesPerSec = si->sample_rate;
942 WaveFormat.wBitsPerSample = 8;
943 WaveFormat.cbSize = 0;
944 WaveFormat.nBlockAlign = (unsigned short)(( WaveFormat.nChannels * WaveFormat.wBitsPerSample ) / 8);
945 WaveFormat.nAvgBytesPerSec = WaveFormat.nBlockAlign * WaveFormat.nSamplesPerSec;
947 nprintf(( "Sound", "SOUND ==> Coverted sound from ADPCM to PCM successfully\n" ));
951 nprintf(( "Sound", "Unsupported sound encoding\n" ));
952 DSOUND_load_buffer_result = -1;
953 goto DSOUND_load_buffer_done;
957 WaveFormat.wFormatTag = WAVE_FORMAT_PCM; // DirectSound only used PCM wave files
959 // Set up a DirectSound buffer
960 ZeroMemory(&BufferDesc, sizeof(BufferDesc));
961 BufferDesc.dwSize = sizeof(BufferDesc);
962 BufferDesc.dwBufferBytes = final_sound_size;
963 BufferDesc.lpwfxFormat = &WaveFormat;
965 // check if DirectSound3D is enabled and the sound is flagged for 3D
966 if ((ds_using_ds3d()) && (flags & DS_USE_DS3D)) {
967 // if (ds_using_ds3d()) {
968 BufferDesc.dwFlags = DSBCAPS_STATIC | DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRLVOLUME | DSBCAPS_CTRL3D | DSBCAPS_MUTE3DATMAXDISTANCE;
970 BufferDesc.dwFlags = DSBCAPS_STATIC | DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRLVOLUME | DSBCAPS_LOCSOFTWARE;
973 // Create a new software buffer using the settings for this wave
974 // All sounds are required to have a software buffer
977 nprintf(("Sound","SOUND ==> No more software secondary buffers available\n"));
980 DSReturn = pDirectSound->CreateSoundBuffer(&BufferDesc, &ds_software_buffers[*sid].pdsb, NULL );
982 if ( DSReturn == DS_OK && ds_software_buffers[*sid].pdsb != NULL ) {
984 ds_software_buffers[*sid].desc = BufferDesc;
985 ds_software_buffers[*sid].wfx = *BufferDesc.lpwfxFormat;
987 // Lock the buffer and copy in the data
988 if ((ds_software_buffers[*sid].pdsb)->Lock(0, final_sound_size, (void**)(&pData), &DataSize, (void**)(&pData2), &DataSize2, 0) == DS_OK) {
990 if ( convert_buffer )
991 memcpy(pData, convert_buffer, final_sound_size); // use converted data (PCM format)
993 memcpy(pData, si->data, final_sound_size);
995 (ds_software_buffers[*sid].pdsb)->Unlock(pData, DataSize, 0, 0);
997 DSOUND_load_buffer_result = 0;
999 // update ram used for sound
1000 Snd_sram += final_sound_size;
1001 *final_size = final_sound_size;
1004 nprintf(("Sound","SOUND => fatal error in DSOUND_load_buffer\n"));
1006 DSOUND_load_buffer_result = -1;
1009 DSOUND_load_buffer_done:
1010 if ( convert_buffer )
1011 free( convert_buffer );
1012 return DSOUND_load_buffer_result;
1016 // ---------------------------------------------------------------------------------------
1017 // ds_init_channels()
1019 // init the Channels[] array
1021 void ds_init_channels()
1028 Channels = (channel*) malloc(sizeof(channel) * MAX_CHANNELS);
1029 if (Channels == NULL) {
1030 Error(LOCATION, "Unable to allocate %d bytes for %d audio channels.", sizeof(channel) * MAX_CHANNELS, MAX_CHANNELS);
1033 // init the channels
1034 for ( i = 0; i < MAX_CHANNELS; i++ ) {
1035 alGenSources(1, &Channels[i].source_id);
1036 Channels[i].buf_id = -1;
1037 Channels[i].vol = 0;
1042 // detect how many channels we can support
1044 ds_get_soundcard_caps(&caps);
1046 // caps.dwSize = sizeof(DSCAPS);
1047 // pDirectSound->GetCaps(&caps);
1049 // minimum 16 channels
1050 MAX_CHANNELS = caps.dwMaxHwMixingStaticBuffers;
1051 int dbg_channels = MAX_CHANNELS;
1052 if (MAX_CHANNELS < 16) {
1056 // allocate the channels array
1057 Channels = (channel*) malloc(sizeof(channel) * MAX_CHANNELS);
1058 if (Channels == NULL) {
1059 Error(LOCATION, "Unable to allocate %d bytes for %d audio channels.", sizeof(channel) * MAX_CHANNELS, MAX_CHANNELS);
1062 // init the channels
1063 for ( i = 0; i < MAX_CHANNELS; i++ ) {
1064 Channels[i].pdsb = NULL;
1065 Channels[i].pds3db = NULL;
1066 Channels[i].vol = 0;
1069 mprintf(("** MAX_CHANNELS set to %d. DS reported %d.\n", MAX_CHANNELS, dbg_channels));
1073 // ---------------------------------------------------------------------------------------
1074 // ds_init_software_buffers()
1076 // init the software buffers
1078 void ds_init_software_buffers()
1083 for ( i = 0; i < MAX_DS_SOFTWARE_BUFFERS; i++ ) {
1084 sound_buffers[i].buf_id = 0;
1085 sound_buffers[i].source_id = -1;
1090 for ( i = 0; i < MAX_DS_SOFTWARE_BUFFERS; i++ ) {
1091 ds_software_buffers[i].pdsb = NULL;
1096 // ---------------------------------------------------------------------------------------
1097 // ds_init_hardware_buffers()
1099 // init the hardware buffers
1101 void ds_init_hardware_buffers()
1104 // STUB_FUNCTION; // not needed with openal (CM)
1109 for ( i = 0; i < MAX_DS_HARDWARE_BUFFERS; i++ ) {
1110 ds_hardware_buffers[i].pdsb = NULL;
1115 // ---------------------------------------------------------------------------------------
1116 // ds_init_buffers()
1118 // init the both the software and hardware buffers
1120 void ds_init_buffers()
1122 ds_init_software_buffers();
1123 ds_init_hardware_buffers();
1126 // Get the current soundcard capabilities
1128 void ds_get_soundcard_caps(DSCAPS *dscaps)
1131 int n_hbuffers, hram;
1133 dscaps->dwSize = sizeof(DSCAPS);
1135 hr = pDirectSound->GetCaps(dscaps);
1137 nprintf(("Sound","SOUND ==> DirectSound GetCaps() failed with code %s\n.",get_DSERR_text(hr) ));
1141 n_hbuffers = dscaps->dwMaxHwMixingStaticBuffers;
1142 hram = dscaps->dwTotalHwMemBytes;
1144 if ( !(dscaps->dwFlags & DSCAPS_CERTIFIED) ) {
1145 nprintf(("Sound","SOUND ==> Warning: audio driver is not Microsoft certified.\n"));
1149 // ---------------------------------------------------------------------------------------
1152 // init the both the software and hardware buffers
1154 void ds_show_caps(DSCAPS *dscaps)
1156 nprintf(("Sound", "SOUND => Soundcard Capabilities:\n"));
1157 nprintf(("Sound", "================================\n"));
1158 nprintf(("Sound", "Number of primary buffers: %d\n", dscaps->dwPrimaryBuffers ));
1159 nprintf(("Sound", "Number of total hw mixing buffers: %d\n", dscaps->dwMaxHwMixingAllBuffers ));
1160 nprintf(("Sound", "Number of total hw mixing static buffers: %d\n", dscaps->dwMaxHwMixingStaticBuffers ));
1161 nprintf(("Sound", "Number of total hw mixing streaming buffers: %d\n", dscaps->dwMaxHwMixingStreamingBuffers ));
1162 nprintf(("Sound", "Number of free hw mixing buffers: %d\n", dscaps->dwFreeHwMixingAllBuffers ));
1163 nprintf(("Sound", "Number of free hw mixing static buffers: %d\n", dscaps->dwFreeHwMixingStaticBuffers ));
1164 nprintf(("Sound", "Number of free hw mixing streaming buffers: %d\n", dscaps->dwFreeHwMixingStreamingBuffers ));
1165 nprintf(("Sound", "Number of hw 3D buffers: %d\n", dscaps->dwMaxHw3DAllBuffers ));
1166 nprintf(("Sound", "Number of hw 3D static buffers: %d\n", dscaps->dwMaxHw3DStaticBuffers ));
1167 nprintf(("Sound", "Number of hw 3D streaming buffers: %d\n", dscaps->dwMaxHw3DStreamingBuffers ));
1168 nprintf(("Sound", "Number of free hw 3D buffers: %d\n", dscaps->dwFreeHw3DAllBuffers ));
1169 nprintf(("Sound", "Number of free hw static 3D buffers: %d\n", dscaps->dwFreeHw3DStaticBuffers ));
1170 nprintf(("Sound", "Number of free hw streaming 3D buffers: %d\n", dscaps->dwFreeHw3DStreamingBuffers ));
1171 nprintf(("Sound", "Number of total hw bytes: %d\n", dscaps->dwTotalHwMemBytes ));
1172 nprintf(("Sound", "Number of free hw bytes: %d\n", dscaps->dwFreeHwMemBytes ));
1173 nprintf(("Sound", "================================\n"));
1178 // Fill in the waveformat struct with the primary buffer characteristics.
1179 void ds_get_primary_format(WAVEFORMATEX *wfx)
1181 // Set 16 bit / 22KHz / mono
1182 wfx->wFormatTag = WAVE_FORMAT_PCM;
1184 wfx->nSamplesPerSec = 22050;
1185 wfx->wBitsPerSample = 16;
1187 wfx->nBlockAlign = (unsigned short)(wfx->nChannels * (wfx->wBitsPerSample / 8));
1188 wfx->nAvgBytesPerSec = wfx->nBlockAlign * wfx->nSamplesPerSec;
1192 // obtain the function pointers from the dsound.dll
1193 void ds_dll_get_functions()
1195 pfn_DirectSoundCreate = (HRESULT(__stdcall *)(LPGUID lpGuid, LPDIRECTSOUND *ppDS, IUnknown FAR *pUnkOuter))GetProcAddress(Ds_dll_handle,"DirectSoundCreate");
1196 pfn_DirectSoundCaptureCreate = (HRESULT(__stdcall *)(LPGUID lpGuid, LPDIRECTSOUNDCAPTURE *lplpDSC, IUnknown FAR *pUnkOuter))GetProcAddress(Ds_dll_handle,"DirectSoundCaptureCreate");
1200 // Load the dsound.dll, and get funtion pointers
1201 // exit: 0 -> dll loaded successfully
1202 // !0 -> dll could not be loaded
1208 if ( !Ds_dll_loaded ) {
1209 Ds_dll_handle = LoadLibrary("dsound.dll");
1210 if ( !Ds_dll_handle ) {
1213 ds_dll_get_functions();
1226 HINSTANCE a3d_handle;
1229 a3d_handle = LoadLibrary("a3d.dll");
1233 FreeLibrary(a3d_handle);
1237 Ds_must_call_couninitialize = 1;
1239 hr = CoCreateInstance(CLSID_A3d_Def, NULL, CLSCTX_INPROC_SERVER, IID_IDirectSound, (void**)&pDirectSound);
1244 Assert(pDirectSound != NULL);
1245 hr = pDirectSound->QueryInterface(IID_IA3d2_Def, (void**)&pIA3d2);
1250 A3DCAPS_SOFTWARE swCaps;
1252 // Get Dll Software CAP to get DLL version number
1253 ZeroMemory(&swCaps,sizeof(swCaps));
1255 swCaps.dwSize = sizeof(swCaps);
1256 pIA3d2->GetSoftwareCaps(&swCaps);
1258 // Compare version from a3d.dll to header version only return A3D_OK if dll version >= to header version
1259 if (swCaps.dwVersion < A3D_CURRENT_VERSION) {
1260 pDirectSound->Release();
1261 pDirectSound = NULL;
1266 // verify this is authentic A3D
1267 int aureal_verified;
1268 aureal_verified = VerifyAurealA3D();
1270 if (aureal_verified == FALSE) {
1271 // This is fake A3D!!! Ignore
1272 pDirectSound->Release();
1273 pDirectSound = NULL;
1277 // Register our version for backwards compatibility with newer A3d.dll
1278 pIA3d2->RegisterVersion(A3D_CURRENT_VERSION);
1280 hr = pDirectSound->Initialize(NULL);
1282 pDirectSound->Release();
1283 pDirectSound = NULL;
1287 pIA3d2->SetResourceManagerMode(A3D_RESOURCE_MODE_DYNAMIC_LOOPERS);
1293 // Initialize the property set interface.
1295 // returns: 0 if successful, otherwise -1. If successful, the global pPropertySet will
1296 // set to a non-NULL value.
1298 int ds_init_property_set()
1305 // Create the secondary buffer required for EAX initialization
1307 wf.wFormatTag = WAVE_FORMAT_PCM;
1309 wf.nSamplesPerSec = 22050;
1310 wf.wBitsPerSample = 16;
1312 wf.nBlockAlign = (unsigned short)(wf.nChannels * (wf.wBitsPerSample / 8));
1313 wf.nAvgBytesPerSec = wf.nBlockAlign * wf.nSamplesPerSec;
1316 ZeroMemory(&dsbd, sizeof(dsbd));
1317 dsbd.dwSize = sizeof(dsbd);
1318 dsbd.dwFlags = DSBCAPS_CTRLDEFAULT | DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_STATIC | DSBCAPS_CTRL3D | DSBCAPS_MUTE3DATMAXDISTANCE;
1319 dsbd.dwBufferBytes = 3 * wf.nAvgBytesPerSec;
1320 dsbd.lpwfxFormat = &wf;
1322 // Create a new buffer using the settings for this wave
1323 hr = pDirectSound->CreateSoundBuffer(&dsbd, &Ds_property_set_pdsb, NULL);
1325 pPropertySet = NULL;
1329 // Get the 3D interface from the secondary buffer, which is used to query the EAX interface
1330 hr = Ds_property_set_pdsb->QueryInterface(IID_IDirectSound3DBuffer, (void**)&Ds_property_set_pds3db);
1332 Ds_property_set_pds3db = NULL;
1336 Assert(Ds_property_set_pds3db != NULL);
1337 hr = Ds_property_set_pds3db->QueryInterface(IID_IKsPropertySet, (void**)&pPropertySet);
1338 if ((FAILED(hr)) || (pPropertySet == NULL)) {
1346 // ---------------------------------------------------------------------------------------
1349 // returns: -1 => init failed
1350 // 0 => init success
1351 int ds_init(int use_a3d, int use_eax)
1354 // NOTE: A3D and EAX are unused in OpenAL
1355 const ALubyte *initStr = (const ALubyte *)"\'( (sampling-rate 22050 ))";
1356 int attr[] = { ALC_FREQUENCY, 22050, ALC_SYNC, AL_FALSE, 0 };
1362 nprintf(( "Sound", "SOUND ==> Initializing OpenAL...\n" ));
1365 ds_sound_device = alcOpenDevice (initStr);
1367 // Create Sound Device
1368 ds_sound_context = alcCreateContext (ds_sound_device, attr);
1369 alcMakeContextCurrent (ds_sound_context);
1371 if (alcGetError(ds_sound_device) != ALC_NO_ERROR) {
1372 nprintf(("Sound", "SOUND ==> Couldn't initialize OpenAL\n"));
1376 OpenAL_ErrorCheck();
1378 // Initialize DirectSound3D. Since software performance of DirectSound3D is unacceptably
1379 // slow, we require the voice manger (a DirectSound extension) to be present. The
1380 // exception is when A3D is being used, since A3D has a resource manager built in.
1381 // if (Ds_use_ds3d && ds3d_init(0) != 0)
1384 ds_build_vol_lookup();
1390 WAVEFORMATEX wave_format;
1391 DSBUFFERDESC BufferDesc;
1393 nprintf(( "Sound", "SOUND ==> Initializing DirectSound...\n" ));
1395 hwnd = (HWND)os_get_window();
1396 if ( hwnd == NULL ) {
1397 nprintf(( "Sound", "SOUND ==> No window handle, so no sound...\n" ));
1401 if ( ds_dll_load() == -1 ) {
1405 pDirectSound = NULL;
1407 Ds_use_a3d = use_a3d;
1408 Ds_use_eax = use_eax;
1410 if (Ds_use_a3d || Ds_use_eax) {
1414 if (Ds_use_a3d && Ds_use_eax) {
1419 // If we want A3D, ensure a3d.dll exists
1420 if (Ds_use_a3d == 1) {
1421 if (ds_init_a3d() != 0) {
1428 if (Ds_use_a3d == 0) {
1429 if (!pfn_DirectSoundCreate) {
1430 nprintf(( "Sound", "SOUND ==> Could not get DirectSoundCreate function pointer\n" ));
1434 hr = pfn_DirectSoundCreate(NULL, &pDirectSound, NULL);
1440 // Set up DirectSound for exclusive mode, so we can change the primary buffer if we want to.
1441 hr = pDirectSound->SetCooperativeLevel(hwnd, DSSCL_EXCLUSIVE);
1443 nprintf(("Sound","SOUND ==> DirectSound pDirectSound->SetCooperativeLevel failed with code %s\n.",get_DSERR_text(hr) ));
1444 pDirectSound = NULL;
1448 // Create the primary buffer
1449 ZeroMemory(&BufferDesc, sizeof(BufferDesc));
1450 BufferDesc.dwSize = sizeof(BufferDesc);
1452 ds_get_soundcard_caps(&Soundcard_caps);
1455 BufferDesc.dwFlags = DSBCAPS_PRIMARYBUFFER | DSBCAPS_CTRL3D;
1457 hr = pDirectSound->CreateSoundBuffer(&BufferDesc, &pPrimaryBuffer, 0);
1459 nprintf(("Sound","SOUND ==> Primary Buffer create failed with DSBCAPS_CTRL3D property... disabling DirectSound3D\n"));
1464 nprintf(("Sound","SOUND ==> Primary Buffer created with DirectSound3D enabled\n"));
1468 // If not using DirectSound3D, then create a normal primary buffer
1469 if (Ds_use_ds3d == 0) {
1470 BufferDesc.dwFlags = DSBCAPS_PRIMARYBUFFER;
1471 hr = pDirectSound->CreateSoundBuffer(&BufferDesc, &pPrimaryBuffer, 0);
1473 nprintf(("Sound","SOUND ==> Primary Buffer create failed with error: %s\n",get_DSERR_text(hr) ));
1474 pDirectSound = NULL;
1478 nprintf(("Sound","SOUND ==> Primary Buffer created with without DirectSound3D enabled\n"));
1482 // Get the primary buffer format
1483 ds_get_primary_format(&wave_format);
1485 hr = pPrimaryBuffer->SetFormat(&wave_format);
1487 nprintf(("Sound","SOUND ==> pPrimaryBuffer->SetFormat() failed with code %s\n",get_DSERR_text(hr) ));
1490 pPrimaryBuffer->GetFormat(&wave_format, sizeof(wave_format), NULL);
1491 nprintf(("Sound","SOUND ==> Primary Buffer forced to: rate: %d Hz bits: %d n_channels: %d\n",
1492 wave_format.nSamplesPerSec, wave_format.wBitsPerSample, wave_format.nChannels));
1494 // start the primary buffer playing. This will reduce sound latency when playing a sound
1495 // if no other sounds are playing.
1496 hr = pPrimaryBuffer->Play(0, 0, DSBPLAY_LOOPING);
1498 nprintf(("Sound","SOUND ==> pPrimaryBuffer->Play() failed with code %s\n",get_DSERR_text(hr) ));
1501 // Initialize DirectSound3D. Since software performance of DirectSound3D is unacceptably
1502 // slow, we require the voice manger (a DirectSound extension) to be present. The
1503 // exception is when A3D is being used, since A3D has a resource manager built in.
1505 int vm_required = 1; // voice manager
1506 if (Ds_use_a3d == 1) {
1510 if (ds3d_init(vm_required) != 0) {
1516 if (Ds_use_eax == 1) {
1517 ds_init_property_set();
1518 if (ds_eax_init() != 0) {
1523 ds_build_vol_lookup();
1527 ds_show_caps(&Soundcard_caps);
1533 // ---------------------------------------------------------------------------------------
1536 // returns the text equivalent for the a DirectSound DSERR_ code
1538 char *get_DSERR_text(int DSResult)
1543 static char buf[20];
1544 snprintf(buf, 19, "unknown %d", DSResult);
1547 switch( DSResult ) {
1553 case DSERR_ALLOCATED:
1554 return "DSERR_ALLOCATED";
1557 case DSERR_ALREADYINITIALIZED:
1558 return "DSERR_ALREADYINITIALIZED";
1561 case DSERR_BADFORMAT:
1562 return "DSERR_BADFORMAT";
1565 case DSERR_BUFFERLOST:
1566 return "DSERR_BUFFERLOST";
1569 case DSERR_CONTROLUNAVAIL:
1570 return "DSERR_CONTROLUNAVAIL";
1574 return "DSERR_GENERIC";
1577 case DSERR_INVALIDCALL:
1578 return "DSERR_INVALIDCALL";
1581 case DSERR_INVALIDPARAM:
1582 return "DSERR_INVALIDPARAM";
1585 case DSERR_NOAGGREGATION:
1586 return "DSERR_NOAGGREGATION";
1589 case DSERR_NODRIVER:
1590 return "DSERR_NODRIVER";
1593 case DSERR_OUTOFMEMORY:
1594 return "DSERR_OUTOFMEMORY";
1597 case DSERR_OTHERAPPHASPRIO:
1598 return "DSERR_OTHERAPPHASPRIO";
1601 case DSERR_PRIOLEVELNEEDED:
1602 return "DSERR_PRIOLEVELNEEDED";
1605 case DSERR_UNINITIALIZED:
1606 return "DSERR_UNINITIALIZED";
1609 case DSERR_UNSUPPORTED:
1610 return "DSERR_UNSUPPORTED";
1621 // ---------------------------------------------------------------------------------------
1622 // ds_close_channel()
1624 // Free a single channel
1626 void ds_close_channel(int i)
1629 if(Channels[i].source_id != 0 && alIsSource (Channels[i].source_id)) {
1630 alSourceStop (Channels[i].source_id);
1631 alDeleteSources(1, &Channels[i].source_id);
1633 Channels[i].source_id = 0;
1640 // If a 3D interface exists, free it
1641 if ( Channels[i].pds3db != NULL ) {
1644 Channels[i].pds3db = NULL;
1647 while(++attempts < 10) {
1648 hr = Channels[i].pds3db->Release();
1649 if ( hr == DS_OK ) {
1652 // nprintf(("Sound", "SOUND ==> Channels[channel].pds3db->Release() failed with return value %s\n", get_DSERR_text(second_hr) ));
1656 Channels[i].pds3db = NULL;
1660 if ( Channels[i].pdsb != NULL ) {
1661 // If a 2D interface exists, free it
1662 if ( Channels[i].pdsb != NULL ) {
1664 while(++attempts < 10) {
1665 hr = Channels[i].pdsb->Release();
1666 if ( hr == DS_OK ) {
1669 nprintf(("Sound", "SOUND ==> Channels[channel].pdsb->Release() failed with return value %s\n", get_DSERR_text(hr) ));
1674 Channels[i].pdsb = NULL;
1681 // ---------------------------------------------------------------------------------------
1682 // ds_close_all_channels()
1684 // Free all the channel buffers
1686 void ds_close_all_channels()
1690 for (i = 0; i < MAX_CHANNELS; i++) {
1691 ds_close_channel(i);
1695 // ---------------------------------------------------------------------------------------
1696 // ds_unload_buffer()
1699 void ds_unload_buffer(int sid, int hid)
1703 ALuint buf_id = sound_buffers[sid].buf_id;
1705 if (buf_id != 0 && alIsBuffer(buf_id)) {
1706 alDeleteBuffers(1, &buf_id);
1709 sound_buffers[sid].buf_id = 0;
1719 if ( ds_software_buffers[sid].pdsb != NULL ) {
1720 hr = ds_software_buffers[sid].pdsb->Release();
1721 if ( hr != DS_OK ) {
1723 nprintf(("Sound", "SOUND ==> ds_software_buffers[sid]->Release() failed with return value %s\n", get_DSERR_text(hr) ));
1725 ds_software_buffers[sid].pdsb = NULL;
1730 if ( ds_hardware_buffers[hid].pdsb != NULL ) {
1731 hr = ds_hardware_buffers[hid].pdsb->Release();
1732 if ( hr != DS_OK ) {
1734 nprintf(("Sound", "SOUND ==> ds_hardware_buffers[hid]->Release() failed with return value %s\n", get_DSERR_text(hr) ));
1736 ds_hardware_buffers[hid].pdsb = NULL;
1742 // ---------------------------------------------------------------------------------------
1743 // ds_close_software_buffers()
1746 void ds_close_software_buffers()
1751 for (i = 0; i < MAX_DS_SOFTWARE_BUFFERS; i++) {
1752 ALuint buf_id = sound_buffers[i].buf_id;
1754 if (buf_id != 0 && alIsBuffer(buf_id)) {
1755 alDeleteBuffers(1, &buf_id);
1758 sound_buffers[i].buf_id = 0;
1764 for (i = 0; i < MAX_DS_SOFTWARE_BUFFERS; i++) {
1765 if ( ds_software_buffers[i].pdsb != NULL ) {
1766 hr = ds_software_buffers[i].pdsb->Release();
1767 if ( hr != DS_OK ) {
1769 nprintf(("Sound", "SOUND ==> ds_software_buffers[i]->Release() failed with return value %s\n", get_DSERR_text(hr) ));
1771 ds_software_buffers[i].pdsb = NULL;
1777 // ---------------------------------------------------------------------------------------
1778 // ds_close_hardware_buffers()
1781 void ds_close_hardware_buffers()
1789 for (i = 0; i < MAX_DS_HARDWARE_BUFFERS; i++) {
1790 if ( ds_hardware_buffers[i].pdsb != NULL ) {
1791 hr = ds_hardware_buffers[i].pdsb->Release();
1792 if ( hr != DS_OK ) {
1794 nprintf(("Sound", "SOUND ==> ds_hardware_buffers[i]->Release() failed with return value %s\n", get_DSERR_text(hr) ));
1796 ds_hardware_buffers[i].pdsb = NULL;
1802 // ---------------------------------------------------------------------------------------
1803 // ds_close_buffers()
1805 // Free the channel buffers
1807 void ds_close_buffers()
1809 ds_close_software_buffers();
1810 ds_close_hardware_buffers();
1813 // ---------------------------------------------------------------------------------------
1816 // Close the DirectSound system
1820 ds_close_all_channels();
1824 if (pPropertySet != NULL) {
1825 pPropertySet->Release();
1826 pPropertySet = NULL;
1829 if (Ds_property_set_pdsb != NULL) {
1830 Ds_property_set_pdsb->Release();
1831 Ds_property_set_pdsb = NULL;
1834 if (Ds_property_set_pds3db != NULL) {
1835 Ds_property_set_pds3db->Release();
1836 Ds_property_set_pds3db = NULL;
1839 if (pPrimaryBuffer) {
1840 pPrimaryBuffer->Release();
1841 pPrimaryBuffer = NULL;
1850 pDirectSound->Release();
1851 pDirectSound = NULL;
1854 if ( Ds_dll_loaded ) {
1855 FreeLibrary(Ds_dll_handle);
1859 if (Ds_must_call_couninitialize == 1) {
1864 // free the Channels[] array, since it was dynamically allocated
1869 // ---------------------------------------------------------------------------------------
1870 // ds_get_3d_interface()
1872 // Get the 3d interface for a secondary buffer.
1874 // If the secondary buffer wasn't created with a DSBCAPS_CTRL3D flag, then no 3d interface
1878 void ds_get_3d_interface(LPDIRECTSOUNDBUFFER pdsb, LPDIRECTSOUND3DBUFFER *ppds3db)
1883 dsbc.dwSize = sizeof(dsbc);
1884 DSResult = pdsb->GetCaps(&dsbc);
1885 if ( DSResult == DS_OK && dsbc.dwFlags & DSBCAPS_CTRL3D ) {
1886 DSResult = pdsb->QueryInterface( IID_IDirectSound3DBuffer, (void**)ppds3db );
1887 if ( DSResult != DS_OK ) {
1888 nprintf(("SOUND","Could not obtain 3D interface for hardware buffer: %s\n", get_DSERR_text(DSResult) ));
1895 // ---------------------------------------------------------------------------------------
1896 // ds_get_free_channel()
1898 // Find a free channel to play a sound on. If no free channels exists, free up one based
1899 // on volume levels.
1901 // input: new_volume => volume in DS units for sound to play at
1902 // snd_id => which kind of sound to play
1903 // priority => DS_MUST_PLAY
1908 // returns: channel number to play sound on
1909 // -1 if no channel could be found
1911 // NOTE: snd_id is needed since we limit the number of concurrent samples
1915 int ds_get_free_channel(int new_volume, int snd_id, int priority)
1918 int i, first_free_channel, limit;
1919 int lowest_vol = 0, lowest_vol_index = -1;
1920 int instance_count; // number of instances of sound already playing
1921 int lowest_instance_vol, lowest_instance_vol_index;
1926 lowest_instance_vol = 99;
1927 lowest_instance_vol_index = -1;
1928 first_free_channel = -1;
1930 // Look for a channel to use to play this sample
1931 for ( i = 0; i < MAX_CHANNELS; i++ ) {
1933 if ( chp->source_id == 0 ) {
1934 if ( first_free_channel == -1 )
1935 first_free_channel = i;
1939 alGetSourceiv(chp->source_id, AL_SOURCE_STATE, &status);
1941 OpenAL_ErrorCheck();
1943 if ( status != AL_PLAYING ) {
1944 if ( first_free_channel == -1 )
1945 first_free_channel = i;
1949 if ( chp->snd_id == snd_id ) {
1951 if ( chp->vol < lowest_instance_vol && chp->looping == FALSE ) {
1952 lowest_instance_vol = chp->vol;
1953 lowest_instance_vol_index = i;
1957 if ( chp->vol < lowest_vol && chp->looping == FALSE ) {
1958 lowest_vol_index = i;
1959 lowest_vol = chp->vol;
1964 // determine the limit of concurrent instances of this sound
1975 case DS_LIMIT_THREE:
1985 // If we've exceeded the limit, then maybe stop the duplicate if it is lower volume
1986 if ( instance_count >= limit ) {
1987 // If there is a lower volume duplicate, stop it.... otherwise, don't play the sound
1988 if ( lowest_instance_vol_index >= 0 && (Channels[lowest_instance_vol_index].vol <= new_volume) ) {
1989 first_free_channel = lowest_instance_vol_index;
1991 first_free_channel = -1;
1994 // there is no limit barrier to play the sound, so see if we've ran out of channels
1995 if ( first_free_channel == -1 ) {
1996 // stop the lowest volume instance to play our sound if priority demands it
1997 if ( lowest_vol_index != -1 && priority == DS_MUST_PLAY ) {
1998 // Check if the lowest volume playing is less than the volume of the requested sound.
1999 // If so, then we are going to trash the lowest volume sound.
2000 if ( Channels[lowest_vol_index].vol <= new_volume ) {
2001 first_free_channel = lowest_vol_index;
2007 return first_free_channel;
2009 int i, first_free_channel, limit;
2010 int lowest_vol = 0, lowest_vol_index = -1;
2011 int instance_count; // number of instances of sound already playing
2012 int lowest_instance_vol, lowest_instance_vol_index;
2013 unsigned long status;
2018 lowest_instance_vol = 99;
2019 lowest_instance_vol_index = -1;
2020 first_free_channel = -1;
2022 // Look for a channel to use to play this sample
2023 for ( i = 0; i < MAX_CHANNELS; i++ ) {
2025 if ( chp->pdsb == NULL ) {
2026 if ( first_free_channel == -1 )
2027 first_free_channel = i;
2031 hr = chp->pdsb->GetStatus(&status);
2032 if ( hr != DS_OK ) {
2033 nprintf(("Sound", "SOUND ==> GetStatus failed with return value %s\n", get_DSERR_text(hr) ));
2036 if ( !(status & DSBSTATUS_PLAYING) ) {
2037 if ( first_free_channel == -1 )
2038 first_free_channel = i;
2039 ds_close_channel(i);
2043 if ( chp->snd_id == snd_id ) {
2045 if ( chp->vol < lowest_instance_vol && chp->looping == FALSE ) {
2046 lowest_instance_vol = chp->vol;
2047 lowest_instance_vol_index = i;
2051 if ( chp->vol < lowest_vol && chp->looping == FALSE ) {
2052 lowest_vol_index = i;
2053 lowest_vol = chp->vol;
2058 // determine the limit of concurrent instances of this sound
2069 case DS_LIMIT_THREE:
2079 // If we've exceeded the limit, then maybe stop the duplicate if it is lower volume
2080 if ( instance_count >= limit ) {
2081 // If there is a lower volume duplicate, stop it.... otherwise, don't play the sound
2082 if ( lowest_instance_vol_index >= 0 && (Channels[lowest_instance_vol_index].vol <= new_volume) ) {
2083 ds_close_channel(lowest_instance_vol_index);
2084 first_free_channel = lowest_instance_vol_index;
2086 first_free_channel = -1;
2089 // there is no limit barrier to play the sound, so see if we've ran out of channels
2090 if ( first_free_channel == -1 ) {
2091 // stop the lowest volume instance to play our sound if priority demands it
2092 if ( lowest_vol_index != -1 && priority == DS_MUST_PLAY ) {
2093 // Check if the lowest volume playing is less than the volume of the requested sound.
2094 // If so, then we are going to trash the lowest volume sound.
2095 if ( Channels[lowest_vol_index].vol <= new_volume ) {
2096 ds_close_channel(lowest_vol_index);
2097 first_free_channel = lowest_vol_index;
2103 return first_free_channel;
2108 // ---------------------------------------------------------------------------------------
2111 // Find a free channel to play a sound on. If no free channels exists, free up one based
2112 // on volume levels.
2114 // returns: 0 => dup was successful
2115 // -1 => dup failed (Channels[channel].pdsb will be NULL)
2118 int ds_channel_dup(LPDIRECTSOUNDBUFFER pdsb, int channel, int use_ds3d)
2122 // Duplicate the master buffer into a channel buffer.
2123 DSResult = pDirectSound->DuplicateSoundBuffer(pdsb, &Channels[channel].pdsb );
2124 if ( DSResult != DS_OK ) {
2125 nprintf(("Sound", "SOUND ==> DuplicateSoundBuffer failed with return value %s\n", get_DSERR_text(DSResult) ));
2126 Channels[channel].pdsb = NULL;
2130 // get the 3d interface for the buffer if it exists
2132 if (Channels[channel].pds3db == NULL) {
2133 ds_get_3d_interface(Channels[channel].pdsb, &Channels[channel].pds3db);
2141 // ---------------------------------------------------------------------------------------
2142 // ds_restore_buffer()
2145 void ds_restore_buffer(LPDIRECTSOUNDBUFFER pdsb)
2149 Int3(); // get Alan, he wants to see this
2150 hr = pdsb->Restore();
2151 if ( hr != DS_OK ) {
2152 nprintf(("Sound", "Sound ==> Lost a buffer, tried restoring but got %s\n", get_DSERR_text(hr) ));
2157 // Create a direct sound buffer in software, without locking any data in
2158 int ds_create_buffer(int frequency, int bits_per_sample, int nchannels, int nseconds)
2164 if (!ds_initialized) {
2170 nprintf(("Sound","SOUND ==> No more OpenAL buffers available\n"));
2174 alGenBuffers (1, &i);
2176 sound_buffers[sid].buf_id = i;
2177 sound_buffers[sid].source_id = -1;
2178 sound_buffers[sid].frequency = frequency;
2179 sound_buffers[sid].bits_per_sample = bits_per_sample;
2180 sound_buffers[sid].nchannels = nchannels;
2181 sound_buffers[sid].nseconds = nseconds;
2190 if (!ds_initialized) {
2196 nprintf(("Sound","SOUND ==> No more software secondary buffers available\n"));
2200 // Set up buffer format
2201 wfx.wFormatTag = WAVE_FORMAT_PCM;
2202 wfx.nChannels = (unsigned short)nchannels;
2203 wfx.nSamplesPerSec = frequency;
2204 wfx.wBitsPerSample = (unsigned short)bits_per_sample;
2206 wfx.nBlockAlign = (unsigned short)(wfx.nChannels * (wfx.wBitsPerSample / 8));
2207 wfx.nAvgBytesPerSec = wfx.nBlockAlign * wfx.nSamplesPerSec;
2209 memset(&dsbd, 0, sizeof(DSBUFFERDESC));
2210 dsbd.dwSize = sizeof(DSBUFFERDESC);
2211 dsbd.dwBufferBytes = wfx.nAvgBytesPerSec * nseconds;
2212 dsbd.lpwfxFormat = &wfx;
2213 dsbd.dwFlags = DSBCAPS_STATIC | DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRLDEFAULT | DSBCAPS_LOCSOFTWARE;
2215 dsrval = pDirectSound->CreateSoundBuffer(&dsbd, &ds_software_buffers[sid].pdsb, NULL);
2216 if ( dsrval != DS_OK ) {
2220 ds_software_buffers[sid].desc = dsbd;
2225 // Lock data into an existing buffer
2226 int ds_lock_data(int sid, unsigned char *data, int size)
2231 ALuint buf_id = sound_buffers[sid].buf_id;
2234 if (sound_buffers[sid].bits_per_sample == 16) {
2235 if (sound_buffers[sid].nchannels == 2) {
2236 format = AL_FORMAT_STEREO16;
2237 } else if (sound_buffers[sid].nchannels == 1) {
2238 format = AL_FORMAT_MONO16;
2242 } else if (sound_buffers[sid].bits_per_sample == 8) {
2243 if (sound_buffers[sid].nchannels == 2) {
2244 format = AL_FORMAT_STEREO8;
2245 } else if (sound_buffers[sid].nchannels == 1) {
2246 format = AL_FORMAT_MONO8;
2254 alBufferData(buf_id, format, data, size, sound_buffers[sid].frequency);
2256 OpenAL_ErrorCheck();
2261 LPDIRECTSOUNDBUFFER pdsb;
2263 void *buffer_data, *buffer_data2;
2264 DWORD buffer_size, buffer_size2;
2267 pdsb = ds_software_buffers[sid].pdsb;
2269 memset(&caps, 0, sizeof(DSBCAPS));
2270 caps.dwSize = sizeof(DSBCAPS);
2271 dsrval = pdsb->GetCaps(&caps);
2272 if ( dsrval != DS_OK ) {
2276 pdsb->SetCurrentPosition(0);
2278 // lock the entire buffer
2279 dsrval = pdsb->Lock(0, caps.dwBufferBytes, &buffer_data, &buffer_size, &buffer_data2, &buffer_size2, 0 );
2280 if ( dsrval != DS_OK ) {
2284 // first clear it out with silence
2285 memset(buffer_data, 0x80, buffer_size);
2286 memcpy(buffer_data, data, size);
2288 dsrval = pdsb->Unlock(buffer_data, buffer_size, 0, 0);
2289 if ( dsrval != DS_OK ) {
2297 // Stop a buffer from playing directly
2298 void ds_stop_easy(int sid)
2303 int cid = sound_buffers[sid].source_id;
2306 ALuint source_id = Channels[cid].source_id;
2308 alSourceStop(source_id);
2312 LPDIRECTSOUNDBUFFER pdsb;
2315 pdsb = ds_software_buffers[sid].pdsb;
2316 dsrval = pdsb->Stop();
2320 // Play a sound without the usual baggage (used for playing back real-time voice)
2323 // sid => software id of sound
2324 // volume => volume of sound effect in DirectSound units
2325 int ds_play_easy(int sid, int volume)
2328 if (!ds_initialized)
2331 int channel = ds_get_free_channel(volume, -1, DS_MUST_PLAY);
2334 ALuint source_id = Channels[channel].source_id;
2336 alSourceStop(source_id);
2338 if (Channels[channel].buf_id != sid) {
2339 ALuint buffer_id = sound_buffers[sid].buf_id;
2341 alSourcei(source_id, AL_BUFFER, buffer_id);
2343 OpenAL_ErrorCheck();
2346 Channels[channel].buf_id = sid;
2350 alSourcei(source_id, AL_LOOPING, AL_FALSE);
2351 alSourcePlay(source_id);
2353 OpenAL_ErrorCheck();
2361 LPDIRECTSOUNDBUFFER pdsb;
2364 pdsb = ds_software_buffers[sid].pdsb;
2366 pdsb->SetVolume(volume);
2367 dsrval=pdsb->Play(0, 0, 0);
2368 if ( dsrval != DS_OK ) {
2376 // ---------------------------------------------------------------------------------------
2377 // Play a DirectSound secondary buffer.
2381 // sid => software id of sound
2382 // hid => hardware id of sound ( -1 if not in hardware )
2383 // snd_id => what kind of sound this is
2384 // priority => DS_MUST_PLAY
2388 // volume => volume of sound effect in DirectSound units
2389 // pan => pan of sound in DirectSound units
2390 // looping => whether the sound effect is looping or not
2392 // returns: -1 => sound effect could not be started
2393 // >=0 => sig for sound effect successfully started
2395 int ds_play(int sid, int hid, int snd_id, int priority, int volume, int pan, int looping, bool is_voice_msg)
2400 if (!ds_initialized)
2403 channel = ds_get_free_channel(volume, snd_id, priority);
2406 if ( Channels[channel].source_id == 0 ) {
2410 if ( ds_using_ds3d() ) {
2414 Channels[channel].vol = volume;
2415 Channels[channel].looping = looping;
2416 Channels[channel].priority = priority;
2419 // Channels[channel].pdsb->SetPan(pan);
2422 // Channels[channel].pdsb->SetVolume(volume);
2424 Channels[channel].is_voice_msg = is_voice_msg;
2426 OpenAL_ErrorCheck();
2429 alGetSourceiv(Channels[channel].source_id, AL_SOURCE_STATE, &status);
2431 OpenAL_ErrorCheck();
2433 if (status == AL_PLAYING)
2434 alSourceStop(Channels[channel].source_id);
2436 OpenAL_ErrorCheck();
2438 alSourcei (Channels[channel].source_id, AL_BUFFER, sound_buffers[sid].buf_id);
2440 OpenAL_ErrorCheck();
2442 alSourcei (Channels[channel].source_id, AL_LOOPING, (looping) ? AL_TRUE : AL_FALSE);
2444 OpenAL_ErrorCheck();
2446 alSourcePlay(Channels[channel].source_id);
2448 OpenAL_ErrorCheck();
2450 sound_buffers[sid].source_id = channel;
2451 Channels[channel].buf_id = sid;
2454 // nprintf(( "Sound", "SOUND ==> Not playing sound requested at volume %.2f\n", ds_get_percentage_vol(volume) ));
2458 Channels[channel].snd_id = snd_id;
2459 Channels[channel].sig = channel_next_sig++;
2460 if (channel_next_sig < 0 ) {
2461 channel_next_sig = 1;
2464 Channels[channel].last_position = 0;
2466 // make sure there aren't any looping voice messages
2467 for (int i=0; i<MAX_CHANNELS; i++) {
2468 if (Channels[i].is_voice_msg == true) {
2469 if (Channels[i].source_id == 0) {
2474 // DWORD current_position = ds_get_play_position(i);
2475 // if (current_position != 0) {
2476 // if (current_position < Channels[i].last_position) {
2477 // ds_close_channel(i);
2479 // Channels[i].last_position = current_position;
2485 return Channels[channel].sig;
2490 if (!ds_initialized)
2493 channel = ds_get_free_channel(volume, snd_id, priority);
2496 if ( Channels[channel].pdsb != NULL ) {
2500 // First check if the sound is in hardware, and try to duplicate from there
2503 if ( ds_channel_dup(ds_hardware_buffers[hid].pdsb, channel, 0) == 0 ) {
2504 // nprintf(("Sound", "SOUND ==> Played sound in hardware..\n"));
2508 // Channel will be NULL if hardware dup failed, or there was no hardware dup attempted
2509 if ( Channels[channel].pdsb == NULL ) {
2510 if ( ds_channel_dup(ds_software_buffers[sid].pdsb, channel, 0) == 0 ) {
2511 // nprintf(("Sound", "SOUND ==> Played sound in software..\n"));
2515 if ( Channels[channel].pdsb == NULL ) {
2519 if ( ds_using_ds3d() ) {
2520 if ( ds_is_3d_buffer(Channels[channel].pdsb) ) {
2521 if (Channels[channel].pds3db == NULL) {
2522 ds_get_3d_interface(Channels[channel].pdsb, &Channels[channel].pds3db);
2524 if ( Channels[channel].pds3db ) {
2525 Channels[channel].pds3db->SetMode(DS3DMODE_DISABLE,DS3D_IMMEDIATE);
2531 Channels[channel].vol = volume;
2532 Channels[channel].looping = looping;
2533 Channels[channel].priority = priority;
2534 Channels[channel].pdsb->SetPan(pan);
2535 Channels[channel].pdsb->SetVolume(volume);
2536 Channels[channel].is_voice_msg = is_voice_msg;
2540 ds_flags |= DSBPLAY_LOOPING;
2542 DSResult = Channels[channel].pdsb->Play(0, 0, ds_flags );
2545 if (Stop_logging_sounds == false) {
2547 sprintf(buf, "channel %d, address: %x, ds_flags: %d", channel, Channels[channel].pdsb, ds_flags);
2548 HUD_add_to_scrollback(buf, 3);
2552 if ( DSResult == DSERR_BUFFERLOST ) {
2553 ds_restore_buffer(Channels[channel].pdsb);
2554 DSResult = Channels[channel].pdsb->Play(0, 0, ds_flags );
2557 if ( DSResult != DS_OK ) {
2558 nprintf(("Sound", "Sound ==> Play failed with return value %s\n", get_DSERR_text(DSResult) ));
2563 // nprintf(( "Sound", "SOUND ==> Not playing sound requested at volume %.2f\n", ds_get_percentage_vol(volume) ));
2567 Channels[channel].snd_id = snd_id;
2568 Channels[channel].sig = channel_next_sig++;
2569 if (channel_next_sig < 0 ) {
2570 channel_next_sig = 1;
2574 if (Stop_logging_sounds == false) {
2577 sprintf(buf, "VOICE sig: %d, sid: %d, snd_id: %d, ch: %d", Channels[channel].sig, sid, snd_id, channel);
2578 HUD_add_to_scrollback(buf, 3);
2583 Channels[channel].last_position = 0;
2585 // make sure there aren't any looping voice messages
2586 for (int i=0; i<MAX_CHANNELS; i++) {
2587 if (Channels[i].is_voice_msg == true) {
2588 if (Channels[i].pdsb == NULL) {
2592 DWORD current_position = ds_get_play_position(i);
2593 if (current_position != 0) {
2594 if (current_position < Channels[i].last_position) {
2595 ds_close_channel(i);
2597 Channels[i].last_position = current_position;
2603 return Channels[channel].sig;
2608 // ---------------------------------------------------------------------------------------
2611 // Return the channel number that is playing the sound identified by sig. If that sound is
2612 // not playing, return -1.
2614 int ds_get_channel(int sig)
2619 for ( i = 0; i < MAX_CHANNELS; i++ ) {
2620 if ( Channels[i].source_id && Channels[i].sig == sig ) {
2621 if ( ds_is_channel_playing(i) == TRUE ) {
2631 for ( i = 0; i < MAX_CHANNELS; i++ ) {
2632 if ( Channels[i].pdsb && Channels[i].sig == sig ) {
2633 if ( ds_is_channel_playing(i) == TRUE ) {
2642 // ---------------------------------------------------------------------------------------
2643 // ds_is_channel_playing()
2646 int ds_is_channel_playing(int channel)
2649 if ( Channels[channel].source_id != 0 ) {
2652 alGetSourceiv(Channels[channel].source_id, AL_SOURCE_STATE, &status);
2653 OpenAL_ErrorCheck();
2655 return (status == AL_PLAYING);
2661 unsigned long status;
2663 if ( !Channels[channel].pdsb ) {
2667 hr = Channels[channel].pdsb->GetStatus(&status);
2668 if ( hr != DS_OK ) {
2669 nprintf(("Sound", "SOUND ==> GetStatus failed with return value %s\n", get_DSERR_text(hr) ));
2673 if ( status & DSBSTATUS_PLAYING )
2680 // ---------------------------------------------------------------------------------------
2681 // ds_stop_channel()
2684 void ds_stop_channel(int channel)
2687 if ( Channels[channel].source_id != 0 ) {
2688 alSourceStop(Channels[channel].source_id);
2691 ds_close_channel(channel);
2695 // ---------------------------------------------------------------------------------------
2696 // ds_stop_channel_all()
2699 void ds_stop_channel_all()
2704 for ( i=0; i<MAX_CHANNELS; i++ ) {
2705 if ( Channels[i].source_id != 0 ) {
2706 alSourceStop(Channels[i].source_id);
2712 for ( i=0; i<MAX_CHANNELS; i++ ) {
2713 if ( Channels[i].pdsb != NULL ) {
2720 // ---------------------------------------------------------------------------------------
2723 // Set the volume for a channel. The volume is expected to be in DirectSound units
2725 // If the sound is a 3D sound buffer, this is like re-establishing the maximum
2728 void ds_set_volume( int channel, int vol )
2734 unsigned long status;
2736 hr = Channels[channel].pdsb->GetStatus(&status);
2737 if ( hr != DS_OK ) {
2738 nprintf(("Sound", "SOUND ==> GetStatus failed with return value %s\n", get_DSERR_text(hr) ));
2742 if ( status & DSBSTATUS_PLAYING ) {
2743 Channels[channel].pdsb->SetVolume(vol);
2748 // ---------------------------------------------------------------------------------------
2751 // Set the pan for a channel. The pan is expected to be in DirectSound units
2753 void ds_set_pan( int channel, int pan )
2759 unsigned long status;
2761 hr = Channels[channel].pdsb->GetStatus(&status);
2762 if ( hr != DS_OK ) {
2763 nprintf(("Sound", "SOUND ==> GetStatus failed with return value %s\n", get_DSERR_text(hr) ));
2767 if ( status & DSBSTATUS_PLAYING ) {
2768 Channels[channel].pdsb->SetPan(pan);
2773 // ---------------------------------------------------------------------------------------
2776 // Get the pitch of a channel
2778 int ds_get_pitch(int channel)
2785 unsigned long status, pitch = 0;
2788 hr = Channels[channel].pdsb->GetStatus(&status);
2790 if ( hr != DS_OK ) {
2791 nprintf(("Sound", "SOUND ==> GetStatus failed with return value %s\n", get_DSERR_text(hr) ));
2795 if ( status & DSBSTATUS_PLAYING ) {
2796 hr = Channels[channel].pdsb->GetFrequency(&pitch);
2797 if ( hr != DS_OK ) {
2798 nprintf(("Sound", "SOUND ==> GetFrequency failed with return value %s\n", get_DSERR_text(hr) ));
2807 // ---------------------------------------------------------------------------------------
2810 // Set the pitch of a channel
2812 void ds_set_pitch(int channel, int pitch)
2817 unsigned long status;
2820 hr = Channels[channel].pdsb->GetStatus(&status);
2821 if ( hr != DS_OK ) {
2822 nprintf(("Sound", "SOUND ==> GetStatus failed with return value %s\n", get_DSERR_text(hr) ));
2826 if ( pitch < MIN_PITCH )
2829 if ( pitch > MAX_PITCH )
2832 if ( status & DSBSTATUS_PLAYING ) {
2833 Channels[channel].pdsb->SetFrequency((unsigned long)pitch);
2838 // ---------------------------------------------------------------------------------------
2839 // ds_chg_loop_status()
2842 void ds_chg_loop_status(int channel, int loop)
2845 ALuint source_id = Channels[channel].source_id;
2847 alSourcei(source_id, AL_LOOPING, loop ? AL_TRUE : AL_FALSE);
2849 unsigned long status;
2852 hr = Channels[channel].pdsb->GetStatus(&status);
2853 if ( hr != DS_OK ) {
2854 nprintf(("Sound", "SOUND ==> GetStatus failed with return value %s\n", get_DSERR_text(hr) ));
2858 if ( !(status & DSBSTATUS_PLAYING) )
2859 return; // sound is not playing anymore
2861 if ( status & DSBSTATUS_LOOPING ) {
2863 return; // we are already looping
2865 // stop the sound from looping
2866 hr = Channels[channel].pdsb->Play(0,0,0);
2871 return; // the sound is already not looping
2873 // start the sound looping
2874 hr = Channels[channel].pdsb->Play(0,0,DSBPLAY_LOOPING);
2880 // ---------------------------------------------------------------------------------------
2883 // Starts a ds3d sound playing
2887 // sid => software id for sound to play
2888 // hid => hardware id for sound to play (-1 if not in hardware)
2889 // snd_id => identifies what type of sound is playing
2890 // pos => world pos of sound
2891 // vel => velocity of object emitting sound
2892 // min => distance at which sound doesn't get any louder
2893 // max => distance at which sound becomes inaudible
2894 // looping => boolean, whether to loop the sound or not
2895 // max_volume => volume (-10000 to 0) for 3d sound at maximum
2896 // estimated_vol => manual estimated volume
2897 // priority => DS_MUST_PLAY
2902 // returns: 0 => sound started successfully
2903 // -1 => sound could not be played
2905 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 )
2915 if (!ds_initialized)
2918 channel = ds_get_free_channel(estimated_vol, snd_id, priority);
2921 Assert(Channels[channel].pdsb == NULL);
2923 // First check if the sound is in hardware, and try to duplicate from there
2926 if ( ds_is_3d_buffer(ds_hardware_buffers[hid].pdsb) == FALSE ) {
2927 nprintf(("Sound", "SOUND ==> Tried to play non-3d buffer in ds3d_play()..\n"));
2931 if ( ds_channel_dup(ds_hardware_buffers[hid].pdsb, channel, 1) == 0 ) {
2932 nprintf(("Sound", "SOUND ==> Played sound using DirectSound3D in hardware..\n"));
2936 // Channel will be NULL if hardware dup failed, or there was no hardware dup attempted
2937 if ( Channels[channel].pdsb == NULL ) {
2940 if ( ds_is_3d_buffer(ds_software_buffers[sid].pdsb) == FALSE ) {
2941 nprintf(("Sound", "SOUND ==> Tried to play non-3d buffer in ds3d_play()..\n"));
2946 if ( ds_channel_dup(ds_software_buffers[sid].pdsb, channel, 1) == 0 ) {
2947 // nprintf(("Sound", "SOUND ==> Played sound using DirectSound3D \n"));
2951 if ( Channels[channel].pdsb == NULL ) {
2956 desc = ds_software_buffers[sid].desc;
2957 desc.lpwfxFormat = &ds_software_buffers[sid].wfx;
2959 // duplicate buffer failed, so call CreateBuffer instead
2961 hr = pDirectSound->CreateSoundBuffer(&desc, &Channels[channel].pdsb, NULL );
2963 if ( (hr == DS_OK) && (Channels[channel].pdsb) ) {
2964 BYTE *pdest, *pdest2;
2966 DWORD src_ds_size, dest_ds_size, not_used;
2969 if ( ds_get_size(sid, &src_size) != 0 ) {
2971 Channels[channel].pdsb->Release();
2975 // lock the src buffer
2976 hr = ds_software_buffers[sid].pdsb->Lock(0, src_size, (void**)&psrc, &src_ds_size, (void**)&psrc2, ¬_used, 0);
2977 if ( hr != DS_OK ) {
2978 mprintf(("err: %s\n", get_DSERR_text(hr)));
2980 Channels[channel].pdsb->Release();
2984 if ( Channels[channel].pdsb->Lock(0, src_ds_size, (void**)(&pdest), &dest_ds_size, (void**)&pdest2, ¬_used, 0) == DS_OK) {
2985 memcpy(pdest, psrc, src_ds_size);
2986 Channels[channel].pdsb->Unlock(pdest, dest_ds_size, 0, 0);
2987 ds_get_3d_interface(Channels[channel].pdsb, &Channels[channel].pds3db);
2989 Channels[channel].pdsb->Release();
2996 Assert(Channels[channel].pds3db );
2997 Channels[channel].pds3db->SetMode(DS3DMODE_NORMAL,DS3D_IMMEDIATE);
2999 // set up 3D sound data here
3000 ds3d_update_buffer(channel, i2fl(min), i2fl(max), pos, vel);
3002 Channels[channel].vol = estimated_vol;
3003 Channels[channel].looping = looping;
3005 // sets the maximum "inner cone" volume
3006 Channels[channel].pdsb->SetVolume(max_volume);
3010 ds_flags |= DSBPLAY_LOOPING;
3013 hr = Channels[channel].pdsb->Play(0, 0, ds_flags );
3015 if ( hr == DSERR_BUFFERLOST ) {
3016 ds_restore_buffer(Channels[channel].pdsb);
3017 hr = Channels[channel].pdsb->Play(0, 0, ds_flags );
3020 if ( hr != DS_OK ) {
3021 nprintf(("Sound", "Sound ==> Play failed with return value %s\n", get_DSERR_text(hr) ));
3022 if ( Channels[channel].pdsb ) {
3024 while(++attempts < 10) {
3025 hr = Channels[channel].pdsb->Release();
3026 if ( hr == DS_OK ) {
3029 nprintf(("Sound","SOUND ==> DirectSound Release() failed with code %s\n.",get_DSERR_text(hr) ));
3033 Channels[channel].pdsb = NULL;
3039 nprintf(( "Sound", "SOUND ==> Not playing requested 3D sound\n"));
3043 Channels[channel].snd_id = snd_id;
3044 Channels[channel].sig = channel_next_sig++;
3045 if (channel_next_sig < 0 ) {
3046 channel_next_sig = 1;
3048 return Channels[channel].sig;
3052 void ds_set_position(int channel, DWORD offset)
3057 // set the position of the sound buffer
3058 Channels[channel].pdsb->SetCurrentPosition(offset);
3062 DWORD ds_get_play_position(int channel)
3070 if ( Channels[channel].pdsb ) {
3071 Channels[channel].pdsb->GetCurrentPosition((LPDWORD)&play,(LPDWORD)&write);
3080 DWORD ds_get_write_position(int channel)
3088 if ( Channels[channel].pdsb ) {
3089 Channels[channel].pdsb->GetCurrentPosition((LPDWORD)&play,(LPDWORD)&write);
3098 int ds_get_channel_size(int channel)
3109 if ( Channels[channel].pdsb ) {
3110 memset(&caps, 0, sizeof(DSBCAPS));
3111 caps.dwSize = sizeof(DSBCAPS);
3112 dsrval = Channels[channel].pdsb->GetCaps(&caps);
3113 if ( dsrval != DS_OK ) {
3116 size = caps.dwBufferBytes;
3125 // Returns the number of channels that are actually playing
3126 int ds_get_number_channels()
3132 for ( i = 0; i < MAX_CHANNELS; i++ ) {
3133 if ( Channels[i].source_id ) {
3134 if ( ds_is_channel_playing(i) == TRUE ) {
3145 for ( i = 0; i < MAX_CHANNELS; i++ ) {
3146 if ( Channels[i].pdsb ) {
3147 if ( ds_is_channel_playing(i) == TRUE ) {
3157 // retreive raw data from a sound buffer
3158 int ds_get_data(int sid, char *data)
3166 LPDIRECTSOUNDBUFFER pdsb;
3172 pdsb = ds_software_buffers[sid].pdsb;
3174 memset(&caps, 0, sizeof(DSBCAPS));
3175 caps.dwSize = sizeof(DSBCAPS);
3176 dsrval = pdsb->GetCaps(&caps);
3177 if ( dsrval != DS_OK ) {
3181 // lock the entire buffer
3182 dsrval = pdsb->Lock(0, caps.dwBufferBytes, &buffer_data, &buffer_size, 0, 0, 0);
3183 if ( dsrval != DS_OK ) {
3187 memcpy(data, buffer_data, buffer_size);
3189 dsrval = pdsb->Unlock(buffer_data, buffer_size, 0, 0);
3190 if ( dsrval != DS_OK ) {
3198 // return the size of the raw sound data
3199 int ds_get_size(int sid, int *size)
3209 LPDIRECTSOUNDBUFFER pdsb;
3213 pdsb = ds_software_buffers[sid].pdsb;
3215 memset(&caps, 0, sizeof(DSBCAPS));
3216 caps.dwSize = sizeof(DSBCAPS);
3217 dsrval = pdsb->GetCaps(&caps);
3218 if ( dsrval != DS_OK ) {
3222 *size = caps.dwBufferBytes;
3231 // Return the primary buffer interface. Note that we cast to a uint to avoid
3232 // having to include dsound.h (and thus windows.h) in ds.h.
3234 uint ds_get_primary_buffer_interface()
3240 return (uint)pPrimaryBuffer;
3244 // Return the DirectSound Interface.
3246 uint ds_get_dsound_interface()
3252 return (uint)pDirectSound;
3256 uint ds_get_property_set_interface()
3261 return (uint)pPropertySet;
3265 // --------------------
3267 // EAX Functions below
3269 // --------------------
3271 // Set the master volume for the reverb added to all sound sources.
3273 // volume: volume, range from 0 to 1.0
3275 // returns: 0 if the volume is set successfully, otherwise return -1
3277 int ds_eax_set_volume(float volume)
3284 if (Ds_eax_inited == 0) {
3288 Assert(Ds_eax_reverb);
3290 CAP(volume, 0.0f, 1.0f);
3292 hr = Ds_eax_reverb->Set(DSPROPSETID_EAX_ReverbProperties_Def, DSPROPERTY_EAX_VOLUME, NULL, 0, &volume, sizeof(float));
3293 if (SUCCEEDED(hr)) {
3301 // Set the decay time for the EAX environment (ie all sound sources)
3303 // seconds: decay time in seconds
3305 // returns: 0 if decay time is successfully set, otherwise return -1
3307 int ds_eax_set_decay_time(float seconds)
3314 if (Ds_eax_inited == 0) {
3318 Assert(Ds_eax_reverb);
3320 CAP(seconds, 0.1f, 20.0f);
3322 hr = Ds_eax_reverb->Set(DSPROPSETID_EAX_ReverbProperties_Def, DSPROPERTY_EAX_DECAYTIME, NULL, 0, &seconds, sizeof(float));
3323 if (SUCCEEDED(hr)) {
3331 // Set the damping value for the EAX environment (ie all sound sources)
3333 // damp: damp value from 0 to 2.0
3335 // returns: 0 if the damp value is successfully set, otherwise return -1
3337 int ds_eax_set_damping(float damp)
3344 if (Ds_eax_inited == 0) {
3348 Assert(Ds_eax_reverb);
3350 CAP(damp, 0.0f, 2.0f);
3352 hr = Ds_eax_reverb->Set(DSPROPSETID_EAX_ReverbProperties_Def, DSPROPERTY_EAX_DAMPING, NULL, 0, &damp, sizeof(float));
3353 if (SUCCEEDED(hr)) {
3361 // Set up the environment type for all sound sources.
3363 // envid: value from the EAX_ENVIRONMENT_* enumeration in ds_eax.h
3365 // returns: 0 if the environment is set successfully, otherwise return -1
3367 int ds_eax_set_environment(unsigned long envid)
3374 if (Ds_eax_inited == 0) {
3378 Assert(Ds_eax_reverb);
3380 hr = Ds_eax_reverb->Set(DSPROPSETID_EAX_ReverbProperties_Def, DSPROPERTY_EAX_ENVIRONMENT, NULL, 0, &envid, sizeof(unsigned long));
3381 if (SUCCEEDED(hr)) {
3389 // Set up a predefined environment for EAX
3391 // envid: value from teh EAX_ENVIRONMENT_* enumeration
3393 // returns: 0 if successful, otherwise return -1
3395 int ds_eax_set_preset(unsigned long envid)
3402 if (Ds_eax_inited == 0) {
3406 Assert(Ds_eax_reverb);
3407 Assert(envid < EAX_ENVIRONMENT_COUNT);
3409 hr = Ds_eax_reverb->Set(DSPROPSETID_EAX_ReverbProperties_Def, DSPROPERTY_EAX_ALL, NULL, 0, &Ds_eax_presets[envid], sizeof(EAX_REVERBPROPERTIES));
3410 if (SUCCEEDED(hr)) {
3419 // Set up all the parameters for an environment
3421 // id: value from teh EAX_ENVIRONMENT_* enumeration
3422 // volume: volume for the environment (0 to 1.0)
3423 // damping: damp value for the environment (0 to 2.0)
3424 // decay: decay time in seconds (0.1 to 20.0)
3426 // returns: 0 if successful, otherwise return -1
3428 int ds_eax_set_all(unsigned long id, float vol, float damping, float decay)
3435 if (Ds_eax_inited == 0) {
3439 Assert(Ds_eax_reverb);
3440 Assert(id < EAX_ENVIRONMENT_COUNT);
3442 EAX_REVERBPROPERTIES er;
3444 er.environment = id;
3446 er.fDecayTime_sec = decay;
3447 er.fDamping = damping;
3449 hr = Ds_eax_reverb->Set(DSPROPSETID_EAX_ReverbProperties_Def, DSPROPERTY_EAX_ALL, NULL, 0, &er, sizeof(EAX_REVERBPROPERTIES));
3450 if (SUCCEEDED(hr)) {
3458 // Get up the parameters for the current environment
3460 // er: (output) hold environment parameters
3462 // returns: 0 if successful, otherwise return -1
3464 int ds_eax_get_all(EAX_REVERBPROPERTIES *er)
3470 unsigned long outsize;
3472 if (Ds_eax_inited == 0) {
3476 Assert(Ds_eax_reverb);
3478 hr = Ds_eax_reverb->Get(DSPROPSETID_EAX_ReverbProperties_Def, DSPROPERTY_EAX_ALL, NULL, 0, er, sizeof(EAX_REVERBPROPERTIES), &outsize);
3479 if (SUCCEEDED(hr)) {
3487 // Close down EAX, freeing any allocated resources
3492 if (Ds_eax_inited == 0) {
3502 // returns: 0 if initialization is successful, otherwise return -1
3508 unsigned long driver_support = 0;
3510 if (Ds_eax_inited) {
3514 Assert(Ds_eax_reverb == NULL);
3516 Ds_eax_reverb = (LPKSPROPERTYSET)ds_get_property_set_interface();
3517 if (Ds_eax_reverb == NULL) {
3521 // check if the listener property is supported by the audio driver
3522 hr = Ds_eax_reverb->QuerySupport(DSPROPSETID_EAX_ReverbProperties_Def, DSPROPERTY_EAX_ALL, &driver_support);
3524 nprintf(("Sound", "QuerySupport for the EAX Listener property set failed.. disabling EAX\n"));
3525 goto ds_eax_init_failed;
3528 if ((driver_support & (KSPROPERTY_SUPPORT_GET | KSPROPERTY_SUPPORT_SET)) != (KSPROPERTY_SUPPORT_GET | KSPROPERTY_SUPPORT_SET)) {
3529 goto ds_eax_init_failed;
3532 ds_eax_set_all(EAX_ENVIRONMENT_GENERIC, 0.0f, 0.0f, 0.0f);
3538 if (Ds_eax_reverb != NULL) {
3539 Ds_eax_reverb->Release();
3540 Ds_eax_reverb = NULL;
3549 int ds_eax_is_inited()
3554 return Ds_eax_inited;
3563 if (Ds_use_a3d == 0) {
3571 // Called once per game frame to make sure voice messages aren't looping
3577 for (int i=0; i<MAX_CHANNELS; i++) {
3579 if (cp->is_voice_msg) {
3580 if (cp->source_id == 0) {
3584 int current_position = ds_get_play_position(i);
3585 if (current_position != 0) {
3586 if (current_position < cp->last_position) {
3587 ds_close_channel(i);
3589 cp->last_position = current_position;
3602 int ds3d_update_buffer(int channel, float min, float max, vector *pos, vector *vel)
3609 int ds3d_update_listener(vector *pos, vector *vel, matrix *orient)
3614 ALfloat posv[] = { pos->x, pos->y, pos->z };
3615 ALfloat velv[] = { vel->x, vel->y, vel->z };
3616 ALfloat oriv[] = { orient->a1d[0],
3617 orient->a1d[1], orient->a1d[2],
3618 orient->a1d[3], orient->a1d[4],
3620 alListenerfv(AL_POSITION, posv);
3621 alListenerfv(AL_VELOCITY, velv);
3622 alListenerfv(AL_ORIENTATION, oriv);
3628 int ds3d_init (int unused)
3633 ALfloat pos[] = { 0.0, 0.0, 0.0 },
3634 vel[] = { 0.0, 0.0, 0.0 },
3635 ori[] = { 0.0, 0.0, 1.0, 0.0, -1.0, 0.0 };
3637 alListenerfv (AL_POSITION, pos);
3638 alListenerfv (AL_VELOCITY, vel);
3639 alListenerfv (AL_ORIENTATION, ori);
3641 if(alGetError() != AL_NO_ERROR)
3655 int dscap_create_buffer(int freq, int bits_per_sample, int nchannels, int nseconds)
3662 int dscap_get_raw_data(unsigned char *outbuf, unsigned int max_size)
3669 int dscap_max_buffersize()
3676 void dscap_release_buffer()
3681 int dscap_start_record()
3688 int dscap_stop_record()
3695 int dscap_supported()