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

📄 sound.cpp

📁 hl2 source code. Do not use it illegal.
💻 CPP
📖 第 1 页 / 共 3 页
字号:
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <mmsystem.h>
#include <stdio.h>
#include <math.h>
#include "snd_audio_source.h"
#include "AudioWaveOutput.h"
#include "ifaceposersound.h"
#include "StudioModel.h"
#include "hlfaceposer.h"
#include "expressions.h"
#include "expclass.h"
#include "PhonemeConverter.h"
#include "utlvector.h"
#include "FileSystem.h"
#include "sentence.h"
#include "faceposer_models.h"
#include "iclosecaptionmanager.h"

typedef struct channel_s
{
	int		leftvol;
	int		rightvol;
	int		rleftvol;
	int		rrightvol;
	float	pitch;
} channel_t;

#define INPUT_BUFFER_COUNT 32

class CAudioWaveInput : public CAudioInput
{
public:
	CAudioWaveInput( void );
	~CAudioWaveInput( void );

	// Returns the current count of available samples
	int SampleCount( void );
	
	// returns the size of each sample in bytes
	int SampleSize( void ) { return m_sampleSize; }
	
	// returns the sampling rate of the data
	int SampleRate( void ) { return m_sampleRate; }

	// returns a pointer to the actual data
	void *SampleData( void );

	// release the available data (mark as done)
	void SampleRelease( void );

	// returns the mono/stereo status of this device (true if stereo)
	bool IsStereo( void )  { return m_isStereo; }

	// begin sampling
	void Start( void );

	// stop sampling
	void Stop( void );

	void WaveMessage( HWAVEIN hdevice, UINT uMsg, DWORD dwParam1, DWORD dwParam2 );

private:
	void	OpenDevice( void );
	bool	ValidDevice( void ) { return m_deviceId >= 0; }
	void	ClearDevice( void ) { m_deviceId = -1; }

	// returns true if the new format is better
	bool	BetterFormat( DWORD dwNewFormat, DWORD dwOldFormat );

	void	InitReadyList( void );
	void	AddToReadyList( WAVEHDR *pBuffer );
	void	PopReadyList( void );

	WAVEHDR	*m_pReadyList;

	int		m_sampleSize;
	int		m_sampleRate;
	bool	m_isStereo;

	UINT	m_deviceId;
	HWAVEIN	m_deviceHandle;

	WAVEHDR	*m_buffers[ INPUT_BUFFER_COUNT ];
};

extern "C" void CALLBACK WaveData( HWAVEIN hwi, UINT uMsg, CAudioWaveInput *pAudio, DWORD dwParam1, DWORD dwParam2 );

CAudioWaveInput::CAudioWaveInput( void )
{
	memset( m_buffers, 0, sizeof( m_buffers ) );
	int deviceCount = (int)waveInGetNumDevs();
	UINT	deviceId;
	DWORD	deviceFormat = 0;

	int i;
	for ( i = 0; i < deviceCount; i++ )
	{
		WAVEINCAPS waveCaps;
		MMRESULT errorCode = waveInGetDevCaps( (UINT)i, &waveCaps, sizeof(waveCaps) );
		if ( errorCode == MMSYSERR_NOERROR )
		{
			// valid device
			if ( BetterFormat( waveCaps.dwFormats, deviceFormat ) )
			{
				deviceId = i;
				deviceFormat = waveCaps.dwFormats;
			}
		}
	}

	if ( !deviceFormat )
	{
		m_deviceId = -1;
		m_sampleSize = 0;
		m_sampleRate = 0;
		m_isStereo = false;
	}
	else
	{
		m_deviceId = deviceId;
		m_sampleRate = 44100;
		m_isStereo = false;
		if ( deviceFormat & WAVE_FORMAT_4M16 )
		{
			m_sampleSize = 2;
		}
		else if ( deviceFormat & WAVE_FORMAT_4M08 )
		{
			m_sampleSize = 1;
		}
		else
		{
			// ERROR!
		}

		OpenDevice();
	}

	InitReadyList();
}

CAudioWaveInput::~CAudioWaveInput( void )
{
	if ( ValidDevice() )
	{
		Stop();
		waveInReset( m_deviceHandle );
		waveInClose( m_deviceHandle );
		for ( int i = 0; i < INPUT_BUFFER_COUNT; i++ )
		{
			if ( m_buffers[i] )
			{
				waveInUnprepareHeader( m_deviceHandle, m_buffers[i], sizeof( *m_buffers[i] ) );
				delete[] m_buffers[i]->lpData;
				delete m_buffers[i];
			}
			m_buffers[i] = NULL;
		}
		ClearDevice();
	}
}

