CLAM-Development
1.1
|
00001 /* 00002 * Copyright (c) 2001-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 "MultiChannelAudioFileReader.hxx" 00023 #include "AudioCodecs_Stream.hxx" 00024 #include "AudioOutPort.hxx" 00025 #include "ProcessingFactory.hxx" 00026 00027 00028 namespace CLAM 00029 { 00030 00031 namespace Hidden 00032 { 00033 static const char * metadata[] = { 00034 "key", "MultiChannelAudioFileReader", 00035 "category", "Audio File I/O", 00036 "description", "MultiChannelAudioFileReader", 00037 0 00038 }; 00039 static FactoryRegistrator<ProcessingFactory, MultiChannelAudioFileReader> reg = metadata; 00040 } 00041 00042 00043 MultiChannelAudioFileReader::MultiChannelAudioFileReader() 00044 : mTimeOutput( "Current Time Position", this) 00045 , mNativeStream( NULL ) 00046 { 00047 Configure(MultiChannelAudioFileReaderConfig()); 00048 } 00049 00050 MultiChannelAudioFileReader::MultiChannelAudioFileReader( const ProcessingConfig& cfg ) 00051 : mTimeOutput( "Current Time Position", this) 00052 , mNativeStream( NULL ) 00053 { 00054 Configure( cfg ); 00055 } 00056 00057 MultiChannelAudioFileReader::~MultiChannelAudioFileReader() 00058 { 00059 if ( mNativeStream ) 00060 delete mNativeStream; 00061 00062 DestroyOldOutputs(); 00063 } 00064 00065 const char* MultiChannelAudioFileReader::GetClassName() const 00066 { 00067 return "MultiChannelAudioFileReader"; 00068 } 00069 00070 bool MultiChannelAudioFileReader::ModifiesPortsAndControlsAtConfiguration() 00071 { 00072 return true; 00073 } 00074 00075 const ProcessingConfig& MultiChannelAudioFileReader::GetConfig() const 00076 { 00077 return mConfig; 00078 } 00079 00080 //TODO remove Do() and Do(vector<Audio>) duplication 00081 bool MultiChannelAudioFileReader::Do( std::vector<Audio>& outputs ) 00082 { 00083 typedef std::vector<Audio> OutputVec; 00084 00085 if ( !AbleToExecute() ) 00086 return false; 00087 00088 // Check all outputs sizes 00089 bool allOutputsSameSize = true; 00090 00091 TSize sizeTmp = 0; 00092 00093 // MRJ: We have to keep internally references to 00094 // the Audio objects yield by Flow Control, since 00095 // the GetData operation not just returns a reference 00096 // to writable/readable data, but also performs 00097 // several checks ( as well as advancing reading/writing 00098 // zones, etc. ) 00099 // TODO: update this code, because GetData doesn't modifies state anymore 00100 00101 sizeTmp = outputs[0].GetSize(); 00102 00103 for( OutputVec::iterator i = outputs.begin(); 00104 i!= outputs.end(); i++ ) 00105 { 00106 allOutputsSameSize &= ( sizeTmp == i->GetSize() ); 00107 } 00108 00109 00110 CLAM_ASSERT( allOutputsSameSize, "Outputs sizes differ!" ); 00111 00112 // build the samples matrix 00113 int j = 0; 00114 for ( OutputVec::iterator i = outputs.begin(); i != outputs.end(); i++ ) 00115 mSamplesMatrix[ j++ ] = (*i).GetBuffer().GetPtr(); 00116 00117 // read the data 00118 if ( !mEOFReached && !mIsPaused ) 00119 { 00120 mEOFReached = mNativeStream->ReadData( mSelectedChannels.GetPtr(), 00121 mSelectedChannels.Size(), 00122 mSamplesMatrix.GetPtr(), 00123 sizeTmp ); 00124 } 00125 else 00126 { 00127 if ( mEOFReached ) 00128 mCurrentBeginTime = GetHeader().GetLength()/1000; 00129 for ( int i = 0; i != mSamplesMatrix.Size(); i++ ) 00130 memset ((void *)mSamplesMatrix[i], 0, sizeTmp*sizeof(TData)); 00131 } 00132 // Audio 'simple meta-data' setup 00133 for ( OutputVec::iterator i = outputs.begin(); 00134 i != outputs.end(); i++ ) 00135 { 00136 (*i).SetSampleRate( mAudioFile.GetHeader().GetSampleRate() ); 00137 (*i).SetBeginTime( mCurrentBeginTime ); 00138 } 00139 00140 00141 if ( !mEOFReached && !mIsPaused ) 00142 { 00143 mDeltaTime = TData(sizeTmp)/mAudioFile.GetHeader().GetSampleRate()*1000; 00144 mCurrentBeginTime += mDeltaTime; 00145 } 00146 mTimeOutput.SendControl( mCurrentBeginTime ); 00147 00148 return !mEOFReached; 00149 } 00150 //TODO remove Do() and Do(vector<Audio>) duplication 00151 bool MultiChannelAudioFileReader::Do() 00152 { 00153 if ( !AbleToExecute() ) 00154 return false; 00155 00156 // Check all outputs sizes 00157 bool allOutputsSameSize = true; 00158 00159 TSize sizeTmp = 0; 00160 00161 // MRJ: We have to keep internally references to 00162 // the Audio objects yield by Flow Control, since 00163 // the GetData operation not just returns a reference 00164 // to writable/readable data, but also performs 00165 // several checks ( as well as advancing reading/writing 00166 // zones, etc. ) 00167 // TODO: update this code, because GetData doesn't modifies state anymore 00168 OutRefsVector outRefs; 00169 00170 for ( OutputVector::iterator i = mOutputs.begin(); 00171 i!= mOutputs.end(); 00172 i++ ) 00173 outRefs.push_back( &((*i)->GetAudio()) ); 00174 00175 00176 sizeTmp = outRefs[0]->GetSize(); 00177 00178 for( OutRefsVector::iterator i = outRefs.begin(); 00179 i!= outRefs.end(); i++ ) 00180 { 00181 allOutputsSameSize = ( sizeTmp == (*i)->GetSize() ); 00182 } 00183 00184 00185 CLAM_ASSERT( allOutputsSameSize, "Outputs sizes differ!" ); 00186 00187 // build the samples matrix 00188 00189 int j = 0; 00190 for ( OutRefsVector::iterator i = outRefs.begin(); 00191 i != outRefs.end(); i++ ) 00192 mSamplesMatrix[ j++ ] = (*i)->GetBuffer().GetPtr(); 00193 00194 // read the data 00195 00196 if ( !mEOFReached && !mIsPaused ) 00197 { 00198 mEOFReached = mNativeStream->ReadData( mSelectedChannels.GetPtr(), 00199 mSelectedChannels.Size(), 00200 mSamplesMatrix.GetPtr(), 00201 sizeTmp ); 00202 } 00203 else 00204 { 00205 if ( mEOFReached ) 00206 mCurrentBeginTime = GetHeader().GetLength()/1000; 00207 for ( int i = 0; i != mSamplesMatrix.Size(); i++) 00208 { 00209 memset ((void *)mSamplesMatrix[i], 0, sizeTmp*sizeof(TData)); 00210 } 00211 } 00212 00213 // Audio 'simple meta-data' setup 00214 00215 for ( OutRefsVector::iterator i = outRefs.begin(); 00216 i != outRefs.end(); i++ ) 00217 { 00218 (*i)->SetSampleRate( mAudioFile.GetHeader().GetSampleRate() ); 00219 (*i)->SetBeginTime( mCurrentBeginTime ); 00220 } 00221 00222 if (!mEOFReached && !mIsPaused) 00223 { 00224 mDeltaTime = TData(sizeTmp)/mAudioFile.GetHeader().GetSampleRate()*1000; 00225 mCurrentBeginTime += mDeltaTime; 00226 } 00227 00228 mTimeOutput.SendControl( mCurrentBeginTime ); 00229 00230 for ( OutputVector::iterator i = mOutputs.begin(); 00231 i!= mOutputs.end(); i++ ) 00232 { 00233 (*i)->Produce(); 00234 } 00235 00236 return !mEOFReached; 00237 } 00238 00239 bool MultiChannelAudioFileReader::ConcreteConfigure( const ProcessingConfig& cfgObj ) 00240 { 00241 CopyAsConcreteConfig( mConfig, cfgObj ); 00242 00243 if ( !mConfig.HasSourceFile() ) 00244 { 00245 AddConfigErrorMessage("No 'source file' was specified in the configuration!"); 00246 return false; 00247 } 00248 00249 if ( mConfig.GetSourceFile() == "" ) 00250 { 00251 AddConfigErrorMessage("No file selected"); 00252 return false; 00253 } 00254 00255 mAudioFile.OpenExisting(mConfig.GetSourceFile()); 00256 if ( !mAudioFile.IsReadable() ) 00257 { 00258 AddConfigErrorMessage("The audio file '" + mConfig.GetSourceFile() + "' could not be opened!"); 00259 return false; 00260 } 00261 00262 if ( !mConfig.HasSelectedChannels() ) 00263 { 00264 mSelectedChannels.Resize( mAudioFile.GetHeader().GetChannels() ); 00265 mSelectedChannels.SetSize( mAudioFile.GetHeader().GetChannels() ); 00266 00267 DestroyOldOutputs(); 00268 00269 for ( int i = 0; i < mSelectedChannels.Size(); i++ ) 00270 { 00271 std::stringstream sstr; 00272 sstr << i; 00273 00274 mOutputs.push_back( 00275 new AudioOutPort( "Channel #" + sstr.str(), this ) 00276 ); 00277 00278 mSelectedChannels[ i ] = i; 00279 } 00280 00281 mSamplesMatrix.Resize( mSelectedChannels.Size() ); 00282 mSamplesMatrix.SetSize( mSelectedChannels.Size() ); 00283 00284 } 00285 else 00286 { 00287 // Checking selected channels validity 00288 mSelectedChannels = mConfig.GetSelectedChannels(); 00289 00290 if ( mSelectedChannels.Size() != mAudioFile.GetHeader().GetChannels() ) 00291 { 00292 AddConfigErrorMessage("The configuration asked for more channels than the audio file has."); 00293 return false; 00294 } 00295 00296 int maxChannels = mAudioFile.GetHeader().GetChannels(); 00297 00298 for ( int i = 0; i < mSelectedChannels.Size(); i++ ) 00299 if ( mSelectedChannels[i] < 0 00300 || mSelectedChannels[i] >= maxChannels ) 00301 { 00302 AddConfigErrorMessage("Invalid channel index in configuration!"); 00303 return false; 00304 } 00305 00306 00307 DestroyOldOutputs(); 00308 00309 for ( int i = 0; i < mSelectedChannels.Size(); i++ ) 00310 { 00311 std::stringstream sstr; 00312 sstr << mSelectedChannels[i]; 00313 00314 mOutputs.push_back( 00315 new AudioOutPort( "Channel #" + sstr.str(), this ) 00316 ); 00317 } 00318 00319 mSamplesMatrix.Resize( maxChannels ); 00320 mSamplesMatrix.SetSize( maxChannels ); 00321 } 00322 00323 mNativeStream = mAudioFile.GetStream(); 00324 00325 if (!mNativeStream ) 00326 { 00327 AddConfigErrorMessage("Could not get a valid audio file stream!"); 00328 return false; 00329 } 00330 00331 return true; 00332 } 00333 00334 void MultiChannelAudioFileReader::DestroyOldOutputs() 00335 { 00336 for( OutputVector::iterator i = mOutputs.begin(); 00337 i != mOutputs.end(); i++ ) 00338 if( *i ) delete *i; 00339 00340 mOutputs.clear(); 00341 GetOutPorts().Clear(); 00342 } 00343 00344 bool MultiChannelAudioFileReader::ConcreteStart() 00345 { 00346 if (mNativeStream == NULL) 00347 mNativeStream = mAudioFile.GetStream(); 00348 mNativeStream->PrepareReading(); 00349 mCurrentBeginTime = 0.0; 00350 mEOFReached = false; 00351 mIsPaused = false; 00352 00353 return true; 00354 } 00355 00356 bool MultiChannelAudioFileReader::ConcreteStop() 00357 { 00358 mNativeStream->Dispose(); 00359 delete mNativeStream; 00360 mNativeStream = NULL; 00361 00362 return true; 00363 } 00364 } 00365