00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "OggVorbisAudioStream.hxx"
00023 #include "AudioFile.hxx"
00024 #include <cstdio>
00025 #include <ctime>
00026 #include <cstdlib>
00027 #include <vorbis/codec.h>
00028 #include <iostream>
00029 #include <algorithm>
00030
00031 #if defined ( __powerpc__ ) || defined ( __POWERPC__ )
00032 #define HOST_ENDIANESS 1
00033 #else
00034 #define HOST_ENDIANESS 0
00035 #endif
00036
00037 namespace CLAM
00038 {
00039
00040 namespace AudioCodecs
00041 {
00042 const TSize OggVorbisAudioStream::mMaxBlockSize = 4096 / sizeof(TInt16);
00043 const TSize OggVorbisAudioStream::mAnalysisWindowSize = 1024;
00044
00045 OggVorbisAudioStream::OggVorbisAudioStream()
00046 : mFileHandle( NULL ), mValidFileParams( false ), mEncoding( false )
00047 {
00048 mBlockBuffer.Resize( mMaxBlockSize );
00049 mBlockBuffer.SetSize( mMaxBlockSize );
00050
00051 }
00052
00053 OggVorbisAudioStream::OggVorbisAudioStream( const AudioFile& file )
00054 : mFileHandle( NULL ), mValidFileParams( false ), mEncoding( false )
00055 {
00056 SetFOI( file );
00057 mBlockBuffer.Resize( mMaxBlockSize );
00058 mBlockBuffer.SetSize( mMaxBlockSize );
00059
00060 }
00061
00062 OggVorbisAudioStream::~OggVorbisAudioStream()
00063 {
00064 if ( mValidFileParams )
00065 Dispose();
00066 }
00067
00068 void OggVorbisAudioStream::SetFOI( const AudioFile& file )
00069 {
00070 if ( mValidFileParams )
00071 Dispose();
00072 AudioFileToNative( file );
00073
00074 }
00075
00076 void OggVorbisAudioStream::AudioFileToNative( const AudioFile& file )
00077 {
00078 mName = file.GetLocation();
00079 mEncodedSampleRate = (int)file.GetHeader().GetSampleRate();
00080 mEncodedChannels = (int)file.GetHeader().GetChannels();
00081
00082 mEncodeBuffer.resize( mEncodedChannels );
00083
00084 }
00085
00086
00087 void OggVorbisAudioStream::PrepareReading()
00088 {
00089 if ( ( mFileHandle = fopen( mName.c_str(), "rb" ) ) == NULL )
00090 {
00091 std::string msgString = "Could not open ";
00092 msgString += mName;
00093 msgString +=" for reading!";
00094 CLAM_ASSERT( false, msgString.c_str() );
00095 }
00096
00097 if ( ov_open( mFileHandle, &mNativeFileParams, NULL, 0 ) < 0 )
00098 {
00099 fclose( mFileHandle );
00100 std::string msgString = mName;
00101 msgString += " is not a valid Ogg/Vorbis file!";
00102
00103 CLAM_ASSERT( false, msgString.c_str() );
00104 }
00105
00106 vorbis_info* info = ov_info( &mNativeFileParams, -1 );
00107
00108 SetChannels( info->channels );
00109 MarkAllChannelsAsConsumed();
00110
00111 mValidFileParams = true;
00112 mCurrentSection = 0;
00113
00114
00115
00116
00117
00118
00119 ov_pcm_seek( &mNativeFileParams, 0 );
00120 }
00121
00122 void OggVorbisAudioStream::PrepareWriting()
00123 {
00124 if ( ( mFileHandle = fopen( mName.c_str(), "wb" ) ) == NULL )
00125 {
00126 std::string msgString = "Could not open ";
00127 msgString += mName;
00128 msgString +=" for writing!";
00129 CLAM_ASSERT( false, msgString.c_str() );
00130 }
00131
00132 VorbisI_EncoderSetup();
00133 MarkAllChannelsAsProduced();
00134 mEncoding = true;
00135
00136 }
00137
00138 void OggVorbisAudioStream::VorbisI_EncoderSetup()
00139 {
00140
00141 vorbis_info_init( &mStreamInfo );
00142
00143
00144
00145 int retValue = vorbis_encode_init_vbr( &mStreamInfo,
00146 mEncodedChannels,
00147 mEncodedSampleRate,
00148 0.5 );
00149
00150 CLAM_ASSERT( retValue == 0, "Error trying to initialize Vorbis encoder!" );
00151
00152
00153 vorbis_comment_init( &mFileComments );
00154 vorbis_comment_add_tag( &mFileComments, "ENCODER", "CLAM" );
00155
00156
00157 vorbis_analysis_init( &mDSPState, &mStreamInfo );
00158 vorbis_block_init( &mDSPState, &mVorbisBlock );
00159
00160
00161
00162
00163 ogg_stream_init( &mOggStreamState, rand() );
00164
00165 WriteBitstreamHeader();
00166
00167 SetChannels( mEncodedChannels );
00168 }
00169
00170 void OggVorbisAudioStream::WriteBitstreamHeader()
00171 {
00172
00173
00174
00175
00176
00177 ogg_packet header_codec_setup;
00178 ogg_packet header_comments;
00179 ogg_packet header_codebooks;
00180
00181
00182
00183 vorbis_analysis_headerout( &mDSPState, &mFileComments,
00184 &header_codec_setup,
00185 &header_comments,
00186 &header_codebooks );
00187
00188
00189 ogg_stream_packetin( &mOggStreamState, &header_codec_setup );
00190 ogg_stream_packetin( &mOggStreamState, &header_comments );
00191 ogg_stream_packetin( &mOggStreamState, &header_codebooks );
00192
00193
00194
00195
00196 while( ogg_stream_flush( &mOggStreamState, &mOggPage ) > 0 )
00197 {
00198 fwrite( mOggPage.header, 1, mOggPage.header_len, mFileHandle );
00199 fwrite( mOggPage.body, 1, mOggPage.body_len, mFileHandle );
00200 }
00201
00202
00203 }
00204
00205 void OggVorbisAudioStream::PrepareReadWrite()
00206 {
00207 CLAM_ASSERT( false, "Cannot be done!" );
00208 }
00209
00210 void OggVorbisAudioStream::Dispose()
00211 {
00212 if ( !mEncoding )
00213 {
00214 ov_clear( &mNativeFileParams );
00215 mValidFileParams = false;
00216 }
00217 else
00218 {
00219
00220
00221 if ( !mEncodeBuffer[0].empty() )
00222 DoVorbisAnalysis();
00223
00224
00225
00226 vorbis_analysis_wrote( &mDSPState, 0 );
00227
00228
00229 PushAnalysisBlocksOntoOggStream();
00230
00231
00232 ogg_stream_clear( &mOggStreamState );
00233 vorbis_block_clear( &mVorbisBlock );
00234 vorbis_dsp_clear( &mDSPState );
00235 vorbis_comment_clear( &mFileComments );
00236 vorbis_info_clear( &mStreamInfo );
00237
00238 fclose( mFileHandle );
00239
00240 mEncoding = false;
00241
00242 }
00243 }
00244
00245 void OggVorbisAudioStream::ConsumeDecodedSamples()
00246 {
00247 CLAM_ASSERT( mDecodeBuffer.size() >= unsigned(mInterleavedData.Size()),
00248 "This method cannot be called if the decode buffer"
00249 " has less samples than requested by the upper level");
00250
00251 static const TData norm = 1.0 / 32768.0;
00252
00253 TData* pSamples = mInterleavedData.GetPtr();
00254 const TData* pSamplesEnd = mInterleavedData.GetPtr() + mInterleavedData.Size();
00255 for( std::deque<TInt16>::iterator i = mDecodeBuffer.begin();
00256 pSamples < pSamplesEnd; i++, pSamples++ )
00257 *pSamples = TData(*i)*norm;
00258
00259 mDecodeBuffer.erase( mDecodeBuffer.begin(),
00260 mDecodeBuffer.begin()+mInterleavedData.Size() );
00261
00262 }
00263
00264 void OggVorbisAudioStream::DiskToMemoryTransfer()
00265 {
00266
00267
00268 unsigned samplesRead = 0;
00269
00270 while ( mDecodeBuffer.size() < unsigned(mInterleavedData.Size()) )
00271 {
00272 mLastBytesRead = ov_read( &mNativeFileParams,
00273 (char*)mBlockBuffer.GetPtr(),
00274 mMaxBlockSize*sizeof(TInt16),
00275 HOST_ENDIANESS,
00276 2, 1, &mCurrentSection );
00277
00278 CLAM_ASSERT( mLastBytesRead >= 0, "Malformed OggVorbis file!" );
00279 CLAM_ASSERT( mLastBytesRead % mEncodedChannels == 0, "BIG Whoops!" );
00280
00281 if ( mLastBytesRead == 0 ) break;
00282
00283 samplesRead = mLastBytesRead / sizeof(TInt16 );
00284
00285
00286 mDecodeBuffer.insert( mDecodeBuffer.end(),
00287 mBlockBuffer.GetPtr(),
00288 mBlockBuffer.GetPtr() + samplesRead);
00289 }
00290
00291 mFramesLastRead = mDecodeBuffer.size();
00292
00293 if ( !mDecodeBuffer.empty() )
00294 {
00295
00296 if ( mDecodeBuffer.size() < unsigned(mInterleavedData.Size()) )
00297 {
00298 mDecodeBuffer.insert( mDecodeBuffer.end(),
00299 mInterleavedData.Size() - mDecodeBuffer.size(),
00300 0);
00301 }
00302
00303 ConsumeDecodedSamples();
00304 }
00305
00306 mEOFReached = ( mLastBytesRead == 0) && (mDecodeBuffer.empty());
00307
00308 }
00309
00310 void OggVorbisAudioStream::MemoryToDiskTransfer()
00311 {
00312
00313
00314
00315
00316
00317 TIndex currentOffset = 0;
00318 int i;
00319
00320 do
00321 {
00322 for ( i = mEncodeBuffer[0].size();
00323 i < mAnalysisWindowSize && currentOffset < mInterleavedDataOut.Size();
00324 i++ )
00325 {
00326 for ( int j = 0; j < mEncodedChannels; j++ )
00327 mEncodeBuffer[j].push_front( mInterleavedDataOut[ currentOffset + j ] );
00328
00329 currentOffset += mEncodedChannels;
00330 }
00331
00332 if ( i == mAnalysisWindowSize )
00333 DoVorbisAnalysis();
00334
00335 } while ( currentOffset < mInterleavedDataOut.Size() );
00336
00337 }
00338
00339 void OggVorbisAudioStream::PushAnalysisBlocksOntoOggStream()
00340 {
00341 int eos = 0;
00342
00343 while( vorbis_analysis_blockout( &mDSPState, &mVorbisBlock ) == 1 && !eos )
00344 {
00345
00346
00347 vorbis_analysis( &mVorbisBlock, NULL );
00348 vorbis_bitrate_addblock( &mVorbisBlock );
00349
00350 while( vorbis_bitrate_flushpacket( &mDSPState, &mOggPacket ) )
00351 {
00352
00353 ogg_stream_packetin( &mOggStreamState, &mOggPacket );
00354
00355
00356
00357
00358 while( ogg_stream_pageout( &mOggStreamState, &mOggPage ) > 0
00359 && !eos)
00360 {
00361 fwrite( mOggPage.header, 1, mOggPage.header_len, mFileHandle );
00362 fwrite( mOggPage.body, 1, mOggPage.body_len, mFileHandle );
00363
00364 eos = ( ogg_page_eos( &mOggPage ) )? 1 : 0;
00365
00366 }
00367
00368 }
00369 }
00370
00371 }
00372
00373 void OggVorbisAudioStream::DoVorbisAnalysis()
00374 {
00375
00376 float** encBuffer = vorbis_analysis_buffer( &mDSPState,
00377 mAnalysisWindowSize);
00378
00379
00380
00381 for ( int j = 0; j < mEncodedChannels; j++ )
00382 {
00383 int i = 0;
00384
00385 while( !mEncodeBuffer[j].empty() )
00386 {
00387
00388 encBuffer[j][i] = mEncodeBuffer[j].back();
00389 mEncodeBuffer[j].pop_back();
00390 i++;
00391 }
00392
00393
00394 while( i < mAnalysisWindowSize )
00395 {
00396 encBuffer[j][i] = 0.0;
00397 i++;
00398 }
00399
00400 }
00401
00402 vorbis_analysis_wrote( &mDSPState, mAnalysisWindowSize );
00403
00404 PushAnalysisBlocksOntoOggStream();
00405
00406
00407 }
00408 }
00409
00410 }
00411