Marsyas  0.6.0-alpha
/usr/src/RPM/BUILD/marsyas-0.6.0/src/marsyas/marsystems/OnsetTimes.cpp
Go to the documentation of this file.
00001 /*
00002 ** Copyright (C) 1998-2006 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 "OnsetTimes.h"
00020 #include "../common_source.h"
00021 #include <algorithm>
00022 #include <functional>
00023 
00024 using namespace std;
00025 using namespace Marsyas;
00026 
00027 OnsetTimes::OnsetTimes(mrs_string name):MarSystem("OnsetTimes", name)
00028 {
00029   addControls();
00030   timeElapsed_ = 0;
00031   count_ = 0;
00032   lastInductionTime_ = 0;
00033   maxCount_ = 0;
00034 }
00035 
00036 OnsetTimes::OnsetTimes(const OnsetTimes& a) : MarSystem(a)
00037 {
00038   // For any MarControlPtr in a MarSystem
00039   // it is necessary to perform this getctrl
00040   // in the copy constructor in order for cloning to work
00041   ctrl_n1stOnsets_ = getctrl("mrs_natural/n1stOnsets");
00042   ctrl_lookAheadSamples_ = getctrl("mrs_natural/lookAheadSamples");
00043   ctrl_nPeriods_ = getctrl("mrs_natural/nPeriods");
00044   ctrl_inductionTime_ = getctrl("mrs_natural/inductionTime");
00045   ctrl_accSize_ = getctrl("mrs_natural/accSize");
00046   ctrl_tickCount_ = getctrl("mrs_natural/tickCount");
00047   ctrl_triggerInduction_ = getctrl("mrs_bool/triggerInduction");
00048 
00049   count_ = a.count_;
00050   lastInductionTime_ = a.lastInductionTime_;
00051   triggerInduction_ = a.triggerInduction_;
00052   size_ = a.size_;
00053   maxCount_ = a.maxCount_;
00054   phasesRaw_ = a.phasesRaw_;
00055 }
00056 
00057 OnsetTimes::~OnsetTimes()
00058 {
00059 }
00060 
00061 MarSystem*
00062 OnsetTimes::clone() const
00063 {
00064   return new OnsetTimes(*this);
00065 }
00066 
00067 void
00068 OnsetTimes::addControls()
00069 {
00070   //Add specific controls needed by this MarSystem.
00071   addctrl("mrs_natural/n1stOnsets", 1, ctrl_n1stOnsets_);
00072   setctrlState("mrs_natural/n1stOnsets", true);
00073   addctrl("mrs_natural/lookAheadSamples", 1, ctrl_lookAheadSamples_);
00074   addctrl("mrs_natural/nPeriods", 1, ctrl_nPeriods_);
00075   setctrlState("mrs_natural/nPeriods", true);
00076   addctrl("mrs_natural/inductionTime", -1, ctrl_inductionTime_);
00077   setctrlState("mrs_natural/inductionTime", true);
00078   addctrl("mrs_natural/accSize", -1, ctrl_accSize_);
00079   setctrlState("mrs_natural/accSize", true);
00080   addctrl("mrs_natural/tickCount", 0, ctrl_tickCount_);
00081   addctrl("mrs_bool/triggerInduction", false, ctrl_triggerInduction_);
00082   setctrlState("mrs_bool/triggerInduction", true);
00083 }
00084 
00085 void
00086 OnsetTimes::myUpdate(MarControlPtr sender)
00087 {
00088   (void) sender;  //suppress warning of unused parameter(s)
00089   MRSDIAG("OnsetTimes.cpp - OnsetTimes:myUpdate");
00090   n_ = ctrl_n1stOnsets_->to<mrs_natural>();
00091   nPeriods_ = ctrl_nPeriods_->to<mrs_natural>();
00092 
00093   //if the nr of requested bpm hypotheses is bigger
00094   //than the requested phases we need to fill the rest of the vector with
00095   //0s -> to avoid crash in tempohypotheses Fanout
00096   size_ = 2 * max(n_, nPeriods_);
00097   setctrl("mrs_natural/onSamples",  size_);
00098 
00099   ctrl_onObservations_->setValue(1, NOUPDATE);
00100   ctrl_osrate_->setValue(ctrl_israte_, NOUPDATE);
00101 
00102   inductionSize_ = ctrl_inductionTime_->to<mrs_natural>();
00103   accSize_ = ctrl_accSize_->to<mrs_natural>();
00104   triggerInduction_ = ctrl_triggerInduction_->to<mrs_bool>();
00105 }
00106 
00107 void
00108 OnsetTimes::delSurpassedOnsets()
00109 {
00110   //clean surpassed onsets given current induction window
00111   for (int i=0; i < n_; i++)
00112   {
00113     mrs_real onset = phasesRaw_(i);
00114     if(onset > 0) //ignore empty bins
00115     {
00116       //cout << "t: " << timeElapsed_ << "====> i: " << i << "-> " << onset << ";";
00117       mrs_real onsetAdj = onset + (accSize_ - 1 - timeElapsed_);
00118       //if onset still inside current induction window (to be sure)
00119       if(onsetAdj < (accSize_ -1 - inductionSize_) || onsetAdj > (accSize_ - 1))
00120       {
00121         //cout << "(" << onsetAdj << ") [" << (accSize_ -1 - inductionSize_) << "; " << (accSize_ - 1) << "]" << endl;
00122         phasesRaw_(i) = 0.0; //if not => delete onset
00123         maxCount_--; //subtract deleted values to realvec
00124 
00125         if(count_ > maxCount_) //assure that count never surpasses maximum count (which may happen when one phase deleted)
00126           count_ = maxCount_;
00127       }
00128       //else cout << endl;
00129     }
00130   }
00131 
00132   //cout << "UNSORTED RAW-> maxCount: " << maxCount_ << "; Count: " << count_ << endl;
00133   //for (int i=0; i < n_; i++)
00134   //{
00135   //    cout << i << "-> " << phasesRaw_(i) << "; ";
00136   //}
00137 
00138   //sort the whole realvec in descending order to take eventual initial zeros
00139   sort(phasesRaw_.getData(), phasesRaw_.getData()+n_, greater<int>());
00140   //sort back to ascending order
00141   sort(phasesRaw_.getData(), phasesRaw_.getData()+maxCount_);
00142 }
00143 
00144 void
00145 OnsetTimes::myProcess(realvec& in, realvec& out)
00146 {
00147   //timeElapsed_ is constantly updated with the referee's next time frame
00148   timeElapsed_ = ctrl_tickCount_->to<mrs_natural>();
00149 
00150   //at every induction step -> update onset positions according to offset
00151   if(triggerInduction_)
00152   {
00153 
00154     //cout << "OnTimes-> Induction at: " << timeElapsed_ << "; accSize: " << accSize_ << "; min: "
00155     //  << (accSize_ -1 - inductionSize_) << "; max: " << (accSize_ - 1) << "; phS: " << phasesRaw_.getCols() << endl;
00156 
00157     //cout << "BEGINING RAW-> maxCount: " << maxCount_ << "; Count: " << count_ << endl;
00158     //for (int i=0; i < n_; i++)
00159     //{
00160     //  cout << i << "-> " << phasesRaw_(i) << "; ";
00161     //}
00162 
00163 
00164     //delSurpassedOnsets();
00165 
00166 
00167     //cout << "SORTED RAW-> maxCount: " << maxCount_ << "; Count: " << count_ << endl;
00168     //for (int i=0; i < n_; i++)
00169     //{
00170     //  cout << i << "-> " << phasesRaw_(i) << "; ";
00171     //}
00172 
00173 
00174     mrs_realvec phasesAdj(size_);
00175     //Adjust given phases (onsets) to current induction window:
00176     for (int i=0; i < n_; i++)
00177     {
00178       mrs_real onset = phasesRaw_(i);
00179       //cout << "O: " << onset << "; ";
00180       if(onset > 0) //ignore empty bins
00181       {
00182         //cout << "i: " << i << "-> " << onset << " (";
00183         phasesAdj(0, (2*i)+1) = onset + (accSize_ - 1 - timeElapsed_);
00184         phasesAdj(0, 2*i) = 1.0;
00185 
00186         //cout << "(" << phasesAdj(0, (2*i)+1) << "); ";
00187       }
00188 
00189     }
00190     //cerr << endl;
00191 
00192     //out = phasesAdj;
00193 
00194     /*
00195     cout << "END-> maxCount: " << maxCount_ << endl;
00196     for (int i=0; i < n_; i++)
00197     {
00198         cout << i << "-> " << phasesAdj(0, (2*i)+1) << "; ";
00199     }
00200     */
00201     out = phasesAdj;
00202   }
00203 
00204   //cout << "OTime: " << timeElapsed_ << endl;
00205 
00206   lookAhead_ = ctrl_lookAheadSamples_->to<mrs_natural>();
00207 
00208   mrs_natural inc = 0; //nr. of first ignored onsets
00209   if((timeElapsed_ - lookAhead_) > 0 && in(0,0) == 1.0) //avoid onset at frame 0
00210   {
00211     if(phasesRaw_.getCols() < n_)
00212       phasesRaw_.stretch(n_);
00213 
00214     //cout << "count: " << count_ << "; inc: " << inc << "; n: " << n_
00215     //  << "; t-l: " << (timeElapsed_-lookAhead_) << "; PR: " << (phasesRaw_(0, (count_-inc-1)) + 5) << endl;
00216     //cout << "LOOKAHEAD: " << lookAhead_ << endl;
00217     //cout << "ONSET AT: " << timeElapsed_ << endl;
00218     //if task isn't still done && (first peak || peak distance at least 5 frames from last peak)
00219     //if(count_ == inc || (count_ > inc && count_ < n_ + inc && ((timeElapsed_-lookAhead_)+(accSize_-1 - inductionTime_)) > out(0, 2*(count_-inc)-1) + 5))
00220     //if(count_ == inc || (count_ > inc && count_ < n_ + inc && ((timeElapsed_-lookAhead_)+(accSize_-1 - inductionSize_)) > out(0, 2*(count_-inc)-1) + 5))
00221     if(count_ == inc || (count_ > inc && count_ < n_ + inc && ((timeElapsed_-lookAhead_) > phasesRaw_(0, (count_-inc-1)) + 5)))
00222     {
00223       //cout << "Out Last Arg: " << out(0, 2*(count_-inc)+1) << " Current Arg: " << timeElapsed_ - lookAhead_ << endl;
00224       //out(0, 2*(count_-inc)) = in(0,0);
00225 
00226       //onsetTime equals to peakerTime within current induction step (curInductionTime_-lookAhead_)
00227       //+ difference between last point in the
00228       //accumulator/ShiftInput (accSize_-1) and the considered inductionTime
00229       //out(0, 2*(count_-inc)+1) = (timeElapsed_-lookAhead_)+(accSize_-1 - inductionSize_);
00230       //out(0, 2*(count_-inc)+1) = ((timeElapsed_-lastInductionTime_) - lookAhead_)+(accSize_-1 - inductionSize_);
00231       //out(0, 2*(count_-inc)+1) = (curInductionTime_-lookAhead_)+(accSize_-1 - inductionTime_);
00232       //out(0, 2*(count_-inc)+1) = ((timeElapsed_-lastInductionTime_) - lookAhead_) + (accSize_-1);
00233       //out(0, 2*(count_-inc)+1) = (timeElapsed_-lookAhead_);
00234 
00235       //use phases_ realvec
00236       phasesRaw_(0, (count_-inc)) = (timeElapsed_-lookAhead_);
00237 
00238       //cout << "t: " << timeElapsed_ << "|" << (timeElapsed_-lookAhead_) << "- " << ((((timeElapsed_-lookAhead_) * 512.0) - 512.0/2) / 44100.0) << "(" << count_ << ") Onset at: " << (timeElapsed_-lookAhead_)+(862-1 - inductionSize_)
00239       //    << "(" << phasesRaw_(0, (count_-inc)) << ")" << endl;
00240 
00241       count_++;
00242       if(count_ > maxCount_) //update maxCount for keeping max nr. of phases from all induction windows
00243         maxCount_ = count_;
00244     }
00245     else if(count_ >= n_) //if onsets' realvec is full and new onsets arrive check if the older onsets have already been surpassed
00246     {
00247       delSurpassedOnsets();
00248 
00249       //cout << "SORTED RAW-> maxCount: " << maxCount_ << "; Count: " << count_ << endl;
00250       //for (int i=0; i < n_; i++)
00251       //{
00252       //    cout << i << "-> " << phasesRaw_(i) << "; ";
00253       //}
00254 
00255       //add new onset
00256       phasesRaw_(0, (count_-inc)) = (timeElapsed_-lookAhead_);
00257 
00258       count_++;
00259       if(count_ > maxCount_) //update maxCount for keeping max nr. of phases from all induction windows
00260         maxCount_ = count_;
00261     }
00262   }
00263 }