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 }