Chris@9: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ Chris@9: Chris@9: /* Chris@9: pYIN - A fundamental frequency estimator for monophonic audio Chris@9: Centre for Digital Music, Queen Mary, University of London. Chris@9: Chris@9: This program is free software; you can redistribute it and/or Chris@9: modify it under the terms of the GNU General Public License as Chris@9: published by the Free Software Foundation; either version 2 of the Chris@9: License, or (at your option) any later version. See the file Chris@9: COPYING included with this distribution for more information. Chris@9: */ Chris@9: matthiasm@0: #include "YinUtil.h" matthiasm@0: matthiasm@0: #include matthiasm@0: matthiasm@0: #include matthiasm@0: #include matthiasm@0: #include matthiasm@0: Chris@140: YinUtil::YinUtil(int yinBufferSize) : Chris@136: m_yinBufferSize(yinBufferSize), Chris@136: m_fft(yinBufferSize * 2) Chris@136: { Chris@136: } Chris@136: Chris@136: YinUtil::~YinUtil() Chris@136: { Chris@136: } Chris@136: matthiasm@0: void Chris@136: YinUtil::slowDifference(const double *in, double *yinBuffer) matthiasm@60: { matthiasm@60: yinBuffer[0] = 0; matthiasm@60: double delta ; matthiasm@60: int startPoint = 0; matthiasm@60: int endPoint = 0; Chris@137: for (int i = 1; i < int(m_yinBufferSize); ++i) { matthiasm@60: yinBuffer[i] = 0; Chris@136: startPoint = m_yinBufferSize/2 - i/2; Chris@136: endPoint = startPoint + m_yinBufferSize; matthiasm@60: for (int j = startPoint; j < endPoint; ++j) { matthiasm@60: delta = in[i+j] - in[j]; matthiasm@60: yinBuffer[i] += delta * delta; matthiasm@60: } matthiasm@60: } matthiasm@60: } matthiasm@60: matthiasm@60: void Chris@136: YinUtil::fastDifference(const double *in, double *yinBuffer) matthiasm@0: { matthiasm@0: // DECLARE AND INITIALISE matthiasm@0: // initialisation of most of the arrays here was done in a separate function, matthiasm@0: // with all the arrays as members of the class... moved them back here. matthiasm@0: Chris@140: int frameSize = 2 * m_yinBufferSize; Chris@140: int halfSize = m_yinBufferSize; Chris@137: Chris@137: double *audioTransformedComplex = new double[frameSize + 2]; Chris@137: double *audioOutReal = new double[frameSize]; matthiasm@0: double *kernel = new double[frameSize]; Chris@137: double *kernelTransformedComplex = new double[frameSize + 2]; Chris@137: double *yinStyleACFComplex = new double[frameSize + 2]; Chris@136: double *powerTerms = new double[m_yinBufferSize]; matthiasm@0: matthiasm@0: // POWER TERM CALCULATION matthiasm@0: // ... for the power terms in equation (7) in the Yin paper matthiasm@0: powerTerms[0] = 0.0; Chris@140: for (int j = 0; j < m_yinBufferSize; ++j) { matthiasm@0: powerTerms[0] += in[j] * in[j]; matthiasm@0: } matthiasm@0: matthiasm@0: // now iteratively calculate all others (saves a few multiplications) Chris@140: for (int tau = 1; tau < m_yinBufferSize; ++tau) { Chris@137: powerTerms[tau] = powerTerms[tau-1] - Chris@137: in[tau-1] * in[tau-1] + Chris@137: in[tau+m_yinBufferSize] * in[tau+m_yinBufferSize]; matthiasm@0: } matthiasm@0: matthiasm@0: // YIN-STYLE AUTOCORRELATION via FFT matthiasm@0: // 1. data Chris@137: m_fft.forward(in, audioTransformedComplex); matthiasm@0: matthiasm@0: // 2. half of the data, disguised as a convolution kernel Chris@140: for (int j = 0; j < m_yinBufferSize; ++j) { Chris@136: kernel[j] = in[m_yinBufferSize-1-j]; matthiasm@0: } Chris@140: for (int j = m_yinBufferSize; j < frameSize; ++j) { Chris@140: kernel[j] = 0.; Chris@140: } Chris@137: m_fft.forward(kernel, kernelTransformedComplex); matthiasm@0: matthiasm@0: // 3. convolution via complex multiplication -- written into Chris@140: for (int j = 0; j <= halfSize; ++j) { Chris@137: yinStyleACFComplex[j*2] = // real Chris@137: audioTransformedComplex[j*2] * kernelTransformedComplex[j*2] - Chris@137: audioTransformedComplex[j*2+1] * kernelTransformedComplex[j*2+1]; Chris@137: yinStyleACFComplex[j*2+1] = // imaginary Chris@137: audioTransformedComplex[j*2] * kernelTransformedComplex[j*2+1] + Chris@137: audioTransformedComplex[j*2+1] * kernelTransformedComplex[j*2]; matthiasm@0: } Chris@137: Chris@137: m_fft.inverse(yinStyleACFComplex, audioOutReal); matthiasm@0: matthiasm@0: // CALCULATION OF difference function matthiasm@0: // ... according to (7) in the Yin paper. Chris@140: for (int j = 0; j < m_yinBufferSize; ++j) { Chris@137: yinBuffer[j] = powerTerms[0] + powerTerms[j] - 2 * Chris@137: audioOutReal[j+m_yinBufferSize-1]; matthiasm@0: } Chris@137: delete [] audioTransformedComplex; Chris@137: delete [] audioOutReal; matthiasm@0: delete [] kernel; Chris@137: delete [] kernelTransformedComplex; Chris@137: delete [] yinStyleACFComplex; matthiasm@0: delete [] powerTerms; matthiasm@0: } matthiasm@0: Chris@137: matthiasm@0: void Chris@136: YinUtil::cumulativeDifference(double *yinBuffer) matthiasm@0: { Chris@140: int tau; matthiasm@0: matthiasm@0: yinBuffer[0] = 1; matthiasm@0: matthiasm@0: double runningSum = 0; matthiasm@0: Chris@136: for (tau = 1; tau < m_yinBufferSize; ++tau) { matthiasm@0: runningSum += yinBuffer[tau]; matthiasm@0: if (runningSum == 0) matthiasm@0: { matthiasm@0: yinBuffer[tau] = 1; matthiasm@0: } else { matthiasm@0: yinBuffer[tau] *= tau / runningSum; matthiasm@0: } matthiasm@0: } matthiasm@0: } matthiasm@0: matthiasm@0: int Chris@140: YinUtil::absoluteThreshold(const double *yinBuffer, double thresh) matthiasm@0: { Chris@140: int tau; Chris@140: int minTau = 0; matthiasm@0: double minVal = 1000.; matthiasm@0: matthiasm@0: // using Joren Six's "loop construct" from TarsosDSP matthiasm@0: tau = 2; Chris@136: while (tau < m_yinBufferSize) matthiasm@0: { matthiasm@0: if (yinBuffer[tau] < thresh) matthiasm@0: { Chris@136: while (tau+1 < m_yinBufferSize && yinBuffer[tau+1] < yinBuffer[tau]) matthiasm@0: { matthiasm@0: ++tau; matthiasm@0: } matthiasm@0: return tau; matthiasm@0: } else { matthiasm@0: if (yinBuffer[tau] < minVal) matthiasm@0: { matthiasm@0: minVal = yinBuffer[tau]; matthiasm@0: minTau = tau; matthiasm@0: } matthiasm@0: } matthiasm@0: ++tau; matthiasm@0: } matthiasm@0: if (minTau > 0) matthiasm@0: { matthiasm@0: return -minTau; matthiasm@0: } matthiasm@0: return 0; matthiasm@0: } matthiasm@0: Chris@154: #pragma GCC diagnostic ignored "-Wfloat-conversion" Chris@154: Chris@61: static float uniformDist[100] = {0.0100000,0.0100000,0.0100000,0.0100000,0.0100000,0.0100000,0.0100000,0.0100000,0.0100000,0.0100000,0.0100000,0.0100000,0.0100000,0.0100000,0.0100000,0.0100000,0.0100000,0.0100000,0.0100000,0.0100000,0.0100000,0.0100000,0.0100000,0.0100000,0.0100000,0.0100000,0.0100000,0.0100000,0.0100000,0.0100000,0.0100000,0.0100000,0.0100000,0.0100000,0.0100000,0.0100000,0.0100000,0.0100000,0.0100000,0.0100000,0.0100000,0.0100000,0.0100000,0.0100000,0.0100000,0.0100000,0.0100000,0.0100000,0.0100000,0.0100000,0.0100000,0.0100000,0.0100000,0.0100000,0.0100000,0.0100000,0.0100000,0.0100000,0.0100000,0.0100000,0.0100000,0.0100000,0.0100000,0.0100000,0.0100000,0.0100000,0.0100000,0.0100000,0.0100000,0.0100000,0.0100000,0.0100000,0.0100000,0.0100000,0.0100000,0.0100000,0.0100000,0.0100000,0.0100000,0.0100000,0.0100000,0.0100000,0.0100000,0.0100000,0.0100000,0.0100000,0.0100000,0.0100000,0.0100000,0.0100000,0.0100000,0.0100000,0.0100000,0.0100000,0.0100000,0.0100000,0.0100000,0.0100000,0.0100000,0.0100000}; Chris@61: static float betaDist1[100] = {0.028911,0.048656,0.061306,0.068539,0.071703,0.071877,0.069915,0.066489,0.062117,0.057199,0.052034,0.046844,0.041786,0.036971,0.032470,0.028323,0.024549,0.021153,0.018124,0.015446,0.013096,0.011048,0.009275,0.007750,0.006445,0.005336,0.004397,0.003606,0.002945,0.002394,0.001937,0.001560,0.001250,0.000998,0.000792,0.000626,0.000492,0.000385,0.000300,0.000232,0.000179,0.000137,0.000104,0.000079,0.000060,0.000045,0.000033,0.000024,0.000018,0.000013,0.000009,0.000007,0.000005,0.000003,0.000002,0.000002,0.000001,0.000001,0.000001,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000}; Chris@61: static float betaDist2[100] = {0.012614,0.022715,0.030646,0.036712,0.041184,0.044301,0.046277,0.047298,0.047528,0.047110,0.046171,0.044817,0.043144,0.041231,0.039147,0.036950,0.034690,0.032406,0.030133,0.027898,0.025722,0.023624,0.021614,0.019704,0.017900,0.016205,0.014621,0.013148,0.011785,0.010530,0.009377,0.008324,0.007366,0.006497,0.005712,0.005005,0.004372,0.003806,0.003302,0.002855,0.002460,0.002112,0.001806,0.001539,0.001307,0.001105,0.000931,0.000781,0.000652,0.000542,0.000449,0.000370,0.000303,0.000247,0.000201,0.000162,0.000130,0.000104,0.000082,0.000065,0.000051,0.000039,0.000030,0.000023,0.000018,0.000013,0.000010,0.000007,0.000005,0.000004,0.000003,0.000002,0.000001,0.000001,0.000001,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000}; Chris@61: static float betaDist3[100] = {0.006715,0.012509,0.017463,0.021655,0.025155,0.028031,0.030344,0.032151,0.033506,0.034458,0.035052,0.035331,0.035332,0.035092,0.034643,0.034015,0.033234,0.032327,0.031314,0.030217,0.029054,0.027841,0.026592,0.025322,0.024042,0.022761,0.021489,0.020234,0.019002,0.017799,0.016630,0.015499,0.014409,0.013362,0.012361,0.011407,0.010500,0.009641,0.008830,0.008067,0.007351,0.006681,0.006056,0.005475,0.004936,0.004437,0.003978,0.003555,0.003168,0.002814,0.002492,0.002199,0.001934,0.001695,0.001481,0.001288,0.001116,0.000963,0.000828,0.000708,0.000603,0.000511,0.000431,0.000361,0.000301,0.000250,0.000206,0.000168,0.000137,0.000110,0.000088,0.000070,0.000055,0.000043,0.000033,0.000025,0.000019,0.000014,0.000010,0.000007,0.000005,0.000004,0.000002,0.000002,0.000001,0.000001,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000}; Chris@61: static float betaDist4[100] = {0.003996,0.007596,0.010824,0.013703,0.016255,0.018501,0.020460,0.022153,0.023597,0.024809,0.025807,0.026607,0.027223,0.027671,0.027963,0.028114,0.028135,0.028038,0.027834,0.027535,0.027149,0.026687,0.026157,0.025567,0.024926,0.024240,0.023517,0.022763,0.021983,0.021184,0.020371,0.019548,0.018719,0.017890,0.017062,0.016241,0.015428,0.014627,0.013839,0.013068,0.012315,0.011582,0.010870,0.010181,0.009515,0.008874,0.008258,0.007668,0.007103,0.006565,0.006053,0.005567,0.005107,0.004673,0.004264,0.003880,0.003521,0.003185,0.002872,0.002581,0.002312,0.002064,0.001835,0.001626,0.001434,0.001260,0.001102,0.000959,0.000830,0.000715,0.000612,0.000521,0.000440,0.000369,0.000308,0.000254,0.000208,0.000169,0.000136,0.000108,0.000084,0.000065,0.000050,0.000037,0.000027,0.000019,0.000014,0.000009,0.000006,0.000004,0.000002,0.000001,0.000001,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000}; Chris@61: static float single10[100] = {0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,1.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000}; Chris@61: static float single15[100] = {0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,1.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000}; Chris@61: static float single20[100] = {0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,1.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000}; Chris@61: matthiasm@31: std::vector Chris@140: YinUtil::yinProb(const double *yinBuffer, int prior, int minTau0, int maxTau0) matthiasm@31: { Chris@140: int minTau = 2; Chris@140: int maxTau = m_yinBufferSize; matthiasm@0: matthiasm@31: // adapt period range, if necessary matthiasm@31: if (minTau0 > 0 && minTau0 < maxTau0) minTau = minTau0; Chris@136: if (maxTau0 > 0 && maxTau0 < m_yinBufferSize && maxTau0 > minTau) maxTau = maxTau0; matthiasm@31: matthiasm@0: double minWeight = 0.01; Chris@140: int tau; matthiasm@0: std::vector thresholds; matthiasm@0: std::vector distribution; Chris@136: std::vector peakProb = std::vector(m_yinBufferSize); matthiasm@0: Chris@140: int nThreshold = 100; matthiasm@0: int nThresholdInt = nThreshold; matthiasm@0: matthiasm@0: for (int i = 0; i < nThresholdInt; ++i) matthiasm@0: { matthiasm@0: switch (prior) { matthiasm@0: case 0: matthiasm@0: distribution.push_back(uniformDist[i]); matthiasm@0: break; matthiasm@0: case 1: matthiasm@0: distribution.push_back(betaDist1[i]); matthiasm@0: break; matthiasm@0: case 2: matthiasm@0: distribution.push_back(betaDist2[i]); matthiasm@0: break; matthiasm@0: case 3: matthiasm@0: distribution.push_back(betaDist3[i]); matthiasm@0: break; matthiasm@0: case 4: matthiasm@0: distribution.push_back(betaDist4[i]); matthiasm@0: break; matthiasm@0: case 5: matthiasm@0: distribution.push_back(single10[i]); matthiasm@0: break; matthiasm@0: case 6: matthiasm@0: distribution.push_back(single15[i]); matthiasm@0: break; matthiasm@0: case 7: matthiasm@0: distribution.push_back(single20[i]); matthiasm@0: break; matthiasm@0: default: matthiasm@0: distribution.push_back(uniformDist[i]); matthiasm@0: } matthiasm@0: thresholds.push_back(0.01 + i*0.01); matthiasm@0: } matthiasm@0: matthiasm@0: matthiasm@0: int currThreshInd = nThreshold-1; matthiasm@31: tau = minTau; matthiasm@0: matthiasm@0: // double factor = 1.0 / (0.25 * (nThresholdInt+1) * (nThresholdInt + 1)); // factor to scale down triangular weight Chris@140: int minInd = 0; matthiasm@0: float minVal = 42.f; matthiasm@46: // while (currThreshInd != -1 && tau < maxTau) matthiasm@46: // { matthiasm@46: // if (yinBuffer[tau] < thresholds[currThreshInd]) matthiasm@46: // { matthiasm@46: // while (tau + 1 < maxTau && yinBuffer[tau+1] < yinBuffer[tau]) matthiasm@46: // { matthiasm@46: // tau++; matthiasm@46: // } matthiasm@46: // // tau is now local minimum matthiasm@46: // // std::cerr << tau << " " << currThreshInd << " "<< thresholds[currThreshInd] << " " << distribution[currThreshInd] << std::endl; matthiasm@46: // if (yinBuffer[tau] < minVal && tau > 2){ matthiasm@46: // minVal = yinBuffer[tau]; matthiasm@46: // minInd = tau; matthiasm@46: // } matthiasm@46: // peakProb[tau] += distribution[currThreshInd]; matthiasm@46: // currThreshInd--; matthiasm@46: // } else { matthiasm@46: // tau++; matthiasm@46: // } matthiasm@46: // } matthiasm@46: // double nonPeakProb = 1; Chris@140: // for (int i = minTau; i < maxTau; ++i) matthiasm@46: // { matthiasm@46: // nonPeakProb -= peakProb[i]; matthiasm@46: // } matthiasm@46: // matthiasm@46: // std::cerr << tau << " " << currThreshInd << " "<< thresholds[currThreshInd] << " " << distribution[currThreshInd] << std::endl; matthiasm@46: float sumProb = 0; Chris@62: while (tau+1 < maxTau) matthiasm@0: { matthiasm@46: if (yinBuffer[tau] < thresholds[thresholds.size()-1] && yinBuffer[tau+1] < yinBuffer[tau]) matthiasm@0: { matthiasm@31: while (tau + 1 < maxTau && yinBuffer[tau+1] < yinBuffer[tau]) matthiasm@0: { matthiasm@0: tau++; matthiasm@0: } matthiasm@0: // tau is now local minimum matthiasm@0: // std::cerr << tau << " " << currThreshInd << " "<< thresholds[currThreshInd] << " " << distribution[currThreshInd] << std::endl; matthiasm@0: if (yinBuffer[tau] < minVal && tau > 2){ matthiasm@0: minVal = yinBuffer[tau]; matthiasm@0: minInd = tau; matthiasm@0: } matthiasm@46: currThreshInd = nThresholdInt-1; Chris@137: while (currThreshInd > -1 && thresholds[currThreshInd] > yinBuffer[tau]) { matthiasm@116: // std::cerr << distribution[currThreshInd] << std::endl; matthiasm@116: peakProb[tau] += distribution[currThreshInd]; matthiasm@116: currThreshInd--; matthiasm@116: } matthiasm@116: // peakProb[tau] = 1 - yinBuffer[tau]; matthiasm@46: sumProb += peakProb[tau]; matthiasm@46: tau++; matthiasm@0: } else { matthiasm@0: tau++; matthiasm@0: } matthiasm@0: } matthiasm@46: matthiasm@58: if (peakProb[minInd] > 1) { matthiasm@58: std::cerr << "WARNING: yin has prob > 1 ??? I'm returning all zeros instead." << std::endl; Chris@136: return(std::vector(m_yinBufferSize)); matthiasm@58: } matthiasm@58: matthiasm@0: double nonPeakProb = 1; matthiasm@46: if (sumProb > 0) { Chris@140: for (int i = minTau; i < maxTau; ++i) matthiasm@46: { matthiasm@46: peakProb[i] = peakProb[i] / sumProb * peakProb[minInd]; matthiasm@46: nonPeakProb -= peakProb[i]; matthiasm@46: } matthiasm@0: } matthiasm@0: if (minInd > 0) matthiasm@0: { matthiasm@0: // std::cerr << "min set " << minVal << " " << minInd << " " << nonPeakProb << std::endl; matthiasm@0: peakProb[minInd] += nonPeakProb * minWeight; matthiasm@0: } matthiasm@0: matthiasm@0: return peakProb; matthiasm@0: } matthiasm@0: matthiasm@0: double Chris@140: YinUtil::parabolicInterpolation(const double *yinBuffer, int tau) matthiasm@0: { matthiasm@0: // this is taken almost literally from Joren Six's Java implementation Chris@136: if (tau == m_yinBufferSize) // not valid anyway. matthiasm@0: { matthiasm@0: return static_cast(tau); matthiasm@0: } matthiasm@0: matthiasm@0: double betterTau = 0.0; Chris@136: if (tau > 0 && tau < m_yinBufferSize-1) { matthiasm@0: float s0, s1, s2; matthiasm@46: s0 = yinBuffer[tau-1]; matthiasm@0: s1 = yinBuffer[tau]; matthiasm@46: s2 = yinBuffer[tau+1]; matthiasm@0: matthiasm@46: double adjustment = (s2 - s0) / (2 * (2 * s1 - s2 - s0)); matthiasm@0: matthiasm@46: if (abs(adjustment)>1) adjustment = 0; matthiasm@46: matthiasm@46: betterTau = tau + adjustment; matthiasm@46: } else { matthiasm@118: // std::cerr << "WARNING: can't do interpolation at the edge (tau = " << tau << "), will return un-interpolated value.\n"; matthiasm@46: betterTau = tau; matthiasm@0: } matthiasm@0: return betterTau; matthiasm@0: } matthiasm@0: matthiasm@0: double Chris@140: YinUtil::sumSquare(const double *in, int start, int end) matthiasm@0: { matthiasm@0: double out = 0; Chris@140: for (int i = start; i < end; ++i) matthiasm@0: { matthiasm@0: out += in[i] * in[i]; matthiasm@0: } matthiasm@0: return out; matthiasm@0: }