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

📄 snd_dev_wave.cpp

📁 hl2 source code. Do not use it illegal.
💻 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 <windows.h>
#include "tier0/dbg.h"
#include "convar.h"
#include "snd_device.h"
#include "sound_private.h"
#include "snd_mix_buf.h"
#include "snd_channels.h"
#include "vstdlib/strtools.h"
#include "SoundService.h"

extern qboolean snd_firsttime;
extern ConVar snd_mixahead;
extern void MIX_ScaleChannelVolume( paintbuffer_t *ppaint, channel_t *pChannel, int volume[CCHANVOLUMES], int mixchans );

// UNDONE: Make these class members
static HGLOBAL		hWaveHdr;
static LPWAVEHDR	lpWaveHdr;
static HWAVEOUT    hWaveOut; 
#if DEAD
static WAVEOUTCAPS	wavecaps;
#endif
static HANDLE		hData;
static HPSTR		lpData;

// 64K is > 1 second at 16-bit, 22050 Hz
// 44k: UNDONE - need to double buffers now that we're playing back at 44100?
#define	WAV_BUFFERS				64
#define	WAV_MASK				0x3F
#define	WAV_BUFFER_SIZE			0x0400

// NOTE: This only allows 16-bit, stereo wave out
class CAudioWave : public IAudioDevice
{
public:

	bool		IsActive( void );
	bool		Init( void );
	void		Shutdown( void );
	void		PaintEnd( void );
	int			GetOutputPosition( void );
	void		ChannelReset( int entnum, int channelIndex, float distanceMod );
	void		Pause( void );
	void		UnPause( void );
	float		MixDryVolume( void );
	bool		Should3DMix( void );
	void		StopAllSounds( void );

	int			PaintBegin( int soundtime, int paintedtime );
	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 );

	void		TransferSamples( int end );
	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 );

	const char *DeviceName( void )			{ return "Windows WAVE"; }
	int			DeviceChannels( void )		{ return 2; }
	int			DeviceSampleBits( void )	{ return 16; }
	int			DeviceSampleBytes( void )	{ return 2; }
	int			DeviceDmaSpeed( void )		{ return SOUND_DMA_SPEED; }
	int			DeviceSampleCount( void )	{ return m_deviceSampleCount; }

	void		*DeviceLockBuffer( void );
	void		DeviceUnlockBuffer( void *pbuffer );

private:
	int			m_deviceSampleCount;
	void		*m_pBuffer;

	int			m_buffersSent;
	int			m_buffersCompleted;
	int			m_pauseCount;
};


IAudioDevice *Audio_CreateWaveDevice( void )
{
	static CAudioWave *wave = NULL;

	if ( !wave )
		wave = new CAudioWave;

	if ( wave->Init() )
		return wave;

	delete wave;
	wave = NULL;

	return NULL;
}

bool CAudioWave::Init( void )
{
	WAVEFORMATEX  format;
	int				i, bufferSize;
	HRESULT			hr;
	
	m_buffersSent = 0;
	m_buffersCompleted = 0;
	m_pauseCount = 0;

	memset (&format, 0, sizeof(format));
	format.wFormatTag = WAVE_FORMAT_PCM;
	format.nChannels = DeviceChannels();
	format.wBitsPerSample = DeviceSampleBits();
	format.nSamplesPerSec = DeviceDmaSpeed();
	format.nBlockAlign = format.nChannels
		*format.wBitsPerSample / 8;
	format.cbSize = 0;
	format.nAvgBytesPerSec = format.nSamplesPerSec
		*format.nBlockAlign; 
	
	/* Open a waveform device for output using window callback. */ 
	while ((hr = waveOutOpen((LPHWAVEOUT)&hWaveOut, WAVE_MAPPER, 
					&format, 
					0, 0L, CALLBACK_NULL)) != MMSYSERR_NOERROR)
	{
		if (hr != MMSYSERR_ALLOCATED)
		{
			DevMsg ("waveOutOpen failed\n");
			return false;
		}

		if (MessageBox (NULL,
						"The sound hardware is in use by another app.\n\n"
					    "Select Retry to try to start sound again or Cancel to run Half-Life with no sound.",
						"Sound not available",
						MB_RETRYCANCEL | MB_SETFOREGROUND | MB_ICONEXCLAMATION) != IDRETRY)
		{
			g_pSoundServices->ConSafePrint ("waveOutOpen failure;\n"
							"  hardware already in use\n");
			return false;
		}
	} 

	/* 
	 * Allocate and lock memory for the waveform data. The memory 
	 * for waveform data must be globally allocated with 
	 * GMEM_MOVEABLE and GMEM_SHARE flags. 

	*/ 
	bufferSize = WAV_BUFFERS*WAV_BUFFER_SIZE;
	hData = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, bufferSize); 
	if (!hData) 
	{ 
		g_pSoundServices->ConSafePrint ("Sound: Out of memory.\n");
		Shutdown();
		return false; 
	}
	lpData = (char *)GlobalLock(hData);
	if (!lpData)
	{ 
		g_pSoundServices->ConSafePrint ("Sound: Failed to lock.\n");
		Shutdown();
		return false; 
	} 
	memset (lpData, 0, bufferSize);

	/* 
	 * Allocate and lock memory for the header. This memory must 
	 * also be globally allocated with GMEM_MOVEABLE and 
	 * GMEM_SHARE flags. 
	 */ 
	hWaveHdr = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, 
		(DWORD) sizeof(WAVEHDR) * WAV_BUFFERS); 

	if (hWaveHdr == NULL)
	{ 
		g_pSoundServices->ConSafePrint ("Sound: Failed to Alloc header.\n");
		Shutdown();
		return false; 
	} 

	lpWaveHdr = (LPWAVEHDR) GlobalLock(hWaveHdr); 

	if (lpWaveHdr == NULL)
	{ 
		g_pSoundServices->ConSafePrint ("Sound: Failed to lock header.\n");
		Shutdown();
		return false; 
	}

	memset (lpWaveHdr, 0, sizeof(WAVEHDR) * WAV_BUFFERS);

	/* After allocation, set up and prepare headers. */ 
	for (i=0 ; i<WAV_BUFFERS ; i++)
	{
		lpWaveHdr[i].dwBufferLength = WAV_BUFFER_SIZE; 
		lpWaveHdr[i].lpData = lpData + i*WAV_BUFFER_SIZE;

		if (waveOutPrepareHeader(hWaveOut, lpWaveHdr+i, sizeof(WAVEHDR)) !=
				MMSYSERR_NOERROR)
		{
			g_pSoundServices->ConSafePrint ("Sound: failed to prepare wave headers\n");
			Shutdown();
			return false;
		}
	}

	m_deviceSampleCount = bufferSize/(DeviceSampleBytes());
	
	m_pBuffer = (void *)lpData;

	if (snd_firsttime)
		DevMsg ("Wave sound initialized\n");

	return true;
}


