Counter Strike : Global Offensive Source Code
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.

273 lines
7.4 KiB

  1. //========= Copyright (c) 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "audio_pch.h"
  8. #include "snd_mp3_source.h"
  9. #include "vaudio/ivaudio.h"
  10. // memdbgon must be the last include file in a .cpp file!!!
  11. #include "tier0/memdbgon.h"
  12. extern IVAudio *vaudio;
  13. static const int MP3_BUFFER_SIZE = 16384;
  14. //-----------------------------------------------------------------------------
  15. // Purpose: Mixer for ADPCM encoded audio
  16. //-----------------------------------------------------------------------------
  17. class CAudioMixerWaveMP3 : public CAudioMixerWave, public IAudioStreamEvent
  18. {
  19. public:
  20. CAudioMixerWaveMP3( IWaveData *data );
  21. ~CAudioMixerWaveMP3( void );
  22. virtual void Mix( channel_t *pChannel, void *pData, int outputOffset, int inputOffset, fixedint fracRate, int outCount, int timecompress );
  23. virtual int GetOutputData( void **pData, int sampleCount, char copyBuf[AUDIOSOURCE_COPYBUF_SIZE] );
  24. // need to override this to fixup blocks
  25. // UNDONE: This doesn't quite work with MP3 - we need a MP3 position, not a sample position
  26. void SetSampleStart( int newPosition );
  27. int GetPositionForSave() { return m_pStream->GetPosition(); }
  28. void SetPositionFromSaved(int position) { m_pStream->SetPosition(position); }
  29. // IAudioStreamEvent
  30. virtual int StreamRequestData( void *pBuffer, int bytesRequested, int offset );
  31. virtual void SetStartupDelaySamples( int delaySamples );
  32. virtual int GetMixSampleSize() { return CalcSampleSize( 16, m_channelCount ); }
  33. bool IsValid() { return m_pStream != NULL; }
  34. virtual int GetStreamOutputRate() { return m_pStream->GetOutputRate(); }
  35. private:
  36. bool DecodeBlock( void );
  37. void GetID3HeaderOffset();
  38. IAudioStream *m_pStream;
  39. char m_samples[MP3_BUFFER_SIZE];
  40. int m_sampleCount;
  41. int m_samplePosition;
  42. int m_channelCount;
  43. int m_offset;
  44. int m_delaySamples;
  45. int m_headerOffset;
  46. };
  47. CAudioMixerWaveMP3::CAudioMixerWaveMP3( IWaveData *data ) : CAudioMixerWave( data )
  48. {
  49. m_sampleCount = 0;
  50. m_samplePosition = 0;
  51. m_offset = 0;
  52. m_delaySamples = 0;
  53. m_headerOffset = 0;
  54. m_pStream = NULL;
  55. if ( vaudio )
  56. m_pStream = vaudio->CreateMP3StreamDecoder( static_cast<IAudioStreamEvent *>(this) );
  57. if ( m_pStream )
  58. {
  59. m_channelCount = m_pStream->GetOutputChannels();
  60. //Assert( m_pStream->GetOutputRate() == m_pData->Source().SampleRate() );
  61. }
  62. }
  63. CAudioMixerWaveMP3::~CAudioMixerWaveMP3( void )
  64. {
  65. if ( m_pStream )
  66. {
  67. vaudio->DestroyMP3StreamDecoder( m_pStream );
  68. m_pStream = NULL;
  69. }
  70. }
  71. void CAudioMixerWaveMP3::Mix( channel_t *pChannel, void *pData, int outputOffset, int inputOffset, fixedint fracRate, int outCount, int timecompress )
  72. {
  73. if ( m_channelCount == 1 )
  74. {
  75. Device_Mix16Mono( pChannel, (short *)pData, outputOffset, inputOffset, fracRate, outCount, timecompress );
  76. }
  77. else
  78. {
  79. Device_Mix16Stereo( pChannel, (short *)pData, outputOffset, inputOffset, fracRate, outCount, timecompress );
  80. }
  81. }
  82. // Some MP3 files are wrapped in ID3
  83. void CAudioMixerWaveMP3::GetID3HeaderOffset()
  84. {
  85. char copyBuf[AUDIOSOURCE_COPYBUF_SIZE];
  86. byte *pData;
  87. int bytesRead = m_pData->ReadSourceData( (void **)&pData, 0, 10, copyBuf );
  88. if ( bytesRead < 10 )
  89. return;
  90. m_headerOffset = 0;
  91. if (( pData[ 0 ] == 0x49 ) &&
  92. ( pData[ 1 ] == 0x44 ) &&
  93. ( pData[ 2 ] == 0x33 ) &&
  94. ( pData[ 3 ] < 0xff ) &&
  95. ( pData[ 4 ] < 0xff ) &&
  96. ( pData[ 6 ] < 0x80 ) &&
  97. ( pData[ 7 ] < 0x80 ) &&
  98. ( pData[ 8 ] < 0x80 ) &&
  99. ( pData[ 9 ] < 0x80 ) )
  100. {
  101. // this is in id3 file
  102. // compute the size of the wrapper and skip it
  103. m_headerOffset = 10 + ( pData[9] | (pData[8]<<7) | (pData[7]<<14) | (pData[6]<<21) );
  104. }
  105. }
  106. int CAudioMixerWaveMP3::StreamRequestData( void *pBuffer, int bytesRequested, int offset )
  107. {
  108. if ( offset < 0 )
  109. {
  110. offset = m_offset;
  111. }
  112. else
  113. {
  114. m_offset = offset;
  115. }
  116. // read the data out of the source
  117. int totalBytesRead = 0;
  118. if ( offset == 0 )
  119. {
  120. // top of file, check for ID3 wrapper
  121. GetID3HeaderOffset();
  122. }
  123. offset += m_headerOffset; // skip any id3 header/wrapper
  124. while ( bytesRequested > 0 )
  125. {
  126. char *pOutputBuffer = (char *)pBuffer;
  127. pOutputBuffer += totalBytesRead;
  128. void *pData = NULL;
  129. int bytesRead = m_pData->ReadSourceData( &pData, offset + totalBytesRead, bytesRequested, pOutputBuffer );
  130. if ( !bytesRead )
  131. break;
  132. if ( bytesRead > bytesRequested )
  133. {
  134. bytesRead = bytesRequested;
  135. }
  136. // if the source is buffering it, copy it to the MP3 decomp buffer
  137. if ( pData != pOutputBuffer )
  138. {
  139. memcpy( pOutputBuffer, pData, bytesRead );
  140. }
  141. totalBytesRead += bytesRead;
  142. bytesRequested -= bytesRead;
  143. }
  144. m_offset += totalBytesRead;
  145. return totalBytesRead;
  146. }
  147. bool CAudioMixerWaveMP3::DecodeBlock()
  148. {
  149. m_sampleCount = m_pStream->Decode( m_samples, sizeof(m_samples) );
  150. m_samplePosition = 0;
  151. return m_sampleCount > 0;
  152. }
  153. //-----------------------------------------------------------------------------
  154. // Purpose: Read existing buffer or decompress a new block when necessary
  155. // Input : **pData - output data pointer
  156. // sampleCount - number of samples (or pairs)
  157. // Output : int - available samples (zero to stop decoding)
  158. //-----------------------------------------------------------------------------
  159. int CAudioMixerWaveMP3::GetOutputData( void **pData, int sampleCount, char copyBuf[AUDIOSOURCE_COPYBUF_SIZE] )
  160. {
  161. if ( m_samplePosition >= m_sampleCount )
  162. {
  163. if ( !DecodeBlock() )
  164. return 0;
  165. }
  166. if ( m_samplePosition < m_sampleCount )
  167. {
  168. int sampleSize = m_channelCount * 2;
  169. *pData = (void *)(m_samples + m_samplePosition);
  170. int available = m_sampleCount - m_samplePosition;
  171. int bytesRequired = sampleCount * sampleSize;
  172. if ( available > bytesRequired )
  173. available = bytesRequired;
  174. m_samplePosition += available;
  175. int samples_loaded = available / sampleSize;
  176. // update count of max samples loaded in CAudioMixerWave
  177. CAudioMixerWave::m_sample_max_loaded += samples_loaded;
  178. // update index of last sample loaded
  179. CAudioMixerWave::m_sample_loaded_index += samples_loaded;
  180. return samples_loaded;
  181. }
  182. return 0;
  183. }
  184. //-----------------------------------------------------------------------------
  185. // Purpose: Seek to a new position in the file
  186. // NOTE: In most cases, only call this once, and call it before playing
  187. // any data.
  188. // Input : newPosition - new position in the sample clocks of this sample
  189. //-----------------------------------------------------------------------------
  190. void CAudioMixerWaveMP3::SetSampleStart( int newPosition )
  191. {
  192. // UNDONE: Implement this?
  193. }
  194. //-----------------------------------------------------------------------------
  195. // Purpose:
  196. // Input : delaySamples -
  197. //-----------------------------------------------------------------------------
  198. void CAudioMixerWaveMP3::SetStartupDelaySamples( int delaySamples )
  199. {
  200. m_delaySamples = delaySamples;
  201. }
  202. //-----------------------------------------------------------------------------
  203. // Purpose: Abstract factory function for MP3 mixers
  204. // Input : *data - wave data access object
  205. // channels -
  206. // Output : CAudioMixer
  207. //-----------------------------------------------------------------------------
  208. CAudioMixer *CreateMP3Mixer( IWaveData *data, int *pSampleRate )
  209. {
  210. CAudioMixerWaveMP3 *pMixer = new CAudioMixerWaveMP3( data );
  211. if ( pMixer->IsValid() )
  212. {
  213. // pass the sample rate back just in time to save parsing the MP3 file twice to get sample rate
  214. if ( pSampleRate )
  215. {
  216. *pSampleRate = pMixer->GetStreamOutputRate();
  217. }
  218. return pMixer;
  219. }
  220. delete pMixer;
  221. return NULL;
  222. }