Team Fortress 2 Source Code as on 22/4/2020
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.8 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: Helper methods + classes for sound
  4. //
  5. //===========================================================================//
  6. #include "tier2/soundutils.h"
  7. #include "tier2/riff.h"
  8. #include "tier2/tier2.h"
  9. #include "filesystem.h"
  10. #ifdef IS_WINDOWS_PC
  11. #include <windows.h> // WAVEFORMATEX, WAVEFORMAT and ADPCM WAVEFORMAT!!!
  12. #include <mmreg.h>
  13. #else
  14. #ifdef _X360
  15. #include "xbox/xbox_win32stubs.h" // WAVEFORMATEX, WAVEFORMAT and ADPCM WAVEFORMAT!!!
  16. #endif
  17. #endif
  18. //-----------------------------------------------------------------------------
  19. // RIFF reader/writers that use the file system
  20. //-----------------------------------------------------------------------------
  21. class CFSIOReadBinary : public IFileReadBinary
  22. {
  23. public:
  24. // inherited from IFileReadBinary
  25. virtual int open( const char *pFileName );
  26. virtual int read( void *pOutput, int size, int file );
  27. virtual void seek( int file, int pos );
  28. virtual unsigned int tell( int file );
  29. virtual unsigned int size( int file );
  30. virtual void close( int file );
  31. };
  32. class CFSIOWriteBinary : public IFileWriteBinary
  33. {
  34. public:
  35. virtual int create( const char *pFileName );
  36. virtual int write( void *pData, int size, int file );
  37. virtual void close( int file );
  38. virtual void seek( int file, int pos );
  39. virtual unsigned int tell( int file );
  40. };
  41. //-----------------------------------------------------------------------------
  42. // Singletons
  43. //-----------------------------------------------------------------------------
  44. static CFSIOReadBinary s_FSIoIn;
  45. static CFSIOWriteBinary s_FSIoOut;
  46. IFileReadBinary *g_pFSIOReadBinary = &s_FSIoIn;
  47. IFileWriteBinary *g_pFSIOWriteBinary = &s_FSIoOut;
  48. //-----------------------------------------------------------------------------
  49. // RIFF reader that use the file system
  50. //-----------------------------------------------------------------------------
  51. int CFSIOReadBinary::open( const char *pFileName )
  52. {
  53. return (int)g_pFullFileSystem->Open( pFileName, "rb" );
  54. }
  55. int CFSIOReadBinary::read( void *pOutput, int size, int file )
  56. {
  57. if ( !file )
  58. return 0;
  59. return g_pFullFileSystem->Read( pOutput, size, (FileHandle_t)file );
  60. }
  61. void CFSIOReadBinary::seek( int file, int pos )
  62. {
  63. if ( !file )
  64. return;
  65. g_pFullFileSystem->Seek( (FileHandle_t)file, pos, FILESYSTEM_SEEK_HEAD );
  66. }
  67. unsigned int CFSIOReadBinary::tell( int file )
  68. {
  69. if ( !file )
  70. return 0;
  71. return g_pFullFileSystem->Tell( (FileHandle_t)file );
  72. }
  73. unsigned int CFSIOReadBinary::size( int file )
  74. {
  75. if ( !file )
  76. return 0;
  77. return g_pFullFileSystem->Size( (FileHandle_t)file );
  78. }
  79. void CFSIOReadBinary::close( int file )
  80. {
  81. if ( !file )
  82. return;
  83. g_pFullFileSystem->Close( (FileHandle_t)file );
  84. }
  85. //-----------------------------------------------------------------------------
  86. // RIFF writer that use the file system
  87. //-----------------------------------------------------------------------------
  88. int CFSIOWriteBinary::create( const char *pFileName )
  89. {
  90. g_pFullFileSystem->SetFileWritable( pFileName, true );
  91. return (int)g_pFullFileSystem->Open( pFileName, "wb" );
  92. }
  93. int CFSIOWriteBinary::write( void *pData, int size, int file )
  94. {
  95. return g_pFullFileSystem->Write( pData, size, (FileHandle_t)file );
  96. }
  97. void CFSIOWriteBinary::close( int file )
  98. {
  99. g_pFullFileSystem->Close( (FileHandle_t)file );
  100. }
  101. void CFSIOWriteBinary::seek( int file, int pos )
  102. {
  103. g_pFullFileSystem->Seek( (FileHandle_t)file, pos, FILESYSTEM_SEEK_HEAD );
  104. }
  105. unsigned int CFSIOWriteBinary::tell( int file )
  106. {
  107. return g_pFullFileSystem->Tell( (FileHandle_t)file );
  108. }
  109. #ifndef POSIX
  110. //-----------------------------------------------------------------------------
  111. // Returns the duration of a wav file
  112. //-----------------------------------------------------------------------------
  113. float GetWavSoundDuration( const char *pWavFile )
  114. {
  115. InFileRIFF riff( pWavFile, *g_pFSIOReadBinary );
  116. // UNDONE: Don't use printf to handle errors
  117. if ( riff.RIFFName() != RIFF_WAVE )
  118. return 0.0f;
  119. int nDataSize = 0;
  120. // set up the iterator for the whole file (root RIFF is a chunk)
  121. IterateRIFF walk( riff, riff.RIFFSize() );
  122. // This chunk must be first as it contains the wave's format
  123. // break out when we've parsed it
  124. char pFormatBuffer[ 1024 ];
  125. int nFormatSize;
  126. bool bFound = false;
  127. for ( ; walk.ChunkAvailable( ); walk.ChunkNext() )
  128. {
  129. switch ( walk.ChunkName() )
  130. {
  131. case WAVE_FMT:
  132. bFound = true;
  133. if ( walk.ChunkSize() > sizeof(pFormatBuffer) )
  134. {
  135. Warning( "oops, format tag too big!!!" );
  136. return 0.0f;
  137. }
  138. nFormatSize = walk.ChunkSize();
  139. walk.ChunkRead( pFormatBuffer );
  140. break;
  141. case WAVE_DATA:
  142. nDataSize += walk.ChunkSize();
  143. break;
  144. }
  145. }
  146. if ( !bFound )
  147. return 0.0f;
  148. const WAVEFORMATEX *pHeader = (const WAVEFORMATEX *)pFormatBuffer;
  149. int format = pHeader->wFormatTag;
  150. int nBits = pHeader->wBitsPerSample;
  151. int nRate = pHeader->nSamplesPerSec;
  152. int nChannels = pHeader->nChannels;
  153. int nSampleSize = ( nBits * nChannels ) / 8;
  154. // this can never be zero -- other functions divide by this.
  155. // This should never happen, but avoid crashing
  156. if ( nSampleSize <= 0 )
  157. {
  158. nSampleSize = 1;
  159. }
  160. int nSampleCount = 0;
  161. float flTrueSampleSize = nSampleSize;
  162. if ( format == WAVE_FORMAT_ADPCM )
  163. {
  164. nSampleSize = 1;
  165. ADPCMWAVEFORMAT *pFormat = (ADPCMWAVEFORMAT *)pFormatBuffer;
  166. int blockSize = ((pFormat->wSamplesPerBlock - 2) * pFormat->wfx.nChannels ) / 2;
  167. blockSize += 7 * pFormat->wfx.nChannels;
  168. int blockCount = nSampleCount / blockSize;
  169. int blockRem = nSampleCount % blockSize;
  170. // total samples in complete blocks
  171. nSampleCount = blockCount * pFormat->wSamplesPerBlock;
  172. // add remaining in a short block
  173. if ( blockRem )
  174. {
  175. nSampleCount += pFormat->wSamplesPerBlock - (((blockSize - blockRem) * 2) / nChannels);
  176. }
  177. flTrueSampleSize = 0.5f;
  178. }
  179. else
  180. {
  181. nSampleCount = nDataSize / nSampleSize;
  182. }
  183. float flDuration = (float)nSampleCount / (float)nRate;
  184. return flDuration;
  185. }
  186. #endif