MultiChannelAudioFileReader.cxx

Go to the documentation of this file.
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 
Generated by  doxygen 1.6.3