📄 win_snd.c
字号:
// PU_CACHE because the data is copied to the DIRECTSOUNDBUFFER, the one here will not be used
dssfx = (byte*) W_CacheLumpNum (sfx->lumpnum, PU_CACHE);
#ifdef SURROUND
// Make a normal (not inverted) sound buffer
return (void*)raw2DS (dssfx, size, FALSE);
#else
// return the LPDIRECTSOUNDBUFFER, which will be stored in S_sfx[].data
return (void *)raw2DS (dssfx, size);
#endif
}
// --------------------------------------------------------------------------
// Free all allocated resources for a single sound
// --------------------------------------------------------------------------
void I_FreeSfx (sfxinfo_t* sfx)
{
LPDIRECTSOUNDBUFFER dsbuffer;
if (sfx->lumpnum<0)
return;
#ifdef HW3SOUND
if (hws_mode != HWS_DEFAULT_MODE)
{
if (sfx->data)
Z_Free(sfx->data);
}
else
#endif
{
//CONS_Printf ("I_FreeSfx(%d)\n", sfx->lumpnum);
// free DIRECTSOUNDBUFFER
dsbuffer = (LPDIRECTSOUNDBUFFER) sfx->data;
if( dsbuffer )
dsbuffer->lpVtbl->Release (dsbuffer);
}
sfx->data = NULL;
sfx->lumpnum = -1;
}
// --------------------------------------------------------------------------
// Set the global volume for sound effects
// --------------------------------------------------------------------------
void I_SetSfxVolume(int volume)
{
int vol;
HRESULT hr;
if (nosound || !sound_started)
return;
// use the last quarter of volume range
if (cv_soundvolume.value)
vol = (cv_soundvolume.value * ((DSBVOLUME_MAX-DSBVOLUME_MIN)/4)) / 31 +
(DSBVOLUME_MAX - ((DSBVOLUME_MAX-DSBVOLUME_MIN)/4));
else
vol = DSBVOLUME_MIN; // make sure 0 is silence
//CONS_Printf ("setvolume to %d\n", vol);
hr = DSndPrimary->lpVtbl->SetVolume (DSndPrimary, vol);
//if (FAILED(hr))
// CONS_Printf ("setvolumne failed\n");
}
// --------------------------------------------------------------------------
// Update the volume for a secondary buffer, make sure it was created with
// DSBCAPS_CTRLVOLUME
// --------------------------------------------------------------------------
static void I_UpdateSoundVolume (LPDIRECTSOUNDBUFFER lpSnd, int volume)
{
HRESULT hr;
volume = (volume * ((DSBVOLUME_MAX-DSBVOLUME_MIN)/4)) / 256 +
(DSBVOLUME_MAX - ((DSBVOLUME_MAX-DSBVOLUME_MIN)/4));
hr = lpSnd->lpVtbl->SetVolume (lpSnd, volume);
//if (FAILED(hr))
// CONS_Printf ("\2SetVolume FAILED\n");
}
// --------------------------------------------------------------------------
// Update the panning for a secondary buffer, make sure it was created with
// DSBCAPS_CTRLPAN
// --------------------------------------------------------------------------
#define DSBPAN_RANGE (DSBPAN_RIGHT-(DSBPAN_LEFT))
#define SEP_RANGE 256 //Doom sounds pan range 0-255 (128 is centre)
static void I_UpdateSoundPanning (LPDIRECTSOUNDBUFFER lpSnd, int sep)
{
HRESULT hr;
hr = lpSnd->lpVtbl->SetPan (lpSnd, (sep * DSBPAN_RANGE)/SEP_RANGE - DSBPAN_RIGHT);
//if (FAILED(hr))
// CONS_Printf ("SetPan FAILED for sep %d pan %d\n", sep, (sep * DSBPAN_RANGE)/SEP_RANGE - DSBPAN_RIGHT);
}
// search a free slot in the stack, free it if needed
static int GetFreeStackNum(int newpriority)
{
int lowestpri,lowestprihandle;
int i;
// DirectSound can't play multiple instances of the same sound buffer
// unless they are duplicated, so if the sound buffer is in use, make a duplicate
lowestpri = 256;
lowestprihandle = 0;
for (i=0; i<MAXSTACKSOUNDS; i++)
{
// find a free 'playing sound slot' to use
if (StackSounds[i].lpSndBuf==NULL) {
//CONS_Printf ("\t\tfound free slot %d\n", i);
return i;
}
else
// check for sounds that finished playing, and can be freed
if( !I_SoundIsPlaying(i) )
{
//CONS_Printf ("\t\tfinished sound in slot %d\n", i);
//stop sound and free the 'slot'
I_StopSound (i);
// we can use this one since it's now freed
return i;
}
else
//remember lowest priority sound
if (StackSounds[i].priority < lowestpri) {
lowestpri = StackSounds[i].priority;
lowestprihandle = i;
}
}
// the maximum of sounds playing at the same time is reached, if we have at least
// one sound playing with a lower priority, stop it and replace it with the new one
//CONS_Printf ("\t\tall slots occupied..");
if (newpriority >= lowestpri) {
I_StopSound (lowestprihandle);
return lowestprihandle;
//CONS_Printf (" kicking out lowest priority slot: %d pri: %d, my priority: %d\n",
// handle, lowestpri, priority);
}
return -1;
}
#ifdef SURROUND
static LPDIRECTSOUNDBUFFER CreateInvertedSound(int id)
{
int lumpnum;
byte *dsdata;
lumpnum = S_sfx[id].lumpnum;
if (lumpnum<0)
lumpnum = S_GetSfxLumpNum (&S_sfx[id]);
dsdata = W_CacheLumpNum (lumpnum, PU_CACHE);
return raw2DS(dsdata, W_LumpLength (lumpnum), TRUE);
}
#endif
// --------------------------------------------------------------------------
// Start the given S_sfx[id] sound with given properties (panning, volume..)
// FIXME: if a specific sound Id is already being played, another instance
// of that sound should be created with DuplicateSound()
// --------------------------------------------------------------------------
int I_StartSound (int id,
int vol,
int sep,
int pitch,
int priority )
{
HRESULT hr;
LPDIRECTSOUNDBUFFER dsbuffer;
DWORD dwStatus;
int handle;
int i;
#ifdef SURROUND
LPDIRECTSOUNDBUFFER dssurround;
#endif
if (nosound)
return -1;
//CONS_Printf ("I_StartSound:\n\t\tS_sfx[%d]\n", id);
handle = GetFreeStackNum(priority);
if( handle<0 )
return -1;
//CONS_Printf ("\t\tusing handle %d\n", handle);
// if the original buffer is playing, duplicate it (DirectSound specific)
// else, use the original buffer
dsbuffer = (LPDIRECTSOUNDBUFFER) S_sfx[id].data;
dsbuffer->lpVtbl->GetStatus (dsbuffer, &dwStatus);
if (dwStatus & (DSBSTATUS_PLAYING | DSBSTATUS_LOOPING))
{
//CONS_Printf ("\t\toriginal sound S_sfx[%d] is playing, duplicating.. ", id);
hr = DSnd->lpVtbl->DuplicateSoundBuffer(DSnd, (LPDIRECTSOUNDBUFFER) S_sfx[id].data, &dsbuffer);
if (FAILED(hr))
{
//CONS_Printf ("Cound't duplicate sound buffer\n");
// re-use the original then..
dsbuffer = (LPDIRECTSOUNDBUFFER) S_sfx[id].data;
// clean up stacksounds info
for (i=0; i<MAXSTACKSOUNDS; i++)
if (handle != i &&
StackSounds[i].lpSndBuf == dsbuffer)
{
StackSounds[i].lpSndBuf = NULL;
}
}
// stop the duplicate or the re-used original
dsbuffer->lpVtbl->Stop (dsbuffer);
}
// store information on the playing sound
StackSounds[handle].lpSndBuf = dsbuffer;
StackSounds[handle].priority = priority;
StackSounds[handle].duplicate = (dsbuffer != (LPDIRECTSOUNDBUFFER)S_sfx[id].data);
//CONS_Printf ("StackSounds[%d].lpSndBuf is %s\n", handle, StackSounds[handle].lpSndBuf==NULL ? "Null":"valid");
//CONS_Printf ("StackSounds[%d].priority is %d\n", handle, StackSounds[handle].priority);
//CONS_Printf ("StackSounds[%d].duplicate is %s\n", handle, StackSounds[handle].duplicate ? "TRUE":"FALSE");
I_UpdateSoundVolume (dsbuffer, vol);
#ifdef SURROUND
// Prepare the surround sound buffer
// Use a normal sound data for the left channel (with pan == 0)
// and an inverted sound data for the right channel (with pan == 255)
dssurround = CreateInvertedSound(id);
if (sep == -128)
{
I_UpdateSoundPanning(dssurround, 255);
I_UpdateSoundVolume(dssurround, vol);
I_UpdateSoundPanning(dsbuffer, 0);
dssurround->lpVtbl->SetCurrentPosition(dssurround, 0);
}
else
// Perform normal operation
#endif
I_UpdateSoundPanning (dsbuffer, sep);
dsbuffer->lpVtbl->SetCurrentPosition (dsbuffer, 0);
hr = dsbuffer->lpVtbl->Play (dsbuffer, 0, 0, 0);
if (hr == DSERR_BUFFERLOST)
{
//CONS_Printf("buffer lost\n");
// restores the buffer memory and all other settings for the buffer
hr = dsbuffer->lpVtbl->Restore (dsbuffer);
if ( SUCCEEDED ( hr ) )
{
byte* dsdata;
// reload sample data here
int lumpnum = S_sfx[id].lumpnum;
if (lumpnum<0)
lumpnum = S_GetSfxLumpNum (&S_sfx[id]);
dsdata = W_CacheLumpNum (lumpnum, PU_CACHE);
// Well... Data lenght must be -8!!!
CopySoundData (dsbuffer, (byte*)dsdata + 8, W_LumpLength (S_sfx[id].lumpnum) - 8);
// play
hr = dsbuffer->lpVtbl->Play (dsbuffer, 0, 0, 0);
}
else
I_Error ("I_StartSound : ->Restore FAILED, %s",DXErrorToString(hr));
}
#ifdef SURROUND
if (sep == -128)
{
hr = dssurround->lpVtbl->Play (dssurround, 0, 0, 0);
//CONS_Printf("Surround playback\n");
if (hr == DSERR_BUFFERLOST)
{
// restores the buffer memory and all other settings for the surround buffer
hr = dssurround->lpVtbl->Restore (dssurround);
if ( SUCCEEDED ( hr ) )
{
byte* dsdata;
int lumpnum = S_sfx[id].lumpnum;
if (lumpnum<0)
lumpnum = S_GetSfxLumpNum (&S_sfx[id]);
dsdata = W_CacheLumpNum (lumpnum, PU_CACHE);
CopyAndInvertSoundData (dssurround, (byte*)dsdata + 8, W_LumpLength (S_sfx[id].lumpnum) - 8);
hr = dssurround->lpVtbl->Play (dssurround, 0, 0, 0);
}
else
I_Error ("I_StartSound : ->Restore FAILED, %s",DXErrorToString(hr));
}
}
StackSounds[handle].lpSurround = dssurround;
#endif
// Returns a handle
return handle;
}
// --------------------------------------------------------------------------
// Stop a sound if it is playing,
// free the corresponding 'playing sound slot' in StackSounds[]
// --------------------------------------------------------------------------
void I_StopSound (int handle)
{
LPDIRECTSOUNDBUFFER dsbuffer;
HRESULT hr;
if (nosound || handle<0)
return;
//CONS_Printf ("I_StopSound (%d)\n", handle);
dsbuffer = StackSounds[handle].lpSndBuf;
hr = dsbuffer->lpVtbl->Stop (dsbuffer);
// free duplicates of original sound buffer (DirectSound hassles)
if (StackSounds[handle].duplicate) {
//CONS_Printf ("\t\trelease a duplicate..\n");
dsbuffer->lpVtbl->Release (dsbuffer);
}
#ifdef SURROUND
// Stop and release the surround sound buffer
dsbuffer = StackSounds[handle].lpSurround;
if (dsbuffer != NULL)
{
dsbuffer->lpVtbl->Stop(dsbuffer);
dsbuffer->lpVtbl->Release(dsbuffer);
}
StackSounds[handle].lpSurround = NULL;
#endif
StackSounds[handle].lpSndBuf = NULL;
}
// --------------------------------------------------------------------------
// Returns whether the sound is currently playing or not
// --------------------------------------------------------------------------
int I_SoundIsPlaying(int handle)
{
LPDIRECTSOUNDBUFFER dsbuffer;
DWORD dwStatus;
if (nosound || handle == -1)
return FALSE;
dsbuffer = StackSounds[handle].lpSndBuf;
if (dsbuffer) {
dsbuffer->lpVtbl->GetStatus (dsbuffer, &dwStatus);
if (dwStatus & (DSBSTATUS_PLAYING | DSBSTATUS_LOOPING))
return TRUE;
}
return FALSE;
}
// --------------------------------------------------------------------------
// Update properties of a sound currently playing
// --------------------------------------------------------------------------
void I_UpdateSoundParams(int handle,
int vol,
int sep,
int pitch)
{
LPDIRECTSOUNDBUFFER dsbuffer;
#ifdef SURROUND
LPDIRECTSOUNDBUFFER dssurround;
DWORD dwStatus;
DWORD pos;
boolean surround_inuse = FALSE;
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -