1 // Emacs style mode select -*- C++ -*-
2 //-----------------------------------------------------------------------------
3 //
4 // $Id: s_ds3d.c 1403 2018-07-06 09:49:21Z wesleyjohnson $
5 //
6 // Copyright (C) 2001 by DooM Legacy Team.
7 //
8 // This program is free software; you can redistribute it and/or
9 // modify it under the terms of the GNU General Public License
10 // as published by the Free Software Foundation; either version 2
11 // of the License, or (at your option) any later version.
12 //
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 // GNU General Public License for more details.
17 //
18 //
19 // $Log: s_ds3d.c,v $
20 // Revision 1.6 2002/10/07 19:28:35 judgecutor
21 //
22 // Revision 1.5 2002/08/16 20:22:31 judgecutor
23 // Added sound pitching
24 //
25 // Revision 1.4 2002/01/21 23:28:09 judgecutor
26 // Added HW3S_I_StartSound low-level fuction for arbitrary managing of 3D sources
27 //
28 // Revision 1.3 2001/08/21 21:50:06 judgecutor
29 // Fixed distance effect
30 //
31 // Revision 1.2 2001/04/06 21:36:53 judgecutor
32 // Added detection for speaker configuration
33 //
34 // Revision 1.1 2001/04/04 19:49:44 judgecutor
35 // Initial release
36 //
37 //
38 // DESCRIPTION:
39 // General driver for 3D sound system.
40 // Implementend via DirectSound3D API
41 //
42 //-----------------------------------------------------------------------------
43
44 //#define DEBUG_SDS3D_TO_FILE
45
46 #ifndef SMIF_WIN_NATIVE
47 # error s_ds3d is WIN_NATIVE only
48 #endif
49
50 #define INITGUID
51 #include <windows.h>
52 #include <cguid.h>
53 #include <dsound.h>
54
55
56 #define HWRAPI_CREATE_DLL
57 #include "hardware/hw3dsdrv.h"
58
59 #include "m_fixed.h"
60
61 #include "win32/win_main.h"
62 // hWndMain
63
64 // Internal sound stack
65 typedef struct stack_snd_s
66 {
67 // Sound data
68 LPDIRECTSOUNDBUFFER dsbuffer;
69
70 // 3D data of 3D source
71 LPDIRECTSOUND3DBUFFER dsbuffer3D; // 3D data
72
73 // Current parameters of 3D source
74 // Valid only when source is 3D source
75 // (dsbuffer3D is not NULL)
76 DS3DBUFFER parameters;
77
78 // Currently unused
79 int sfx_id;
80
81 // Currently unused
82 int LRU;
83
84 // Flag of static source
85 // Driver does not manage intrenally such sources
86 int permanent;
87
88 } stack_t;
89
90 // Just for now...
91 #define SOUND_ALLOCATE_DELTA 16 // Amount of sources per stack incrementation
92 #define MAX_LRU 16 // Maximum iterations to keep source in stack
93
94 static stack_t *_stack; // Sound stack
95 static int allocated_sounds; // Size of stack
96
97 static int srate; // Default sample rate
98
99
100 // output all debugging messages to this file
101 #ifdef DEBUG_SDS3D_TO_FILE
102 static HANDLE s3d_logstream;
103 #endif
104
105 static LPDIRECTSOUND DSnd = NULL; // Main DirectSound object
106 static LPDIRECTSOUNDBUFFER PrimaryBuffer = NULL; //
107 static LPDIRECTSOUND3DLISTENER Listener = NULL; //
108
109 static DS3DLISTENER listener_parms; // Listener papameters
110
111 static BOOL virtualization; // TRUE if HRTF virtualization enabled
112 static DWORD update_mode; // Current update mode of listener
113 //static DWORD max_3d_buffers;
114
115 static I_Error_t I_ErrorDS3D = NULL;
116
117 //static stack_snd_t sound_stack[MAX_SOUNDS];
118
119 // Safe buffer release
120 #define RELEASE_BUFFER(buf) {if (buf) { IDirectSoundBuffer_Release(buf); (buf) = NULL; }}
121 #define RELEASE_3DBUFFER(buf) {if (buf) { IDirectSound3DBuffer_Release(buf); (buf) = NULL; }}
122
123 // Default flags for buffers
124 #define _2DSOURCE_FLAGS (DSBCAPS_CTRLPAN | DSBCAPS_CTRLVOLUME | DSBCAPS_STICKYFOCUS | DSBCAPS_STATIC | DSBCAPS_CTRLFREQUENCY)
125 #define _3DSOURCE_FLAGS (DSBCAPS_CTRL3D | DSBCAPS_STATIC | DSBCAPS_MUTE3DATMAXDISTANCE | DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLFREQUENCY)
126
127
128 enum {IS_2DSOURCE = 0, IS_3DSOURCE = 1};
129
130 #define NEW_HANDLE -1
131
132
DllMain(HANDLE hModule,DWORD fdwReason,LPVOID lpReserved)133 BOOL APIENTRY DllMain( HANDLE hModule, // handle to DLL module
134 DWORD fdwReason, // reason for calling function
135 LPVOID lpReserved ) // reserved
136 {
137 // Perform actions based on the reason for calling.
138 switch( fdwReason )
139 {
140 case DLL_PROCESS_ATTACH:
141 // Initialize once for each new process.
142 // Return FALSE to fail DLL load.
143 #ifdef DEBUG_SDS3D_TO_FILE
144 s3d_logstream = INVALID_HANDLE_VALUE;
145 s3d_logstream = CreateFile ("s_ds3d.log", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
146 FILE_ATTRIBUTE_NORMAL/*|FILE_FLAG_WRITE_THROUGH*/, NULL);
147 if (s3d_logstream == INVALID_HANDLE_VALUE)
148 return FALSE;
149 #endif
150 break;
151
152 case DLL_THREAD_ATTACH:
153 // Do thread-specific initialization.
154 break;
155
156 case DLL_THREAD_DETACH:
157 // Do thread-specific cleanup.
158 break;
159
160 case DLL_PROCESS_DETACH:
161 // Perform any necessary cleanup.
162 #ifdef DEBUG_SDS3D_TO_FILE
163 if ( s3d_logstream != INVALID_HANDLE_VALUE ) {
164 CloseHandle ( s3d_logstream );
165 s3d_logstream = INVALID_HANDLE_VALUE;
166 }
167 #endif
168 break;
169 }
170 return TRUE; // Successful DLL_PROCESS_ATTACH.
171 }
172
173 /***************************************************************
174 *
175 * DBG_Printf
176 * Output error messages to debug log if DEBUG_SDS3D_TO_FILE is defined,
177 * else do nothing
178 *
179 ***************************************************************
180 */
DBG_Printf(LPCTSTR lpFmt,...)181 void DBG_Printf (LPCTSTR lpFmt, ...)
182 {
183 #ifdef DEBUG_SDS3D_TO_FILE
184 char str[1999];
185 va_list arglist;
186 DWORD bytesWritten;
187
188 va_start (arglist, lpFmt);
189 vsprintf (str, lpFmt, arglist);
190 va_end (arglist);
191
192 if ( s3d_logstream != INVALID_HANDLE_VALUE )
193 WriteFile (s3d_logstream, str, lstrlen(str), &bytesWritten, NULL);
194 #endif
195 }
196
197
198 /***************************************************************
199 *
200 * Grow intrenal sound stack by SOUND_ALLOCATE_DELTA amount
201 *
202 ***************************************************************
203 */
reallocate_stack(void)204 static BOOL reallocate_stack(void)
205 {
206 stack_t* new_stack;
207
208 new_stack = realloc(_stack, sizeof(stack_t) * (allocated_sounds + SOUND_ALLOCATE_DELTA));
209 if (new_stack)
210 {
211 _stack = new_stack;
212 ZeroMemory(&_stack[allocated_sounds], SOUND_ALLOCATE_DELTA * sizeof(stack_t));
213 allocated_sounds += SOUND_ALLOCATE_DELTA;
214 }
215 return (new_stack != NULL);
216 }
217
218
219 /***************************************************************
220 *
221 * Destroys source in stack
222 *
223 ***************************************************************
224 */
kill_sound(stack_t * snd)225 static void kill_sound(stack_t *snd)
226 {
227 //stack_t *snd = _stack + handle;
228
229 if (snd->dsbuffer3D)
230 RELEASE_3DBUFFER(snd->dsbuffer3D);
231
232 if (snd->dsbuffer)
233 RELEASE_BUFFER(snd->dsbuffer);
234
235 ZeroMemory(snd, sizeof(stack_t));
236
237 }
238
239
240 /***************************************************************
241 *
242 * Returns TRUE if source currently playing
243 *
244 ***************************************************************
245 */
is_playing(stack_t * snd)246 BOOL is_playing(stack_t *snd)
247 {
248 DWORD status;
249 LPDIRECTSOUNDBUFFER dsbuffer = snd->dsbuffer;
250
251 if (dsbuffer == NULL)
252 return 0;
253
254 IDirectSoundBuffer_GetStatus(dsbuffer, &status);
255 return (status & (DSBSTATUS_PLAYING | DSBSTATUS_LOOPING));
256
257 }
258
259
260 /***************************************************************
261 *
262 * Creates DirectSound buffer and fills with sound data
263 * NULL sound data pointer are valid (empty buffer
264 * will be created)
265 *
266 ***************************************************************
267 */
create_buffer(void * data,int length,BOOL as3d)268 static LPDIRECTSOUNDBUFFER create_buffer (void *data, int length, BOOL as3d)
269 {
270 LPDIRECTSOUNDBUFFER dsbuffer;
271 HRESULT hr;
272 WAVEFORMATEX wfm;
273 DSBUFFERDESC dsbdesc;
274 LPVOID lpvAudio1; // receives address of lock start
275 DWORD dwBytes1; // receives number of bytes locked
276 LPVOID lpvAudio2; // receives address of lock start
277 DWORD dwBytes2; // receives number of bytes locked
278
279 ZeroMemory (&wfm, sizeof(WAVEFORMATEX));
280 wfm.wFormatTag = WAVE_FORMAT_PCM;
281 wfm.nChannels = 1;
282 wfm.nSamplesPerSec = data?*((unsigned short*)data+1):srate; //mostly 11025, but some at 22050.
283 wfm.wBitsPerSample = 8;
284 wfm.nBlockAlign = wfm.wBitsPerSample / 8 * wfm.nChannels;
285 wfm.nAvgBytesPerSec = wfm.nSamplesPerSec * wfm.nBlockAlign;
286
287 // Set up DSBUFFERDESC structure.
288 ZeroMemory (&dsbdesc, sizeof(DSBUFFERDESC) );
289 dsbdesc.dwSize = sizeof (DSBUFFERDESC);
290 dsbdesc.dwFlags = as3d?_3DSOURCE_FLAGS:_2DSOURCE_FLAGS;
291 dsbdesc.dwBufferBytes = length;
292 dsbdesc.lpwfxFormat = &wfm;
293
294 // DirectX 7.0 and above!
295 // Try to enable full HRTF virtualization algorithm for
296 // two-speakers or headphones
297 if (as3d)
298 dsbdesc.guid3DAlgorithm = (virtualization?DS3DALG_HRTF_FULL:DS3DALG_DEFAULT);
299
300 hr = IDirectSound_CreateSoundBuffer (DSnd, &dsbdesc, &dsbuffer, NULL);
301
302 // CreateSoundBuffer might return DS_NO_VIRTUALIZATION so uses FAILED
303 // macro rather than check explictly for DS_OK value
304 if (FAILED(hr))
305 {
306 DBG_Printf("CreateSoundBuffer FAILED. Code %d\n", hr);
307 return NULL;
308 }
309
310 if (data)
311 {
312 hr = IDirectSoundBuffer_Lock (dsbuffer, 0, length, &lpvAudio1, &dwBytes1, &lpvAudio2, &dwBytes2, 0);
313
314 // If DSERR_BUFFERLOST is returned, restore and retry lock.
315 if (hr == DSERR_BUFFERLOST)
316 {
317 hr = IDirectSoundBuffer_Restore (dsbuffer);
318 if( FAILED (hr) )
319 I_ErrorDS3D("Restore fail on %x, code %d\n",dsbuffer, hr);
320 hr = IDirectSoundBuffer_Lock (dsbuffer, 0, length, &lpvAudio1, &dwBytes1, NULL, NULL, 0);
321 if( FAILED (hr) )
322 I_ErrorDS3D("Lock fail(2) on %x, code %d\n",dsbuffer, hr);
323 }
324 else
325 if( FAILED (hr) )
326 I_ErrorDS3D("Lock fail(1) on %x, code %d\n",dsbuffer, hr);
327
328 // copy wave data into the buffer (note: dwBytes1 should equal to dsbdesc->dwBufferBytes ...)
329 CopyMemory (lpvAudio1, (byte*)data+8, dwBytes1);
330
331 if ( dwBytes2 && lpvAudio2)
332 CopyMemory(lpvAudio2, ((byte*)data + 8) + dwBytes1, dwBytes2);
333
334
335 // finally, unlock the buffer
336 hr = IDirectSoundBuffer_Unlock (dsbuffer, lpvAudio1, dwBytes1, lpvAudio2, dwBytes2);
337
338 if( FAILED (hr) )
339 I_ErrorDS3D("Unlock fail on %x, code %d\n",dsbuffer, hr);
340 }
341
342 return dsbuffer;
343 }
344
345
346 /***************************************************************
347 *
348 * Creates 3D source data buffer
349 *
350 ***************************************************************
351 */
create_3dbuffer(LPDIRECTSOUNDBUFFER dsbuffer,LPDIRECTSOUND3DBUFFER source3d)352 static LPDIRECTSOUND3DBUFFER create_3dbuffer(LPDIRECTSOUNDBUFFER dsbuffer, LPDIRECTSOUND3DBUFFER source3d)
353 {
354 HRESULT hr;
355
356 hr = IDirectSoundBuffer_QueryInterface(dsbuffer,
357 &IID_IDirectSound3DBuffer, (void **)&source3d);
358
359 if (FAILED(hr))
360 {
361 DBG_Printf("Couldn't obtain 3D Buffer interface. Code %d\n", hr);
362 return NULL;
363 }
364
365 if (hr == DS_NO_VIRTUALIZATION)
366 {
367 DBG_Printf("The 3D virtualization does not supported under this OS.\n");
368 virtualization = FALSE;
369 }
370 return source3d;
371 }
372
373
374 /***************************************************************
375 *
376 * Returns free (unused) source stack slot
377 * If none available sound stack will be increased
378 *
379 ***************************************************************
380 */
find_handle(int new_sfx_id,int new_is3d)381 static int find_handle(int new_sfx_id, int new_is3d)
382 {
383 int free_sfx;
384 stack_t *snd;
385
386
387 // At first do look for sound with same sfx ID and reuse it
388 for (free_sfx = 0, snd = _stack; free_sfx < allocated_sounds; snd++, free_sfx++)
389 {
390
391 if (snd->permanent)
392 continue;
393 /*
394 if (!is_playing(snd))
395 {
396 if (same_sfx == 0 && snd->sfx_id == new_sfx_id && snd->dsbuffer)
397 {
398 same_sfx = i;
399 continue;
400 }
401
402 if (snd->sfx_id && ++snd->LRU >= MAX_LRU)
403 kill_sound(snd);
404 }
405 */
406 if (snd->dsbuffer == 0)
407 break;
408 //free_sfx = i;
409
410 }
411
412 // No suitable resource found so increase sound stack
413 if (free_sfx == allocated_sounds)
414 {
415 DBG_Printf("No free or same sfx found so increase stack (currently %d srcs)\n", allocated_sounds);
416 free_sfx = reallocate_stack() ? free_sfx : -1;
417 };
418
419 return free_sfx;
420
421 }
422
423
424 /***************************************************************
425 *
426 * Recalculates volume from Doom scale to DirectSound scale
427 *
428 ***************************************************************
429 */
recalc_volume(int base_vol,int steps)430 static int recalc_volume(int base_vol, int steps)
431 {
432 return (base_vol * ((DSBVOLUME_MAX-DSBVOLUME_MIN)/4)) / steps
433 + (DSBVOLUME_MAX - ((DSBVOLUME_MAX-DSBVOLUME_MIN)/4));
434 }
435
436
437 /***************************************************************
438 *
439 * Updates sound volume of the DirectSound buffer
440 *
441 ***************************************************************
442 */
UpdateSoundVolume(LPDIRECTSOUNDBUFFER lpSnd,int volume)443 static void UpdateSoundVolume (LPDIRECTSOUNDBUFFER lpSnd, int volume)
444 {
445 /*volume = (volume * ((DSBVOLUME_MAX-DSBVOLUME_MIN)/4)) / 256 +
446 (DSBVOLUME_MAX - ((DSBVOLUME_MAX-DSBVOLUME_MIN)/4));
447
448 IDirectSoundBuffer_SetVolume (lpSnd, volume);*/
449 IDirectSoundBuffer_SetVolume (lpSnd, recalc_volume(volume, 256));
450 }
451
452
453 // --------------------------------------------------------------------------
454 // Update the panning for a secondary buffer, make sure it was created with
455 // DSBCAPS_CTRLPAN
456 // --------------------------------------------------------------------------
457 #define DSBPAN_RANGE (DSBPAN_RIGHT-(DSBPAN_LEFT))
458
459 // Doom originally has sep range 1..256, but DoomLegacy is now using +/- 127.
460 // Doom sounds pan range +/- 127 (0 is centre)
461 #define SEP_RANGE 256
462 // sep : +/- 127, 0 is center
Update2DSoundPanning(LPDIRECTSOUNDBUFFER lpSnd,int sep)463 static void Update2DSoundPanning (LPDIRECTSOUNDBUFFER lpSnd, int sep)
464 {
465 HRESULT hr;
466 // DirectSound sep has 0 as center.
467 hr = IDirectSoundBuffer_SetPan (lpSnd, (sep * DSBPAN_RANGE)/SEP_RANGE);
468 //if (FAILED(hr))
469 // CONS_Printf ("SetPan FAILED for sep %d pan %d\n", sep, (sep * DSBPAN_RANGE)/SEP_RANGE);
470 }
471
472
473
474 /******************************************************************************
475 *
476 * Initialise driver and listener
477 *
478 *****************************************************************************/
HWRAPI(Startup)479 EXPORT BOOL HWRAPI( Startup ) (I_Error_t FatalErrorFunction, snddev_t *snd_dev)
480 {
481 HRESULT hr;
482 DSBUFFERDESC desc;
483 WAVEFORMATEX wfm;
484 DSCAPS dscaps;
485 DWORD speakers;
486 DWORD speaker_config;
487 DWORD speaker_geometry;
488
489 I_ErrorDS3D = FatalErrorFunction;
490 DBG_Printf ("S_DS3D Init(): DirectSound3D driver for Doom Legacy v%d.%d\n", VERSION / 100, VERSION % 100);
491
492 DBG_Printf("Initialising DirectSound3D...\n");
493 hr = DirectSoundCreate( NULL, &DSnd, NULL);
494 if (FAILED(hr))
495 {
496 DBG_Printf("Failed to obtain DirectSound\n");
497 return FALSE;
498 }
499
500 #ifdef SMIF_WIN_NATIVE
501 // these paramters are only defined for WIN_NATIVE
502 hr = IDirectSound_SetCooperativeLevel(DSnd, hWndMain, snd_dev->cooplevel);
503 if (FAILED (hr))
504 {
505 DBG_Printf("Couldn't set coopertive level\n");
506 return FALSE;
507 }
508 #endif
509
510 dscaps.dwSize = sizeof(DSCAPS);
511
512 IDirectSound_GetCaps(DSnd, &dscaps);
513 IDirectSound_GetSpeakerConfig(DSnd, &speakers);
514
515 DBG_Printf("Sound hardware capabilities:\n");
516 DBG_Printf(" Driver is %scertified.\n", (dscaps.dwFlags & DSCAPS_CERTIFIED) == DSCAPS_CERTIFIED?"":"not ");
517 DBG_Printf(" Maximum hardware mixing buffers %d\n", dscaps.dwMaxHwMixingAllBuffers);
518 DBG_Printf(" Maximum hardware 3D buffers %d\n", dscaps.dwFreeHw3DAllBuffers);
519
520 speaker_config = DSSPEAKER_CONFIG(speakers);
521 speaker_geometry = DSSPEAKER_GEOMETRY(speakers);
522
523 DBG_Printf("Current speaker configuration: ");
524
525 switch (speaker_config)
526 {
527 case DSSPEAKER_5POINT1:
528 DBG_Printf("5.1 (5 speakers with subwoofer).\n");
529 break;
530
531 case DSSPEAKER_HEADPHONE:
532 DBG_Printf("headphone.\n");
533 break;
534
535 case DSSPEAKER_MONO:
536 DBG_Printf("single speaker (mono).\n");
537 break;
538
539 case DSSPEAKER_QUAD:
540 DBG_Printf("quadrophonic\n");
541 break;
542
543 case DSSPEAKER_SURROUND:
544 DBG_Printf("surround.\n");
545 break;
546
547 case DSSPEAKER_STEREO:
548 DBG_Printf("stereo with %s geometry ",
549 speaker_geometry == DSSPEAKER_GEOMETRY_WIDE
550 ? "wide (arc of 20 deg.)"
551 : speaker_geometry == DSSPEAKER_GEOMETRY_NARROW
552 ? "narrow (arc of 10 deg.)"
553 : speaker_geometry == DSSPEAKER_GEOMETRY_MIN
554 ? "min (arc of 5 deg.)"
555 : speaker_geometry == DSSPEAKER_GEOMETRY_MAX
556 ? "max (arc of 180 deg.)"
557 : "unknown");
558 break;
559 default:
560 DBG_Printf("undetectable.\n");
561
562 }
563
564 update_mode = DS3D_IMMEDIATE;
565
566 // Create primary sound buffer
567 ZeroMemory(&desc, sizeof(DSBUFFERDESC));
568 desc.dwSize = sizeof(DSBUFFERDESC);
569 desc.dwFlags = DSBCAPS_CTRL3D | DSBCAPS_PRIMARYBUFFER | DSBCAPS_CTRLVOLUME;
570 desc.dwBufferBytes = 0;
571 desc.lpwfxFormat = NULL;
572
573 hr = IDirectSound_CreateSoundBuffer(DSnd, &desc, &PrimaryBuffer, NULL);
574 if (FAILED(hr))
575 {
576 DBG_Printf("CreateSoundBuffer FAILED (ErrNo %d)\n", hr);
577 return FALSE;
578 }
579
580 // Query for 3D Listener object
581 hr = IDirectSoundBuffer_QueryInterface(PrimaryBuffer,
582 &IID_IDirectSound3DListener, (void **)&Listener);
583
584 if (FAILED( hr ) )
585 {
586 DBG_Printf("Couldn't obtain 3D Listener interface (ErrNo %d)\n", hr);
587 return FALSE;
588 }
589
590 // Set up initial listsner parameters
591 IDirectSound3DListener_SetDistanceFactor(Listener, (float)1/(float)72.0, DS3D_IMMEDIATE);
592 //IDirectSound3DListener_SetRolloffFactor(Listener, DS3D_MAXROLLOFFFACTOR, DS3D_IMMEDIATE);
593 IDirectSound3DListener_SetRolloffFactor(Listener, 1.6, DS3D_IMMEDIATE);
594 listener_parms.dwSize = sizeof(DS3DLISTENER);
595 IDirectSound3DListener_GetAllParameters(Listener, &listener_parms);
596
597 ZeroMemory (&wfm, sizeof(WAVEFORMATEX));
598 wfm.wFormatTag = WAVE_FORMAT_PCM;
599 wfm.nChannels = 2;
600 wfm.nSamplesPerSec = srate = snd_dev->sample_rate;
601 wfm.wBitsPerSample = snd_dev->bps;
602 wfm.nBlockAlign = wfm.wBitsPerSample / 8 * wfm.nChannels;
603 wfm.nAvgBytesPerSec = wfm.nSamplesPerSec * wfm.nBlockAlign;
604
605 if (snd_dev->cooplevel >= DSSCL_PRIORITY)
606 {
607 hr = IDirectSoundBuffer_SetFormat (PrimaryBuffer, &wfm);
608 if (FAILED(hr))
609 DBG_Printf ("Couldn't set primary buffer format.\n");
610
611 DBG_Printf (" Compacting onboard sound-memory...");
612 hr = IDirectSound_Compact (DSnd);
613 DBG_Printf (" %s\n", SUCCEEDED(hr) ? "done" : "FAILED");
614 }
615
616 // Initially enables HRTF virtualization (may be changed later)
617 virtualization = TRUE;
618
619 _stack = NULL;
620 allocated_sounds = 0;
621 IDirectSoundBuffer_Play(PrimaryBuffer, 0, 0, DSBPLAY_LOOPING);
622 return reallocate_stack();
623 }
624
625
626
627 /***************************************************************
628 *
629 * Shutdown driver
630 *
631 ***************************************************************
632 */
HWRAPI(Shutdown)633 EXPORT void HWRAPI( Shutdown ) (void)
634 {
635 int i;
636
637 DBG_Printf ("S_DS3D Shutdown()\n");
638
639 for (i = 0; i < allocated_sounds; i++)
640 {
641 StopSource(i);
642 kill_sound(_stack + i);
643 }
644
645 if (_stack)
646 free(_stack);
647
648 if (Listener)
649 {
650 IDirectSound3DListener_Release(Listener);
651 Listener = NULL;
652 }
653
654 if (PrimaryBuffer)
655 RELEASE_BUFFER(PrimaryBuffer);
656
657 if (DSnd)
658 {
659 IDirectSound_Release(DSnd);
660 DSnd = NULL;
661 }
662
663 }
664
665
666
HWRAPI(IsPlaying)667 EXPORT int HWRAPI (IsPlaying) (int handle)
668 {
669 if (handle < 0 || handle >= allocated_sounds)
670 return FALSE;
671
672 return is_playing(_stack + handle);
673 }
674
675
676 // Calculate sound pitching
recalc_pitch(int doom_pitch)677 static float recalc_pitch(int doom_pitch)
678 {
679 return doom_pitch < NORMAL_PITCH ?
680 (float)(doom_pitch + NORMAL_PITCH) / (NORMAL_PITCH * 2)
681 :(float)doom_pitch / (float)NORMAL_PITCH;
682 }
683
684
setup_source(int handle,sfx_data_t * sfx,BOOL is_3dsource)685 static stack_t *setup_source(int handle, sfx_data_t *sfx, BOOL is_3dsource)
686 {
687 stack_t *snd;
688 //int handle;
689 int data_length;
690 LPDIRECTSOUNDBUFFER dsbuffer = NULL;
691 LPDIRECTSOUND3DBUFFER ds3dbuffer = NULL;
692
693 if (handle == NEW_HANDLE)
694 handle = find_handle(sfx?sfx->id:0, is_3dsource);
695
696 snd = _stack + handle;
697
698 // Check for reused source
699 if (snd->dsbuffer)
700 return snd;
701
702 data_length = sfx?sfx->length - 8:DSBSIZE_MIN;
703
704 dsbuffer = create_buffer(sfx ? sfx->data : NULL, data_length, is_3dsource);
705 if (dsbuffer)
706 {
707
708
709 if (is_3dsource)
710 {
711 ds3dbuffer = create_3dbuffer(dsbuffer, ds3dbuffer);
712 if (!ds3dbuffer)
713 {
714 RELEASE_BUFFER(dsbuffer);
715 return NULL;
716 }
717 snd->parameters.dwSize = sizeof(DS3DBUFFER);
718 IDirectSound3DBuffer_GetAllParameters(ds3dbuffer, &snd->parameters);
719
720 }
721
722 // judgecutor: sound pitching
723 if (sfx)
724 {
725 DWORD freq;
726
727 freq = (float)(*((unsigned short*)sfx->data+1)) * recalc_pitch(sfx->pitch);
728 IDirectSoundBuffer_SetFrequency(dsbuffer, freq);
729 }
730
731 snd->dsbuffer = dsbuffer;
732 snd->dsbuffer3D = ds3dbuffer;
733 snd->LRU = 0;
734 snd->sfx_id = sfx ? sfx->id : 0;
735 if (!is_3dsource)
736 snd->permanent = 0;
737 return snd;
738 }
739 return NULL;
740
741 }
742
743 /******************************************************************************
744 *
745 * Creates 2D (stereo) source
746 *
747 ******************************************************************************/
HWRAPI(Add2DSource)748 EXPORT int HWRAPI ( Add2DSource ) (sfx_data_t *sfx)
749 {
750 stack_t *snd;
751
752 if (!sfx)
753 return -1;
754
755 snd = setup_source(NEW_HANDLE, sfx, IS_2DSOURCE);
756 if (snd)
757 {
758 UpdateSoundVolume(snd->dsbuffer, sfx->volume);
759 Update2DSoundPanning(snd->dsbuffer, sfx->sep);
760 }
761 return snd - _stack;
762 }
763
764 /******************************************************************************
765 *
766 * Creates 3D source
767 *
768 ******************************************************************************/
769
HWRAPI(Add3DSource)770 EXPORT int HWRAPI ( Add3DSource ) (source3D_data_t *src, sfx_data_t *sfx)
771 {
772 stack_t *snd;
773
774 snd = setup_source(NEW_HANDLE, sfx, IS_3DSOURCE);
775
776 if (snd)
777 {
778
779 /*x = src->pos.x;
780 y = src->pos.z;
781 z = src->pos.y;
782
783 IDirectSound3DBuffer_SetPosition(source, x, y, z, update_mode);
784 IDirectSound3DBuffer_SetVelocity(source, src->pos.momx, src->pos.momz, src->pos.momy, update_mode);
785 IDirectSound3DBuffer_SetMode(source, src->head_relative?DS3DMODE_HEADRELATIVE:DS3DMODE_NORMAL, update_mode);*/
786
787 snd->parameters.vPosition.x = src->pos.x;
788 snd->parameters.vPosition.y = src->pos.z;
789 snd->parameters.vPosition.z = src->pos.y;
790
791 snd->parameters.vVelocity.x = src->pos.momx;
792 snd->parameters.vVelocity.y = src->pos.momz;
793 snd->parameters.vVelocity.z = src->pos.momy;
794
795 snd->parameters.dwMode = src->head_relative ? DS3DMODE_HEADRELATIVE : DS3DMODE_NORMAL;
796
797 snd->parameters.flMinDistance = src->min_distance;
798 snd->parameters.flMaxDistance = src->max_distance;
799 //snd->parameters.flMaxDistance = DS3D_DEFAULTMAXDISTANCE;
800
801 snd->permanent = src->permanent;
802
803 UpdateSoundVolume(snd->dsbuffer, sfx?sfx->volume:255);
804 IDirectSound3DBuffer_SetAllParameters(snd->dsbuffer3D, &snd->parameters, DS3D_IMMEDIATE);
805
806 IDirectSoundBuffer_SetCurrentPosition(snd->dsbuffer, 0);
807
808 }
809
810 return (snd - _stack);
811 }
812
813 /******************************************************************************
814 *
815 * Destroy source and remove it from stack if it is a 2D source.
816 * Otherwise put source into cache
817 *
818 *****************************************************************************/
HWRAPI(KillSource)819 EXPORT void HWRAPI (KillSource) (int handle)
820 {
821
822 if (handle < 0 || handle >= allocated_sounds)
823 return;
824 /*
825 if (_stack[handle].dsbuffer3D)
826 {
827 // It's a 3D source so let him chance to be reused :-)
828 _stack[handle].LRU = 1;
829 }
830 else
831 { */
832 // No, it is a 2D source so kill him
833 kill_sound(_stack + handle);
834 //}
835 }
836
837
838 /******************************************************************************
839 *
840 * Update volume and separation (panning) of 2D source
841 *
842 *****************************************************************************/
HWRAPI(Update2DSoundParms)843 EXPORT void HWRAPI (Update2DSoundParms) (int handle, int vol, int sep)
844 {
845 LPDIRECTSOUNDBUFFER dsbuffer;
846
847 if (handle < 0 || handle >= allocated_sounds)
848 return;
849
850 if ((_stack+handle)->dsbuffer3D)
851 return;
852 dsbuffer = (_stack + handle)->dsbuffer;
853 UpdateSoundVolume(dsbuffer, vol);
854 Update2DSoundPanning(dsbuffer, sep);
855 }
856
857
858
859 // --------------------------------------------------------------------------
860 // Set the global volume for sound effects
861 // --------------------------------------------------------------------------
HWRAPI(SetGlobalSfxVolume)862 EXPORT void HWRAPI (SetGlobalSfxVolume) (int volume)
863 {
864 int vol;
865 HRESULT hr;
866
867 // use the last quarter of volume range
868 if (volume)
869 vol = recalc_volume(volume, 31);
870 else
871 vol = DSBVOLUME_MIN;
872
873 hr = IDirectSoundBuffer_SetVolume (PrimaryBuffer, vol);
874
875 }
876
HWRAPI(StopSource)877 EXPORT void HWRAPI ( StopSource) (int handle)
878 {
879 LPDIRECTSOUNDBUFFER dsbuffer;
880
881 if (handle < 0 || handle >= allocated_sounds)
882 return;
883 dsbuffer = (_stack + handle)->dsbuffer;
884
885 if (dsbuffer)
886 {
887 IDirectSoundBuffer_Stop(dsbuffer);
888 IDirectSoundBuffer_SetCurrentPosition(dsbuffer, 0);
889 }
890 }
891
892
HWRAPI(GetHW3DSVersion)893 EXPORT int HWRAPI ( GetHW3DSVersion) (void)
894 {
895 return VERSION;
896 }
897
898
HWRAPI(BeginFrameUpdate)899 EXPORT void HWRAPI (BeginFrameUpdate) (void)
900 {
901 update_mode = DS3D_DEFERRED;
902 }
903
904
HWRAPI(EndFrameUpdate)905 EXPORT void HWRAPI (EndFrameUpdate) (void)
906 {
907 if (update_mode == DS3D_DEFERRED)
908 IDirectSound3DListener_CommitDeferredSettings(Listener);
909
910 update_mode = DS3D_IMMEDIATE;
911 }
912
913
914 /******************************************************************************
915 * UpdateListener
916 *
917 * Set up main listener properties:
918 * - position
919 * - orientation
920 * - velocity
921 *****************************************************************************/
HWRAPI(UpdateListener)922 EXPORT void HWRAPI (UpdateListener) (listener_data_t* data)
923 {
924 D3DVECTOR pos;
925 D3DVECTOR face;
926 D3DVECTOR head;
927 D3DVECTOR velocity;
928
929 double f_angle;
930 //double h_angle, t_angle;
931 //double f_cos, f_sin, t_sin;
932
933 pos.x = data->x;
934 pos.y = data->z;
935 pos.z = data->y;
936
937 velocity.x = data->momx;
938 velocity.y = data->momz;
939 velocity.z = data->momy;
940
941 f_angle = (data->f_angle) / 180 * PI;
942 //h_angle = data->h_angle / 180 * PI;
943 //h_angle = 90 / 180 * PI;
944
945 // Treat listener orientation angles as spherical coordinates.
946 // x = sin h * cos f
947 // y = sin h * sin f
948 // z = cos h
949
950 // Front vector
951 //t_angle = (PI/2 - h_angle);
952 //t_angle = PI/2;
953
954 //face.x = (t_sin = sin(t_angle)) * (f_cos = cos(f_angle));
955 //face.z = t_sin * (f_sin = sin(f_angle));
956 //face.y = cos(t_angle);
957 face.x = cos(f_angle);
958 face.z = sin(f_angle);
959 face.y = 0;
960
961 head.x = 0.0;
962 head.y = 1.0;
963 head.z = 0.0;
964
965
966 // Top vector
967 //h_angle = (-data->h_angle) / 180 * PI;
968
969 /*
970 t_angle = -h_angle;
971
972 head.z = (t_sin = sin(t_angle)) * f_cos;
973 head.x = t_sin * f_sin;
974 head.y = cos(t_angle);
975 */
976
977 // Update at once
978 memcpy(&listener_parms.vPosition, &pos, sizeof(D3DVECTOR));
979 memcpy(&listener_parms.vOrientFront, &face, sizeof(D3DVECTOR));
980 memcpy(&listener_parms.vOrientTop, &head, sizeof(D3DVECTOR));
981 memcpy(&listener_parms.vVelocity, &velocity, sizeof(D3DVECTOR));
982 //IDirectSound3DListener_SetAllParameters(Listener, &listener_parms, DS3D_IMMEDIATE);
983 IDirectSound3DListener_SetAllParameters(Listener, &listener_parms, update_mode);
984 }
985
HWRAPI(SetCone)986 EXPORT int HWRAPI (SetCone) (int handle, cone_def_t *cone_def)
987 {
988 stack_t *snd;
989 //DS3DBUFFER parms;
990
991 if (handle < 0 || handle >= allocated_sounds)
992 return -1;
993
994 snd = _stack + handle;
995
996 if (snd->dsbuffer3D)
997 {
998
999 /*f_angle = cone_def->f_angle / 180 * PI;
1000 h_angle = (90 - cone_def->h_angle) / 180 * PI;
1001 parms.vConeOrientation.x = sin(h_angle) * cos(f_angle);
1002 parms.vConeOrientation.z = sin(h_angle) * sin(f_angle);
1003 parms.vConeOrientation.y = cos(h_angle);*/
1004
1005 snd->parameters.dwInsideConeAngle = cone_def->inner;
1006 snd->parameters.dwOutsideConeAngle = cone_def->outer;
1007 snd->parameters.lConeOutsideVolume = recalc_volume(cone_def->outer_gain, 256);
1008
1009 return IDirectSound3DBuffer_SetAllParameters(snd->dsbuffer3D, &snd->parameters, update_mode);
1010 }
1011
1012 return -1;
1013 }
1014
HWRAPI(Update3DSource)1015 EXPORT void HWRAPI (Update3DSource) (int handle, source3D_pos_t *data)
1016 {
1017 stack_t *snd;
1018
1019 if (handle < 0 || handle >= allocated_sounds)
1020 return;
1021
1022 snd = _stack + handle;
1023 if (snd->dsbuffer3D)
1024 {
1025
1026 /*parms.dwSize = sizeof(DS3DBUFFER);
1027 IDirectSound3DBuffer_GetAllParameters(snd, &parms);*/
1028
1029 //angle = data->angle * 180 / PI;
1030
1031 snd->parameters.vPosition.x = data->x;
1032 snd->parameters.vPosition.y = data->z;
1033 snd->parameters.vPosition.z = data->y;
1034
1035 /*parms.vConeOrientation.x = cos(angle);
1036 parms.vConeOrientation.z = sin(angle);
1037 parms.vConeOrientation.y = 0;*/
1038
1039 snd->parameters.vVelocity.x = data->momx;
1040 snd->parameters.vVelocity.y = data->momz;
1041 snd->parameters.vVelocity.z = data->momy;
1042
1043 //snd->parameters.flMinDistance = data->min_distance;
1044 //snd->parameters.flMaxDistance = data->max_distance;
1045 //snd->parameters.dwMode = pos->head_realtive?DS3DMODE_HEADREALTIVE:DS3DMODE_NORMAL;
1046
1047 IDirectSound3DBuffer_SetAllParameters(snd->dsbuffer3D, &snd->parameters, update_mode);
1048 }
1049 }
1050
1051
HWRAPI(StartSource)1052 EXPORT int HWRAPI (StartSource) (int handle)
1053 {
1054 LPDIRECTSOUNDBUFFER snd;
1055
1056 if (handle < 0 || handle >= allocated_sounds)
1057 return -1;
1058
1059 snd = (_stack + handle)->dsbuffer;
1060 IDirectSoundBuffer_SetCurrentPosition(snd, 0);
1061 return IDirectSoundBuffer_Play(snd, 0, 0, 0);
1062
1063 }
1064
1065 //-------------------------------------------------------------
1066 // Load new sound data into source
1067 //-------------------------------------------------------------
HWRAPI(Reload3DSource)1068 EXPORT int HWRAPI (Reload3DSource) (int handle, sfx_data_t *data)
1069 {
1070 DS3DBUFFER temp;
1071 stack_t *snd;
1072 int perm;
1073
1074 // DirectX could not load new sound data into source
1075 // so recreate sound buffers
1076 if (handle < 0 || handle >= allocated_sounds)
1077 return -1;
1078
1079 snd = _stack + handle;
1080 CopyMemory(&temp, &snd->parameters, sizeof(DS3DBUFFER));
1081 perm = snd->permanent;
1082
1083 kill_sound(snd);
1084
1085 snd = setup_source(handle, data, IS_3DSOURCE);
1086 /*snd->dsbuffer = create_buffer(data->data, data->length, true);
1087 if (snd->dsbuffer == NULL)
1088 return -1;
1089 snd->dsbuffer3D = create_3dbuffer(snd->dsbuffer, snd->dsbuffer3D);
1090 if (snd->dsbuffer3D == NULL)
1091 {
1092 RELEASE_BUFFER(snd->dsbuffer);
1093 return -1;
1094 }
1095
1096 snd->sfx_id = data->id;
1097 snd->LRU = 0;*/
1098 if (snd)
1099 {
1100 snd->permanent = perm;
1101 IDirectSound3DBuffer_SetAllParameters(snd->dsbuffer3D, &temp, DS3D_IMMEDIATE);
1102 CopyMemory(&snd->parameters, &temp, sizeof(DS3DBUFFER));
1103 }
1104
1105 return (snd - _stack);
1106 }
1107
HWRAPI(UpdateSourceVolume)1108 EXPORT void HWRAPI (UpdateSourceVolume) (int handle, int volume)
1109 {
1110 if (handle < 0 || handle >= allocated_sounds)
1111 return;
1112 UpdateSoundVolume((_stack + handle)->dsbuffer, volume);
1113 }