⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 snd_dev_direct.cpp

📁 hl2 source code. Do not use it illegal.
💻 CPP
📖 第 1 页 / 共 4 页
字号:
//=========== (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 + -