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 "BeatAgent.h" 00020 #include <string.h> 00021 #include "../common_source.h" 00022 00023 using namespace std; 00024 using namespace Marsyas; 00025 00026 #define NONE 0.0 00027 #define BEAT 1.0 00028 #define EVAL 2.0 00029 00030 #define INNER 3.0 00031 #define OUTTER 4.0 00032 00033 BeatAgent::BeatAgent(mrs_string name):MarSystem("BeatAgent", name) 00034 { 00035 addControls(); 00036 beatCount_ = 0; 00037 score_ = 0; 00038 curBeatPointValue_ = 0; 00039 myIndex_ = -1; 00040 fraction_ = 0.0; 00041 } 00042 00043 BeatAgent::BeatAgent(const BeatAgent& a) : MarSystem(a) 00044 { 00045 // For any MarControlPtr in a MarSystem 00046 // it is necessary to perform this getctrl 00047 // in the copy constructor in order for cloning to work 00048 ctrl_identity_ = getctrl("mrs_string/identity"); 00049 ctrl_timming_ = getctrl("mrs_natural/timming"); 00050 ctrl_agentControl_ = getctrl("mrs_realvec/agentControl"); 00051 ctrl_scoreFunc_ = getctrl("mrs_string/scoreFunc"); 00052 ctrl_lftOutterMargin_ = getctrl("mrs_real/lftOutterMargin"); 00053 ctrl_rgtOutterMargin_ = getctrl("mrs_real/rgtOutterMargin"); 00054 ctrl_innerMargin_ = getctrl("mrs_real/innerMargin"); 00055 ctrl_maxPeriod_ = getctrl("mrs_natural/maxPeriod"); 00056 ctrl_minPeriod_ = getctrl("mrs_natural/minPeriod"); 00057 00058 beatCount_ = a.beatCount_; 00059 lastBeatPoint_ = a.lastBeatPoint_; 00060 score_ = a.score_; 00061 curBeatPointValue_ = a.curBeatPointValue_; 00062 myIndex_ = a.myIndex_; 00063 } 00064 00065 BeatAgent::~BeatAgent() 00066 { 00067 } 00068 00069 MarSystem* 00070 BeatAgent::clone() const 00071 { 00072 return new BeatAgent(*this); 00073 } 00074 00075 void 00076 BeatAgent::addControls() 00077 { 00078 //Add specific controls needed by this MarSystem. 00079 addctrl("mrs_string/identity", "AgentX", ctrl_identity_); 00080 addctrl("mrs_natural/timming", 0, ctrl_timming_); 00081 addctrl("mrs_realvec/agentControl", realvec(), ctrl_agentControl_); 00082 addctrl("mrs_string/scoreFunc", "regular", ctrl_scoreFunc_); 00083 setctrlState("mrs_string/scoreFunc", true); 00084 addctrl("mrs_real/lftOutterMargin", 0.2, ctrl_lftOutterMargin_); 00085 setctrlState("mrs_real/lftOutterMargin", true); 00086 addctrl("mrs_real/rgtOutterMargin", 0.4, ctrl_rgtOutterMargin_); 00087 setctrlState("mrs_real/rgtOutterMargin", true); 00088 addctrl("mrs_real/innerMargin", 3.0, ctrl_innerMargin_); 00089 setctrlState("mrs_real/innerMargin", true); 00090 addctrl("mrs_natural/maxPeriod", -1, ctrl_maxPeriod_); 00091 setctrlState("mrs_natural/maxPeriod", true); 00092 addctrl("mrs_natural/minPeriod", -1, ctrl_minPeriod_); 00093 setctrlState("mrs_natural/minPeriod", true); 00094 } 00095 00096 void 00097 BeatAgent::myUpdate(MarControlPtr sender) 00098 { 00099 (void) sender; //suppress warning of unused parameter(s) 00100 MRSDIAG("BeatAgent.cpp - BeatAgent:myUpdate"); 00101 00102 ctrl_onSamples_->setValue(6, NOUPDATE); 00103 ctrl_onObservations_->setValue(1, NOUPDATE); 00104 ctrl_osrate_->setValue(ctrl_israte_, NOUPDATE); 00105 00106 //history_.create(1000,2); 00107 lastBeatPoint_ = inSamples_-1; 00108 00109 myIndex_ = getChildIndex(); 00110 if(myIndex_ == -1) { 00111 MRSWARN("Agent Index Not Found!"); 00112 } 00113 00114 scoreFunc_ = ctrl_scoreFunc_->to<mrs_string>(); 00115 00116 lftOutterMargin_ = ctrl_lftOutterMargin_->to<mrs_real>(); 00117 rgtOutterMargin_ = ctrl_rgtOutterMargin_->to<mrs_real>(); 00118 innerMargin_ = ctrl_innerMargin_->to<mrs_real>(); 00119 maxPeriod_ = ctrl_maxPeriod_->to<mrs_natural>(); 00120 minPeriod_ = ctrl_minPeriod_->to<mrs_natural>(); 00121 } 00122 00123 00124 00125 mrs_real 00126 BeatAgent::calcDScoreCorrSquare(realvec& in) 00127 { 00128 mrs_real dScore = 0.0; 00129 00130 //outterLeft Tolerance: 00131 for(mrs_natural t = lastBeatPoint_ - outterWinLft_; t < lastBeatPoint_ - innerWin_; t++) 00132 { 00133 fraction_ = (mrs_real) abs(error_) / outterWinRgt_; 00134 //fraction_ = (mrs_real) abs(lastBeatPoint_-t) / (((outterWinRgt_+outterWinLft_)/2)+0.5); 00135 //dScore += -1 * pow((fraction_)* in(t),2) ; 00136 dScore += -1 * pow((fraction_),2) * in(t); 00137 } 00138 00139 //innerTolerance: 00140 for(mrs_natural t = lastBeatPoint_ - innerWin_; t <= lastBeatPoint_ + innerWin_; t++) 00141 { 00142 fraction_ = (mrs_real) abs(error_) / (((outterWinRgt_+outterWinLft_)/2)+0.5); 00143 //fraction_ = (mrs_real) abs(lastBeatPoint_-t) / (((outterWinRgt_+outterWinLft_)/2)+0.5); 00144 //fraction_ = (mrs_real) abs(lastBeatPoint_-t) / outterWinRgt_; 00145 dScore += pow((1 - fraction_),2) * in(t); 00146 //dScore += pow((1 - fraction_) * in(t),2); 00147 } 00148 00149 //outterRight Tolerance: 00150 for(mrs_natural t = (lastBeatPoint_ + innerWin_)+1; t <= lastBeatPoint_ + outterWinRgt_; t++) 00151 { 00152 fraction_ = (mrs_real) abs(error_) / outterWinLft_; 00153 //fraction_ = (mrs_real) abs(lastBeatPoint_-t) / outterWinRgt_; 00154 //dScore += -1 * pow((fraction_)* in(t),2) ; 00155 dScore += -1 * pow((fraction_),2) * in(t); 00156 } 00157 00158 //if(strcmp(identity_.c_str(), "Agent0") == 0); 00159 // cout << "MAX: " << max << "; ERRROR: " << error_ << "; dSCORE: " << dScore << endl; 00160 00161 //dScore /= (outterWinLft_+outterWinRgt_); //normalized by the full window size 00162 //multiplied by sqrt(period) for disinflating the faster agents (with smaller periods) [!] 00163 //return dScore * sqrt((mrs_real)period_) / (outterWinLft_+outterWinRgt_); 00164 return dScore * (period_ / maxPeriod_); 00165 } 00166 00167 mrs_real 00168 BeatAgent::calcDScoreCorr(realvec& in, mrs_natural maxInd) 00169 { 00170 (void) maxInd; // [!] what was this supposed to do? 00171 mrs_real dScore = 0.0; 00172 00173 //outterLeft Tolerance: 00174 for(mrs_natural t = lastBeatPoint_ - outterWinLft_; t < lastBeatPoint_ - innerWin_; t++) 00175 { 00176 fraction_ = (mrs_real) abs(error_) / outterWinRgt_; 00177 //fraction_ = (mrs_real) abs(lastBeatPoint_-t) / outterWinRgt_; 00178 dScore += (-1 * fraction_) * in(t);//pow(in(t),2); 00179 } 00180 00181 //innerTolerance: 00182 for(mrs_natural t = lastBeatPoint_ - innerWin_; t <= lastBeatPoint_ + innerWin_; t++) 00183 { 00184 fraction_ = (mrs_real) abs(error_) / outterWinRgt_;//(((outterWinRgt_+outterWinLft_)/2)+0.5); 00185 //fraction_ = (mrs_real) abs(lastBeatPoint_-t) / outterWinRgt_;//(((outterWinRgt_+outterWinLft_)/2)+0.5); 00186 dScore += (1 - fraction_) * in(t);//pow(in(t),2); 00187 } 00188 00189 //outterRight Tolerance: 00190 for(mrs_natural t = (lastBeatPoint_ + innerWin_)+1; t <= lastBeatPoint_ + outterWinRgt_; t++) 00191 { 00192 fraction_ = (mrs_real) abs(error_) / outterWinRgt_; 00193 //fraction_ = (mrs_real) abs(lastBeatPoint_-t) / outterWinRgt_; 00194 dScore += (-1 * fraction_) * in(t);//pow(in(t),2); 00195 } 00196 00197 //dScore /= (outterWinLft_+outterWinRgt_); //normalized by the full window size 00198 //multiplied by sqrt(period) for disinflating the faster agents (with smaller periods) [!] 00199 //return dScore * sqrt((mrs_real)period_) / (outterWinLft_+outterWinRgt_); 00200 return dScore * (period_ / maxPeriod_); 00201 //return dScore; 00202 } 00203 00204 mrs_natural 00205 BeatAgent::getChildIndex() 00206 { 00207 //check for parent: 00208 MarSystem* parent = this->getParent(); 00209 myIndex_ = -1; 00210 if(parent) 00211 { 00212 vector<MarSystem*> siblings = parent->getChildren(); 00213 for(mrs_natural i = 0; i < (mrs_natural)siblings.size(); i++) 00214 { 00215 if(this == siblings[i]) 00216 { 00217 myIndex_ = i; 00218 break; 00219 } 00220 } 00221 } 00222 return myIndex_; 00223 } 00224 00225 void 00226 BeatAgent::fillOutput(realvec& out, mrs_real flag, mrs_real period, mrs_real curBeat, 00227 mrs_real tolerance, mrs_real error, mrs_real score) 00228 { 00229 out(0) = flag; 00230 out(1) = period; 00231 out(2) = curBeat; 00232 out(3) = tolerance; 00233 out(4) = error; 00234 out(5) = score; 00235 } 00236 00237 void 00238 BeatAgent::myProcess(realvec& in, realvec& out) 00239 { 00240 //Output Format: [Beat/Eval/None|Period|CurBeat|Inner/Outter|Error|Score] -> OnSamples = 6 00241 agentControl_ = ctrl_agentControl_->to<mrs_realvec>(); 00242 00243 //timeElapsed_ is constantly updated with the referee's next time frame 00244 timeElapsed_ = (mrs_natural) agentControl_(myIndex_, 3); 00245 00246 //cout << "Agent: " << myIndex_ << "-" << timeElapsed_ << endl; 00247 00248 //At first no beat info is considered - while no beat detected: 00249 fillOutput(out, NONE, 0.0, 0.0, 0.0, 0.0, 0.0); 00250 00251 identity_ = ctrl_identity_->to<mrs_string>(); 00252 00253 isNewOrUpdated_ = (mrs_bool) (agentControl_(myIndex_, 0) == 1); 00254 period_ = (mrs_natural) agentControl_(myIndex_, 1); 00255 phase_ = (mrs_natural) agentControl_(myIndex_, 2); 00256 periodFraction_ = ((mrs_real)period_ / (mrs_real)maxPeriod_); 00257 00258 outterWinLft_ = (mrs_natural) ceil(period_ * lftOutterMargin_); //(% of IBI) 00259 outterWinRgt_ = (mrs_natural) ceil(period_ * rgtOutterMargin_); //(% of IBI) 00260 innerWin_ = (mrs_natural) innerMargin_; 00261 //innerWin_ = (mrs_natural) min(4.0, ceil(period_ * innerMargin_)); 00262 00263 mrs_natural curBeatPoint = inSamples_-1; //curBeatPoint always point to the end point of the full flux window. 00264 00265 mrs_real max = 0.0; 00266 mrs_natural max_i = 0; 00267 00268 //If the agent was just created or its hypothesis updated: 00269 if(isNewOrUpdated_) 00270 curBeat_ = phase_; 00271 //If the agent already existed and is keeping its hypothesis: 00272 else 00273 curBeat_ = prevBeat_ + period_; 00274 00275 //cout << "t:" << timeElapsed_ << "-" << identity_ << " -> BEAT: " << curBeat_ << "(" << beatCount_ << ")" << endl; 00276 00277 //Considers beat hypothesis every phase + period 00278 if(timeElapsed_ == curBeat_) 00279 { 00280 //cout << "t:" << timeElapsed_ << "-" << identity_ << " -> BEAT (" << beatCount_ << ")" << endl; 00281 00282 //Beat Info filling the remaining indexes of output with undef. value 00283 fillOutput(out, BEAT, -1.0, -1.0, -1.0, -1.0, -1.0); 00284 00285 curBeatPointValue_ = in(curBeatPoint); 00286 00287 //history_(beatCount_,0) = timeElapsed_; 00288 //history_(beatCount_,1) = curBeatPointValue_; 00289 00290 //lastBeatPoint points to the beat time point to be evaluated 00291 //(corresponds to the end point of the flux window - the outter rgt tolerance) 00292 lastBeatPoint_ = curBeatPoint - outterWinRgt_; 00293 00294 beatCount_++; 00295 00296 return; 00297 } 00298 00299 mrs_natural evalPoint = curBeat_ + outterWinRgt_; 00300 //Evaluates each beat at the end of its beat position + outterWindow tolerance: 00301 if(timeElapsed_ == evalPoint) 00302 { 00303 //point in flux window corresponding to the beat time point being evaluated 00304 max_i = lastBeatPoint_; 00305 00306 for(mrs_natural t = lastBeatPoint_ - outterWinLft_; t <= lastBeatPoint_ + outterWinRgt_; t++) 00307 { 00308 //check over the full eval window ([lastBeatPoint_-outterWinLft_; lastBeatPoint_+outterWinRgt_]) for maximum flux 00309 if(max < in(t)) 00310 { 00311 max = in(t); 00312 max_i = t; 00313 } 00314 } 00315 00316 //error = difference between predicted beat time point and the point, in the eval window, with maximum flux value 00317 error_ = max_i - lastBeatPoint_; 00318 00319 //cout << identity_ << " -> MAX -> pred: " << in(lastBeatPoint_) << " ; act: " << max << endl; 00320 00321 //Classification of last beat based on above evaluation: 00322 00323 //cout << identity_ << " -> Score: " << score_ << endl; 00324 if(strcmp(scoreFunc_.c_str(), "squareCorr") == 0) 00325 score_ = calcDScoreCorrSquare(in); 00326 00327 else if(strcmp(scoreFunc_.c_str(), "correlation") == 0) 00328 score_ = calcDScoreCorr(in, max_i); 00329 00330 //mrs_real phase; 00331 //1st Condition: is beat inside innerWindow? 00332 if(max_i >= lastBeatPoint_ - innerWin_ && max_i <= lastBeatPoint_) 00333 { 00334 if(strcmp(scoreFunc_.c_str(), "regular") == 0) 00335 { 00336 fraction_ = (mrs_real) abs(error_) / outterWinRgt_; 00337 //score_ = (1 - fraction_); 00338 //score_ = (1 - fraction_) * max; 00339 score_ = (1 - fraction_) * max * periodFraction_; 00340 00341 //multiplied by sqrt(period) for disinflating the faster agents (with smaller periods) [!] 00342 //score_*= sqrt((mrs_real)period_); 00343 } 00344 00345 MRSDIAG("BeatAgent::myProcess() - Beat Inside innerWindow!"); 00346 //cout << identity_ << "(" << timeElapsed_ <<") -> Beat (" << curBeat_ << ") Inside innerWindow! with error: "; 00347 00348 //Evaluation info: 00349 //phase = actualBeatPoint = max_i 00350 fillOutput(out, EVAL, period_, curBeat_, INNER, error_, score_); 00351 } 00352 else if(max_i > lastBeatPoint_ && max_i <= lastBeatPoint_ + innerWin_) 00353 { 00354 if(strcmp(scoreFunc_.c_str(), "regular") == 0) 00355 { 00356 fraction_ = (mrs_real) abs(error_) / outterWinRgt_; 00357 //score_ = (1 - fraction_) * max; 00358 //score_ = (1 - fraction_); 00359 score_ = (1 - fraction_) * max * periodFraction_; 00360 00361 //multiplied by sqrt(period) for disinflating the faster agents (with smaller periods) [!] 00362 //score_*= sqrt((mrs_real)period_); 00363 } 00364 00365 MRSDIAG("BeatAgent::myProcess() - Beat Inside innerWindow!"); 00366 //cout << identity_ << "(" << timeElapsed_ <<") -> Beat (" << curBeat_ << ") Inside innerWindow! with error: "; 00367 00368 //Evaluation info: 00369 //phase = actualBeatPoint = max_i 00370 fillOutput(out, EVAL, period_, curBeat_, INNER, error_, score_); 00371 } 00372 00373 //2nd Condition: is beat insdie outterWindow but outside innerWindow? 00374 else 00375 { 00376 if((max_i >= lastBeatPoint_ - outterWinLft_) && (max_i < lastBeatPoint_ - innerWin_)) 00377 { 00378 if(strcmp(scoreFunc_.c_str(), "regular") == 0) 00379 { 00380 fraction_ = (mrs_real) abs(error_) / outterWinRgt_; 00381 //score_ = -1 * fraction_ * max; 00382 //score_ = (1 - fraction_) * max; 00383 score_ = -1 * fraction_ * max * periodFraction_; 00384 00385 //multiplied by sqrt(period) for disinflating the faster agents (with smaller periods) [!] 00386 //score_*= sqrt((mrs_real)period_); 00387 } 00388 } 00389 if((max_i > lastBeatPoint_ + innerWin_) && (max_i <= lastBeatPoint_ + outterWinRgt_)) 00390 { 00391 if(strcmp(scoreFunc_.c_str(), "regular") == 0) 00392 { 00393 fraction_ = (mrs_real) abs(error_) / outterWinRgt_; 00394 //score_ = -1 * fraction_ * max; 00395 //score_ = (1 - fraction_) * max; 00396 score_ = -1 * fraction_ * max * periodFraction_; 00397 00398 //multiplied by sqrt(period) for disinflating the faster agents (with smaller periods) [!] 00399 //score_*= sqrt((mrs_real)period_); 00400 } 00401 } 00402 00403 //Evaluation info: 00404 //phase = actualBeatPoint = max_i 00405 //cout << identity_ << "(" << timeElapsed_ <<") -> Beat (" << curBeat_ << ") Outside innerWindow! with error: "; 00406 MRSDIAG("BeatAgent::myProcess() - Beat Inside OutterWindow but outside innerWindow!"); 00407 00408 fillOutput(out, EVAL, period_, curBeat_, OUTTER, error_, score_); 00409 } 00410 00411 //cout << "t:" << timeElapsed_ << "-" << identity_ << "(error:" << error_ << "): curBeat-" << curBeat_ << "; act-" 00412 // << curBeat_+error_ << " -> flux: " << in(lastBeatPoint_) << "-" << lastBeatPoint_ << "(" 00413 // << max << "-" << max_i << ") dS: " << score_ << " NextBeat(ifNotChanged): " << curBeat_+period_ << endl; 00414 00415 /* 00416 for(mrs_natural i = 0; i < beatCount_; i++) 00417 { 00418 cout << identity_ << " -> "History Phase(" << i << "): " << history_(i, 0) << endl; 00419 cout << identity_ << " -> "History Value(" << i << "): " << history_(i, 1) << endl; 00420 } 00421 */ 00422 00423 //Updates previous Beat 00424 prevBeat_ = curBeat_; 00425 00426 //Disbales new/updated flag: 00427 agentControl_(myIndex_, 0) = 0.0; 00428 updControl(ctrl_agentControl_, agentControl_); 00429 } 00430 00431 //MATLAB_EVAL("plot(FluxTrack/max(FluxTrack))"); 00432 //MATLAB_EVAL("hold on;"); 00433 /*MATLAB_PUT(out, "BeatAgent"); 00434 MATLAB_PUT(lastBeatPoint_ + 2, "t"); 00435 MATLAB_PUT(lastBeatPoint_ - outterWinLft_ + 2, "t1"); 00436 MATLAB_PUT(lastBeatPoint_ + outterWinRgt_ + 2, "t2"); 00437 MATLAB_EVAL("BeatAgentTS = [BeatAgentTS, BeatAgent];"); 00438 MATLAB_EVAL("stem(t1,1, 'g');"); 00439 MATLAB_EVAL("stem(t,1, 'r');"); 00440 MATLAB_EVAL("stem(t2,1, 'g');"); 00441 MATLAB_EVAL("hold off;"); 00442 */ 00443 }