diff options
Diffstat (limited to 'tier2/soundutils.cpp')
| -rw-r--r-- | tier2/soundutils.cpp | 237 |
1 files changed, 237 insertions, 0 deletions
diff --git a/tier2/soundutils.cpp b/tier2/soundutils.cpp new file mode 100644 index 0000000..bebda85 --- /dev/null +++ b/tier2/soundutils.cpp @@ -0,0 +1,237 @@ +//========= 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 int open( const char *pFileName ); + virtual int read( void *pOutput, int size, int file ); + virtual void seek( int file, int pos ); + virtual unsigned int tell( int file ); + virtual unsigned int size( int file ); + virtual void close( int file ); +}; + +class CFSIOWriteBinary : public IFileWriteBinary +{ +public: + virtual int create( const char *pFileName ); + virtual int write( void *pData, int size, int file ); + virtual void close( int file ); + virtual void seek( int file, int pos ); + virtual unsigned int tell( int 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 +//----------------------------------------------------------------------------- +int CFSIOReadBinary::open( const char *pFileName ) +{ + return (int)g_pFullFileSystem->Open( pFileName, "rb" ); +} + +int CFSIOReadBinary::read( void *pOutput, int size, int file ) +{ + if ( !file ) + return 0; + + return g_pFullFileSystem->Read( pOutput, size, (FileHandle_t)file ); +} + +void CFSIOReadBinary::seek( int file, int pos ) +{ + if ( !file ) + return; + + g_pFullFileSystem->Seek( (FileHandle_t)file, pos, FILESYSTEM_SEEK_HEAD ); +} + +unsigned int CFSIOReadBinary::tell( int file ) +{ + if ( !file ) + return 0; + + return g_pFullFileSystem->Tell( (FileHandle_t)file ); +} + +unsigned int CFSIOReadBinary::size( int file ) +{ + if ( !file ) + return 0; + + return g_pFullFileSystem->Size( (FileHandle_t)file ); +} + +void CFSIOReadBinary::close( int file ) +{ + if ( !file ) + return; + + g_pFullFileSystem->Close( (FileHandle_t)file ); +} + + +//----------------------------------------------------------------------------- +// RIFF writer that use the file system +//----------------------------------------------------------------------------- +int CFSIOWriteBinary::create( const char *pFileName ) +{ + g_pFullFileSystem->SetFileWritable( pFileName, true ); + return (int)g_pFullFileSystem->Open( pFileName, "wb" ); +} + +int CFSIOWriteBinary::write( void *pData, int size, int file ) +{ + return g_pFullFileSystem->Write( pData, size, (FileHandle_t)file ); +} + +void CFSIOWriteBinary::close( int file ) +{ + g_pFullFileSystem->Close( (FileHandle_t)file ); +} + +void CFSIOWriteBinary::seek( int file, int pos ) +{ + g_pFullFileSystem->Seek( (FileHandle_t)file, pos, FILESYSTEM_SEEK_HEAD ); +} + +unsigned int CFSIOWriteBinary::tell( int 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 |