Marsyas  0.2
/home/gperciva/src/marsyas/src/marsyas/TempoHypotheses.cpp
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 "TempoHypotheses.h"
00020 #include "common.h"
00021 
00022 using namespace std;
00023 using namespace Marsyas;
00024 
00025 TempoHypotheses::TempoHypotheses(mrs_string name):MarSystem("TempoHypotheses", name)
00026 {
00027   addControls();
00028   timeElapsed_ = 0;
00029   foundPeriods_ = false;
00030   foundPhases_ = false;
00031 }
00032 
00033 TempoHypotheses::TempoHypotheses(const TempoHypotheses& a) : MarSystem(a)
00034 {
00035   // For any MarControlPtr in a MarSystem 
00036   // it is necessary to perform this getctrl 
00037   // in the copy constructor in order for cloning to work 
00038   ctrl_nPhases_ = getctrl("mrs_natural/nPhases");
00039   ctrl_nPeriods_ = getctrl("mrs_natural/nPeriods");
00040   ctrl_inductionTime_ = getctrl("mrs_natural/inductionTime");
00041   ctrl_hopSize_ = getctrl("mrs_natural/hopSize");
00042   ctrl_srcFs_ = getctrl("mrs_real/srcFs");
00043   ctrl_dumbInduction_ = getctrl("mrs_bool/dumbInduction");
00044   ctrl_dumbInductionRequest_ = getctrl("mrs_bool/dumbInductionRequest");
00045   ctrl_tickCount_ = getctrl("mrs_natural/tickCount");
00046   ctrl_triggerInduction_ = getctrl("mrs_bool/triggerInduction");
00047   ctrl_accSize_ = getctrl("mrs_natural/accSize");
00048   ctrl_maxPeriod_ = getctrl("mrs_natural/maxPeriod");
00049   ctrl_minPeriod_ = getctrl("mrs_natural/minPeriod");
00050 
00051   foundPeriods_ = a.foundPeriods_;
00052   foundPhases_ = a.foundPhases_;
00053   dumbInductionRequest_ = a.dumbInductionRequest_;
00054   triggerInduction_ = a.triggerInduction_;
00055 }
00056 
00057 TempoHypotheses::~TempoHypotheses()
00058 {
00059 }
00060 
00061 MarSystem* 
00062 TempoHypotheses::clone() const 
00063 {
00064   return new TempoHypotheses(*this);
00065 }
00066 
00067 void 
00068 TempoHypotheses::addControls()
00069 {
00070   //Add specific controls needed by this MarSystem.
00071   addctrl("mrs_natural/nPhases", 1, ctrl_nPhases_);
00072   setctrlState("mrs_natural/nPhases", true);
00073   addctrl("mrs_natural/nPeriods", 1, ctrl_nPeriods_);
00074   setctrlState("mrs_natural/nPeriods", true);
00075   addctrl("mrs_natural/inductionTime", -1, ctrl_inductionTime_);
00076   setctrlState("mrs_natural/inductionTime", true);
00077   addctrl("mrs_natural/hopSize", 1, ctrl_hopSize_);
00078   addctrl("mrs_real/srcFs", 1.0, ctrl_srcFs_);
00079   setctrlState("mrs_real/srcFs", true);
00080   addctrl("mrs_bool/dumbInduction", false, ctrl_dumbInduction_);
00081   addctrl("mrs_bool/dumbInductionRequest", false, ctrl_dumbInductionRequest_);
00082   addctrl("mrs_natural/tickCount", 0, ctrl_tickCount_);
00083   addctrl("mrs_bool/triggerInduction", false, ctrl_triggerInduction_);
00084   setctrlState("mrs_bool/triggerInduction", true);
00085   addctrl("mrs_natural/accSize", -1, ctrl_accSize_);
00086   addctrl("mrs_natural/maxPeriod", -1, ctrl_maxPeriod_);
00087   setctrlState("mrs_natural/maxPeriod", true);
00088   addctrl("mrs_natural/minPeriod", -1, ctrl_minPeriod_);
00089   setctrlState("mrs_natural/minPeriod", true);
00090 }
00091 
00092 void
00093 TempoHypotheses::myUpdate(MarControlPtr sender)
00094 {
00095   MRSDIAG("TempoHypotheses.cpp - TempoHypotheses:myUpdate");
00096   
00097     nPhases_ = ctrl_nPhases_->to<mrs_natural>();
00098     nPeriods_ = ctrl_nPeriods_->to<mrs_natural>();
00099     inductionSize_ = ctrl_inductionTime_->to<mrs_natural>();
00100     srcFs_ = ctrl_srcFs_->to<mrs_real>();
00101     hopSize_ = ctrl_hopSize_->to<mrs_natural>();
00102     triggerInduction_ = ctrl_triggerInduction_->to<mrs_bool>();
00103     accSize_ = ctrl_accSize_->to<mrs_natural>();
00104     dumbInductionRequest_ = ctrl_dumbInductionRequest_->to<mrs_bool>();
00105     maxPeriod_ = ctrl_maxPeriod_->to<mrs_natural>();
00106     minPeriod_ = ctrl_minPeriod_->to<mrs_natural>();
00107 
00108     setctrl("mrs_real/osrate", getctrl("mrs_real/israte"));
00109     setctrl("mrs_natural/onSamples", 3);
00110     setctrl("mrs_natural/onObservations", nPhases_ * nPeriods_);
00111 }
00112 
00113 
00114 void 
00115 TempoHypotheses::myProcess(realvec& in, realvec& out)
00116 {
00117     //timeElapsed_ is constantly updated with the referee's next time frame
00118     timeElapsed_ = ctrl_tickCount_->to<mrs_natural>();
00119 
00120     //cout << "THyp: " << timeElapsed_ << "; Ind: " << inductionSize_ << "; accSize: " << accSize_ 
00121     //  << "; maxPer: " << maxPeriod_ << "; minPer: " << minPeriod_ << endl;
00122 
00123     triggerInduction_ = ctrl_triggerInduction_->to<mrs_bool>();
00124     if(triggerInduction_)
00125     {
00126         mrs_natural maxPeriod = 0;
00127 
00128         //reset flags
00129         foundPeriods_ = false;
00130         foundPhases_ = false;
00131         if(!dumbInductionRequest_) //if not in dumb induction mode (requested by user)
00132         {
00133             //retrieve Max Period Peak and check if found periods and/or phases
00134             mrs_real maxPeriodPeak = 0.0;
00135             for (int i=0; i < nPeriods_; i++)
00136             {
00137                 if(in(0, 2*i+1) > 1) //if found any period (period > 1 because it may appear as decimals meaning 0)
00138                     foundPeriods_ = true;
00139                 
00140                 if(in(0, 2*i) > maxPeriodPeak)
00141                     maxPeriodPeak = in(0, 2*i);
00142 
00143                 //keep maximum period
00144                 if(in(0, 2*i+1) > maxPeriod)
00145                     maxPeriod = (mrs_natural)in(0, 2*i+1);
00146 
00147                 int z = 0;
00148                 //cout << "TH-Phases: " << endl;
00149                 for (int j = (i * nPhases_); j < ((i+1) * nPhases_); j++)
00150                 {
00151                     //cout << "i: " << in(1, 2*z+1) << "; ";
00152                     if(in(1, 2*z+1) > 0) //if found any phases
00153                         foundPhases_ = true;
00154                         //foundPhases_ = false;
00155                     z++;
00156                 }
00157                 //cout << endl;
00158             }
00159 
00160             //cout << "FoundPer: " << foundPeriods_ << "; foundPh: " << foundPhases_ << endl;
00161 
00162             if(foundPeriods_) //if found periods
00163             {
00164                 for (int i=0; i < nPeriods_; i++)
00165                 {   
00166                     int z = 0;
00167                     for (int j = (i * nPhases_); j < ((i+1) * nPhases_); j++)
00168                     {
00169                         out(j, 0) = in(0, 2*i+1); //Periods
00170                         out(j, 1) = in(1, 2*z+1); //Phases
00171                         out(j, 2) = in(0, 2*i);// / maxPeriodPeak; //Normalized period peak magnitudes
00172                         
00173                         z++;
00174                     }
00175                 }
00176             }
00177         }
00178         
00179         //if no periods found or in dumb induction mode (requested by user)
00180         if(!foundPeriods_ || dumbInductionRequest_)
00181         {
00182             //Manual assorted values for filling BPM hypotheses vector when none are generated
00183             int manualBPMs_[] = {120, 60, 240, 100, 160, 200, 80, 140, 180, 220, 150};
00184 
00185             if(!foundPeriods_ && !dumbInductionRequest_)
00186                 cerr << "\nUnable to find salient periodicities within the given induction window..." << endl;
00187             if(dumbInductionRequest_)
00188                 cerr << "\nDumb Induction Mode..." << endl;
00189             
00190             cerr << "...Replacing induction with the following BPMs: ";
00191 
00192             mrs_natural assignedPerCount = 0;
00193             for (int i=0; i < (sizeof(manualBPMs_) / sizeof(int)); i++)
00194             {
00195                 if(assignedPerCount == nPeriods_) break;
00196 
00197                 mrs_natural manualPeriod = (mrs_natural) (((mrs_real) 60 / (manualBPMs_[i] * hopSize_)) * (srcFs_));
00198                 
00199                 //cout << i << "-> manBPM: " << manualBPMs_[i] << "[" << manualPeriod << "] maxPer: " 
00200                 //  << maxPeriod_ << "; minPer: " << minPeriod_ << "; ASS: " << assignedPerCount << endl;
00201 
00202                 //assure that the chosen manual periods are within the user-defined BPM range
00203                 if(manualPeriod >= minPeriod_ && manualPeriod <= maxPeriod_)
00204                 {
00205                     cerr << manualBPMs_[i] << "; ";
00206                 
00207                     int z = 0;
00208                     for (int j = (assignedPerCount * nPhases_); j < ((assignedPerCount+1) * nPhases_); j++)
00209                     {
00210                         out(j, 0) = manualPeriod; //Periods
00211                         out(j, 1) = in(1, 2*z+1); //Phases
00212                         out(j, 2) = 1.0; //equal (max) peak sizes to all manual periods
00213                         z++;
00214 
00215                         if(out(j,0) > maxPeriod) //save maximum manual period
00216                             maxPeriod = (mrs_natural) out(j,0);
00217                     }
00218 
00219                     assignedPerCount++;
00220                 }
00221             }
00222 
00223             //request dumbInduction to PhaseLock
00224             ctrl_dumbInduction_->setValue(true); 
00225         }
00226 
00227         if(!foundPhases_) //if no phases found
00228         {
00229             //cerr << "\nUnable to find potential phases (onsets) within the given induction window..." << endl;
00230             //cerr << "...Assuming the maximum nr. of possible phases." << endl;
00231 
00232             //calculate minimum spacing between possible phases
00233             mrs_natural spacing = (mrs_natural) ceil(((mrs_real)maxPeriod / (mrs_real)nPhases_));
00234             //start phases on the analysis start point of the given induction window
00235             mrs_natural accBeginning = (accSize_-1-inductionSize_);
00236 
00237             //fill phases vector
00238             mrs_realvec phases(nPhases_);
00239             mrs_natural index = 0;
00240             for(int ph = accBeginning; ph <= accBeginning+maxPeriod+spacing; ph += spacing)
00241             {
00242                 if(index == nPhases_) break;
00243                 
00244                 phases(index) = ph; //Phases
00245                 index++;
00246             }
00247 
00248             for (int i=0; i < nPeriods_; i++)
00249             {   
00250                 int z = 0;
00251                 for (int j = (i * nPhases_); j < ((i+1) * nPhases_); j++)
00252                 {
00253                     out(j, 1) = phases(z); //Phases
00254                     z++;
00255                 }
00256             }
00257             //MATLAB_PUT(in, "BeatData");
00258             //MATLAB_PUT(out, "TempoHypotheses");
00259         }
00260 
00261         //MATLAB_PUT(out, "TempoHypotheses2");  
00262         //MATLAB_PUT(in, "BeatData");
00263         //MATLAB_EVAL("plot(BeatData)");
00264     }
00265     
00266     /*
00267     //FOR TESTING ONSETS IN REPEATED INDUCTION=========================
00268     MATLAB_PUT((mrs_natural)triggerInduction_, "Induction_flag");
00269     MATLAB_EVAL("Induction = Induction2;");
00270     MATLAB_EVAL("Induction(end) = Induction_flag*max(PeakerOnset_in);");
00271     */
00272 }
00273 
00274 
00275 
00276 
00277 
00278 
00279 
00280