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

📄 snd_wave_source.cpp

📁 hl2 source code. Do not use it illegal.
💻 CPP
📖 第 1 页 / 共 2 页
字号:
	// byte offset in sample database
	samplePosition *= m_sampleSize;

	// if we are returning some samples, store the pointer
	if ( sampleCount )
	{
		*pData = GetDataPointer() + samplePosition;
		Assert( *pData );
	}

	return sampleCount;
}


// Hardcoded macros to test for zero crossing
#define ZERO_X_8(b)		((b)<2 && (b)>-2)
#define ZERO_X_16(b)	((b)<512 && (b)>-512)

//-----------------------------------------------------------------------------
// Purpose: Search backward for a zero crossing starting at sample
// Input  : sample - starting point
// Output : position of zero crossing
//-----------------------------------------------------------------------------
int	CAudioSourceMemWave::ZeroCrossingBefore( int sample )
{
	char *pWaveData = GetDataPointer();

	if ( m_format == WAVE_FORMAT_PCM )
	{
		if ( m_bits == 8 )
		{
			char *pData = pWaveData + sample * m_sampleSize;
			bool zero = false;

			if ( m_channels == 1 )
			{
				while ( sample > 0 && !zero )
				{
					if ( ZERO_X_8(*pData) )
						zero = true;
					else
					{
						sample--;
						pData--;
					}
				}
			}
			else
			{
				while ( sample > 0 && !zero )
				{
					if ( ZERO_X_8(*pData) && ZERO_X_8(pData[1]) )
						zero = true;
					else
					{
						sample--;
						pData--;
					}
				}
			}
		}
		else
		{
			short *pData = (short *)(pWaveData + sample * m_sampleSize);
			bool zero = false;

			if ( m_channels == 1 )
			{
				while ( sample > 0 && !zero )
				{
					if ( ZERO_X_16(*pData) )
						zero = true;
					else
					{
						pData--;
						sample--;
					}
				}
			}
			else
			{
				while ( sample > 0 && !zero )
				{
					if ( ZERO_X_16(*pData) && ZERO_X_16(pData[1]) )
						zero = true;
					else
					{
						sample--;
						pData--;
					}
				}
			}
		}
	}
	return sample;
}


//-----------------------------------------------------------------------------
// Purpose: Search forward for a zero crossing
// Input  : sample - starting point
// Output : position of found zero crossing
//-----------------------------------------------------------------------------
int	CAudioSourceMemWave::ZeroCrossingAfter( int sample )
{
	char *pWaveData = GetDataPointer();
	if ( m_format == WAVE_FORMAT_PCM )
	{
		if ( m_bits == 8 )
		{
			char *pData = pWaveData + sample * m_sampleSize;
			bool zero = false;

			if ( m_channels == 1 )
			{
				while ( sample < SampleCount() && !zero )
				{
					if ( ZERO_X_8(*pData) )
						zero = true;
					else
					{
						sample++;
						pData++;
					}
				}
			}
			else
			{
				while ( sample < SampleCount() && !zero )
				{
					if ( ZERO_X_8(*pData) && ZERO_X_8(pData[1]) )
						zero = true;
					else
					{
						sample++;
						pData++;
					}
				}
			}
		}
		else
		{
			short *pData = (short *)(pWaveData + sample * m_sampleSize);
			bool zero = false;

			if ( m_channels == 1 )
			{
				while ( sample > 0 && !zero )
				{
					if ( ZERO_X_16(*pData) )
						zero = true;
					else
					{
						pData++;
						sample++;
					}
				}
			}
			else
			{
				while ( sample > 0 && !zero )
				{
					if ( ZERO_X_16(*pData) && ZERO_X_16(pData[1]) )
						zero = true;
					else
					{
						sample++;
						pData++;
					}
				}
			}
		}
	}
	return sample;
}



// This is a CAudioSourceMemWave and gets all of its data from the cache.
class CAudioSourceMemWaveCache : public CAudioSourceMemWave
{
public:
	CAudioSourceMemWaveCache( const char *pName );
	~CAudioSourceMemWaveCache( void );

	virtual void			ParseChunk( IterateRIFF &walk, int chunkName );
	void					ParseDataChunk( IterateRIFF &walk );

	bool					IsCached( void );
	void					CacheTouch( void );
	void					CacheLoad( void );
	void					CacheUnload( void );

protected:
	virtual char			*GetDataPointer( void );

	cache_user_t	m_cache;

private:
	CAudioSourceMemWaveCache( const CAudioSourceMemWaveCache & );
};


//-----------------------------------------------------------------------------
// Purpose: NULL the wave data pointer (we haven't loaded yet)
//-----------------------------------------------------------------------------
CAudioSourceMemWaveCache::CAudioSourceMemWaveCache( const char *pName ) : 
	CAudioSourceMemWave( pName )
{
	memset( &m_cache, 0, sizeof(m_cache) );
}


//-----------------------------------------------------------------------------
// Purpose: Free any wave data we've allocated
//-----------------------------------------------------------------------------
CAudioSourceMemWaveCache::~CAudioSourceMemWaveCache( void )
{
	CacheUnload();
}


