Marsyas  0.6.0-alpha
/usr/src/RPM/BUILD/marsyas-0.6.0/src/marsyas/marsystems/AubioYin.cpp
Go to the documentation of this file.
00001 /*
00002 ** Copyright (C) 1998-2014 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 "AubioYin.h"
00020 #include "../common_source.h"
00021 
00022 using std::ostringstream;
00023 using namespace Marsyas;
00024 
00025 AubioYin::AubioYin(mrs_string name):MarSystem("AubioYin", name)
00026 {
00027   addControls();
00028 }
00029 
00030 AubioYin::AubioYin(const AubioYin& a) : MarSystem(a)
00031 {
00032   ctrl_tolerance_ = getctrl("mrs_real/tolerance");
00033 }
00034 
00035 
00036 AubioYin::~AubioYin()
00037 {
00038 }
00039 
00040 MarSystem*
00041 AubioYin::clone() const
00042 {
00043   return new AubioYin(*this);
00044 }
00045 
00046 void
00047 AubioYin::addControls()
00048 {
00049 
00050   // The value of 0.15 was the default in Aubio
00051   addctrl("mrs_real/tolerance", 0.15, ctrl_tolerance_);
00052 
00053 }
00054 
00055 void
00056 AubioYin::myUpdate(MarControlPtr sender)
00057 {
00058   MRSDIAG("AubioYin.cpp - AubioYin:myUpdate");
00059 
00060   MarSystem::myUpdate(sender);
00061 
00062   ctrl_onSamples_->setValue(1, NOUPDATE);
00063   ctrl_onObservations_->setValue(ctrl_inObservations_, NOUPDATE);
00064   ctrl_osrate_->setValue(ctrl_israte_, NOUPDATE);
00065   ctrl_onObsNames_->setValue(ctrl_inObsNames_, NOUPDATE);
00066 
00067 }
00068 
00069 double AubioYin::aubio_quadfrac(double s0, double s1, double s2, double pf) {
00070   double tmp = s0 + (pf/2.) * (pf * ( s0 - 2.*s1 + s2 ) - 3.*s0 + 4.*s1 - s2);
00071   return tmp;
00072 }
00073 
00074 double AubioYin::vec_quadint_min(realvec *x,unsigned int pos, unsigned int span) {
00075   double step = 1./200.;
00076   /* init resold to - something (in case x[pos+-span]<0)) */
00077   double res, frac, s0, s1, s2, exactpos = (double)pos, resold = 100000.;
00078   if ((pos > span) && (pos < x->getSize()-span)) {
00079     s0 = (*x)(0,pos-span);
00080     s1 = (*x)(0,pos);
00081     s2 = (*x)(0,pos+span);
00082     /* increase frac */
00083     for (frac = 0.; frac < 2.; frac = frac + step) {
00084       res = AubioYin::aubio_quadfrac(s0, s1, s2, frac);
00085       if (res < resold) {
00086         resold = res;
00087       } else {
00088         exactpos += (frac-step)*span - span/2.;
00089         break;
00090       }
00091     }
00092   }
00093   return exactpos;
00094 }
00095 
00096 unsigned int AubioYin::vec_min_elem(realvec *s)
00097 {
00098   int i = 0;
00099   int j = 0;
00100   int pos=0;
00101   double tmp = (*s)(0,0);
00102 //   for (i=0; i < s->channels; ++i)
00103   for (j=0; j < s->getSize(); j++) {
00104     pos = (tmp < (*s)(i,j))? pos : j;
00105     tmp = (tmp < (*s)(i,j))? tmp : (*s)(i,j);
00106   }
00107 //     }
00108   return pos;
00109 }
00110 
00111 void
00112 AubioYin::myProcess(realvec& in, realvec& out)
00113 {
00114   mrs_natural c=0;
00115 
00116   // Make a temporary realvec to build up the yin function in
00117   // sness - This is very inefficient - Move to update function
00118   realvec yin((mrs_natural)(inSamples_/2.0));
00119 
00120   // The tolerance for the yin algorithm
00121   mrs_real tol = ctrl_tolerance_->to<mrs_real>();
00122 
00123   double pitch = -1.0;
00124 
00125 //   cout << "yin.getSize()=" << yin.getSize() << endl;
00126 //   cout << "tol=" << tol << endl;
00127 
00128   // Calculate the pitch with the Yin method
00129   int j,tau = 0;
00130   int period;
00131   double tmp = 0., tmp2 = 0.;
00132   yin(c,0) = 1.;
00133   for (tau=1; tau<yin.getSize(); tau++)
00134   {
00135 //    cout << "tau=" << tau << endl;
00136     yin(c,tau) = 0.;
00137     for (j=0; j<yin.getSize(); j++)
00138     {
00139       tmp = in(c,j) - in(c,j+tau);
00140       yin(c,tau) += tmp * tmp;
00141     }
00142     tmp2 += yin(c,tau);
00143     yin(c,tau) *= tau/tmp2;
00144     period = tau-3;
00145     if(tau > 4 && (yin(c,period) < tol) &&
00146         (yin(c,period) < yin(c,period+1))) {
00147       pitch = vec_quadint_min(&yin,period,1);
00148       break;
00149     }
00150   }
00151   if (pitch < 0) {
00152     pitch = vec_quadint_min(&yin,vec_min_elem(&yin),1);
00153   }
00154   
00155   out(0,0) = ctrl_osrate_/pitch;
00156 //   while (out(0,0) > 500) // ignore above 1000Hz 
00157 //     out(0,0) = out(0,0) / 2;
00158   
00159   
00160 
00161 //   std::cout << out(0,0) << " - " << pitch  << std::endl;
00162 
00163 }