|
CLAM-Development
1.3
|
00001 /* 00002 * Copyright (c) 2004 MUSIC TECHNOLOGY GROUP (MTG) 00003 * UNIVERSITAT POMPEU FABRA 00004 * 00005 * 00006 * This program is free software; you can redistribute it and/or modify 00007 * it under the terms of the GNU General Public License as published by 00008 * the Free Software Foundation; either version 2 of the License, or 00009 * (at your option) any later version. 00010 * 00011 * This program is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 * GNU General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU General Public License 00017 * along with this program; if not, write to the Free Software 00018 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00019 * 00020 */ 00021 00022 #include "MpegAudioStream.hxx" 00023 #include "AudioFile.hxx" 00024 #include "Assert.hxx" 00025 #include <iostream> 00026 00027 namespace CLAM 00028 { 00029 00030 namespace AudioCodecs 00031 { 00032 // A reasonable multiple of four 00033 const TSize MpegAudioStream::mMaxDecodedBlockSize = 8192; 00034 00035 MpegAudioStream::MpegAudioStream( const AudioFile& file ) 00036 : mpHandle( NULL ) 00037 { 00038 mName = file.GetLocation(); 00039 mEncodedSampleRate = (int)file.GetHeader().GetSampleRate(); 00040 mChannels = (int)file.GetHeader().GetChannels(); 00041 mDecodeBuffer.resize( mChannels ); 00042 } 00043 00044 MpegAudioStream::~MpegAudioStream() 00045 { 00046 if ( not mpHandle ) return; 00047 fclose(mpHandle); 00048 } 00049 00050 void MpegAudioStream::PrepareReading() 00051 { 00052 mpHandle = fopen( mName.c_str(), "rb"); 00053 00054 if ( !mpHandle ) 00055 { 00056 std::string msgString = "Could not open "; 00057 msgString += mName; 00058 msgString += " for reading!"; 00059 00060 CLAM_ASSERT( false, msgString.c_str() ); 00061 } 00062 00063 mBitstream.Init( mpHandle ); 00064 00065 mSamplesDecoded = 0; 00066 mFramePosition = 0; 00067 _mp3Frame = 0; 00068 } 00069 00070 void MpegAudioStream::PrepareWriting() 00071 { 00072 CLAM_ASSERT( false, "CLAM does not encode Mpeg Audio!!!"); 00073 } 00074 00075 void MpegAudioStream::Dispose() 00076 { 00077 mBitstream.Finish(); 00078 } 00079 00080 void MpegAudioStream::DiskToMemoryTransfer() 00081 { 00082 unsigned nFrames = mInterleavedData.size()/mChannels; 00083 while( mDecodeBuffer[0].size() < nFrames 00084 && mBitstream.NextFrame() ) 00085 { 00086 unsigned long filePos = mBitstream.CurrentFrameFileOffset(); 00087 if (_mp3Frame>=_seekCache.size()) 00088 _seekCache.push_back(filePos); 00089 else 00090 { 00091 /* 00092 std::cout 00093 << "Mp3 frame " 00094 << mFramePosition << " " 00095 << _mp3Frame << " R:" 00096 << filePos << " E:" 00097 << _seekCache[_mp3Frame] << " R-E:" 00098 << int(filePos)-int(_seekCache[_mp3Frame]) 00099 << std::endl; 00100 */ 00101 CLAM_WARNING(filePos==_seekCache[_mp3Frame], 00102 "MP3 indexing not matching"); 00103 } 00104 mBitstream.SynthesizeCurrent(); 00105 00106 CLAM_ASSERT( mChannels == MAD_NCHANNELS( &mBitstream.CurrentFrame().header ), 00107 "MpegAudioStream: A frame had not the expected channels." ); 00108 CLAM_ASSERT( mChannels == mBitstream.CurrentSynthesis().pcm.channels, 00109 "MpegAudioStream: Synthesis result had not the expected number of channels" ); 00110 00111 TSize samplesDecodedThisTime = mBitstream.CurrentSynthesis().pcm.length; 00112 for(unsigned i = 0; i < mChannels; i++ ) 00113 { 00114 mad_fixed_t* channelData = mBitstream.CurrentSynthesis().pcm.samples[i]; 00115 mDecodeBuffer[i].insert( mDecodeBuffer[i].end(), 00116 channelData, 00117 channelData + samplesDecodedThisTime ); 00118 } 00119 mSamplesDecoded += samplesDecodedThisTime; 00120 _mp3Frame++; 00121 } 00122 00123 mFramesLastRead = mDecodeBuffer[0].size(); 00124 mEOFReached = mBitstream.EOS() && mDecodeBuffer[0].empty(); 00125 00126 if (mDecodeBuffer[0].empty()) return; 00127 00128 for (unsigned i = 0; i < mChannels; i++ ) 00129 { 00130 if ( mDecodeBuffer[i].size() < nFrames ) 00131 { 00132 mDecodeBuffer[i].insert( 00133 mDecodeBuffer[i].end(), 00134 nFrames - mDecodeBuffer[i].size(), 00135 mad_fixed_t(0) ); 00136 } 00137 } 00138 ConsumeDecodedSamples(); 00139 } 00140 00141 void MpegAudioStream::ConsumeDecodedSamples() 00142 { 00143 unsigned nFrames = mInterleavedData.size()/mChannels; 00144 for (unsigned i = 0; i < mChannels; i++ ) 00145 { 00146 unsigned currOffset = 0; 00147 for ( std::deque<mad_fixed_t>::iterator j = mDecodeBuffer[i].begin(); 00148 currOffset < mInterleavedData.size(); 00149 j++, currOffset+=mChannels ) 00150 { 00151 double sampleValue = mad_f_todouble(*j); 00152 00153 // :TODO: Finding a nicer way to clamp things 00154 // to the -1,1 could be necessary 00155 // clipping 00156 if ( sampleValue > 1.0 ) 00157 sampleValue = 1.0; 00158 else if ( sampleValue < -1.0 ) 00159 sampleValue = -1.0; 00160 00161 mInterleavedData[ currOffset + i ] = TData(sampleValue); 00162 } 00163 mDecodeBuffer[i].erase( mDecodeBuffer[i].begin(), 00164 mDecodeBuffer[i].begin() + nFrames ); 00165 } 00166 mFramePosition += nFrames; 00167 } 00168 00169 void MpegAudioStream::MemoryToDiskTransfer() 00170 { 00171 CLAM_ASSERT( false, "CLAM does not encode Mpeg Audio!!!"); 00172 } 00173 00174 void MpegAudioStream::SeekTo(unsigned long framePosition) 00175 { 00176 // Warning: two 'frames' here, mp3's and AudioStream's (items*channels) 00177 if (framePosition==mFramePosition) return; 00178 unsigned mp3FrameSize = 32*MAD_NSBSAMPLES(&mBitstream.CurrentFrame().header); 00179 unsigned targetMp3Frame = framePosition/mp3FrameSize; 00180 std::cout << "targetMp3Frame: " << targetMp3Frame << std::endl; 00181 // TODO: Jumps beyond the last played frame are too expensive to be frame accurate 00182 unsigned maxForwarJump = _seekCache.size()+100; 00183 if (targetMp3Frame>maxForwarJump) targetMp3Frame=maxForwarJump; 00184 if (targetMp3Frame>=_seekCache.size()) 00185 { 00186 // Construct the index beyond current limits, til the target frame 00187 fseek(mpHandle, _seekCache[_seekCache.size()-2], SEEK_SET); 00188 mBitstream.Init(); 00189 for (unsigned mp3Frame=_seekCache.size(); 00190 mp3Frame<=targetMp3Frame; mp3Frame++) 00191 { 00192 if (not mBitstream.NextFrame()) return; 00193 unsigned long filePos = mBitstream.CurrentFrameFileOffset(); 00194 /* 00195 std::cout << "fwd " 00196 << _seekCache.back() << " " 00197 << filePos << " " 00198 << int(filePos)-_seekCache.back() << std::endl; 00199 */ 00200 if (filePos<=_seekCache.back()) continue; // filtering already done 00201 _seekCache.push_back(filePos); 00202 } 00203 } 00204 unsigned skip = targetMp3Frame>4?3:0; 00205 unsigned jumpingFrame = targetMp3Frame-skip; 00206 std::cout << "jumpingFrame:" << jumpingFrame << std::endl; 00207 fseek(mpHandle, _seekCache[jumpingFrame], SEEK_SET); 00208 mBitstream.Init(); 00209 _mp3Frame = targetMp3Frame; 00210 // TODO: Because the already buffered bins this is not true 00211 mFramePosition = mp3FrameSize * _mp3Frame; 00212 if (targetMp3Frame == 0) return; 00213 unsigned long previousFrameFilePos = _seekCache[targetMp3Frame-1]; 00214 while (true) 00215 { 00216 mBitstream.NextFrame(); 00217 unsigned long filePos = mBitstream.CurrentFrameFileOffset(); 00218 /* 00219 std::cout << "seek " 00220 << filePos << " " 00221 << previousFrameFilePos << std::endl; 00222 */ 00223 if (filePos >= previousFrameFilePos) break; 00224 } 00225 mBitstream.SynthesizeCurrent(); 00226 00227 unsigned long filePos = mBitstream.CurrentFrameFileOffset(); 00228 /* 00229 std::cout << "Jump n target: " 00230 << _mp3Frame << " " 00231 << targetMp3Frame << " " 00232 << filePos << " " 00233 << _seekCache[targetMp3Frame-1] 00234 << std::endl; 00235 */ 00236 // TODO: Sample accurate seek (now it is frame accurate) 00237 /* 00238 CLAM_ASSERT(_seekCache[targetMp3Frame-1]==filePos, 00239 "File postions don't match"); 00240 CLAM_ASSERT(_mp3Frame==targetMp3Frame, "Seek mp3 frames don't match"); 00241 // We should synthesize the previous frame to the one we want. 00242 */ } 00243 } 00244 00245 } 00246
1.7.6.1