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 "Yin.h" 00020 #include "../common_source.h" 00021 00022 /* 00023 THIS MARSYSTEM IS VERY SIMILAR TO AUBIO_YIN, BUT DO NOT DELETE 00024 IT BECAUSE I NEED IT. - Graham 00025 */ 00026 00027 using namespace std; 00028 using namespace Marsyas; 00029 00030 Yin::Yin(mrs_string name):MarSystem("Yin", name) 00031 { 00032 addControls(); 00033 } 00034 00035 Yin::Yin(const Yin& a) : MarSystem(a) 00036 { 00037 ctrl_tolerance_ = getctrl("mrs_real/tolerance"); 00038 ctrl_frequency_min_ = getctrl("mrs_real/frequency_min"); 00039 ctrl_frequency_max_ = getctrl("mrs_real/frequency_max"); 00040 } 00041 00042 00043 Yin::~Yin() 00044 { 00045 } 00046 00047 MarSystem* 00048 Yin::clone() const 00049 { 00050 return new Yin(*this); 00051 } 00052 00053 void 00054 Yin::addControls() 00055 { 00056 00057 // The value of 0.15 was the default in Aubio 00058 addctrl("mrs_real/tolerance", 0.15, ctrl_tolerance_); 00059 addctrl("mrs_real/frequency_min", 0.0, ctrl_frequency_min_); 00060 addctrl("mrs_real/frequency_max", 0.0, ctrl_frequency_max_); 00061 } 00062 00063 void 00064 Yin::myUpdate(MarControlPtr sender) 00065 { 00066 MRSDIAG("Yin.cpp - Yin:myUpdate"); 00067 00068 MarSystem::myUpdate(sender); 00069 00070 ctrl_onSamples_->setValue(1, NOUPDATE); 00071 ctrl_onObservations_->setValue(ctrl_inObservations_, NOUPDATE); 00072 ctrl_osrate_->setValue(ctrl_israte_, NOUPDATE); 00073 ctrl_onObsNames_->setValue(ctrl_inObsNames_, NOUPDATE); 00074 00075 if (yin_buffer_realvec_.getSize() != inSamples_/2) { 00076 yin_buffer_realvec_.allocate(inSamples_ / 2); 00077 } 00078 00079 // Add prefix to the observation names. 00080 mrs_string inObsNames = ctrl_inObsNames_->to<mrs_string>(); 00081 ctrl_onObsNames_->setValue(obsNamesAddPrefix(inObsNames, "Yin_"), NOUPDATE); 00082 } 00083 00084 double Yin::aubio_quadfrac(double s0, double s1, double s2, double pf) { 00085 double tmp = s0 + (pf/2.) * (pf * ( s0 - 2.*s1 + s2 ) - 3.*s0 + 4.*s1 - s2); 00086 return tmp; 00087 } 00088 00089 double Yin::vec_quadint_min(realvec *x,unsigned int pos, unsigned int span) { 00090 double step = 1./200.; 00091 /* init resold to - something (in case x[pos+-span]<0)) */ 00092 double res, frac, s0, s1, s2, exactpos = (double)pos, resold = 100000.; 00093 if ((pos > span) && (pos < x->getSize()-span)) { 00094 //s0 = (*x)(0,pos-span); 00095 //s1 = (*x)(0,pos); 00096 //s2 = (*x)(0,pos+span); 00097 s0 = (*x)(pos-span); 00098 s1 = (*x)(pos); 00099 s2 = (*x)(pos+span); 00100 /* increase frac */ 00101 for (frac = 0.; frac < 2.; frac = frac + step) { 00102 res = Yin::aubio_quadfrac(s0, s1, s2, frac); 00103 if (res < resold) { 00104 resold = res; 00105 } else { 00106 exactpos += (frac-step)*span - span/2.; 00107 break; 00108 } 00109 } 00110 } 00111 return exactpos; 00112 } 00113 00114 unsigned int Yin::vec_min_elem(realvec *s) 00115 { 00116 mrs_natural i = 0; 00117 int pos=0; 00118 double tmp = (*s)(0,0); 00119 // for (i=0; i < s->channels; ++i) 00120 for (mrs_natural j=0; j < s->getSize(); j++) { 00121 pos = (tmp < (*s)(+6))? pos : j; 00122 tmp = (tmp < (*s)(i,j))? tmp : (*s)(i,j); 00123 } 00124 // } 00125 return pos; 00126 } 00127 00128 void 00129 Yin::myProcess(realvec& in, realvec& out) 00130 { 00131 00132 // The tolerance for the yin algorithm 00133 const mrs_real tol = ctrl_tolerance_->to<mrs_real>(); 00134 00135 // get pointers to avoid excessive (long,long) lookups 00136 mrs_real *yin_buffer = yin_buffer_realvec_.getData(); 00137 const mrs_natural yin_buffer_size = yin_buffer_realvec_.getSize(); 00138 // ASSUME: only one channel 00139 mrs_real *input = in.getData(); 00140 00141 00142 mrs_real pitch = -1.0; 00143 00144 // cout << "yin.getSize()=" << yin.getSize() << endl; 00145 // cout << "tol=" << tol << endl; 00146 00147 const mrs_real freq_max = ctrl_frequency_max_->to<mrs_real>(); 00148 const mrs_real freq_min = ctrl_frequency_min_->to<mrs_real>(); 00149 00150 // yes, low_sample comes from the highest pitch 00151 mrs_natural low_sample = 4; 00152 if (freq_max > 0) { 00153 low_sample = (mrs_natural) (israte_ / freq_max); 00154 } 00155 mrs_natural high_sample = yin_buffer_size; 00156 if (freq_min > 0) { 00157 high_sample = (mrs_natural) (israte_ / freq_min); 00158 } 00159 00160 // Calculate the pitch with the Yin method 00161 //mrs_natural c=0; 00162 mrs_real cmndf = 0.; // cumulative mean normalized difference function 00163 00164 00165 std::fill(yin_buffer, yin_buffer + yin_buffer_size, 0.0); 00166 yin_buffer[0] = 1.; 00167 00168 //for (mrs_natural tau=1; tau < yin_size_; tau++) 00169 for (mrs_natural tau=1; tau < high_sample; tau++) 00170 { 00171 // d_t( tau ) 00172 for (mrs_natural j=0; j < yin_buffer_size; j++) 00173 { 00174 const mrs_real delta = input[j] - input[j+tau]; 00175 yin_buffer[tau] += delta * delta; 00176 } 00177 cmndf += yin_buffer[tau]; 00178 yin_buffer[tau] *= tau / cmndf; 00179 if (tau > low_sample) { 00180 const mrs_natural period = tau-3; 00181 //if(tau > 4 && (yin_buffer_(c,period) < tol) && 00182 // (yin_buffer_(c,period) < yin_buffer_(c,period+1))) 00183 if((yin_buffer[period] < tol) && 00184 (yin_buffer[period] < yin_buffer[period+1])) { 00185 pitch = vec_quadint_min(&yin_buffer_realvec_,period,1); 00186 break; 00187 } 00188 } 00189 } 00190 if (pitch < 0) { 00191 pitch = vec_quadint_min(&yin_buffer_realvec_, 00192 vec_min_elem(&yin_buffer_realvec_),1); 00193 } 00194 00195 if (pitch !=0) 00196 out(0,0) = ctrl_osrate_/pitch; 00197 else 00198 out(0,0) = 0.0; 00199 00200 }