//-----------------------------------------------------------------------------
// Purpose: parse chunks with unique processing to in-memory waves
// Input  : &walk - RIFF file
//-----------------------------------------------------------------------------
void CAudioSourceMemWaveCache::ParseChunk( IterateRIFF &walk, int chunkName )
{
	switch( chunkName )
	{
		// this is the audio data
	case WAVE_DATA:
		{
			ParseDataChunk( walk );
		}
		return;
	}

	CAudioSourceWave::ParseChunk( walk, chunkName );
}


//-----------------------------------------------------------------------------
// Purpose: reads the actual sample data and parses it
// Input  : &walk - RIFF file
//-----------------------------------------------------------------------------
void CAudioSourceMemWaveCache::ParseDataChunk( IterateRIFF &walk )
{
	int size = walk.ChunkSize();
	
	// create a buffer for the samples
	char *pData = (char *)Cache_Alloc( &m_cache, size, m_pName );

	// load them into memory
	walk.ChunkRead( pData );

	if ( m_format == WAVE_FORMAT_PCM )
	{
		// number of samples loaded
		m_sampleCount = size / m_sampleSize;

		// some samples need to be converted
		ConvertSamples( pData, m_sampleCount );
	}
	else if ( m_format == WAVE_FORMAT_ADPCM )
	{
		// The ADPCM mixers treat the wave source as a flat file of bytes.
		m_sampleSize = 1;
		// Since each "sample" is a byte (this is a flat file), the number of samples is the file size
		m_sampleCount = size;

		// file says 4, output is 16
		m_bits = 16;
	}
}



bool CAudioSourceMemWaveCache::IsCached( void )
{
	if ( m_cache.data )
	{
		if ( Cache_Check( &m_cache ) != NULL )
			return true;
	}

	return false;
}


void CAudioSourceMemWaveCache::CacheTouch( void )
{
	IsCached();
}


void CAudioSourceMemWaveCache::CacheLoad( void )
{
	if ( IsCached() )
		return;

	InFileRIFF riff( m_pName, *g_pSndIO );

	// UNDONE: Don't use printf to handle errors
	if ( riff.RIFFName() != RIFF_WAVE )
	{
		return;
	}

	// set up the iterator for the whole file (root RIFF is a chunk)
	IterateRIFF walk( riff, riff.RIFFSize() );
	while ( walk.ChunkAvailable() )
	{
		switch( walk.ChunkName() )
		{
		case WAVE_DATA:
			ParseDataChunk( walk );
			return;
		}
		walk.ChunkNext();
	}
}

void CAudioSourceMemWaveCache::CacheUnload( void )
{
	if ( !m_cache.data )
		return;

	Cache_Free( &m_cache );
}

char *CAudioSourceMemWaveCache::GetDataPointer( void )
{
	char *pData = (char *)Cache_Check( &m_cache );
	if ( !pData )
		CacheLoad();
	return (char *)Cache_Check( &m_cache );
}

//-----------------------------------------------------------------------------
// Purpose: Wave source for streaming wave files
// UNDONE: Handle looping
//-----------------------------------------------------------------------------
class CAudioSourceStreamWave : public CAudioSourceWave, public IWaveStreamSource
{
public:
	CAudioSourceStreamWave( const char * );
	~CAudioSourceStreamWave();

	CAudioMixer		*CreateMixer( void );
	int				GetOutputData( void **pData, int samplePosition, int sampleCount, char copyBuf[AUDIOSOURCE_COPYBUF_SIZE] );
	void			ParseChunk( IterateRIFF &walk, int chunkName );
	bool			IsStreaming( void ) { return true; }

	// IWaveStreamSource
	virtual int UpdateLoopingSamplePosition( int samplePosition )
	{
		return ConvertLoopedPosition( samplePosition );
	}
	virtual void UpdateSamples( char *pData, int sampleCount )
	{
		ConvertSamples( pData, sampleCount );
	}

private:
	CAudioSourceStreamWave( const CAudioSourceStreamWave & ); // not implemented, not accessible

	int				m_dataStart;	// offset of wave data chunk
	int				m_dataSize;		// size of wave data chunk

};

//-----------------------------------------------------------------------------
// Purpose: Save a copy of the file name for instances to open later
// Input  : *pFileName - filename
//-----------------------------------------------------------------------------
CAudioSourceStreamWave::CAudioSourceStreamWave( const char *pFileName ) : CAudioSourceWave( pFileName )
{
	m_pName = pFileName;
	m_dataStart = -1;
	m_dataSize = 0;
	m_sampleCount = 0;
}



//-----------------------------------------------------------------------------
// Purpose: free the filename buffer
//-----------------------------------------------------------------------------
CAudioSourceStreamWave::~CAudioSourceStreamWave( void )
{
}


//-----------------------------------------------------------------------------
// Purpose: Create an instance (mixer & wavedata) of this sound
// Output : CAudioMixer * - pointer to the mixer
//-----------------------------------------------------------------------------
CAudioMixer *CAudioSourceStreamWave::CreateMixer( void )
{
	// BUGBUG: Source constructs the IWaveData, mixer frees it, fix this?
	IWaveData *pWaveData = CreateWaveDataStream(*this, static_cast<IWaveStreamSource *>(this), *g_pSndIO, m_pName, m_dataStart, m_dataSize);
	if ( pWaveData )
	{
		CAudioMixer *pMixer = CreateWaveMixer( pWaveData, m_format, m_channels, m_bits );
		if ( pMixer )
		{
			ReferenceAdd( pMixer );
			return pMixer;
		}

		// no mixer, delete the stream buffer/instance
		delete pWaveData;
	}

	return NULL;
}


//-----------------------------------------------------------------------------
// Purpose: Parse a stream wave file chunk
//			unlike the in-memory file, don't load the data, just get a reference to it.
// Input  : &walk - RIFF file
//-----------------------------------------------------------------------------
void CAudioSourceStreamWave::ParseChunk( IterateRIFF &walk, int chunkName )
{
	// NOTE: It would be nice to break out of parsing once we have the data start and
	//		save seeking over the whole file.  But to do so, we'd have to make
	//		sure that the CUE chunks occur before the data chunks.  In the first
	//		test file I used, this was not the case.
	switch( chunkName )
	{
	case WAVE_DATA:
		{
			// data starts at chunk + 8 (chunk name, chunk size = 8 bytes)
			m_dataStart = walk.ChunkFilePosition() + 8;
			m_dataSize = walk.ChunkSize();
			m_sampleCount = m_dataSize / m_sampleSize;
			// don't load the data, just know where it is so each instance 
			// can load it later
		}
		return;
	}
	CAudioSourceWave::ParseChunk( walk, chunkName );
}

//-----------------------------------------------------------------------------
// Purpose: This is not implemented here.  This source has no data.  It is the
//			WaveData's responsibility to load/serve the data
//-----------------------------------------------------------------------------
int CAudioSourceStreamWave::GetOutputData( void **pData, int samplePosition, int sampleCount, char copyBuf[AUDIOSOURCE_COPYBUF_SIZE] )
{
	return 0;
}


//-----------------------------------------------------------------------------
// Purpose: Create a wave audio source (streaming or in memory)
// Input  : *pName - file name (NOTE: CAUDIOSOURCE KEEPS A POINTER TO pName)
//			streaming - if true, don't load, stream each instance
// Output : CAudioSource * - a new source
//-----------------------------------------------------------------------------
CAudioSource *CreateWave( const char *pName, bool streaming )
{
	char formatBuffer[1024];
	InFileRIFF riff( pName, *g_pSndIO );

	// UNDONE: Don't use printf to handle errors
	if ( riff.RIFFName() != RIFF_WAVE )
	{
		static CUtlSymbolTable wavErrors;

		CUtlSymbol sym;
		sym = wavErrors.Find( pName );
		if ( UTL_INVAL_SYMBOL == sym )
		{
			// See if file exists
			if ( g_pFileSystem->FileExists( pName ) )
			{
				Warning("Bad RIFF file '%s'\n", pName );
			}
			else
			{
				Warning("Missing wav file '%s'\n", pName );
			}
			wavErrors.AddString( pName );
		}
		return NULL;
	}

	// set up the iterator for the whole file (root RIFF is a chunk)
	IterateRIFF walk( riff, riff.RIFFSize() );

	int format = 0;
	int formatSize = 0;

	// This chunk must be first as it contains the wave's format
	// break out when we've parsed it
	while ( walk.ChunkAvailable() && format == 0 )
	{
		switch( walk.ChunkName() )
		{
		case WAVE_FMT:
			{
				if ( walk.ChunkSize() <= 1024 )
				{
					walk.ChunkRead( formatBuffer );
					formatSize = walk.ChunkSize();
					format = ((WAVEFORMATEX *)formatBuffer)->wFormatTag;
				}
			}
			break;
		default:
			{
				ChunkError( walk.ChunkName() );
			}
			break;
		}
		walk.ChunkNext();
	}

	// Not really a WAVE file or no format chunk, bail
	if ( !format )
		return NULL;

	CAudioSourceWave *pWave;

	// create the source from this file
	if ( streaming )
		pWave = new CAudioSourceStreamWave( pName );
	else
		pWave = new CAudioSourceMemWaveCache( pName );

	// init the wave source
	pWave->Setup( formatBuffer, formatSize, walk );

	return pWave;
}


//-----------------------------------------------------------------------------
// Purpose: Wrapper for CreateWave()
//-----------------------------------------------------------------------------
CAudioSource *Audio_CreateStreamedWave( const char *pName )
{
	if ( Audio_IsMP3( pName ) )
	{
		return Audio_CreateStreamedMP3( pName );
	}
	return CreateWave( pName, true );
}


//-----------------------------------------------------------------------------
// Purpose: Wrapper for CreateWave()
//-----------------------------------------------------------------------------
CAudioSource *Audio_CreateMemoryWave( const char *pName )
{
	if ( Audio_IsMP3( pName ) )
	{
		return Audio_CreateMemoryMP3( pName );
	}
	return CreateWave( pName, false );
}

⌨️ 快捷键说明

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