00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "Yin.h"
00020
00021
00022
00023
00024
00025
00026 using namespace std;
00027 using namespace Marsyas;
00028
00029 Yin::Yin(mrs_string name):MarSystem("Yin", name)
00030 {
00031 addControls();
00032 }
00033
00034 Yin::Yin(const Yin& a) : MarSystem(a)
00035 {
00036 ctrl_tolerance_ = getctrl("mrs_real/tolerance");
00037 ctrl_frequency_min_ = getctrl("mrs_real/frequency_min");
00038 ctrl_frequency_max_ = getctrl("mrs_real/frequency_max");
00039 }
00040
00041
00042 Yin::~Yin()
00043 {
00044 }
00045
00046 MarSystem*
00047 Yin::clone() const
00048 {
00049 return new Yin(*this);
00050 }
00051
00052 void
00053 Yin::addControls()
00054 {
00055
00056
00057 addctrl("mrs_real/tolerance", 0.15, ctrl_tolerance_);
00058 addctrl("mrs_real/frequency_min", 0.0, ctrl_frequency_min_);
00059 addctrl("mrs_real/frequency_max", 0.0, ctrl_frequency_max_);
00060 }
00061
00062 void
00063 Yin::myUpdate(MarControlPtr sender)
00064 {
00065 MRSDIAG("Yin.cpp - Yin:myUpdate");
00066
00067 MarSystem::myUpdate(sender);
00068
00069 ctrl_onSamples_->setValue(1, NOUPDATE);
00070 ctrl_onObservations_->setValue(ctrl_inObservations_, NOUPDATE);
00071 ctrl_osrate_->setValue(ctrl_israte_, NOUPDATE);
00072 ctrl_onObsNames_->setValue(ctrl_inObsNames_, NOUPDATE);
00073
00074 if (yin_buffer_realvec_.getSize() != inSamples_/2) {
00075 yin_buffer_realvec_.allocate(inSamples_ / 2);
00076 }
00077
00078
00079 mrs_string inObsNames = ctrl_inObsNames_->to<mrs_string>();
00080 ctrl_onObsNames_->setValue(obsNamesAddPrefix(inObsNames, "Yin_"), NOUPDATE);
00081 }
00082
00083 double Yin::aubio_quadfrac(double s0, double s1, double s2, double pf) {
00084 double tmp = s0 + (pf/2.) * (pf * ( s0 - 2.*s1 + s2 ) - 3.*s0 + 4.*s1 - s2);
00085 return tmp;
00086 }
00087
00088 double Yin::vec_quadint_min(realvec *x,unsigned int pos, unsigned int span) {
00089 double step = 1./200.;
00090
00091 double res, frac, s0, s1, s2, exactpos = (double)pos, resold = 100000.;
00092 if ((pos > span) && (pos < x->getSize()-span)) {
00093
00094
00095
00096 s0 = (*x)(pos-span);
00097 s1 = (*x)(pos);
00098 s2 = (*x)(pos+span);
00099
00100 for (frac = 0.; frac < 2.; frac = frac + step) {
00101 res = Yin::aubio_quadfrac(s0, s1, s2, frac);
00102 if (res < resold) {
00103 resold = res;
00104 } else {
00105 exactpos += (frac-step)*span - span/2.;
00106 break;
00107 }
00108 }
00109 }
00110 return exactpos;
00111 }
00112
00113 unsigned int Yin::vec_min_elem(realvec *s)
00114 {
00115 size_t i = 0;
00116 int pos=0;
00117 double tmp = (*s)(0,0);
00118
00119 for (mrs_natural j=0; j < s->getSize(); j++) {
00120 pos = (tmp < (*s)(+6))? pos : j;
00121 tmp = (tmp < (*s)(i,j))? tmp : (*s)(i,j);
00122 }
00123
00124 return pos;
00125 }
00126
00127 void
00128 Yin::myProcess(realvec& in, realvec& out)
00129 {
00130
00131
00132 const mrs_real tol = ctrl_tolerance_->to<mrs_real>();
00133
00134
00135 mrs_real *yin_buffer = yin_buffer_realvec_.getData();
00136 const mrs_natural yin_buffer_size = yin_buffer_realvec_.getSize();
00137
00138 mrs_real *input = in.getData();
00139
00140
00141 mrs_real pitch = -1.0;
00142
00143
00144
00145
00146 const mrs_real freq_max = ctrl_frequency_max_->to<mrs_real>();
00147 const mrs_real freq_min = ctrl_frequency_min_->to<mrs_real>();
00148
00149
00150 mrs_natural low_sample = 4;
00151 if (freq_max > 0) {
00152 low_sample = israte_ / freq_max;
00153 }
00154 mrs_natural high_sample = yin_buffer_size;
00155 if (freq_min > 0) {
00156 high_sample = israte_ / freq_min;
00157 }
00158
00159
00160
00161 mrs_real cmndf = 0.;
00162
00163
00164 std::fill(yin_buffer, yin_buffer + yin_buffer_size, 0.0);
00165 yin_buffer[0] = 1.;
00166
00167
00168 for (mrs_natural tau=1; tau < high_sample; tau++)
00169 {
00170
00171 for (mrs_natural j=0; j < yin_buffer_size;j++)
00172 {
00173 const mrs_real delta = input[j] - input[j+tau];
00174 yin_buffer[tau] += delta * delta;
00175 }
00176 cmndf += yin_buffer[tau];
00177 yin_buffer[tau] *= tau / cmndf;
00178 if (tau > low_sample) {
00179 const mrs_natural period = tau-3;
00180
00181
00182 if((yin_buffer[period] < tol) &&
00183 (yin_buffer[period] < yin_buffer[period+1])) {
00184 pitch = vec_quadint_min(&yin_buffer_realvec_,period,1);
00185 break;
00186 }
00187 }
00188 }
00189 if (pitch < 0) {
00190 pitch = vec_quadint_min(&yin_buffer_realvec_,
00191 vec_min_elem(&yin_buffer_realvec_),1);
00192 }
00193
00194 if (pitch !=0)
00195 out(0,0) = ctrl_osrate_/pitch;
00196 else
00197 out(0,0) = 0.0;
00198
00199 }