Marsyas
0.6.0-alpha
|
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_source.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 (void) sender; //suppress warning of unused parameter(s) 00096 MRSDIAG("TempoHypotheses.cpp - TempoHypotheses:myUpdate"); 00097 00098 nPhases_ = ctrl_nPhases_->to<mrs_natural>(); 00099 nPeriods_ = ctrl_nPeriods_->to<mrs_natural>(); 00100 inductionSize_ = ctrl_inductionTime_->to<mrs_natural>(); 00101 srcFs_ = ctrl_srcFs_->to<mrs_real>(); 00102 hopSize_ = ctrl_hopSize_->to<mrs_natural>(); 00103 triggerInduction_ = ctrl_triggerInduction_->to<mrs_bool>(); 00104 accSize_ = ctrl_accSize_->to<mrs_natural>(); 00105 dumbInductionRequest_ = ctrl_dumbInductionRequest_->to<mrs_bool>(); 00106 maxPeriod_ = ctrl_maxPeriod_->to<mrs_natural>(); 00107 minPeriod_ = ctrl_minPeriod_->to<mrs_natural>(); 00108 00109 setctrl("mrs_real/osrate", getctrl("mrs_real/israte")); 00110 setctrl("mrs_natural/onSamples", 3); 00111 setctrl("mrs_natural/onObservations", nPhases_ * nPeriods_); 00112 } 00113 00114 00115 void 00116 TempoHypotheses::myProcess(realvec& in, realvec& out) 00117 { 00118 //timeElapsed_ is constantly updated with the referee's next time frame 00119 timeElapsed_ = ctrl_tickCount_->to<mrs_natural>(); 00120 00121 //cout << "THyp: " << timeElapsed_ << "; Ind: " << inductionSize_ << "; accSize: " << accSize_ 00122 // << "; maxPer: " << maxPeriod_ << "; minPer: " << minPeriod_ << endl; 00123 00124 triggerInduction_ = ctrl_triggerInduction_->to<mrs_bool>(); 00125 if(triggerInduction_) 00126 { 00127 mrs_natural maxPeriod = 0; 00128 00129 //reset flags 00130 foundPeriods_ = false; 00131 foundPhases_ = false; 00132 if(!dumbInductionRequest_) //if not in dumb induction mode (requested by user) 00133 { 00134 //retrieve Max Period Peak and check if found periods and/or phases 00135 mrs_real maxPeriodPeak = 0.0; 00136 for (int i=0; i < nPeriods_; i++) 00137 { 00138 if(in(0, 2*i+1) > 1) //if found any period (period > 1 because it may appear as decimals meaning 0) 00139 foundPeriods_ = true; 00140 00141 if(in(0, 2*i) > maxPeriodPeak) 00142 maxPeriodPeak = in(0, 2*i); 00143 00144 //keep maximum period 00145 if(in(0, 2*i+1) > maxPeriod) 00146 maxPeriod = (mrs_natural)in(0, 2*i+1); 00147 00148 int z = 0; 00149 //cout << "TH-Phases: " << endl; 00150 for (int j = (i * nPhases_); j < ((i+1) * nPhases_); j++) 00151 { 00152 //cout << "i: " << in(1, 2*z+1) << "; "; 00153 if(in(1, 2*z+1) > 0) //if found any phases 00154 foundPhases_ = true; 00155 //foundPhases_ = false; 00156 z++; 00157 } 00158 //cout << endl; 00159 } 00160 00161 //cout << "FoundPer: " << foundPeriods_ << "; foundPh: " << foundPhases_ << endl; 00162 00163 if(foundPeriods_) //if found periods 00164 { 00165 for (int i=0; i < nPeriods_; i++) 00166 { 00167 int z = 0; 00168 for (int j = (i * nPhases_); j < ((i+1) * nPhases_); j++) 00169 { 00170 out(j, 0) = in(0, 2*i+1); //Periods 00171 out(j, 1) = in(1, 2*z+1); //Phases 00172 out(j, 2) = in(0, 2*i);// / maxPeriodPeak; //Normalized period peak magnitudes 00173 00174 z++; 00175 } 00176 } 00177 } 00178 } 00179 00180 //if no periods found or in dumb induction mode (requested by user) 00181 if(!foundPeriods_ || dumbInductionRequest_) 00182 { 00183 //Manual assorted values for filling BPM hypotheses vector when none are generated 00184 int manualBPMs_[] = {120, 60, 240, 100, 160, 200, 80, 140, 180, 220, 150}; 00185 00186 if(!foundPeriods_ && !dumbInductionRequest_) 00187 cerr << "\nUnable to find salient periodicities within the given induction window..." << endl; 00188 if(dumbInductionRequest_) 00189 cerr << "\nDumb Induction Mode..." << endl; 00190 00191 cerr << "...Replacing induction with the following BPMs: "; 00192 00193 mrs_natural assignedPerCount = 0; 00194 for (unsigned int i=0; i < (sizeof(manualBPMs_) / sizeof(int)); i++) 00195 { 00196 if(assignedPerCount == nPeriods_) break; 00197 00198 mrs_natural manualPeriod = (mrs_natural) (((mrs_real) 60 / (manualBPMs_[i] * hopSize_)) * (srcFs_)); 00199 00200 //cout << i << "-> manBPM: " << manualBPMs_[i] << "[" << manualPeriod << "] maxPer: " 00201 // << maxPeriod_ << "; minPer: " << minPeriod_ << "; ASS: " << assignedPerCount << endl; 00202 00203 //assure that the chosen manual periods are within the user-defined BPM range 00204 if(manualPeriod >= minPeriod_ && manualPeriod <= maxPeriod_) 00205 { 00206 cerr << manualBPMs_[i] << "; "; 00207 00208 int z = 0; 00209 for (int j = (assignedPerCount * nPhases_); j < ((assignedPerCount+1) * nPhases_); j++) 00210 { 00211 out(j, 0) = manualPeriod; //Periods 00212 out(j, 1) = in(1, 2*z+1); //Phases 00213 out(j, 2) = 1.0; //equal (max) peak sizes to all manual periods 00214 z++; 00215 00216 if(out(j,0) > maxPeriod) //save maximum manual period 00217 maxPeriod = (mrs_natural) out(j,0); 00218 } 00219 00220 assignedPerCount++; 00221 } 00222 } 00223 00224 //request dumbInduction to PhaseLock 00225 ctrl_dumbInduction_->setValue(true); 00226 } 00227 00228 if(!foundPhases_) //if no phases found 00229 { 00230 //cerr << "\nUnable to find potential phases (onsets) within the given induction window..." << endl; 00231 //cerr << "...Assuming the maximum nr. of possible phases." << endl; 00232 00233 //calculate minimum spacing between possible phases 00234 mrs_natural spacing = (mrs_natural) ceil(((mrs_real)maxPeriod / (mrs_real)nPhases_)); 00235 //start phases on the analysis start point of the given induction window 00236 mrs_natural accBeginning = (accSize_-1-inductionSize_); 00237 00238 //fill phases vector 00239 mrs_realvec phases(nPhases_); 00240 mrs_natural index = 0; 00241 for(int ph = accBeginning; ph <= accBeginning+maxPeriod+spacing; ph += spacing) 00242 { 00243 if(index == nPhases_) break; 00244 00245 phases(index) = ph; //Phases 00246 index++; 00247 } 00248 00249 for (int i=0; i < nPeriods_; i++) 00250 { 00251 int z = 0; 00252 for (int j = (i * nPhases_); j < ((i+1) * nPhases_); j++) 00253 { 00254 out(j, 1) = phases(z); //Phases 00255 z++; 00256 } 00257 } 00258 //MATLAB_PUT(in, "BeatData"); 00259 //MATLAB_PUT(out, "TempoHypotheses"); 00260 } 00261 00262 //MATLAB_PUT(out, "TempoHypotheses2"); 00263 //MATLAB_PUT(in, "BeatData"); 00264 //MATLAB_EVAL("plot(BeatData)"); 00265 } 00266 00267 /* 00268 //FOR TESTING ONSETS IN REPEATED INDUCTION========================= 00269 MATLAB_PUT((mrs_natural)triggerInduction_, "Induction_flag"); 00270 MATLAB_EVAL("Induction = Induction2;"); 00271 MATLAB_EVAL("Induction(end) = Induction_flag*max(PeakerOnset_in);"); 00272 */ 00273 } 00274 00275 00276 00277 00278 00279 00280 00281