void CALLBACK WaveData( HWAVEIN hwi, UINT uMsg, CAudioWaveInput *pAudio, DWORD dwParam1, DWORD dwParam2 )
{
	if ( pAudio )
	{
		pAudio->WaveMessage( hwi, uMsg, dwParam1, dwParam2 );
	}
}

void CAudioWaveInput::WaveMessage( HWAVEIN hdevice, UINT uMsg, DWORD dwParam1, DWORD dwParam2 )
{
	if ( hdevice != m_deviceHandle )
		return;
	switch( uMsg )
	{
	case WIM_DATA:
		WAVEHDR *pHeader = (WAVEHDR *)dwParam1;
		AddToReadyList( pHeader );
		break;
	}
}

void CAudioWaveInput::OpenDevice( void )
{
	if ( !ValidDevice() )
		return;

	WAVEFORMATEX format;

	memset( &format, 0, sizeof(format) );
	format.nAvgBytesPerSec = m_sampleRate * m_sampleSize;
	format.nChannels = 1;
	format.wBitsPerSample = m_sampleSize * 8;
	format.nSamplesPerSec = m_sampleRate;
	format.wFormatTag = WAVE_FORMAT_PCM;
	format.nBlockAlign = m_sampleSize;

	MMRESULT errorCode = waveInOpen( &m_deviceHandle, m_deviceId, &format, (DWORD)WaveData, (DWORD)this, CALLBACK_FUNCTION );
	if ( errorCode == MMSYSERR_NOERROR )
	{
		// valid device opened
		int bufferSize = m_sampleSize * m_sampleRate / INPUT_BUFFER_COUNT; // total of one second of data

		// allocate buffers
		for ( int i = 0; i < INPUT_BUFFER_COUNT; i++ )
		{
			m_buffers[i] = new WAVEHDR;
			m_buffers[i]->lpData = new char[ bufferSize ];
			m_buffers[i]->dwBufferLength = bufferSize;
			m_buffers[i]->dwUser = 0;
			m_buffers[i]->dwFlags = 0;
	
			waveInPrepareHeader( m_deviceHandle, m_buffers[i], sizeof( *m_buffers[i] ) );
			waveInAddBuffer( m_deviceHandle, m_buffers[i], sizeof( *m_buffers[i] ) );
		}
	}
	else
	{
		ClearDevice();
	}
}

void CAudioWaveInput::Start( void )
{
	if ( !ValidDevice() )
		return;

	waveInStart( m_deviceHandle );
}

void CAudioWaveInput::Stop( void )
{
	if ( !ValidDevice() )
		return;

	waveInStop( m_deviceHandle );
}

void CAudioWaveInput::InitReadyList( void )
{
	m_pReadyList = NULL;
}

void CAudioWaveInput::AddToReadyList( WAVEHDR *pBuffer )
{
	WAVEHDR **pList = &m_pReadyList;

	waveInUnprepareHeader( m_deviceHandle, pBuffer, sizeof(*pBuffer) );
	// insert at the tail of the list
	while ( *pList )
	{
		pList = reinterpret_cast<WAVEHDR **>(&((*pList)->dwUser));
	}
	pBuffer->dwUser = NULL;
	*pList = pBuffer;
}


void CAudioWaveInput::PopReadyList( void )
{
	if ( m_pReadyList )
	{
		WAVEHDR *pBuffer = m_pReadyList;
		m_pReadyList = reinterpret_cast<WAVEHDR *>(m_pReadyList->dwUser);
		waveInPrepareHeader( m_deviceHandle, pBuffer, sizeof(*pBuffer) );
		waveInAddBuffer( m_deviceHandle, pBuffer, sizeof(*pBuffer) );
	}
}



#define WAVE_FORMAT_STEREO		(WAVE_FORMAT_1S08|WAVE_FORMAT_1S16|WAVE_FORMAT_2S08|WAVE_FORMAT_2S16|WAVE_FORMAT_4S08|WAVE_FORMAT_4S16)
#define WAVE_FORMATS_UNDERSTOOD	(0xFFF)
#define WAVE_FORMAT_11K			(WAVE_FORMAT_1M08|WAVE_FORMAT_1M16)
#define WAVE_FORMAT_22K			(WAVE_FORMAT_2M08|WAVE_FORMAT_2M16)
#define WAVE_FORMAT_44K			(WAVE_FORMAT_4M08|WAVE_FORMAT_4M16)

static int HighestBit( DWORD dwFlags )
{
	int i = 31;
	while ( i )
	{
		if ( dwFlags & (1<<i) )
			return i;
		i--;
	}

	return 0;
}