void CAudioWave::Shutdown( void )
{
	int		i;

	/////////////////////////////////////////////////////////////////////////////////////////////
	if (hWaveOut)
	{
		waveOutReset (hWaveOut);

		if (lpWaveHdr)
		{
			for (i=0 ; i< WAV_BUFFERS ; i++)
				waveOutUnprepareHeader (hWaveOut, lpWaveHdr+i, sizeof(WAVEHDR));
		}

		waveOutClose (hWaveOut);

		if (hWaveHdr)
		{
			GlobalUnlock(hWaveHdr); 
			GlobalFree(hWaveHdr);
		}

		if (hData)
		{
			GlobalUnlock(hData);
			GlobalFree(hData);
		}

	}

	hWaveOut = 0;
	hData = 0;
	hWaveHdr = 0;
	lpData = NULL;
	lpWaveHdr = NULL;
}


void CAudioWave::PaintEnd( void )
{
	LPWAVEHDR	h;
	int			wResult;
	int			cblocks;

	//
	// find which sound blocks have completed
	//
	while (1)
	{
		if ( m_buffersCompleted == m_buffersSent )
		{
			DevMsg ("Sound overrun\n");
			break;
		}

		if ( ! (lpWaveHdr[ m_buffersCompleted & WAV_MASK].dwFlags & WHDR_DONE) )
		{
			break;
		}

		m_buffersCompleted++;	// this buffer has been played
	}

	//
	// submit a few new sound blocks
	//
	// 22K sound support
	// 44k: UNDONE - double blocks out now that we're at 44k playback? 
	cblocks = 4 << 1; 

	while (((m_buffersSent - m_buffersCompleted) >> SAMPLE_16BIT_SHIFT) < cblocks)
	{
		h = lpWaveHdr + ( m_buffersSent&WAV_MASK );

		m_buffersSent++;
		/* 
		 * Now the data block can be sent to the output device. The 
		 * waveOutWrite function returns immediately and waveform 
		 * data is sent to the output device in the background. 
		 */ 
		wResult = waveOutWrite(hWaveOut, h, sizeof(WAVEHDR)); 

		if (wResult != MMSYSERR_NOERROR)
		{ 
			g_pSoundServices->ConSafePrint ("Failed to write block to device\n");
			Shutdown();
			return; 
		} 
	}
}

int CAudioWave::GetOutputPosition( void )
{
	int s = m_buffersSent * WAV_BUFFER_SIZE;

	s >>= SAMPLE_16BIT_SHIFT;

	s &= (DeviceSampleCount()-1);

	return s;
}


int CAudioWave::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

	unsigned int endtime = soundtime + snd_mixahead.GetFloat() * DeviceDmaSpeed();
	
	int samps = DeviceSampleCount() >> (DeviceChannels()-1);

	if ((int)(endtime - soundtime) > samps)
		endtime = soundtime + samps;

	return endtime;
}


