Marsyas
0.6.0-alpha
|
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 }