bool CAudioWaveInput::BetterFormat( DWORD dwNewFormat, DWORD dwOldFormat )
{
	dwNewFormat &= WAVE_FORMATS_UNDERSTOOD & (~WAVE_FORMAT_STEREO);
	dwOldFormat &= WAVE_FORMATS_UNDERSTOOD & (~WAVE_FORMAT_STEREO);

	// our target format is 44.1KHz, mono, 16-bit
	if ( HighestBit(dwOldFormat) >= HighestBit(dwNewFormat) )
		return false;

	return true;
}


int CAudioWaveInput::SampleCount( void )
{
	if ( !ValidDevice() )
		return 0;

	if ( m_pReadyList )
	{
		switch( SampleSize() )
		{
		case 2:
			return m_pReadyList->dwBytesRecorded >> 1;
		case 1:
			return m_pReadyList->dwBytesRecorded;
		default:
			break;
		}
	}
	return 0;
}

void *CAudioWaveInput::SampleData( void )
{
	if ( !ValidDevice() )
		return NULL;

	if ( m_pReadyList )
	{
		return m_pReadyList->lpData;
	}

	return NULL;
}


// release the available data (mark as done)
void CAudioWaveInput::SampleRelease( void )
{
	PopReadyList();
}


// factory to create a suitable audio input for this system
CAudioInput *CAudioInput::Create( void )
{
	// sound source is a singleton for now
	static CAudioInput *pSource = NULL;

	if ( !pSource )
	{
		pSource = new CAudioWaveInput;
	}

	return pSource;
}

void CAudioDeviceSWMix::Mix8Mono( channel_t *pChannel, char *pData, int outputOffset, int inputOffset, int rateScaleFix, int outCount, int timecompress, bool forward )
{
	int sampleIndex = 0;
	fixedint sampleFrac = inputOffset;

	int fixup = 0;
	int fixupstep = 1;

	if ( !forward )
	{
		fixup = outCount - 1;
		fixupstep = -1;
	}

	for ( int i = 0; i < outCount; i++, fixup += fixupstep )
	{
		int dest = max( outputOffset + fixup, 0 );

		m_paintbuffer[ dest ].left += pChannel->leftvol * pData[sampleIndex];
		m_paintbuffer[ dest ].right += pChannel->rightvol * pData[sampleIndex];
		sampleFrac += rateScaleFix;
		sampleIndex += FIX_INTPART(sampleFrac);
		sampleFrac = FIX_FRACPART(sampleFrac);
	}
}


void CAudioDeviceSWMix::Mix8Stereo( channel_t *pChannel, char *pData, int outputOffset, int inputOffset, int rateScaleFix, int outCount, int timecompress, bool forward )
{
	int sampleIndex = 0;
	fixedint sampleFrac = inputOffset;

	int fixup = 0;
	int fixupstep = 1;

	if ( !forward )
	{
		fixup = outCount - 1;
		fixupstep = -1;
	}

	for ( int i = 0; i < outCount; i++, fixup += fixupstep )
	{
		int dest = max( outputOffset + fixup, 0 );

		m_paintbuffer[ dest ].left += pChannel->leftvol * pData[sampleIndex];
		m_paintbuffer[ dest ].right += pChannel->rightvol * pData[sampleIndex+1];
		sampleFrac += rateScaleFix;
		sampleIndex += FIX_INTPART(sampleFrac)<<1;
		sampleFrac = FIX_FRACPART(sampleFrac);
	}
}


void CAudioDeviceSWMix::Mix16Mono( channel_t *pChannel, short *pData, int outputOffset, int inputOffset, int rateScaleFix, int outCount, int timecompress, bool forward )
{
	int sampleIndex = 0;
	fixedint sampleFrac = inputOffset;

	int fixup = 0;
	int fixupstep = 1;

	if ( !forward )
	{
		fixup = outCount - 1;
		fixupstep = -1;
	}

	for ( int i = 0; i < outCount; i++, fixup += fixupstep )
	{
		int dest = max( outputOffset + fixup, 0 );

		m_paintbuffer[ dest ].left += (pChannel->leftvol * pData[sampleIndex])>>8;
		m_paintbuffer[ dest ].right += (pChannel->rightvol * pData[sampleIndex])>>8;
		sampleFrac += rateScaleFix;
		sampleIndex += FIX_INTPART(sampleFrac);
		sampleFrac = FIX_FRACPART(sampleFrac);
	}
}