void CAudioWave::Pause( void )
{
	m_pauseCount++;

	if (m_pauseCount == 1)
		waveOutReset (hWaveOut);
}


void CAudioWave::UnPause( void )
{
	if ( m_pauseCount > 0 )
		m_pauseCount--;
}

bool CAudioWave::IsActive( void )
{
	if ( m_pauseCount )
		return false;

	return true;
}

float CAudioWave::MixDryVolume( void )
{
	return 0;
}


bool CAudioWave::Should3DMix( void )
{
	return false;
}


void CAudioWave::ClearBuffer( void )
{
	int		clear;

	if ( !m_pBuffer )
		return;

	clear = 0;

	Q_memset(m_pBuffer, clear, DeviceSampleCount() * DeviceSampleBytes() );
}

void CAudioWave::UpdateListener( const Vector& position, const Vector& forward, const Vector& right, const Vector& up )
{
}


void CAudioWave::MixBegin( int sampleCount )
{
	MIX_ClearAllPaintBuffers( sampleCount, false );
}


void CAudioWave::MixUpsample( int sampleCount, int filtertype )
{
	paintbuffer_t *ppaint = MIX_GetCurrentPaintbufferPtr();
	int ifilter = ppaint->ifilter;
	
	Assert (ifilter < CPAINTFILTERS);

	S_MixBufferUpsample2x( sampleCount, ppaint->pbuf, &(ppaint->fltmem[ifilter][0]), CPAINTFILTERMEM, filtertype );

	ppaint->ifilter++;
}


void CAudioWave::Mix8Mono( channel_t *pChannel, char *pData, int outputOffset, int inputOffset, fixedint rateScaleFix, int outCount, int timecompress )
{
	int volume[CCHANVOLUMES];
	paintbuffer_t *ppaint = MIX_GetCurrentPaintbufferPtr();

	MIX_ScaleChannelVolume( ppaint, pChannel, volume, 1);

	Mix8MonoWavtype( pChannel, ppaint->pbuf + outputOffset, volume, (byte *)pData, inputOffset, rateScaleFix, outCount );
}


void CAudioWave::Mix8Stereo( channel_t *pChannel, char *pData, int outputOffset, int inputOffset, fixedint rateScaleFix, int outCount, int timecompress )
{
	int volume[CCHANVOLUMES];
	paintbuffer_t *ppaint = MIX_GetCurrentPaintbufferPtr();

	MIX_ScaleChannelVolume( ppaint, pChannel, volume, 2 );

	Mix8StereoWavtype( pChannel, ppaint->pbuf + outputOffset, volume, (byte *)pData, inputOffset, rateScaleFix, outCount );
}


void CAudioWave::Mix16Mono( channel_t *pChannel, short *pData, int outputOffset, int inputOffset, fixedint rateScaleFix, int outCount, int timecompress )
{
	int volume[CCHANVOLUMES];
	paintbuffer_t *ppaint = MIX_GetCurrentPaintbufferPtr();

	MIX_ScaleChannelVolume( ppaint, pChannel, volume, 1 );

	Mix16MonoWavtype( pChannel, ppaint->pbuf + outputOffset, volume, pData, inputOffset, rateScaleFix, outCount );
}


void CAudioWave::Mix16Stereo( channel_t *pChannel, short *pData, int outputOffset, int inputOffset, fixedint rateScaleFix, int outCount, int timecompress )
{
	int volume[CCHANVOLUMES];
	paintbuffer_t *ppaint = MIX_GetCurrentPaintbufferPtr();

	MIX_ScaleChannelVolume( ppaint, pChannel, volume, 2 );

	Mix16StereoWavtype( pChannel, ppaint->pbuf + outputOffset, volume, pData, inputOffset, rateScaleFix, outCount );
}


void CAudioWave::ChannelReset( int entnum, int channelIndex, float distanceMod )
{
}


void *CAudioWave::DeviceLockBuffer( void )
{
	return m_pBuffer;
}

void CAudioWave::DeviceUnlockBuffer( void *pbuffer )
{
}


void CAudioWave::TransferSamples( int end )
{
	S_TransferStereo16( end );
}

void CAudioWave::SpatializeChannel( int volume[4], int master_vol, const Vector& sourceDir, float gain, float dotRight, float dotFront )
{
	S_SpatializeChannel( volume, master_vol, gain, dotRight );
}

void CAudioWave::StopAllSounds( void )
{
}


void CAudioWave::ApplyDSPEffects( int idsp, portable_samplepair_t *pbuffront, portable_samplepair_t *pbufrear, int samplecount )
{
	//SX_RoomFX( endtime, filter, timefx );
	DSP_Process( idsp, pbuffront, pbufrear, samplecount );
}

/*
==================
S_GetWAVPointer

Returns a pointer to pDS, if it exists, NULL otherwise
==================
*/
void *S_GetWAVPointer(void)
{
	if (hWaveOut)
		return ( void * )&hWaveOut;

	return NULL;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -