Marsyas  0.6.0-alpha
/usr/src/RPM/BUILD/marsyas-0.6.0/src/marsyas/marsystems/BeatTimesSink.cpp
Go to the documentation of this file.
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