void CAudioDeviceSWMix::Mix16Stereo( channel_t *pChannel, short *pData, int outputOffset, int inputOffset, int rateScaleFix, int outCount, int timecompress, bool forward )
{
	int sampleIndex = 0;
	fixedint sampleFrac = inputOffset;

	int fixup = 0;
	int fixupstep = 1;

	if ( !forward )
	{
		fixup = outCount - 1;
		fixupstep = -1;
	}

	for ( int i = 0; i < outCount; i++, fixup += fixupstep )
	{
		int dest = max( outputOffset + fixup, 0 );

		m_paintbuffer[ dest ].left += (pChannel->leftvol * pData[sampleIndex])>>8;
		m_paintbuffer[ dest ].right += (pChannel->rightvol * pData[sampleIndex+1])>>8;

		sampleFrac += rateScaleFix;
		sampleIndex += FIX_INTPART(sampleFrac)<<1;
		sampleFrac = FIX_FRACPART(sampleFrac);
	}
}


int CAudioDeviceSWMix::MaxSampleCount( void )
{
	return PAINTBUFFER_SIZE;
}

void CAudioDeviceSWMix::MixBegin( void )
{
	memset( m_paintbuffer, 0, sizeof(m_paintbuffer) );
}

void CAudioDeviceSWMix::TransferBufferStereo16( short *pOutput, int sampleCount )
{
	for ( int i = 0; i < sampleCount; i++ )
	{
		if ( m_paintbuffer[i].left > 32767 )
			m_paintbuffer[i].left = 32767;
		else if ( m_paintbuffer[i].left < -32768 )
			m_paintbuffer[i].left = -32768;

		if ( m_paintbuffer[i].right > 32767 )
			m_paintbuffer[i].right = 32767;
		else if ( m_paintbuffer[i].right < -32768 )
			m_paintbuffer[i].right = -32768;

		*pOutput++ = (short)m_paintbuffer[i].left;
		*pOutput++ = (short)m_paintbuffer[i].right;
	}
}

CAudioWaveOutput::CAudioWaveOutput( void )
{
	for ( int i = 0; i < OUTPUT_BUFFER_COUNT; i++ )
	{
		CAudioBuffer *buffer = &m_buffers[ i ];
		Assert( buffer );
		buffer->hdr = NULL;
		buffer->submitted = false;
		buffer->submit_sample_count = false;
	}

	ClearDevice();
	OpenDevice();

	m_mixTime = -1;
	m_sampleIndex = 0;
	memset( m_sourceList, 0, sizeof(m_sourceList) );

	m_nEstimatedSamplesAhead = (int)( ( float ) OUTPUT_SAMPLE_RATE / 10.0f );
}

void CAudioWaveOutput::RemoveMixerChannelReferences( CAudioMixer *mixer )
{
	for ( int i = 0; i < OUTPUT_BUFFER_COUNT; i++ )
	{
		RemoveFromReferencedList( mixer, &m_buffers[ i ] );
	}
}

void CAudioWaveOutput::AddToReferencedList( CAudioMixer *mixer, CAudioBuffer *buffer )
{
	// Already in list
	for ( int i = 0; i < buffer->m_Referenced.Size(); i++ )
	{
		if ( buffer->m_Referenced[ i ].mixer == mixer )
		{
			return;
		}
	}

	// Just remove it
	int idx = buffer->m_Referenced.AddToTail();

	CAudioMixerState *state = &buffer->m_Referenced[ idx ];
	state->mixer = mixer;
	state->submit_mixer_sample = mixer->GetSamplePosition();

}

void CAudioWaveOutput::RemoveFromReferencedList( CAudioMixer *mixer, CAudioBuffer *buffer )
{
	for ( int i = 0; i < buffer->m_Referenced.Size(); i++ )
	{
		if ( buffer->m_Referenced[ i ].mixer == mixer )
		{
			buffer->m_Referenced.Remove( i );
			break;
		}
	}
}

bool CAudioWaveOutput::IsSoundInReferencedList( CAudioMixer *mixer, CAudioBuffer *buffer )
{
	for ( int i = 0; i < buffer->m_Referenced.Size(); i++ )
	{
		if ( buffer->m_Referenced[ i ].mixer == mixer )
		{
			return true;
		}
	}
	return false;
}

bool CAudioWaveOutput::IsSourceReferencedByActiveBuffer( CAudioMixer *mixer )
{
	if ( !ValidDevice() )
		return false;

	CAudioBuffer *buffer;
	for ( int i = 0; i < OUTPUT_BUFFER_COUNT; i++ )
	{
		buffer = &m_buffers[ i ];
		if ( !buffer->submitted )
			continue;

		if ( buffer->hdr->dwFlags & WHDR_DONE )

⌨️ 快捷键说明

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