|
|
//========= 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
|