|
CLAM-Development
1.3
|
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 ResizePorts(0); 00062 } 00063 00064 const char* MultiChannelAudioFileReader::GetClassName() const 00065 { 00066 return "MultiChannelAudioFileReader"; 00067 } 00068 00069 bool MultiChannelAudioFileReader::ModifiesPortsAndControlsAtConfiguration() 00070 { 00071 return true; 00072 } 00073 00074 const ProcessingConfig& MultiChannelAudioFileReader::GetConfig() const 00075 { 00076 return mConfig; 00077 } 00078 00079 //TODO remove Do() and Do(vector<Audio>) duplication 00080 bool MultiChannelAudioFileReader::Do( std::vector<Audio>& outputs ) 00081 { 00082 typedef std::vector<Audio> OutputVec; 00083 00084 if ( !AbleToExecute() ) 00085 return false; 00086 00087 // Check all outputs sizes 00088 bool allOutputsSameSize = true; 00089 00090 TSize sizeTmp = 0; 00091 00092 // MRJ: We have to keep internally references to 00093 // the Audio objects yield by Flow Control, since 00094 // the GetData operation not just returns a reference 00095 // to writable/readable data, but also performs 00096 // several checks ( as well as advancing reading/writing 00097 // zones, etc. ) 00098 // TODO: update this code, because GetData doesn't modifies state anymore 00099 00100 sizeTmp = outputs[0].GetSize(); 00101 00102 for( OutputVec::iterator i = outputs.begin(); 00103 i!= outputs.end(); i++ ) 00104 { 00105 allOutputsSameSize &= ( sizeTmp == i->GetSize() ); 00106 } 00107 00108 00109 CLAM_ASSERT( allOutputsSameSize, "Outputs sizes differ!" ); 00110 00111 // build the samples matrix 00112 int j = 0; 00113 for ( OutputVec::iterator i = outputs.begin(); i != outputs.end(); i++ ) 00114 mSamplesMatrix[ j++ ] = (*i).GetBuffer().GetPtr(); 00115 00116 // read the data 00117 if ( !mEOFReached && !mIsPaused ) 00118 { 00119 mEOFReached = mNativeStream->ReadData( 00120 &mSelectedChannels[0], 00121 mSelectedChannels.size(), 00122 &mSamplesMatrix[0], 00123 sizeTmp ); 00124 } 00125 else 00126 { 00127 if ( mEOFReached ) 00128 mCurrentBeginTime = GetHeader().GetLength()/1000; 00129 for (unsigned 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 = _outputs.begin(); 00171 i!= _outputs.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( 00199 &mSelectedChannels[0], 00200 mSelectedChannels.size(), 00201 &mSamplesMatrix[0], 00202 sizeTmp ); 00203 } 00204 else 00205 { 00206 if ( mEOFReached ) 00207 mCurrentBeginTime = GetHeader().GetLength()/1000; 00208 for (unsigned i = 0; i != mSamplesMatrix.size(); i++) 00209 { 00210 memset ((void *)mSamplesMatrix[i], 0, sizeTmp*sizeof(TData)); 00211 } 00212 } 00213 00214 // Audio 'simple meta-data' setup 00215 00216 for ( OutRefsVector::iterator i = outRefs.begin(); 00217 i != outRefs.end(); i++ ) 00218 { 00219 (*i)->SetSampleRate( mAudioFile.GetHeader().GetSampleRate() ); 00220 (*i)->SetBeginTime( mCurrentBeginTime ); 00221 } 00222 00223 if (!mEOFReached && !mIsPaused) 00224 { 00225 mDeltaTime = TData(sizeTmp)/mAudioFile.GetHeader().GetSampleRate()*1000; 00226 mCurrentBeginTime += mDeltaTime; 00227 } 00228 00229 mTimeOutput.SendControl( mCurrentBeginTime ); 00230 00231 for ( OutputVector::iterator i = _outputs.begin(); 00232 i!= _outputs.end(); i++ ) 00233 { 00234 (*i)->Produce(); 00235 } 00236 00237 return !mEOFReached; 00238 } 00239 00240 bool MultiChannelAudioFileReader::ConcreteConfigure( const ProcessingConfig& cfgObj ) 00241 { 00242 CopyAsConcreteConfig( mConfig, cfgObj ); 00243 00244 if ( !mConfig.HasSourceFile() ) 00245 { 00246 AddConfigErrorMessage("No 'source file' was specified in the configuration!"); 00247 return false; 00248 } 00249 00250 if ( mConfig.GetSourceFile() == "" ) 00251 { 00252 AddConfigErrorMessage("No file selected"); 00253 return false; 00254 } 00255 00256 mAudioFile.OpenExisting(mConfig.GetSourceFile()); 00257 if ( !mAudioFile.IsReadable() ) 00258 { 00259 AddConfigErrorMessage("The audio file '" + mConfig.GetSourceFile() + "' could not be opened!"); 00260 return false; 00261 } 00262 00263 if ( !mConfig.HasSelectedChannels() ) 00264 { 00265 mSelectedChannels.resize( mAudioFile.GetHeader().GetChannels() ); 00266 00267 ResizePorts(mSelectedChannels.size()); 00268 00269 for (unsigned i = 0; i < mSelectedChannels.size(); i++ ) 00270 { 00271 mSelectedChannels[ i ] = i; 00272 } 00273 00274 mSamplesMatrix.resize( mSelectedChannels.size() ); 00275 00276 } 00277 else 00278 { 00279 // Checking selected channels validity 00280 const Array<TIndex> & selectedChannels = mConfig.GetSelectedChannels(); 00281 mSelectedChannels.assign( 00282 selectedChannels.GetPtr(), 00283 selectedChannels.GetPtr()+selectedChannels.Size()); 00284 00285 if ( mSelectedChannels.size() != mAudioFile.GetHeader().GetChannels() ) 00286 { 00287 return AddConfigErrorMessage( 00288 "The configuration asked for more channels than the audio file has."); 00289 } 00290 00291 int maxChannels = mAudioFile.GetHeader().GetChannels(); 00292 00293 for (unsigned i = 0; i < mSelectedChannels.size(); i++ ) 00294 if ( mSelectedChannels[i] < 0 00295 || mSelectedChannels[i] >= maxChannels ) 00296 { 00297 return AddConfigErrorMessage( 00298 "Invalid channel index in configuration!"); 00299 } 00300 00301 ResizePorts(0); 00302 00303 for (unsigned i = 0; i < mSelectedChannels.size(); i++ ) 00304 { 00305 std::stringstream sstr; 00306 sstr << mSelectedChannels[i]; 00307 00308 _outputs.push_back( 00309 new AudioOutPort( "Channel #" + sstr.str(), this ) 00310 ); 00311 } 00312 00313 mSamplesMatrix.resize( maxChannels ); 00314 } 00315 00316 mNativeStream = mAudioFile.GetStream(); 00317 00318 if (not mNativeStream ) 00319 { 00320 return AddConfigErrorMessage("Could not get a valid audio file stream!"); 00321 } 00322 00323 return true; 00324 } 00325 00326 bool MultiChannelAudioFileReader::ConcreteStart() 00327 { 00328 if (mNativeStream == NULL) 00329 mNativeStream = mAudioFile.GetStream(); 00330 mNativeStream->PrepareReading(); 00331 mCurrentBeginTime = 0.0; 00332 mEOFReached = false; 00333 mIsPaused = false; 00334 00335 return true; 00336 } 00337 00338 bool MultiChannelAudioFileReader::ConcreteStop() 00339 { 00340 mNativeStream->Dispose(); 00341 delete mNativeStream; 00342 mNativeStream = NULL; 00343 00344 return true; 00345 } 00346 void MultiChannelAudioFileReader::ResizePorts(unsigned nPorts) 00347 { 00348 const std::string nameBase = "Channel #"; 00349 for (unsigned i=_outputs.size(); i<nPorts; i++) 00350 { 00351 std::ostringstream nameStream; 00352 nameStream << nameBase << i; 00353 AudioOutPort * port = new AudioOutPort( nameStream.str(), this); 00354 _outputs.push_back( port ); 00355 } 00356 for (unsigned i=nPorts; i<_outputs.size(); i++) 00357 delete _outputs[i]; 00358 _outputs.resize(nPorts); 00359 /* 00360 const unsigned portSize = BackendBufferSize(); 00361 for (unsigned i=0; i<_outputs.size(); i++) 00362 { 00363 _outputs[i]->SetSize( portSize ); 00364 _outputs[i]->SetHop( portSize ); 00365 } 00366 */ 00367 } 00368 00369 } 00370
1.7.6.1