Marsyas
0.6.0-alpha
|
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 }