📄 snd_dev_direct.cpp
字号:
//=========== (C) Copyright 1999 Valve, L.L.C. All rights reserved. ===========
//
// The copyright to the contents herein is the property of Valve, L.L.C.
// The contents may be used and/or copied only with the written permission of
// Valve, L.L.C., or in accordance with the terms and conditions stipulated in
// the agreement/contract under which the contents have been supplied.
//
// Purpose:
//
// $Workfile: $
// $Date: $
// $NoKeywords: $
//=============================================================================
#include <dsound.h>
#include "tier0/dbg.h"
#include "sound.h"
#include "convar.h"
#include "sound_private.h"
#include "snd_device.h"
#include "iprediction.h"
#include "eax.h"
#include "snd_mix_buf.h"
#include "snd_env_fx.h"
#include "snd_channels.h"
#include "snd_audio_source.h"
#include "snd_convars.h"
#include "SoundService.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
extern qboolean snd_firsttime;
extern ConVar snd_mixahead;
extern ConVar s_surround;
extern void DEBUG_StartSoundMeasure(int type, int samplecount );
extern void DEBUG_StopSoundMeasure(int type, int samplecount );
// legacy support
extern ConVar sxroom_off;
extern ConVar sxroom_type;
extern ConVar sxroomwater_type;
extern float sxroom_typeprev;
extern HWND* pmainwindow;
typedef enum {SIS_SUCCESS, SIS_FAILURE, SIS_NOTAVAIL} sndinitstat;
#define SECONDARY_BUFFER_SIZE 0x10000
#define iDirectSoundCreate(a,b,c) pDirectSoundCreate(a,b,c)
HRESULT (WINAPI *pDirectSoundCreate)(GUID FAR *lpGUID, LPDIRECTSOUND FAR *lplpDS, IUnknown FAR *pUnkOuter);
extern void ReleaseSurround(void);
extern void MIX_ScaleChannelVolume( paintbuffer_t *ppaint, channel_t *pChannel, int volume[CCHANVOLUMES], int mixchans );
LPDIRECTSOUND pDS;
LPDIRECTSOUNDBUFFER pDSBuf, pDSPBuf;
//////////////////////////////////////////////////////////////////////////////////
typedef struct _EAXPRESET
{
int dwEnvironment;
float fVolume;
float fDecay;
float fDamping;
} EAXPRESET;
EAXPRESET eax_preset[CSXROOM] = {
{EAX_ENVIRONMENT_GENERIC,0.0F,0.0F,0.0F},
{EAX_ENVIRONMENT_ROOM,0.417F,0.4F,0.666F},
{EAX_ENVIRONMENT_BATHROOM,0.3F,1.499F,0.166F},
{EAX_ENVIRONMENT_BATHROOM,0.4F,1.499F,0.166F},
{EAX_ENVIRONMENT_BATHROOM,0.6F,1.499F,0.166F},
{EAX_ENVIRONMENT_SEWERPIPE,0.4F,2.886F,0.25F},
{EAX_ENVIRONMENT_SEWERPIPE,0.6F,2.886F,0.25F},
{EAX_ENVIRONMENT_SEWERPIPE,0.8F,2.886F,0.25F},
{EAX_ENVIRONMENT_STONEROOM,0.5F,2.309F,0.888F},
{EAX_ENVIRONMENT_STONEROOM,0.65F,2.309F,0.888F},
{EAX_ENVIRONMENT_STONEROOM,0.8F,2.309F,0.888F},
{EAX_ENVIRONMENT_STONECORRIDOR,0.3F,2.697F,0.638F},
{EAX_ENVIRONMENT_STONECORRIDOR,0.5F,2.697F,0.638F},
{EAX_ENVIRONMENT_STONECORRIDOR,0.65F,2.697F,0.638F},
{EAX_ENVIRONMENT_UNDERWATER,1.0F,1.499F,0.0F},
{EAX_ENVIRONMENT_UNDERWATER,1.0F,2.499F,0.0F},
{EAX_ENVIRONMENT_UNDERWATER,1.0F,3.499F,0.0F},
{EAX_ENVIRONMENT_GENERIC,0.65F,1.493F,0.5F},
{EAX_ENVIRONMENT_GENERIC,0.85F,1.493F,0.5F},
{EAX_ENVIRONMENT_GENERIC,1.0F,1.493F,0.5F},
{EAX_ENVIRONMENT_ARENA,0.40F,7.284F,0.332F},
{EAX_ENVIRONMENT_ARENA,0.55F,7.284F,0.332F},
{EAX_ENVIRONMENT_ARENA,0.70F,7.284F,0.332F},
{EAX_ENVIRONMENT_CONCERTHALL,0.5F,3.961F,0.5F},
{EAX_ENVIRONMENT_CONCERTHALL,0.7F,3.961F,0.5F},
{EAX_ENVIRONMENT_CONCERTHALL,1.0F,3.961F,0.5F},
{EAX_ENVIRONMENT_DIZZY,0.2F,17.234F,0.666F},
{EAX_ENVIRONMENT_DIZZY,0.3F,17.234F,0.666F},
{EAX_ENVIRONMENT_DIZZY,0.4F,17.234F,0.666F},
};
//////////////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
// Purpose: Implementation of direct sound & EAX as an audio device
// UNDONE: Split EAX into a derived class?
//-----------------------------------------------------------------------------
class CAudioDirectSound : public IAudioDevice
{
public:
~CAudioDirectSound( void );
bool IsActive( void ) { return true; }
bool Init( void );
void Shutdown( void );
int GetOutputPosition( void );
int GetOutputPositionSurround( void );
void Pause( void );
void UnPause( void );
float MixDryVolume( void );
bool Should3DMix( void );
void StopAllSounds( void );
void SpatializeChannel( int volume[4], int master_vol, const Vector& sourceDir, float gain, float dotRight, float dotFront );
void ApplyDSPEffects( int idsp, portable_samplepair_t *pbuffront, portable_samplepair_t *pbufrear, int samplecount );
void ClearBuffer( void );
void UpdateListener( const Vector& position, const Vector& forward, const Vector& right, const Vector& up );
void MixBegin( int sampleCount );
void MixUpsample( int sampleCount, int filtertype );
void Mix8Mono( channel_t *pChannel, char *pData, int outputOffset, int inputOffset, fixedint rateScaleFix, int outCount, int timecompress );
void Mix8Stereo( channel_t *pChannel, char *pData, int outputOffset, int inputOffset, fixedint rateScaleFix, int outCount, int timecompress );
void Mix16Mono( channel_t *pChannel, short *pData, int outputOffset, int inputOffset, fixedint rateScaleFix, int outCount, int timecompress );
void Mix16Stereo( channel_t *pChannel, short *pData, int outputOffset, int inputOffset, fixedint rateScaleFix, int outCount, int timecompress );
int PaintBegin( int soundtime, int paintedtime );
void PaintEnd( void );
void ChannelReset( int entnum, int channelIndex, float distanceMod );
void TransferSamples( int end );
const char *DeviceName( void );
int DeviceChannels( void ) { return m_deviceChannels; }
int DeviceSampleBits( void ) { return m_deviceSampleBits; }
int DeviceSampleBytes( void ) { return m_deviceSampleBits/8; }
int DeviceDmaSpeed( void ) { return m_deviceDmaSpeed; }
int DeviceSampleCount( void ) { return m_deviceSampleCount; }
void *DeviceLockBuffer( void );
void DeviceUnlockBuffer( void *pbuffer );
sndinitstat SNDDMA_InitDirect( void );
bool SNDDMA_InitSurround(LPDIRECTSOUND lpDS, WAVEFORMATEX* lpFormat, DSBCAPS* lpdsbc);
void S_TransferStereo16Surround( portable_samplepair_t *pfront, portable_samplepair_t *prear, int lpaintedtime, int endtime);
// Singleton object
static CAudioDirectSound *m_pSingleton;
private:
int m_bufferRefCount;
int m_deviceChannels;
int m_deviceSampleBits;
int m_deviceSampleCount;
int m_deviceDmaSpeed;
int m_bufferSize;
// save this to do front/back on EAX
Vector m_listenerForward;
MMTIME m_mmstarttime;
DWORD m_lockBufferSize;
HINSTANCE m_hInstDS;
};
CAudioDirectSound *CAudioDirectSound::m_pSingleton = NULL;
bool SURROUND_ON;
/////////////////////////////////////////////////////////////////////////////////////////////
void ReleaseSurround(void);
GUID IID_IKsPropertySetDef = {0x31efac30, 0x515c, 0x11d0, {0xa9, 0xaa, 0x00, 0xaa, 0x00, 0x61, 0xbe, 0x93}};
GUID DSPROPSETID_EAX_ReverbPropertiesDef = {0x4a4e6fc1, 0xc341, 0x11d1, {0xb7, 0x3a, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}};
GUID IID_IDirectSound3DBufferDef = {0x279AFA86, 0x4981, 0x11CE, {0xA5, 0x21, 0x00, 0x20, 0xAF, 0x0B, 0xE5, 0x60}};
GUID DSPROPSETID_EAXBUFFER_ReverbPropertiesDef = {0x4a4e6fc0, 0xc341, 0x11d1, {0xb7, 0x3a, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}};
LPDIRECTSOUNDBUFFER pDSBufFL = NULL;
LPDIRECTSOUNDBUFFER pDSBufFR = NULL;
LPDIRECTSOUNDBUFFER pDSBufRL = NULL;
LPDIRECTSOUNDBUFFER pDSBufRR = NULL;
LPDIRECTSOUND3DBUFFER pDSBuf3DFL = NULL;
LPDIRECTSOUND3DBUFFER pDSBuf3DFR = NULL;
LPDIRECTSOUND3DBUFFER pDSBuf3DRL = NULL;
LPDIRECTSOUND3DBUFFER pDSBuf3DRR = NULL;
LPKSPROPERTYSET pDSPropSetFL = NULL;
LPKSPROPERTYSET pDSPropSetFR = NULL;
LPKSPROPERTYSET pDSPropSetRL = NULL;
LPKSPROPERTYSET pDSPropSetRR = NULL;
DWORD dwSurroundStart = 0;
int g_iEaxPreset = 0;
extern EAXPRESET eax_preset[29];
// ----------------------------------------------------------------------------- //
// Helpers.
// ----------------------------------------------------------------------------- //
CAudioDirectSound::~CAudioDirectSound( void )
{
m_pSingleton = NULL;
}
bool CAudioDirectSound::Init( void )
{
m_hInstDS = NULL;
m_bufferRefCount = 1;
if ( SNDDMA_InitDirect() == SIS_SUCCESS)
{
return true;
}
return false;
}
void CAudioDirectSound::Shutdown( void )
{
/////////////////////////////////////////////////////////////////////////////////////////////
ReleaseSurround();
/////////////////////////////////////////////////////////////////////////////////////////////
if (pDSBuf)
{
pDSBuf->Stop();
pDSBuf->Release();
}
// only release primary buffer if it's not also the mixing buffer we just released
if (pDSPBuf && (pDSBuf != pDSPBuf))
{
pDSPBuf->Release();
}
if (pDS)
{
pDS->SetCooperativeLevel (*pmainwindow, DSSCL_NORMAL);
pDS->Release();
}
pDS = NULL;
pDSBuf = NULL;
pDSPBuf = NULL;
if ( m_hInstDS )
{
FreeLibrary( m_hInstDS );
m_hInstDS = NULL;
}
}
int CAudioDirectSound::GetOutputPosition( void )
{
MMTIME mmtime;
int s;
DWORD dwWrite;
if( SURROUND_ON )
{
return GetOutputPositionSurround();
}
else
{
mmtime.wType = TIME_SAMPLES;
pDSBuf->GetCurrentPosition(&mmtime.u.sample, &dwWrite);
s = mmtime.u.sample - m_mmstarttime.u.sample;
}
s >>= SAMPLE_16BIT_SHIFT;
s &= (DeviceSampleCount()-1);
return s;
}
void CAudioDirectSound::Pause( void )
{
if (pDSBuf)
pDSBuf->Stop();
///////////////////////////////////////////////////////////////////////////////////
// Need to shut off reverb.
if ( pDSPropSetFL )
pDSPropSetFL->Set(DSPROPSETID_EAX_ReverbPropertiesDef,
DSPROPERTY_EAX_ALL, NULL, 0, &eax_preset[0],
sizeof(EAX_REVERBPROPERTIES));
if ( pDSBufFL ) pDSBufFL->Stop();
if ( pDSBufFR ) pDSBufFR->Stop();
if ( pDSBufRL ) pDSBufRL->Stop();
if ( pDSBufRR ) pDSBufRR->Stop();
///////////////////////////////////////////////////////////////////////////////////
}
void CAudioDirectSound::UnPause( void )
{
if (pDSBuf)
pDSBuf->Play(0, 0, DSBPLAY_LOOPING);
///////////////////////////////////////////////////////////////////////////////////
// Need to restore reverb if restarting in middle somewhere.
if ( pDSPropSetFL )
pDSPropSetFL->Set(DSPROPSETID_EAX_ReverbPropertiesDef,
DSPROPERTY_EAX_ALL, NULL, 0, &eax_preset[g_iEaxPreset],
sizeof(EAX_REVERBPROPERTIES));
if (pDSBufFL) pDSBufFL->Play(0, 0, DSBPLAY_LOOPING);
if (pDSBufFR) pDSBufFR->Play(0, 0, DSBPLAY_LOOPING);
if (pDSBufRL) pDSBufRL->Play(0, 0, DSBPLAY_LOOPING);
if (pDSBufRR) pDSBufRR->Play( 0, 0, DSBPLAY_LOOPING);
///////////////////////////////////////////////////////////////////////////////////
}
float CAudioDirectSound::MixDryVolume( void )
{
return 0;
}
bool CAudioDirectSound::Should3DMix( void )
{
if ( SURROUND_ON )
return true;
return false;
}
IAudioDevice *Audio_CreateDirectSoundDevice( void )
{
if ( !CAudioDirectSound::m_pSingleton )
CAudioDirectSound::m_pSingleton = new CAudioDirectSound;
if ( CAudioDirectSound::m_pSingleton->Init() )
{
if (snd_firsttime)
DevMsg ("DirectSound initialized\n");
return CAudioDirectSound::m_pSingleton;
}
DevMsg ("DirectSound failed to init\n");
delete CAudioDirectSound::m_pSingleton;
CAudioDirectSound::m_pSingleton = NULL;
return NULL;
}
int CAudioDirectSound::PaintBegin( int soundtime, int paintedtime )
{
// soundtime - total samples that have been played out to hardware at dmaspeed
// paintedtime - total samples that have been mixed at speed
// endtime - target for samples in mixahead buffer at speed
int endtime = soundtime + snd_mixahead.GetFloat() * DeviceDmaSpeed();
int samps = DeviceSampleCount() >> (DeviceChannels()-1);
if ((int)(endtime - soundtime) > samps)
endtime = soundtime + samps;
if ((endtime - paintedtime) & 0x3)
{
// The difference between endtime and painted time should align on
// boundaries of 4 samples. This is important when upsampling from 11khz -> 44khz.
endtime -= (endtime - paintedtime) & 0x3;
}
DWORD dwStatus;
/////////////////////////////////////////////////////////////////////////////////////////
// If using surround, there are 4 different buffers being used and the pDSBuf is NULL.
if( SURROUND_ON )
{
if (pDSBufFL->GetStatus(&dwStatus) != DS_OK)
Msg ("Couldn't get SURROUND FL sound buffer status\n");
if (dwStatus & DSBSTATUS_BUFFERLOST)
pDSBufFL->Restore();
if (!(dwStatus & DSBSTATUS_PLAYING))
pDSBufFL->Play(0, 0, DSBPLAY_LOOPING);
if (pDSBufFR->GetStatus(&dwStatus) != DS_OK)
Msg ("Couldn't get SURROUND FR sound buffer status\n");
if (dwStatus & DSBSTATUS_BUFFERLOST)
pDSBufFR->Restore();
if (!(dwStatus & DSBSTATUS_PLAYING))
pDSBufFR->Play(0, 0, DSBPLAY_LOOPING);
if (pDSBufRL->GetStatus(&dwStatus) != DS_OK)
Msg ("Couldn't get SURROUND RL sound buffer status\n");
if (dwStatus & DSBSTATUS_BUFFERLOST)
pDSBufRL->Restore();
if (!(dwStatus & DSBSTATUS_PLAYING))
pDSBufRL->Play(0, 0, DSBPLAY_LOOPING);
if (pDSBufRR->GetStatus(&dwStatus) != DS_OK)
Msg ("Couldn't get SURROUND RR sound buffer status\n");
if (dwStatus & DSBSTATUS_BUFFERLOST)
pDSBufRR->Restore();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -