Torque3D Documentation / _generateds / oggVorbisDecoder.cpp

oggVorbisDecoder.cpp

Engine/source/core/ogg/oggVorbisDecoder.cpp

More...

Detailed Description

  1
  2//-----------------------------------------------------------------------------
  3// Copyright (c) 2012 GarageGames, LLC
  4//
  5// Permission is hereby granted, free of charge, to any person obtaining a copy
  6// of this software and associated documentation files (the "Software"), to
  7// deal in the Software without restriction, including without limitation the
  8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  9// sell copies of the Software, and to permit persons to whom the Software is
 10// furnished to do so, subject to the following conditions:
 11//
 12// The above copyright notice and this permission notice shall be included in
 13// all copies or substantial portions of the Software.
 14//
 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 21// IN THE SOFTWARE.
 22//-----------------------------------------------------------------------------
 23
 24#include "core/ogg/oggVorbisDecoder.h"
 25#include "console/console.h"
 26
 27
 28//#define DEBUG_SPEW
 29
 30
 31//-----------------------------------------------------------------------------
 32
 33OggVorbisDecoder::OggVorbisDecoder( const ThreadSafeRef< OggInputStream>& stream )
 34   : Parent( stream )
 35#ifdef TORQUE_DEBUG
 36     , mLock( 0 )
 37#endif
 38{
 39   // Initialize.
 40   
 41   vorbis_info_init( &mVorbisInfo );
 42   vorbis_comment_init( &mVorbisComment );
 43   dMemset( &mVorbisBlock, 0, sizeof( mVorbisBlock ) );
 44   dMemset( &mVorbisDspState, 0, sizeof( mVorbisDspState ) );
 45}
 46
 47//-----------------------------------------------------------------------------
 48
 49OggVorbisDecoder::~OggVorbisDecoder()
 50{
 51   vorbis_block_clear( &mVorbisBlock );
 52   vorbis_dsp_clear( &mVorbisDspState );
 53   vorbis_info_clear( &mVorbisInfo );
 54   vorbis_comment_clear( &mVorbisComment );
 55}
 56
 57//-----------------------------------------------------------------------------
 58
 59bool OggVorbisDecoder::_detect( ogg_page* startPage )
 60{
 61   _setStartPage( startPage );
 62
 63   // Read initial header packet.
 64   
 65   ogg_packet nextPacket;
 66   if( !_readNextPacket( &nextPacket )
 67       || vorbis_synthesis_headerin( &mVorbisInfo, &mVorbisComment, &nextPacket ) < 0 )
 68   {
 69      vorbis_info_clear( &mVorbisInfo );
 70      vorbis_comment_clear( &mVorbisComment );
 71      return false;
 72   }
 73   
 74   return true;
 75}
 76
 77//-----------------------------------------------------------------------------
 78
 79bool OggVorbisDecoder::_init()
 80{   
 81   // Read header packets.
 82   
 83   bool haveVorbisHeader = true;
 84   for( U32 i = 0; i < 2; ++ i )
 85   {
 86      ogg_packet nextPacket;
 87      if( !_readNextPacket( &nextPacket ) )
 88      {
 89         haveVorbisHeader = false;
 90         break;
 91      }
 92          
 93      S32 result = vorbis_synthesis_headerin( &mVorbisInfo, &mVorbisComment, &nextPacket );
 94      if( result != 0 )
 95      {
 96         haveVorbisHeader = false;
 97         break;
 98      }
 99   }
100   
101   // Fail if we don't have a complete and valid Vorbis header.
102   
103   if( !haveVorbisHeader )
104   {
105      vorbis_info_clear( &mVorbisInfo );
106      vorbis_comment_clear( &mVorbisComment );
107      
108      Con::errorf( "OggVorbisDecoder::_init() - Incorrect or corrupt Vorbis headers" );
109      
110      return false;
111   }
112   
113   // Init synthesis.
114   
115   vorbis_synthesis_init( &mVorbisDspState, &mVorbisInfo );
116   vorbis_block_init( &mVorbisDspState, &mVorbisBlock );
117   
118   return true;
119}
120
121//-----------------------------------------------------------------------------
122
123bool OggVorbisDecoder::_packetin( ogg_packet* packet )
124{
125   return ( vorbis_synthesis( &mVorbisBlock, packet ) == 0 );
126}
127
128//-----------------------------------------------------------------------------
129
130U32 OggVorbisDecoder::read( RawData** buffer, U32 num )
131{
132   #ifdef TORQUE_DEBUG
133   AssertFatal( dCompareAndSwap( mLock, 0, 1 ), "OggVorbisDecoder::read() - simultaneous reads not thread-safe" );
134   #endif
135   
136   U32 numRead = 0;
137   
138   for( U32 i = 0; i < num; ++ i )
139   {
140      float** pcmData;
141      U32 numSamples;
142      
143      // Read sample data.
144      
145      while( 1 )
146      {
147         numSamples = vorbis_synthesis_pcmout( &mVorbisDspState, &pcmData );
148         if( numSamples )
149            break;
150         else
151         {
152            if( !_nextPacket() )
153               return numRead; // End of stream.
154               
155            vorbis_synthesis_blockin( &mVorbisDspState, &mVorbisBlock );
156         }
157      }
158      vorbis_synthesis_read( &mVorbisDspState, numSamples );
159      
160      #ifdef DEBUG_SPEW
161      Platform::outputDebugString( "[OggVorbisDecoder] read %i samples", numSamples );
162      #endif
163      
164      // Allocate a packet.
165      
166      const U32 numChannels = getNumChannels();
167      RawData* packet = constructSingle< RawData* >( numSamples * 2 * numChannels ); // Two bytes per channel.
168      
169      // Convert and copy the samples.
170      
171      S16* samplePtr = ( S16* ) packet->data;
172      for( U32 n = 0; n < numSamples; ++ n )
173         for( U32 c = 0; c < numChannels; ++ c )
174         {
175            S32 val = S32( pcmData[ c ][ n ] * 32767.f );
176            if( val > 32767 )
177               val = 32767;
178            else if( val < -32768 )
179               val = -32768;
180               
181            *samplePtr = val;
182            ++ samplePtr;
183         }         
184      
185      // Success.
186      
187      buffer[ i ] = packet;
188      numRead ++;
189   }
190   
191   #ifdef TORQUE_DEBUG
192   AssertFatal( dCompareAndSwap( mLock, 1, 0 ), "" );
193   #endif
194   
195   return numRead;
196}
197