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