📄 s_ds3d.c
字号:
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id: s_ds3d.c,v 1.2 2001/04/06 21:36:53 judgecutor Exp $
//
// Copyright (C) 2001 by DooM Legacy Team.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
//
// $Log: s_ds3d.c,v $
// Revision 1.2 2001/04/06 21:36:53 judgecutor
// Added detection for speaker configuration
//
// Revision 1.1 2001/04/04 19:49:44 judgecutor
// Initial release
//
//
// DESCRIPTION:
// General driver for 3D sound system.
// Implementend via DirectSound3D API
//
//-----------------------------------------------------------------------------
#define INITGUID
#include <windows.h>
#include <cguid.h>
#include <dsound.h>
#define _CREATE_DLL_
#include "../hw3dsdrv.h"
#include "../../m_fixed.h"
#undef DEBUG_TO_FILE
#define DEBUG_TO_FILE
// Internal sound stack
typedef struct stack_snd_s
{
// Sound data
LPDIRECTSOUNDBUFFER dsbuffer;
// 3D data of 3D source
LPDIRECTSOUND3DBUFFER dsbuffer3D; // 3D data
// Current parameters of 3D source
// Valid only when source is 3D source
// (dsbuffer3D is not NULL)
DS3DBUFFER parameters;
// Currently unused
int sfx_id;
// Currently unused
int LRU;
// Flag of static source
// Driver does not manage intrenally such sources
int permanent;
} stack_t;
// Just for now...
#define SOUND_ALLOCATE_DELTA 16 // Amount of sources per stack incrementation
#define MAX_LRU 16 // Maximum iterations to keep source in stack
static stack_t *_stack; // Sound stack
static int allocated_sounds; // Size of stack
static int srate; // Default sample rate
// output all debugging messages to this file
#ifdef DEBUG_TO_FILE
static HANDLE logstream;
#endif
static LPDIRECTSOUND DSnd = NULL; // Main DirectSound object
static LPDIRECTSOUNDBUFFER PrimaryBuffer = NULL; //
static LPDIRECTSOUND3DLISTENER Listener = NULL; //
static DS3DLISTENER listener_parms; // Listener papameters
static BOOL virtualization; // TRUE if HRTF virtualization enabled
static DWORD update_mode; // Current update mode of listener
//static DWORD max_3d_buffers;
static I_Error_t I_ErrorDS3D = NULL;
//static stack_snd_t sound_stack[MAX_SOUNDS];
// Safe buffer release
#define RELEASE_BUFFER(buf) {if (buf) { IDirectSoundBuffer_Release(buf); (buf) = NULL; }}
#define RELEASE_3DBUFFER(buf) {if (buf) { IDirectSound3DBuffer_Release(buf); (buf) = NULL; }}
// Default flags for buffers
#define _2DSOURCE_FLAGS (DSBCAPS_CTRLPAN | DSBCAPS_CTRLVOLUME | DSBCAPS_STICKYFOCUS | DSBCAPS_STATIC)
#define _3DSOURCE_FLAGS (DSBCAPS_CTRL3D | DSBCAPS_STATIC | DSBCAPS_MUTE3DATMAXDISTANCE | DSBCAPS_CTRLVOLUME)
enum {IS_2DSOURCE = 0, IS_3DSOURCE = 1};
#define NEW_HANDLE -1
BOOL APIENTRY DllMain( HANDLE hModule, // handle to DLL module
DWORD fdwReason, // reason for calling function
LPVOID lpReserved ) // reserved
{
// Perform actions based on the reason for calling.
switch( fdwReason )
{
case DLL_PROCESS_ATTACH:
// Initialize once for each new process.
// Return FALSE to fail DLL load.
#ifdef DEBUG_TO_FILE
logstream = INVALID_HANDLE_VALUE;
logstream = CreateFile ("s_ds3d.log", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL/*|FILE_FLAG_WRITE_THROUGH*/, NULL);
if (logstream == INVALID_HANDLE_VALUE)
return FALSE;
#endif
break;
case DLL_THREAD_ATTACH:
// Do thread-specific initialization.
break;
case DLL_THREAD_DETACH:
// Do thread-specific cleanup.
break;
case DLL_PROCESS_DETACH:
// Perform any necessary cleanup.
#ifdef DEBUG_TO_FILE
if ( logstream != INVALID_HANDLE_VALUE ) {
CloseHandle ( logstream );
logstream = INVALID_HANDLE_VALUE;
}
#endif
break;
}
return TRUE; // Successful DLL_PROCESS_ATTACH.
}
/***************************************************************
*
* DBG_Printf
* Output error messages to debug log if DEBUG_TO_FILE is defined,
* else do nothing
*
***************************************************************
*/
void DBG_Printf (LPCTSTR lpFmt, ...)
{
#ifdef DEBUG_TO_FILE
char str[1999];
va_list arglist;
DWORD bytesWritten;
va_start (arglist, lpFmt);
vsprintf (str, lpFmt, arglist);
va_end (arglist);
if ( logstream != INVALID_HANDLE_VALUE )
WriteFile (logstream, str, lstrlen(str), &bytesWritten, NULL);
#endif
}
/***************************************************************
*
* Grow intrenal sound stack by SOUND_ALLOCATE_DELTA amount
*
***************************************************************
*/
static BOOL reallocate_stack(void)
{
stack_t* new_stack;
new_stack = realloc(_stack, sizeof(stack_t) * (allocated_sounds + SOUND_ALLOCATE_DELTA));
if (new_stack)
{
_stack = new_stack;
ZeroMemory(&_stack[allocated_sounds], SOUND_ALLOCATE_DELTA * sizeof(stack_t));
allocated_sounds += SOUND_ALLOCATE_DELTA;
}
return (new_stack != NULL);
}
/***************************************************************
*
* Destroys source in stack
*
***************************************************************
*/
static void kill_sound(stack_t *snd)
{
//stack_t *snd = _stack + handle;
if (snd->dsbuffer3D)
RELEASE_3DBUFFER(snd->dsbuffer3D);
if (snd->dsbuffer)
RELEASE_BUFFER(snd->dsbuffer);
ZeroMemory(snd, sizeof(stack_t));
}
/***************************************************************
*
* Returns TRUE if source currently playing
*
***************************************************************
*/
BOOL is_playing(stack_t *snd)
{
DWORD status;
LPDIRECTSOUNDBUFFER dsbuffer = snd->dsbuffer;
if (dsbuffer == NULL)
return 0;
IDirectSoundBuffer_GetStatus(dsbuffer, &status);
return (status & (DSBSTATUS_PLAYING | DSBSTATUS_LOOPING));
}
/***************************************************************
*
* Creates DirectSound buffer and fills with sound data
* NULL sound data pointer are valid (empty buffer
* will be created)
*
***************************************************************
*/
static LPDIRECTSOUNDBUFFER create_buffer (void *data, int length, BOOL as3d)
{
LPDIRECTSOUNDBUFFER dsbuffer;
HRESULT hr;
WAVEFORMATEX wfm;
DSBUFFERDESC dsbdesc;
LPVOID lpvAudio1; // receives address of lock start
DWORD dwBytes1; // receives number of bytes locked
LPVOID lpvAudio2; // receives address of lock start
DWORD dwBytes2; // receives number of bytes locked
ZeroMemory (&wfm, sizeof(WAVEFORMATEX));
wfm.wFormatTag = WAVE_FORMAT_PCM;
wfm.nChannels = 1;
wfm.nSamplesPerSec = data?*((unsigned short*)data+1):srate; //mostly 11025, but some at 22050.
wfm.wBitsPerSample = 8;
wfm.nBlockAlign = wfm.wBitsPerSample / 8 * wfm.nChannels;
wfm.nAvgBytesPerSec = wfm.nSamplesPerSec * wfm.nBlockAlign;
// Set up DSBUFFERDESC structure.
ZeroMemory (&dsbdesc, sizeof(DSBUFFERDESC) );
dsbdesc.dwSize = sizeof (DSBUFFERDESC);
dsbdesc.dwFlags = as3d?_3DSOURCE_FLAGS:_2DSOURCE_FLAGS;
dsbdesc.dwBufferBytes = length;
dsbdesc.lpwfxFormat = &wfm;
// DirectX 7.0 and above!
// Try to enable full HRTF virtualization algorithm for
// two-speakers or headphones
if (as3d)
dsbdesc.guid3DAlgorithm = (virtualization?DS3DALG_HRTF_FULL:DS3DALG_DEFAULT);
hr = IDirectSound_CreateSoundBuffer (DSnd, &dsbdesc, &dsbuffer, NULL);
// CreateSoundBuffer might return DS_NO_VIRTUALIZATION so uses FAILED
// macro rather than check explictly for DS_OK value
if (FAILED(hr))
{
DBG_Printf("CreateSoundBuffer FAILED. Code %d\n", hr);
return NULL;
}
if (data)
{
hr = IDirectSoundBuffer_Lock (dsbuffer, 0, length, &lpvAudio1, &dwBytes1, &lpvAudio2, &dwBytes2, 0);
// If DSERR_BUFFERLOST is returned, restore and retry lock.
if (hr == DSERR_BUFFERLOST)
{
hr = IDirectSoundBuffer_Restore (dsbuffer);
if( FAILED (hr) )
I_ErrorDS3D("Restore fail on %x, code %d\n",dsbuffer, hr);
hr = IDirectSoundBuffer_Lock (dsbuffer, 0, length, &lpvAudio1, &dwBytes1, NULL, NULL, 0);
if( FAILED (hr) )
I_ErrorDS3D("Lock fail(2) on %x, code %d\n",dsbuffer, hr);
}
else
if( FAILED (hr) )
I_ErrorDS3D("Lock fail(1) on %x, code %d\n",dsbuffer, hr);
// copy wave data into the buffer (note: dwBytes1 should equal to dsbdesc->dwBufferBytes ...)
CopyMemory (lpvAudio1, (byte*)data+8, dwBytes1);
if ( dwBytes2 && lpvAudio2)
CopyMemory(lpvAudio2, ((byte*)data + 8) + dwBytes1, dwBytes2);
// finally, unlock the buffer
hr = IDirectSoundBuffer_Unlock (dsbuffer, lpvAudio1, dwBytes1, lpvAudio2, dwBytes2);
if( FAILED (hr) )
I_ErrorDS3D("Unlock fail on %x, code %d\n",dsbuffer, hr);
}
return dsbuffer;
}
/***************************************************************
*
* Creates 3D source data buffer
*
***************************************************************
*/
static LPDIRECTSOUND3DBUFFER create_3dbuffer(LPDIRECTSOUNDBUFFER dsbuffer, LPDIRECTSOUND3DBUFFER source3d)
{
HRESULT hr;
hr = IDirectSoundBuffer_QueryInterface(dsbuffer,
&IID_IDirectSound3DBuffer, (void **)&source3d);
if (FAILED(hr))
{
DBG_Printf("Couldn't obtain 3D Buffer interface. Code %d\n", hr);
return NULL;
}
if (hr == DS_NO_VIRTUALIZATION)
{
DBG_Printf("The 3D virtualization not supported under this OS.\n");
virtualization = FALSE;
}
return source3d;
}
/***************************************************************
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -