You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
237 lines
5.9 KiB
237 lines
5.9 KiB
//========= Copyright Valve Corporation, All rights reserved. ============// |
|
// |
|
// Purpose: Helper methods + classes for sound |
|
// |
|
//===========================================================================// |
|
|
|
#include "tier2/soundutils.h" |
|
#include "tier2/riff.h" |
|
#include "tier2/tier2.h" |
|
#include "filesystem.h" |
|
|
|
#ifdef IS_WINDOWS_PC |
|
|
|
#include <windows.h> // WAVEFORMATEX, WAVEFORMAT and ADPCM WAVEFORMAT!!! |
|
#include <mmreg.h> |
|
|
|
#else |
|
|
|
#ifdef _X360 |
|
#include "xbox/xbox_win32stubs.h" // WAVEFORMATEX, WAVEFORMAT and ADPCM WAVEFORMAT!!! |
|
#endif |
|
|
|
#endif |
|
|
|
//----------------------------------------------------------------------------- |
|
// RIFF reader/writers that use the file system |
|
//----------------------------------------------------------------------------- |
|
class CFSIOReadBinary : public IFileReadBinary |
|
{ |
|
public: |
|
// inherited from IFileReadBinary |
|
virtual intp open( const char *pFileName ); |
|
virtual int read( void *pOutput, int size, intp file ); |
|
virtual void seek( intp file, int pos ); |
|
virtual unsigned int tell( intp file ); |
|
virtual unsigned int size( intp file ); |
|
virtual void close( intp file ); |
|
}; |
|
|
|
class CFSIOWriteBinary : public IFileWriteBinary |
|
{ |
|
public: |
|
virtual intp create( const char *pFileName ); |
|
virtual int write( void *pData, int size, intp file ); |
|
virtual void close( intp file ); |
|
virtual void seek( intp file, int pos ); |
|
virtual unsigned int tell( intp file ); |
|
}; |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Singletons |
|
//----------------------------------------------------------------------------- |
|
static CFSIOReadBinary s_FSIoIn; |
|
static CFSIOWriteBinary s_FSIoOut; |
|
|
|
IFileReadBinary *g_pFSIOReadBinary = &s_FSIoIn; |
|
IFileWriteBinary *g_pFSIOWriteBinary = &s_FSIoOut; |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// RIFF reader that use the file system |
|
//----------------------------------------------------------------------------- |
|
intp CFSIOReadBinary::open( const char *pFileName ) |
|
{ |
|
return (intp)g_pFullFileSystem->Open( pFileName, "rb" ); |
|
} |
|
|
|
int CFSIOReadBinary::read( void *pOutput, int size, intp file ) |
|
{ |
|
if ( !file ) |
|
return 0; |
|
|
|
return g_pFullFileSystem->Read( pOutput, size, (FileHandle_t)file ); |
|
} |
|
|
|
void CFSIOReadBinary::seek( intp file, int pos ) |
|
{ |
|
if ( !file ) |
|
return; |
|
|
|
g_pFullFileSystem->Seek( (FileHandle_t)file, pos, FILESYSTEM_SEEK_HEAD ); |
|
} |
|
|
|
unsigned int CFSIOReadBinary::tell( intp file ) |
|
{ |
|
if ( !file ) |
|
return 0; |
|
|
|
return g_pFullFileSystem->Tell( (FileHandle_t)file ); |
|
} |
|
|
|
unsigned int CFSIOReadBinary::size( intp file ) |
|
{ |
|
if ( !file ) |
|
return 0; |
|
|
|
return g_pFullFileSystem->Size( (FileHandle_t)file ); |
|
} |
|
|
|
void CFSIOReadBinary::close( intp file ) |
|
{ |
|
if ( !file ) |
|
return; |
|
|
|
g_pFullFileSystem->Close( (FileHandle_t)file ); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// RIFF writer that use the file system |
|
//----------------------------------------------------------------------------- |
|
intp CFSIOWriteBinary::create( const char *pFileName ) |
|
{ |
|
g_pFullFileSystem->SetFileWritable( pFileName, true ); |
|
return (intp)g_pFullFileSystem->Open( pFileName, "wb" ); |
|
} |
|
|
|
int CFSIOWriteBinary::write( void *pData, int size, intp file ) |
|
{ |
|
return g_pFullFileSystem->Write( pData, size, (FileHandle_t)file ); |
|
} |
|
|
|
void CFSIOWriteBinary::close( intp file ) |
|
{ |
|
g_pFullFileSystem->Close( (FileHandle_t)file ); |
|
} |
|
|
|
void CFSIOWriteBinary::seek( intp file, int pos ) |
|
{ |
|
g_pFullFileSystem->Seek( (FileHandle_t)file, pos, FILESYSTEM_SEEK_HEAD ); |
|
} |
|
|
|
unsigned int CFSIOWriteBinary::tell( intp file ) |
|
{ |
|
return g_pFullFileSystem->Tell( (FileHandle_t)file ); |
|
} |
|
|
|
|
|
#ifndef POSIX |
|
//----------------------------------------------------------------------------- |
|
// Returns the duration of a wav file |
|
//----------------------------------------------------------------------------- |
|
float GetWavSoundDuration( const char *pWavFile ) |
|
{ |
|
InFileRIFF riff( pWavFile, *g_pFSIOReadBinary ); |
|
|
|
// UNDONE: Don't use printf to handle errors |
|
if ( riff.RIFFName() != RIFF_WAVE ) |
|
return 0.0f; |
|
|
|
int nDataSize = 0; |
|
|
|
// set up the iterator for the whole file (root RIFF is a chunk) |
|
IterateRIFF walk( riff, riff.RIFFSize() ); |
|
|
|
// This chunk must be first as it contains the wave's format |
|
// break out when we've parsed it |
|
char pFormatBuffer[ 1024 ]; |
|
int nFormatSize; |
|
bool bFound = false; |
|
for ( ; walk.ChunkAvailable( ); walk.ChunkNext() ) |
|
{ |
|
switch ( walk.ChunkName() ) |
|
{ |
|
case WAVE_FMT: |
|
bFound = true; |
|
if ( walk.ChunkSize() > sizeof(pFormatBuffer) ) |
|
{ |
|
Warning( "oops, format tag too big!!!" ); |
|
return 0.0f; |
|
} |
|
|
|
nFormatSize = walk.ChunkSize(); |
|
walk.ChunkRead( pFormatBuffer ); |
|
break; |
|
|
|
case WAVE_DATA: |
|
nDataSize += walk.ChunkSize(); |
|
break; |
|
} |
|
} |
|
|
|
if ( !bFound ) |
|
return 0.0f; |
|
|
|
const WAVEFORMATEX *pHeader = (const WAVEFORMATEX *)pFormatBuffer; |
|
|
|
int format = pHeader->wFormatTag; |
|
|
|
int nBits = pHeader->wBitsPerSample; |
|
int nRate = pHeader->nSamplesPerSec; |
|
int nChannels = pHeader->nChannels; |
|
int nSampleSize = ( nBits * nChannels ) / 8; |
|
|
|
// this can never be zero -- other functions divide by this. |
|
// This should never happen, but avoid crashing |
|
if ( nSampleSize <= 0 ) |
|
{ |
|
nSampleSize = 1; |
|
} |
|
|
|
int nSampleCount = 0; |
|
float flTrueSampleSize = nSampleSize; |
|
|
|
if ( format == WAVE_FORMAT_ADPCM ) |
|
{ |
|
nSampleSize = 1; |
|
|
|
ADPCMWAVEFORMAT *pFormat = (ADPCMWAVEFORMAT *)pFormatBuffer; |
|
int blockSize = ((pFormat->wSamplesPerBlock - 2) * pFormat->wfx.nChannels ) / 2; |
|
blockSize += 7 * pFormat->wfx.nChannels; |
|
|
|
int blockCount = nSampleCount / blockSize; |
|
int blockRem = nSampleCount % blockSize; |
|
|
|
// total samples in complete blocks |
|
nSampleCount = blockCount * pFormat->wSamplesPerBlock; |
|
|
|
// add remaining in a short block |
|
if ( blockRem ) |
|
{ |
|
nSampleCount += pFormat->wSamplesPerBlock - (((blockSize - blockRem) * 2) / nChannels); |
|
} |
|
|
|
flTrueSampleSize = 0.5f; |
|
|
|
} |
|
else |
|
{ |
|
nSampleCount = nDataSize / nSampleSize; |
|
} |
|
|
|
float flDuration = (float)nSampleCount / (float)nRate; |
|
return flDuration; |
|
} |
|
#endif
|
|
|