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 "BeatTimesSink.h" 00020 #include "../common_source.h" 00021 #include <fstream> 00022 #include <string.h> 00023 00024 using namespace std; 00025 using namespace Marsyas; 00026 00027 const char *szServer = "localhost"; //assume UDP sockets at localhost [CHANGE IF OTHER!!] 00028 00029 BeatTimesSink::BeatTimesSink(mrs_string name):MarSystem("BeatTimesSink", name) 00030 { 00031 addControls(); 00032 ibiBPM_ = 0.0; 00033 ibiBPMSum_ = 0.0; 00034 beatCount_ = 0; 00035 timeElapsed_ = 0; 00036 inc_ = 0; //initial beat counting... 00037 nonCausal_ = true; 00038 lastIbi_ = 0.0; 00039 initialOut_ = true; 00040 initialOut2_ = true; 00041 initialOut3_ = true; 00042 tempoVec_.resize(1); 00043 // mySocket_ = -1; 00044 } 00045 00046 BeatTimesSink::BeatTimesSink(const BeatTimesSink& a) : MarSystem(a) 00047 { 00048 // For any MarControlPtr in a MarSystem 00049 // it is necessary to perform this getctrl 00050 // in the copy constructor in order for cloning to work 00051 ctrl_hopSize_ = getctrl("mrs_natural/hopSize"); 00052 ctrl_winSize_ = getctrl("mrs_natural/winSize"); 00053 ctrl_srcFs_ = getctrl("mrs_real/srcFs"); 00054 ctrl_destFileName_ = getctrl("mrs_string/destFileName"); 00055 ctrl_mode_ = getctrl("mrs_string/mode"); 00056 ctrl_tickCount_ = getctrl("mrs_natural/tickCount"); 00057 ctrl_curMedianTempo_ = getctrl("mrs_natural/curMedianTempo"); 00058 ctrl_adjustment_ = getctrl("mrs_natural/adjustment"); 00059 ctrl_bestFinalAgentHistory_= getctrl("mrs_realvec/bestFinalAgentHistory"); 00060 ctrl_soundFileSize_= getctrl("mrs_natural/soundFileSize"); 00061 ctrl_nonCausal_ = getctrl("mrs_bool/nonCausal"); 00062 ctrl_socketsPort_ = getctrl("mrs_natural/socketsPort"); 00063 ctrl_tempo_ = getctrl("mrs_real/tempo"); 00064 ibiBPM_ = a.ibiBPM_; 00065 beatCount_ = a.beatCount_; 00066 ibiBPMSum_ = a.ibiBPMSum_; 00067 inc_ = a.inc_; 00068 ibiBPMVec_ = a.ibiBPMVec_; 00069 initialOut_ = a.initialOut_; 00070 initialOut2_ = a.initialOut2_; 00071 initialOut3_ = a.initialOut3_; 00072 tempoVec_ = a.tempoVec_; 00073 00074 // socketsPort_ = a.socketsPort_; 00075 // mySocket_ = a.mySocket_; 00076 // myAcceptSocket_ = a.myAcceptSocket_; 00077 } 00078 00079 BeatTimesSink::~BeatTimesSink() 00080 { 00081 } 00082 00083 MarSystem* 00084 BeatTimesSink::clone() const 00085 { 00086 return new BeatTimesSink(*this); 00087 } 00088 00089 void 00090 BeatTimesSink::addControls() 00091 { 00092 //Add specific controls needed by this MarSystem. 00093 addctrl("mrs_natural/tickCount", 0, ctrl_tickCount_); 00094 addctrl("mrs_natural/hopSize", -1, ctrl_hopSize_); 00095 setctrlState("mrs_natural/hopSize", true); 00096 addctrl("mrs_natural/winSize", -1, ctrl_winSize_); 00097 setctrlState("mrs_natural/winSize", true); 00098 addctrl("mrs_real/srcFs", -1.0, ctrl_srcFs_); 00099 setctrlState("mrs_real/srcFs", true); 00100 addctrl("mrs_string/destFileName", "output", ctrl_destFileName_); 00101 addctrl("mrs_string/mode", "beats+tempo", ctrl_destFileName_); 00102 setctrlState("mrs_string/mode", true); 00103 addctrl("mrs_natural/curMedianTempo", 0, ctrl_curMedianTempo_); 00104 addctrl("mrs_natural/adjustment", 0, ctrl_adjustment_); 00105 setctrlState("mrs_natural/adjustment", true); 00106 addctrl("mrs_realvec/bestFinalAgentHistory", realvec(), ctrl_bestFinalAgentHistory_); 00107 setctrlState("mrs_realvec/bestFinalAgentHistory", true); 00108 addctrl("mrs_natural/soundFileSize", 0, ctrl_soundFileSize_); 00109 setctrlState("mrs_natural/soundFileSize", true); 00110 addctrl("mrs_bool/nonCausal", false, ctrl_nonCausal_); 00111 setctrlState("mrs_bool/nonCausal", true); 00112 addctrl("mrs_natural/socketsPort", -1, ctrl_socketsPort_); 00113 setctrlState("mrs_natural/socketsPort", true); 00114 addctrl("mrs_real/tempo", 80.0, ctrl_tempo_); 00115 00116 00117 } 00118 00119 void 00120 BeatTimesSink::myUpdate(MarControlPtr sender) 00121 { 00122 MRSDIAG("BeatTimesSink.cpp - BeatTimesSink:myUpdate"); 00123 MarSystem::myUpdate(sender); 00124 00125 hopSize_ = ctrl_hopSize_->to<mrs_natural>(); 00126 winSize_ = ctrl_winSize_->to<mrs_natural>(); 00127 srcFs_ = ctrl_srcFs_->to<mrs_real>(); 00128 00129 adjustment_ = (mrs_real) ctrl_adjustment_->to<mrs_natural>(); 00130 00131 mode_ = ctrl_mode_->to<mrs_string>(); 00132 00133 bestFinalAgentHistory_ = ctrl_bestFinalAgentHistory_->to<mrs_realvec>(); 00134 soundFileSize_ = ctrl_soundFileSize_->to<mrs_natural>(); 00135 nonCausal_ = ctrl_nonCausal_->to<mrs_bool>(); 00136 socketsPort_ = ctrl_socketsPort_->to<mrs_natural>(); 00137 } 00138 00139 mrs_natural 00140 BeatTimesSink::refreshSocket() 00141 { 00142 #ifdef _WIN32 00143 #pragma comment(lib, "Ws2_32.lib") //include Ws2_32.lib 00144 #endif 00145 00146 /* WSADATA wsaData; 00147 int error; 00148 struct sockaddr_in mySckAd; 00149 DWORD myError; 00150 myError=GetLastError(); 00151 */ 00152 00153 // error=WSAStartup(MAKEWORD(2,2),&wsaData); 00154 // mySocket_=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP); //UDP 00155 // if(mySocket_==INVALID_SOCKET) 00156 // cout << "Socket Error - Invalid socket!" << endl; 00157 // myError=GetLastError(); 00158 00159 /* struct hostent *host; 00160 if((host=gethostbyname(szServer))==NULL) 00161 { 00162 cout << "Socket Error server problem!" << endl; 00163 } 00164 00165 memset(&mySckAd,0,sizeof(mySckAd)); 00166 mySckAd.sin_family=AF_INET; 00167 mySckAd.sin_addr.s_addr=((struct in_addr*) (host->h_addr))->s_addr; 00168 mySckAd.sin_port=htons((u_short)socketsPort_); 00169 error=connect(mySocket_,(LPSOCKADDR) &mySckAd ,sizeof(mySckAd)); 00170 myError=GetLastError(); 00171 */ 00172 return 1; 00173 } 00174 00175 mrs_realvec 00176 BeatTimesSink::addMedianVector(mrs_real ibiBPM) 00177 { 00178 mrs_bool bigger = false; 00179 mrs_realvec tmp(beatCount_); 00180 00181 //stretch median bpm vector if it reaches its limit 00182 if(beatCount_ >= ibiBPMVec_.getSize()) 00183 ibiBPMVec_.stretch(beatCount_); 00184 00185 for(mrs_natural j = 0; j < beatCount_-1; j++) 00186 { 00187 //copy all 00188 tmp(j) = ibiBPMVec_(j); 00189 } 00190 for(mrs_natural i = beatCount_-2; i >=0 ; i--) 00191 { 00192 if(ibiBPM > ibiBPMVec_(i)) 00193 { 00194 ibiBPMVec_(i+1) = ibiBPM; 00195 for(mrs_natural z = i+1; z < beatCount_-1; z++) 00196 ibiBPMVec_(z+1) = tmp(z); 00197 //ibiBPMVec_.stretchWrite((z+1), tmp(z)); 00198 00199 bigger = true; 00200 break; 00201 } 00202 } 00203 if(!bigger) 00204 { 00205 ibiBPMVec_(0) = ibiBPM; 00206 for(mrs_natural z = 0; z < beatCount_-1; z++) 00207 ibiBPMVec_(z+1) = tmp(z); 00208 //ibiBPMVec_.stretchWrite((z+1), tmp(z)); 00209 } 00210 00211 //for(int i = 0; i<ibiBPMVec_.getSize(); i++) 00212 // cout << i << ": " << ibiBPMVec_(i) << "; " << endl; 00213 00214 return ibiBPMVec_; 00215 } 00216 00217 void 00218 BeatTimesSink::myProcess(realvec& in, realvec& out) 00219 { 00220 //Frame (tick) counter: (updated from BeatReferee's next time frame -1) 00221 timeElapsed_ = ctrl_tickCount_->to<mrs_natural>()-1; 00222 00223 //cout << "BSink: " << timeElapsed_ << endl; 00224 00225 //FlowThru input 00226 out = in; 00227 00228 if(!nonCausal_) 00229 { 00230 //If Beat: 00231 if(in(0,0) == 1.0) //only count after 1st beat 00232 { 00233 //For writing only beats after inc_ (to avoid writing first unconsistent beats) 00234 if(beatCount_ >= inc_) 00235 { 00236 //Output BeatTime (in Seconds) = ((timeElapsed_ (inFrames) * hopSize_) - adjustment) / srcFs_ 00237 srcFs_ = ctrl_srcFs_->to<mrs_real>(); 00238 beatTime_ = ((timeElapsed_ * hopSize_) - adjustment_) / srcFs_; 00239 00240 //cout << "Beat at: " << beatTime_ << " (s)" << endl; 00241 00242 //after the 1st beat calculate ibi 00243 if(beatCount_ > inc_) 00244 { 00245 ibiBPM_ = (60.0 / (beatTime_ - lastBeatTime_)); //inter-beat-interval (in BPMs) 00246 tempoVec_.push_back(ibiBPM_); 00247 } 00248 00249 //curMedianTempo = (mrs_natural) (ibiBPMVec_((mrs_natural)(beatCount_ / 2.0)) + 0.5); 00250 mrs_natural curMedianTempo; 00251 mrs_realvec tempoVecMedian_(1); 00252 if(tempoVec_.size() > 10) 00253 { 00254 tempoVecMedian_.stretch(10); //account for last 10IBIs (11beats) 00255 mrs_natural ii = 0; 00256 for(mrs_natural s = (mrs_natural) (tempoVec_.size()-10); s < (mrs_natural) tempoVec_.size(); s++) 00257 { 00258 tempoVecMedian_(ii) = tempoVec_.at(s); 00259 ii++; 00260 } 00261 } 00262 else 00263 { 00264 tempoVecMedian_.stretch((mrs_natural)tempoVec_.size()); 00265 for(mrs_natural s = 0; s < (mrs_natural) tempoVec_.size(); s++) 00266 tempoVecMedian_(s) = tempoVec_.at(s); 00267 00268 } 00269 curMedianTempo = (mrs_natural) tempoVecMedian_.median(); 00270 00271 //cout << "Beat at: " << beatTime_ << " (s) - " << curMedianTempo << " (BPMs)" << endl; 00272 00273 updControl(ctrl_curMedianTempo_, curMedianTempo); 00274 00275 fstream outStream; 00276 fstream outStream2; 00277 fstream outStream3; 00278 00279 if((strcmp(mode_.c_str(), "beatTimes") == 0) || (strcmp(mode_.c_str(), "beats+meanTempo") == 0) 00280 || (strcmp(mode_.c_str(), "beats+medianTempo") == 0) || (strcmp(mode_.c_str(), "beats+meanTempo+medianTempo") == 0)) 00281 { 00282 ostringstream oss; 00283 00284 //initially a new output file is created 00285 //(If the file exists, its content is deleted and it is treated as a new file) 00286 if(initialOut_) 00287 { 00288 oss << ctrl_destFileName_->to<mrs_string>() << ".txt"; 00289 outStream.open(oss.str().c_str(), ios::out|ios::trunc); 00290 outStream << beatTime_ << endl; 00291 outStream.close(); 00292 initialOut_ = false; 00293 } 00294 00295 //output is appended in the end of the file 00296 else 00297 { 00298 oss << ctrl_destFileName_->to<mrs_string>() << ".txt"; 00299 outStream.open(oss.str().c_str(), ios::out|ios::app); 00300 00301 outStream << beatTime_ << " " << ibiBPM_ << endl; 00302 //outStream << beatTime_ << endl; 00303 } 00304 } 00305 00306 if((strcmp(mode_.c_str(), "meanTempo") == 0) || (strcmp(mode_.c_str(), "beats+meanTempo") == 0) 00307 || (strcmp(mode_.c_str(), "beats+meanTempo+medianTempo") == 0)) 00308 { 00309 ostringstream oss2; 00310 if(initialOut2_) 00311 { 00312 oss2 << ctrl_destFileName_->to<mrs_string>() << "_meanTempo.txt"; 00313 00314 outStream2.open(oss2.str().c_str(), ios::out|ios::trunc); 00315 outStream2.close(); 00316 initialOut2_ = false; 00317 } 00318 00319 if(beatCount_ > inc_) 00320 { 00321 ibiBPMSum_ += ibiBPM_; 00322 mrs_natural output = (mrs_natural) ((ibiBPMSum_ / (beatCount_-inc_)) + 0.5); 00323 00324 oss2 << ctrl_destFileName_->to<mrs_string>() << "_meanTempo.txt"; 00325 outStream2.open(oss2.str().c_str()); 00326 outStream2 << output << endl; 00327 outStream2.close(); 00328 } 00329 } 00330 00331 if((strcmp(mode_.c_str(), "medianTempo") == 0) || (strcmp(mode_.c_str(), "beats+medianTempo") == 0) 00332 || (strcmp(mode_.c_str(), "beats+meanTempo+medianTempo") == 0)) 00333 { 00334 ostringstream oss3; 00335 if(initialOut3_) 00336 { 00337 oss3 << ctrl_destFileName_->to<mrs_string>() << "_medianTempo.txt"; 00338 outStream3.open(oss3.str().c_str(), ios::out|ios::trunc); 00339 outStream3.close(); 00340 initialOut3_ = false; 00341 } 00342 00343 if(beatCount_ > inc_) 00344 { 00345 addMedianVector(ibiBPM_); 00346 00347 mrs_natural output; 00348 output = (mrs_natural) (ibiBPMVec_((mrs_natural)(beatCount_ / 2.0)) + 0.5); 00349 ctrl_tempo_->setValue(output * 1.0, NOUPDATE); 00350 00351 /* 00352 if(beatCount_ % 2 == 0) 00353 { 00354 output = (mrs_natural) (ibiBPMVec_((mrs_natural)(beatCount_ / 2.0)) + 0.5); 00355 } 00356 else 00357 { 00358 output = (mrs_natural) ((ibiBPMVec_((mrs_natural)floor((beatCount_ / 2.0))) 00359 + ibiBPMVec_((mrs_natural)ceil((beatCount_ / 2.0))) / 2.0) +0.5); 00360 } 00361 */ 00362 00363 oss3 << ctrl_destFileName_->to<mrs_string>() << "_medianTempo.txt"; 00364 outStream3.open(oss3.str().c_str()); 00365 outStream3 << output << endl; 00366 outStream3.close(); 00367 00368 //MATLAB_PUT(ibiBPMVec_, "IBIVector1"); 00369 } 00370 00371 else if(beatCount_ == 2) //if only two beats => equal to ibi 00372 { 00373 oss3 << ctrl_destFileName_->to<mrs_string>() << "_medianTempo.txt"; 00374 outStream.open(oss3.str().c_str()); 00375 outStream << (mrs_natural) (ibiBPM_ + 0.5); //(+0.5 for round integer) 00376 outStream.close(); 00377 } 00378 } 00379 00380 00381 //MATLAB_PUT(ibiBPMVec_, "IBIVector"); 00382 lastBeatTime_ = beatTime_; 00383 } 00384 beatCount_ ++; 00385 } 00386 00387 //send beats via UDP sockets 00388 /* if(socketsPort_ > 0) 00389 { 00390 if ( mySocket_ > 1000 ) //check if socket already initialized 00391 refreshSocket(); //intialize socket 00392 00393 else 00394 { 00395 //fill the buffer with samples... 00396 data_ = in.getData(); //pointer to input data 00397 ostringstream msg; 00398 msg << *data_ << "(" << tempo_ << ")\n"; //build msg to send via sockets 00399 00400 if(*data_ != -1.0) //if valid data 00401 send(mySocket_, msg.str().c_str(),strlen(msg.str().c_str()),0); 00402 00403 } 00404 } 00405 */ 00406 } 00407 if(nonCausal_) 00408 { 00409 if(timeElapsed_ == soundFileSize_-1) //[! -1 for acouting on time of timing reset on backtrace mode] 00410 { 00411 //if no beats detected [to avoid writing beatTimes output file] 00412 if(bestFinalAgentHistory_(0) >= 0.0) 00413 { 00414 //reset beatCount, ibiBPMSum, and ibiBPMVec, from causal analysis 00415 for(mrs_natural i = 0; i < beatCount_; i++) 00416 ibiBPMVec_(i) = 0.0; 00417 beatCount_ = 0; 00418 ibiBPMSum_ = 0.0; 00419 00420 //first beatTime: 00421 beatTime_ = ((bestFinalAgentHistory_(0) * hopSize_) - adjustment_) / srcFs_; 00422 lastBeatTime_ = beatTime_; 00423 beatTimeTmp_ = beatTime_; 00424 beatCount_++; 00425 00426 fstream outStream; 00427 ostringstream oss; 00428 if((strcmp(mode_.c_str(), "beatTimes") == 0) || (strcmp(mode_.c_str(), "beats+medianTempo") == 0) 00429 || (strcmp(mode_.c_str(), "beats+meanTempo") == 0) || (strcmp(mode_.c_str(), "beats+meanTempo+medianTempo") == 0)) 00430 { 00431 oss << ctrl_destFileName_->to<mrs_string>() << ".txt"; 00432 outStream.open(oss.str().c_str(), ios::out|ios::trunc); 00433 outStream << beatTime_ << endl; 00434 } 00435 00436 //remaining beatTimes 00437 for(int i = 1; i < bestFinalAgentHistory_.getCols(); i++) 00438 { 00439 beatTime_ = ((bestFinalAgentHistory_(i) * hopSize_) - adjustment_) / srcFs_; 00440 00441 mrs_real ibi = (beatTime_ - lastBeatTime_); 00442 00443 //cout << "BEAT " << i << ": " << beatTime_ << "; IBI: " << ibi << endl; 00444 00445 //mrs_real nextIbi = 0; 00446 mrs_real nextBeatTime = 0; 00447 //if(i < bestFinalAgentHistory_.getCols()-1) //everything commented is for handle transition (see thres below) 00448 //{ 00449 nextBeatTime = ((bestFinalAgentHistory_(i+1) * hopSize_) - adjustment_) / srcFs_; 00450 //nextIbi = (nextBeatTime - beatTimeTmp_); 00451 //} 00452 // 00453 //else //if last beat always write 00454 //{ 00455 // ibiBPM_ = (60.0 / ibi); //inter-beat-interval (in BPMs) 00456 // outStream << beatTime_ << " " << ibiBPM_ << endl; 00457 00458 addMedianVector(ibiBPM_); //for calculating medianTempo 00459 //} 00460 00461 //cout << "i: " << i << "; beatTime: " << beatTime_ << "; ibi: " << ibi << "; lastIbi: " << lastIbi_ << endl; 00462 //to avoid supurious beats at the transitions (on best agent changes) 00463 //[prioritize replacing (next) agent] 00464 //if(nextIbi > (0.3*ibi)) //REMOVE!?!?!? 00465 //{ 00466 ibiBPM_ = (60.0 / ibi); //inter-beat-interval (in BPMs) 00467 00468 if((strcmp(mode_.c_str(), "beatTimes") == 0) || (strcmp(mode_.c_str(), "beats+meanTempo") == 0) 00469 || (strcmp(mode_.c_str(), "beats+medianTempo") == 0) || (strcmp(mode_.c_str(), "beats+meanTempo+medianTempo") == 0)) 00470 { 00471 outStream << beatTime_ << " " << ibiBPM_ << endl; 00472 } 00473 00474 addMedianVector(ibiBPM_); //for calculating medianTempo 00475 ibiBPMSum_ += ibiBPM_; //for calculating meanTempo 00476 lastBeatTime_ = beatTime_; 00477 beatTimeTmp_ = nextBeatTime; 00478 beatCount_ ++; 00479 //} 00480 lastIbi_ = ibi; 00481 } 00482 00483 if((strcmp(mode_.c_str(), "meanTempo") == 0) || (strcmp(mode_.c_str(), "beats+meanTempo") == 0) 00484 || (strcmp(mode_.c_str(), "beats+meanTempo+medianTempo") == 0)) 00485 { 00486 ostringstream oss2; 00487 fstream outStream2; 00488 oss2 << ctrl_destFileName_->to<mrs_string>() << "_meanTempo.txt"; 00489 outStream2.open(oss2.str().c_str(), ios::out|ios::trunc); 00490 outStream2 << (mrs_natural) ((ibiBPMSum_/beatCount_) + 0.5) << endl; 00491 outStream2.close(); 00492 } 00493 00494 if((strcmp(mode_.c_str(), "medianTempo") == 0) || (strcmp(mode_.c_str(), "beats+medianTempo") == 0) 00495 || (strcmp(mode_.c_str(), "beats+meanTempo+medianTempo") == 0)) 00496 { 00497 mrs_natural output; 00498 output = (mrs_natural) (ibiBPMVec_((mrs_natural)(beatCount_ / 2.0)) + 0.5); 00499 00500 ostringstream oss3; 00501 fstream outStream3; 00502 oss3 << ctrl_destFileName_->to<mrs_string>() << "_medianTempo.txt"; 00503 outStream3.open(oss3.str().c_str(), ios::out|ios::trunc); 00504 outStream3 << output << endl; 00505 outStream3.close(); 00506 00507 //MATLAB_PUT(ibiBPMVec_, "IBIVector"); 00508 //MATLAB_PUT(bestFinalAgentHistory_, "bestAgentHistory"); 00509 } 00510 } 00511 } 00512 } 00513 //MATLAB_PUT(out, "BeatTimesSink"); 00514 } 00515 00516 00517 00518 00519 00520 00521 00522