Marsyas  0.6.0-alpha
/usr/src/RPM/BUILD/marsyas-0.6.0/src/marsyas/marsystems/SoundFileSource.cpp
Go to the documentation of this file.
00001 /*
00002 ** Copyright (C) 1998-2010 George Tzanetakis <gtzan@cs.uvic.ca>
00003 **
00004 ** This program is free software; you can redistribute it and/or modify
00005 ** it under the terms of the GNU General Public License as published by
00006 ** the Free Software Foundation; either version 2 of the License, or
00007 ** (at your option) any later version.
00008 **
00009 ** This program is distributed in the hope that it will be useful,
00010 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 ** GNU General Public License for more details.
00013 **
00014 ** You should have received a copy of the GNU General Public License
00015 ** along with this program; if not, write to the Free Software
00016 ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00017 */
00018 
00019 #include "../common_source.h"
00020 
00021 #ifdef MARSYAS_MAD
00022 #include "MP3FileSource.h"
00023 #endif
00024 
00025 #ifdef MARSYAS_VORBIS
00026 #include "OggFileSource.h"
00027 #endif
00028 
00029 #ifdef MARSYAS_GSTREAMER
00030 #include "GStreamerSource.h"
00031 #endif
00032 
00033 
00034 #include "SoundFileSource.h"
00035 #include <string>
00036 #include <cctype>
00037 #include <algorithm>
00038 
00039 
00040 //#define MTLB_DBG_LOG
00041 
00042 
00043 using namespace std;
00044 using namespace Marsyas;
00045 
00046 SoundFileSource::SoundFileSource(mrs_string name):
00047   MarSystem("SoundFileSource",name),
00048   backend_ (0),
00049   updateCurrDuration(false)
00050 {
00051   addControls();
00052 }
00053 
00054 SoundFileSource::~SoundFileSource()
00055 {
00056   delete backend_;
00057 }
00058 
00059 MarSystem*
00060 SoundFileSource::clone() const
00061 {
00062   return new SoundFileSource(*this);
00063 }
00064 
00065 SoundFileSource::SoundFileSource(const SoundFileSource& a):
00066   MarSystem(a),
00067   backend_ (0),
00068   updateCurrDuration(false)
00069 {
00070   ctrl_pos_ = getctrl("mrs_natural/pos");
00071   ctrl_loop_ = getctrl("mrs_natural/loopPos");
00072   ctrl_hasData_ = getctrl("mrs_bool/hasData");
00073   ctrl_lastTickWithData_ = getctrl("mrs_bool/lastTickWithData");
00074   ctrl_mute_ = getctrl("mrs_bool/mute");
00075   ctrl_advance_ = getctrl("mrs_natural/advance");
00076   ctrl_filename_ = getctrl("mrs_string/filename");
00077   ctrl_currentlyPlaying_ = getctrl("mrs_string/currentlyPlaying");
00078   ctrl_previouslyPlaying_ = getctrl("mrs_string/previouslyPlaying");
00079   ctrl_regression_ = getctrl("mrs_bool/regression");
00080   ctrl_currentLabel_ = getctrl("mrs_real/currentLabel");
00081   ctrl_previousLabel_ = getctrl("mrs_real/previousLabel");
00082   ctrl_labelNames_ = getctrl("mrs_string/labelNames");
00083   ctrl_nLabels_ = getctrl("mrs_natural/nLabels");
00084   ctrl_currentHasData_ = getctrl("mrs_bool/currentHasData");
00085   ctrl_currentLastTickWithData_ = getctrl("mrs_bool/currentLastTickWithData");
00086   ctrl_currentCollectionNewFile_ = getctrl("mrs_bool/currentCollectionNewFile");
00087   ctrl_startStable_ = getctrl("mrs_bool/startStable");
00088 
00089   //ctrl_rewindToPos_ = getctrl("mrs_natural/moveToSamplePos");
00090 }
00091 
00092 void
00093 SoundFileSource::addControls()
00094 {
00095   addctrl("mrs_bool/hasData", true, ctrl_hasData_);
00096 
00097   addctrl("mrs_bool/lastTickWithData", false, ctrl_lastTickWithData_);
00098 
00099   addctrl("mrs_natural/pos", 0, ctrl_pos_);
00100   setctrlState("mrs_natural/pos", true);
00101 
00102   addctrl("mrs_natural/loopPos", 0, ctrl_loop_);
00103   setctrlState("mrs_natural/loopPos", true);
00104 
00105   addctrl("mrs_string/filename", string(), ctrl_filename_);
00106   setctrlState("mrs_string/filename", true);
00107 
00108   addctrl("mrs_string/allfilenames", ",");
00109   setctrlState("mrs_string/allfilenames",true);
00110 
00111   addctrl("mrs_natural/numFiles", 0);
00112 
00113   addctrl("mrs_natural/size", 0);
00114 
00115   addctrl("mrs_real/frequency", (mrs_real)0.0);
00116   setctrlState("mrs_real/frequency",true);
00117 
00118   addctrl("mrs_bool/noteon", false);
00119   setctrlState("mrs_bool/noteon", true);
00120 
00121   addctrl("mrs_real/repetitions", 1.0);
00122   setctrlState("mrs_real/repetitions", true);
00123 
00124   addctrl("mrs_real/duration", -1.0);
00125   setctrlState("mrs_real/duration", true);
00126 
00127   addctrl("mrs_natural/advance", 0, ctrl_advance_);
00128   setctrlState("mrs_natural/advance", true);
00129 
00130   addctrl("mrs_bool/shuffle", false);
00131   setctrlState("mrs_bool/shuffle", true);
00132 
00133   addctrl("mrs_natural/cindex", 0);
00134   setctrlState("mrs_natural/cindex", true);
00135 
00136   addctrl("mrs_string/currentlyPlaying", "daufile", ctrl_currentlyPlaying_);
00137   addctrl("mrs_string/previouslyPlaying", "daufile", ctrl_previouslyPlaying_);
00138   addctrl("mrs_bool/regression", false, ctrl_regression_);
00139   addctrl("mrs_real/currentLabel", 0.0, ctrl_currentLabel_);
00140   addctrl("mrs_real/previousLabel", 0.0, ctrl_previousLabel_);
00141   addctrl("mrs_natural/nLabels", 0, ctrl_nLabels_);
00142   addctrl("mrs_string/labelNames", ",", ctrl_labelNames_);
00143   ctrl_mute_ = getctrl("mrs_bool/mute");
00144 
00145   addctrl("mrs_real/fullDuration", 0.);
00146   setctrlState("mrs_real/fullDuration", true);
00147 
00148   addctrl("mrs_natural/moveToSamplePos", 0);
00149   setctrlState("mrs_natural/moveToSamplePos", true);
00150 
00151   addctrl("mrs_bool/currentHasData", true, ctrl_currentHasData_);
00152   addctrl("mrs_bool/currentLastTickWithData", false, ctrl_currentLastTickWithData_);
00153   addctrl("mrs_bool/currentCollectionNewFile", true, ctrl_currentCollectionNewFile_);
00154 
00155 
00156   addctrl("mrs_bool/startStable", true, ctrl_startStable_);
00157   setctrlState("mrs_bool/startStable", true);
00158 }
00159 
00160 void
00161 SoundFileSource::myUpdate(MarControlPtr sender)
00162 {
00163   MRSDIAG("SoundFileSource::myUpdate");
00164 
00165   // Do nothing on output-only controls
00166   if (sender() == ctrl_hasData_())
00167   {
00168     return;
00169   }
00170 
00171   ctrl_inObsNames_->setValue("audio,", NOUPDATE);
00172 
00173   const string &new_filename = getctrl("mrs_string/filename")->to<mrs_string>();
00174 
00175   if (new_filename != filename_)
00176   {
00177     filename_ = new_filename;
00178 
00179     if (updateBackend())
00180     {
00181       getHeader();
00182       filename_ = ctrl_filename_->to<mrs_string>();
00183       ctrl_currentlyPlaying_->setValue(backend_->getctrl("mrs_string/currentlyPlaying"));
00184       ctrl_previouslyPlaying_->setValue(backend_->getctrl("mrs_string/previouslyPlaying"));
00185       ctrl_currentLabel_->setValue(backend_->getctrl("mrs_real/currentLabel"));
00186       ctrl_previousLabel_->setValue(backend_->getctrl("mrs_real/previousLabel"));
00187 
00188       ctrl_labelNames_->setValue(backend_->getctrl("mrs_string/labelNames"));
00189       ctrl_nLabels_->setValue(backend_->getctrl("mrs_natural/nLabels"));
00190       ctrl_onObservations_->setValue(backend_->ctrl_onObservations_, NOUPDATE);
00191 
00192       ostringstream oss;
00193       for (int ch = 0; ch < ctrl_onObservations_->to<mrs_natural>(); ch++)
00194       {
00195         oss << "AudioCh" << ch << ",";
00196       }
00197       ctrl_onObsNames_->setValue(oss.str(), NOUPDATE);
00198 
00199       ctrl_israte_->setValue(backend_->ctrl_israte_, NOUPDATE);
00200       ctrl_osrate_->setValue(backend_->ctrl_osrate_, NOUPDATE);
00201 
00202 
00203       if (backend_->getctrl("mrs_natural/size")->to<mrs_natural>() != 0)
00204       {
00205         ctrl_hasData_->setValue(true);
00206         backend_->hasData_ = true;
00207 
00208         ctrl_lastTickWithData_->setValue(false, NOUPDATE);
00209         backend_->lastTickWithData_ =false;
00210       }
00211     }
00212     else
00213     {
00214       ctrl_onObservations_->setValue(1, NOUPDATE);
00215       ctrl_israte_->setValue((mrs_real)22050.0, NOUPDATE); //[!] why not set to 0 or some invalid value?
00216       ctrl_hasData_->setValue(false);
00217       ctrl_lastTickWithData_->setValue(true, NOUPDATE);
00218     }
00219 
00220   } else if(!sender.isInvalid()) {
00221 
00222     // Allow the user to jump to any given sample position. It appears to
00223     // work across collections as well.
00224 
00225     mrs_string name = sender->getName();
00226     if(!name.compare("mrs_natural/moveToSamplePos")) {
00227 
00228       mrs_natural newPos = sender->to<mrs_natural>();
00229       //cout << "Move to sample: " << newPos << endl;
00230 
00231       // getHeader() call seems to be the only way to
00232       // initialize the playback position.
00233       getHeader();
00234 
00235       ctrl_pos_->setValue(newPos, NOUPDATE);
00236 
00237       // from here you could run the common last section,
00238       // but this seems redundant, so for efficiency reasons we
00239       // return after making these (crucial) updates:
00240 
00241       backend_->setctrl("mrs_natural/pos", getctrl("mrs_natural/pos"));
00242       backend_->update();
00243       updControl("mrs_bool/hasData", backend_->hasData_);
00244       setctrl("mrs_bool/lastTickWithData", backend_->lastTickWithData_);
00245       return;
00246     }
00247   }
00248 
00249 
00250 
00251 
00252   if (backend_ != NULL)
00253   {
00254 
00255     //pass configuration to audio source object and update it
00256     backend_->ctrl_inSamples_->setValue(ctrl_inSamples_, NOUPDATE);
00257     backend_->ctrl_inObservations_->setValue(ctrl_inObservations_, NOUPDATE);
00258     backend_->ctrl_regression_->setValue(ctrl_regression_, NOUPDATE);
00259     backend_->setctrl("mrs_real/repetitions", getctrl("mrs_real/repetitions"));
00260     backend_->setctrl("mrs_real/duration", getctrl("mrs_real/duration"));
00261     backend_->setctrl("mrs_natural/advance", getctrl("mrs_natural/advance"));
00262     // src_->setctrl("mrs_natural/cindex", getctrl("mrs_natural/cindex"));
00263     backend_->setctrl("mrs_bool/shuffle", getctrl("mrs_bool/shuffle"));
00264     backend_->setctrl("mrs_bool/hasData", getctrl("mrs_bool/hasData"));
00265     backend_->setctrl("mrs_bool/lastTickWithData", getctrl("mrs_bool/lastTickWithData"));
00266     backend_->setctrl("mrs_natural/pos", getctrl("mrs_natural/pos"));
00267     backend_->pos_ = getctrl("mrs_natural/pos")->to<mrs_natural>();//[!]
00268     backend_->setctrl("mrs_natural/loopPos", getctrl("mrs_natural/loopPos"));
00269     backend_->rewindpos_ = getctrl("mrs_natural/loopPos")->to<mrs_natural>();//[!]
00270     backend_->update();
00271 
00272     //sync local controls with the controls from the audio source object
00273     ctrl_onSamples_->setValue(backend_->ctrl_onSamples_, NOUPDATE);
00274     ctrl_onObservations_->setValue(backend_->ctrl_onObservations_, NOUPDATE);
00275     ctrl_osrate_->setValue(backend_->ctrl_osrate_, NOUPDATE);
00276 
00277     setctrl("mrs_natural/pos", backend_->pos_);//[!]
00278     setctrl("mrs_natural/loopPos", backend_->rewindpos_);//[!]
00279     updControl("mrs_bool/hasData", backend_->hasData_);//[!]
00280     setctrl("mrs_bool/lastTickWithData", backend_->lastTickWithData_);
00281     setctrl("mrs_natural/size", backend_->getctrl("mrs_natural/size"));
00282     setctrl("mrs_real/repetitions", backend_->getctrl("mrs_real/repetitions"));
00283     setctrl("mrs_real/duration", backend_->getctrl("mrs_real/duration"));
00284 
00285     advance_ = ctrl_advance_->to<mrs_natural>();//?!?!!? [!][?]
00286     setctrl("mrs_natural/advance", backend_->getctrl("mrs_natural/advance"));
00287 
00288     setctrl("mrs_bool/shuffle", backend_->getctrl("mrs_bool/shuffle"));
00289     setctrl("mrs_natural/cindex", backend_->getctrl("mrs_natural/cindex"));
00290     setctrl("mrs_string/currentlyPlaying", backend_->getctrl("mrs_string/currentlyPlaying"));
00291     setctrl("mrs_string/previouslyPlaying", backend_->getctrl("mrs_string/previouslyPlaying"));
00292     setctrl("mrs_real/currentLabel", backend_->getctrl("mrs_real/currentLabel"));
00293     setctrl("mrs_real/previousLabel", backend_->getctrl("mrs_real/previousLabel"));
00294     setctrl("mrs_natural/nLabels", backend_->getctrl("mrs_natural/nLabels"));
00295     setctrl("mrs_string/labelNames", backend_->getctrl("mrs_string/labelNames"));
00296     setctrl("mrs_string/allfilenames", backend_->getctrl("mrs_string/allfilenames"));
00297     setctrl("mrs_natural/numFiles", backend_->getctrl("mrs_natural/numFiles"));
00298 
00299     if (backend_->getctrl("mrs_string/filetype")->to<mrs_string>() == "raw")
00300     {
00301       setctrl("mrs_real/frequency", backend_->getctrl("mrs_real/frequency"));
00302       setctrl("mrs_bool/noteon", backend_->getctrl("mrs_bool/noteon"));
00303     }
00304     else if (backend_->getctrl("mrs_string/filetype")->to<mrs_string>() == "mp3")
00305     {
00306       updateCurrDuration = true;
00307       //setctrl("mrs_real/fullDuration", src_->getctrl("mrs_real/fullDuration"));
00308       //std::cout<<"setting mrs/fullDuration to "<<src_->durFull_<<std::endl;
00309       //setctrl("mrs_real/fullDuration", src_->durFull_);
00310     }
00311 
00312   }
00313 
00314 }
00315 
00316 void SoundFileSource::clearBackend()
00317 {
00318   delete backend_;
00319   backend_ = 0;
00320   file_extension_.clear();
00321 }
00322 
00323 bool
00324 SoundFileSource::updateBackend()
00325 {
00326   if (filename_.empty())
00327   {
00328     clearBackend();
00329     return false;
00330   }
00331 
00332   // check if file exists
00333   bool file_exists;
00334   {
00335     FILE *file = fopen(filename_.c_str(), "rb");
00336     file_exists = file != 0;
00337     if (file)
00338       fclose(file);
00339   }
00340   if (!file_exists)
00341   {
00342     clearBackend();
00343     MRSWARN("SoundFileSource: Failed to open file for reading: " << filename_);
00344     return false;
00345   }
00346 
00347   mrs_string extension;
00348   {
00349     mrs_string::size_type pos = filename_.rfind(".", filename_.length());
00350     if (pos != mrs_string::npos)
00351     {
00352       extension = filename_.substr(pos);
00353       // need this to be lowercase for the checks below.
00354       std::transform(extension.begin(), extension.end(), extension.begin(), (int(*)(int))tolower);
00355     }
00356   }
00357 
00358   if (file_extension_ == extension)
00359     return true;
00360 
00361   file_extension_ = extension;
00362 
00363   clearBackend();
00364 
00365   if (extension == ".au")
00366   {
00367     backend_ = new AuFileSource(getName());
00368   }
00369   else if (extension == ".wav")
00370   {
00371     backend_ = new WavFileSource(getName());
00372   }
00373   else if (extension == ".raw")
00374   {
00375     backend_ = new RawFileSource(getName());
00376   }
00377   else if (extension == ".txt")
00378   {
00379     backend_ = new CollectionFileSource(getName());
00380   }
00381   else if (extension == ".mf")
00382   {
00383     backend_ = new CollectionFileSource(getName());
00384   }
00385 #ifdef MARSYAS_MAD
00386   else if (extension == ".mp3")
00387   {
00388     backend_ = new MP3FileSource(getName());
00389   }
00390 #endif
00391 #ifdef MARSYAS_VORBIS
00392   else if (extension == ".ogg")
00393   {
00394     backend_ = new OggFileSource(getName());
00395   }
00396 #endif
00397   else
00398 #ifdef MARSYAS_GSTREAMER
00399     // use GStreamer as a fallback
00400   {
00401     MRSDIAG("SoundFileSource is falling back to GStreamerSource\n");
00402     backend_ = new GStreamerSource(getName());
00403   }
00404 #else
00405   {
00406     MRSWARN("Unknown file extension: " << filename_);
00407     return false;
00408   }
00409 #endif
00410 
00411   return true;
00412 }
00413 
00414 void
00415 SoundFileSource::getHeader()
00416 {
00417   assert(!filename_.empty());
00418   assert(backend_ != 0);
00419 
00420   backend_->getHeader(filename_);
00421   ctrl_pos_->setValue(0, NOUPDATE);
00422   ctrl_loop_->setValue(0, NOUPDATE);
00423 }
00424 
00425 void
00426 SoundFileSource::myProcess(realvec& in, realvec &out)
00427 {
00428   if (backend_ != NULL)
00429   {
00430     backend_->process(in,out);
00431     // if (ctrl_mute_->isTrue())
00432     // out.setval(0.0);
00433 
00434 #ifdef MARSYAS_MATLAB
00435 #ifdef MTLB_DBG_LOG
00436     MATLAB_PUT(out, "out");
00437     MATLAB_EVAL("figure(41),subplot(212),plot(out'),axis('tight'),grid on, title('out')");
00438 #endif
00439 #endif
00440 
00441     /* setctrl("mrs_natural/pos", src_->pos_); //[!]
00442     setctrl("mrs_natural/loopPos", src_->rewindpos_);//[!]
00443     setctrl("mrs_bool/hasData", src_->hasData_);//[!]
00444     */
00445     // replaced by gtzan
00446     ctrl_pos_->setValue(backend_->getctrl("mrs_natural/pos")->to<mrs_natural>(), NOUPDATE);
00447     ctrl_loop_->setValue(backend_->rewindpos_, NOUPDATE);
00448     ctrl_hasData_->setValue(backend_->hasData_);
00449     ctrl_lastTickWithData_->setValue(backend_->lastTickWithData_, NOUPDATE);
00450     ctrl_currentlyPlaying_->setValue(backend_->getctrl("mrs_string/currentlyPlaying"));
00451     ctrl_previouslyPlaying_->setValue(backend_->getctrl("mrs_string/previouslyPlaying"));
00452 
00453     ctrl_currentLabel_->setValue(backend_->getctrl("mrs_real/currentLabel"));
00454     ctrl_previousLabel_->setValue(backend_->getctrl("mrs_real/previousLabel"));
00455     ctrl_labelNames_->setValue(backend_->getctrl("mrs_string/labelNames"));
00456     ctrl_nLabels_->setValue(backend_->getctrl("mrs_natural/nLabels"));
00457 
00458     if (updateCurrDuration)
00459     {
00460       setctrl("mrs_real/fullDuration", backend_->durFull_);
00461     }
00462 
00463 
00464     if (backend_->getType() == "CollectionFileSource") {
00465       CollectionFileSource *coll = (CollectionFileSource*)backend_;
00466       ctrl_currentHasData_->setValue(coll->iHasData_,
00467                                      NOUPDATE);
00468 
00469       ctrl_currentLastTickWithData_->setValue(coll->iLastTickWithData_, NOUPDATE);
00470       ctrl_currentCollectionNewFile_->setValue(coll->iNewFile_,
00471           NOUPDATE);
00472       if ( !(coll->iHasData_) ||
00473            (coll->iNewFile_)) {
00474         ctrl_startStable_->setValue((mrs_bool)true,
00475                                     NOUPDATE);
00476       } else {
00477         ctrl_startStable_->setValue((mrs_bool)false,
00478                                     NOUPDATE);
00479       }
00480     } else {
00481       ctrl_currentHasData_->setValue(backend_->hasData_);
00482       ctrl_currentLastTickWithData_->setValue(backend_->lastTickWithData_);
00483     }
00484 
00485     // MRSMSG("currentLastTickWithData_" << ctrl_currentLastTickWithData_->to<mrs_bool>())
00486     // MRSMSG("currentHasData" << ctrl_currentHasData_->to<mrs_bool>())
00487   }
00488 
00489 
00490 
00491 
00492   //used for toy_with_onsets.m (DO NOT DELETE! - COMMENT INSTEAD)
00493   //MATLAB_PUT(out, "SoundFileSource_out");
00494   //MATLAB_EVAL("srcAudio = [srcAudio, SoundFileSource_out];");
00495 
00496 
00497 }