|
Chris@9
|
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
|
Chris@9
|
2
|
|
Chris@9
|
3 /*
|
|
Chris@9
|
4 pYIN - A fundamental frequency estimator for monophonic audio
|
|
Chris@9
|
5 Centre for Digital Music, Queen Mary, University of London.
|
|
Chris@9
|
6
|
|
Chris@9
|
7 This program is free software; you can redistribute it and/or
|
|
Chris@9
|
8 modify it under the terms of the GNU General Public License as
|
|
Chris@9
|
9 published by the Free Software Foundation; either version 2 of the
|
|
Chris@9
|
10 License, or (at your option) any later version. See the file
|
|
Chris@9
|
11 COPYING included with this distribution for more information.
|
|
Chris@9
|
12 */
|
|
Chris@9
|
13
|
|
matthiasm@0
|
14 #include "YinUtil.h"
|
|
matthiasm@0
|
15
|
|
matthiasm@0
|
16 #include <vector>
|
|
matthiasm@0
|
17
|
|
matthiasm@0
|
18 #include <cstdio>
|
|
matthiasm@0
|
19 #include <cmath>
|
|
matthiasm@0
|
20 #include <algorithm>
|
|
matthiasm@0
|
21
|
|
matthiasm@0
|
22 #include <boost/math/distributions.hpp>
|
|
matthiasm@0
|
23
|
|
Chris@136
|
24 YinUtil::YinUtil(size_t yinBufferSize) :
|
|
Chris@136
|
25 m_yinBufferSize(yinBufferSize),
|
|
Chris@136
|
26 m_fft(yinBufferSize * 2)
|
|
Chris@136
|
27 {
|
|
Chris@136
|
28 }
|
|
Chris@136
|
29
|
|
Chris@136
|
30 YinUtil::~YinUtil()
|
|
Chris@136
|
31 {
|
|
Chris@136
|
32 }
|
|
Chris@136
|
33
|
|
matthiasm@0
|
34 void
|
|
Chris@136
|
35 YinUtil::slowDifference(const double *in, double *yinBuffer)
|
|
matthiasm@60
|
36 {
|
|
matthiasm@60
|
37 yinBuffer[0] = 0;
|
|
matthiasm@60
|
38 double delta ;
|
|
matthiasm@60
|
39 int startPoint = 0;
|
|
matthiasm@60
|
40 int endPoint = 0;
|
|
Chris@137
|
41 for (int i = 1; i < int(m_yinBufferSize); ++i) {
|
|
matthiasm@60
|
42 yinBuffer[i] = 0;
|
|
Chris@136
|
43 startPoint = m_yinBufferSize/2 - i/2;
|
|
Chris@136
|
44 endPoint = startPoint + m_yinBufferSize;
|
|
matthiasm@60
|
45 for (int j = startPoint; j < endPoint; ++j) {
|
|
matthiasm@60
|
46 delta = in[i+j] - in[j];
|
|
matthiasm@60
|
47 yinBuffer[i] += delta * delta;
|
|
matthiasm@60
|
48 }
|
|
matthiasm@60
|
49 }
|
|
matthiasm@60
|
50 }
|
|
matthiasm@60
|
51
|
|
matthiasm@60
|
52 void
|
|
Chris@136
|
53 YinUtil::fastDifference(const double *in, double *yinBuffer)
|
|
matthiasm@0
|
54 {
|
|
matthiasm@0
|
55 // DECLARE AND INITIALISE
|
|
matthiasm@0
|
56 // initialisation of most of the arrays here was done in a separate function,
|
|
matthiasm@0
|
57 // with all the arrays as members of the class... moved them back here.
|
|
matthiasm@0
|
58
|
|
Chris@136
|
59 size_t frameSize = 2 * m_yinBufferSize;
|
|
Chris@137
|
60 size_t halfSize = m_yinBufferSize;
|
|
Chris@137
|
61
|
|
Chris@137
|
62 double *audioTransformedComplex = new double[frameSize + 2];
|
|
Chris@137
|
63 double *audioOutReal = new double[frameSize];
|
|
matthiasm@0
|
64 double *kernel = new double[frameSize];
|
|
Chris@137
|
65 double *kernelTransformedComplex = new double[frameSize + 2];
|
|
Chris@137
|
66 double *yinStyleACFComplex = new double[frameSize + 2];
|
|
Chris@136
|
67 double *powerTerms = new double[m_yinBufferSize];
|
|
matthiasm@0
|
68
|
|
Chris@136
|
69 for (size_t j = 0; j < m_yinBufferSize; ++j)
|
|
matthiasm@0
|
70 {
|
|
matthiasm@58
|
71 yinBuffer[j] = 0.; // set to zero
|
|
matthiasm@58
|
72 powerTerms[j] = 0.; // set to zero
|
|
matthiasm@0
|
73 }
|
|
matthiasm@0
|
74
|
|
matthiasm@0
|
75 for (size_t j = 0; j < frameSize; ++j)
|
|
matthiasm@0
|
76 {
|
|
matthiasm@0
|
77 kernel[j] = 0.;
|
|
matthiasm@0
|
78 }
|
|
matthiasm@0
|
79
|
|
matthiasm@0
|
80 // POWER TERM CALCULATION
|
|
matthiasm@0
|
81 // ... for the power terms in equation (7) in the Yin paper
|
|
matthiasm@0
|
82 powerTerms[0] = 0.0;
|
|
Chris@136
|
83 for (size_t j = 0; j < m_yinBufferSize; ++j) {
|
|
matthiasm@0
|
84 powerTerms[0] += in[j] * in[j];
|
|
matthiasm@0
|
85 }
|
|
matthiasm@0
|
86
|
|
matthiasm@0
|
87 // now iteratively calculate all others (saves a few multiplications)
|
|
Chris@136
|
88 for (size_t tau = 1; tau < m_yinBufferSize; ++tau) {
|
|
Chris@137
|
89 powerTerms[tau] = powerTerms[tau-1] -
|
|
Chris@137
|
90 in[tau-1] * in[tau-1] +
|
|
Chris@137
|
91 in[tau+m_yinBufferSize] * in[tau+m_yinBufferSize];
|
|
matthiasm@0
|
92 }
|
|
matthiasm@0
|
93
|
|
matthiasm@0
|
94 // YIN-STYLE AUTOCORRELATION via FFT
|
|
matthiasm@0
|
95 // 1. data
|
|
Chris@137
|
96 m_fft.forward(in, audioTransformedComplex);
|
|
matthiasm@0
|
97
|
|
matthiasm@0
|
98 // 2. half of the data, disguised as a convolution kernel
|
|
Chris@136
|
99 for (size_t j = 0; j < m_yinBufferSize; ++j) {
|
|
Chris@136
|
100 kernel[j] = in[m_yinBufferSize-1-j];
|
|
matthiasm@0
|
101 }
|
|
Chris@137
|
102 m_fft.forward(kernel, kernelTransformedComplex);
|
|
matthiasm@0
|
103
|
|
matthiasm@0
|
104 // 3. convolution via complex multiplication -- written into
|
|
Chris@137
|
105 for (size_t j = 0; j <= halfSize; ++j) {
|
|
Chris@137
|
106 yinStyleACFComplex[j*2] = // real
|
|
Chris@137
|
107 audioTransformedComplex[j*2] * kernelTransformedComplex[j*2] -
|
|
Chris@137
|
108 audioTransformedComplex[j*2+1] * kernelTransformedComplex[j*2+1];
|
|
Chris@137
|
109 yinStyleACFComplex[j*2+1] = // imaginary
|
|
Chris@137
|
110 audioTransformedComplex[j*2] * kernelTransformedComplex[j*2+1] +
|
|
Chris@137
|
111 audioTransformedComplex[j*2+1] * kernelTransformedComplex[j*2];
|
|
matthiasm@0
|
112 }
|
|
Chris@137
|
113
|
|
Chris@137
|
114 m_fft.inverse(yinStyleACFComplex, audioOutReal);
|
|
matthiasm@0
|
115
|
|
matthiasm@0
|
116 // CALCULATION OF difference function
|
|
matthiasm@0
|
117 // ... according to (7) in the Yin paper.
|
|
Chris@136
|
118 for (size_t j = 0; j < m_yinBufferSize; ++j) {
|
|
Chris@137
|
119 yinBuffer[j] = powerTerms[0] + powerTerms[j] - 2 *
|
|
Chris@137
|
120 audioOutReal[j+m_yinBufferSize-1];
|
|
matthiasm@0
|
121 }
|
|
Chris@137
|
122 delete [] audioTransformedComplex;
|
|
Chris@137
|
123 delete [] audioOutReal;
|
|
matthiasm@0
|
124 delete [] kernel;
|
|
Chris@137
|
125 delete [] kernelTransformedComplex;
|
|
Chris@137
|
126 delete [] yinStyleACFComplex;
|
|
matthiasm@0
|
127 delete [] powerTerms;
|
|
matthiasm@0
|
128 }
|
|
matthiasm@0
|
129
|
|
Chris@137
|
130
|
|
matthiasm@0
|
131 void
|
|
Chris@136
|
132 YinUtil::cumulativeDifference(double *yinBuffer)
|
|
matthiasm@0
|
133 {
|
|
matthiasm@0
|
134 size_t tau;
|
|
matthiasm@0
|
135
|
|
matthiasm@0
|
136 yinBuffer[0] = 1;
|
|
matthiasm@0
|
137
|
|
matthiasm@0
|
138 double runningSum = 0;
|
|
matthiasm@0
|
139
|
|
Chris@136
|
140 for (tau = 1; tau < m_yinBufferSize; ++tau) {
|
|
matthiasm@0
|
141 runningSum += yinBuffer[tau];
|
|
matthiasm@0
|
142 if (runningSum == 0)
|
|
matthiasm@0
|
143 {
|
|
matthiasm@0
|
144 yinBuffer[tau] = 1;
|
|
matthiasm@0
|
145 } else {
|
|
matthiasm@0
|
146 yinBuffer[tau] *= tau / runningSum;
|
|
matthiasm@0
|
147 }
|
|
matthiasm@0
|
148 }
|
|
matthiasm@0
|
149 }
|
|
matthiasm@0
|
150
|
|
matthiasm@0
|
151 int
|
|
Chris@136
|
152 YinUtil::absoluteThreshold(const double *yinBuffer, const double thresh)
|
|
matthiasm@0
|
153 {
|
|
matthiasm@0
|
154 size_t tau;
|
|
matthiasm@0
|
155 size_t minTau = 0;
|
|
matthiasm@0
|
156 double minVal = 1000.;
|
|
matthiasm@0
|
157
|
|
matthiasm@0
|
158 // using Joren Six's "loop construct" from TarsosDSP
|
|
matthiasm@0
|
159 tau = 2;
|
|
Chris@136
|
160 while (tau < m_yinBufferSize)
|
|
matthiasm@0
|
161 {
|
|
matthiasm@0
|
162 if (yinBuffer[tau] < thresh)
|
|
matthiasm@0
|
163 {
|
|
Chris@136
|
164 while (tau+1 < m_yinBufferSize && yinBuffer[tau+1] < yinBuffer[tau])
|
|
matthiasm@0
|
165 {
|
|
matthiasm@0
|
166 ++tau;
|
|
matthiasm@0
|
167 }
|
|
matthiasm@0
|
168 return tau;
|
|
matthiasm@0
|
169 } else {
|
|
matthiasm@0
|
170 if (yinBuffer[tau] < minVal)
|
|
matthiasm@0
|
171 {
|
|
matthiasm@0
|
172 minVal = yinBuffer[tau];
|
|
matthiasm@0
|
173 minTau = tau;
|
|
matthiasm@0
|
174 }
|
|
matthiasm@0
|
175 }
|
|
matthiasm@0
|
176 ++tau;
|
|
matthiasm@0
|
177 }
|
|
matthiasm@0
|
178 if (minTau > 0)
|
|
matthiasm@0
|
179 {
|
|
matthiasm@0
|
180 return -minTau;
|
|
matthiasm@0
|
181 }
|
|
matthiasm@0
|
182 return 0;
|
|
matthiasm@0
|
183 }
|
|
matthiasm@0
|
184
|
|
Chris@61
|
185 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
|
186 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
|
187 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
|
188 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
|
189 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
|
190 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
|
191 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
|
192 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
|
193
|
|
matthiasm@31
|
194 std::vector<double>
|
|
Chris@136
|
195 YinUtil::yinProb(const double *yinBuffer, const size_t prior, const size_t minTau0, const size_t maxTau0)
|
|
matthiasm@31
|
196 {
|
|
matthiasm@31
|
197 size_t minTau = 2;
|
|
Chris@136
|
198 size_t maxTau = m_yinBufferSize;
|
|
matthiasm@0
|
199
|
|
matthiasm@31
|
200 // adapt period range, if necessary
|
|
matthiasm@31
|
201 if (minTau0 > 0 && minTau0 < maxTau0) minTau = minTau0;
|
|
Chris@136
|
202 if (maxTau0 > 0 && maxTau0 < m_yinBufferSize && maxTau0 > minTau) maxTau = maxTau0;
|
|
matthiasm@31
|
203
|
|
matthiasm@0
|
204 double minWeight = 0.01;
|
|
matthiasm@0
|
205 size_t tau;
|
|
matthiasm@0
|
206 std::vector<float> thresholds;
|
|
matthiasm@0
|
207 std::vector<float> distribution;
|
|
Chris@136
|
208 std::vector<double> peakProb = std::vector<double>(m_yinBufferSize);
|
|
matthiasm@0
|
209
|
|
matthiasm@0
|
210 size_t nThreshold = 100;
|
|
matthiasm@0
|
211 int nThresholdInt = nThreshold;
|
|
matthiasm@0
|
212
|
|
matthiasm@0
|
213 for (int i = 0; i < nThresholdInt; ++i)
|
|
matthiasm@0
|
214 {
|
|
matthiasm@0
|
215 switch (prior) {
|
|
matthiasm@0
|
216 case 0:
|
|
matthiasm@0
|
217 distribution.push_back(uniformDist[i]);
|
|
matthiasm@0
|
218 break;
|
|
matthiasm@0
|
219 case 1:
|
|
matthiasm@0
|
220 distribution.push_back(betaDist1[i]);
|
|
matthiasm@0
|
221 break;
|
|
matthiasm@0
|
222 case 2:
|
|
matthiasm@0
|
223 distribution.push_back(betaDist2[i]);
|
|
matthiasm@0
|
224 break;
|
|
matthiasm@0
|
225 case 3:
|
|
matthiasm@0
|
226 distribution.push_back(betaDist3[i]);
|
|
matthiasm@0
|
227 break;
|
|
matthiasm@0
|
228 case 4:
|
|
matthiasm@0
|
229 distribution.push_back(betaDist4[i]);
|
|
matthiasm@0
|
230 break;
|
|
matthiasm@0
|
231 case 5:
|
|
matthiasm@0
|
232 distribution.push_back(single10[i]);
|
|
matthiasm@0
|
233 break;
|
|
matthiasm@0
|
234 case 6:
|
|
matthiasm@0
|
235 distribution.push_back(single15[i]);
|
|
matthiasm@0
|
236 break;
|
|
matthiasm@0
|
237 case 7:
|
|
matthiasm@0
|
238 distribution.push_back(single20[i]);
|
|
matthiasm@0
|
239 break;
|
|
matthiasm@0
|
240 default:
|
|
matthiasm@0
|
241 distribution.push_back(uniformDist[i]);
|
|
matthiasm@0
|
242 }
|
|
matthiasm@0
|
243 thresholds.push_back(0.01 + i*0.01);
|
|
matthiasm@0
|
244 }
|
|
matthiasm@0
|
245
|
|
matthiasm@0
|
246
|
|
matthiasm@0
|
247 int currThreshInd = nThreshold-1;
|
|
matthiasm@31
|
248 tau = minTau;
|
|
matthiasm@0
|
249
|
|
matthiasm@0
|
250 // double factor = 1.0 / (0.25 * (nThresholdInt+1) * (nThresholdInt + 1)); // factor to scale down triangular weight
|
|
matthiasm@0
|
251 size_t minInd = 0;
|
|
matthiasm@0
|
252 float minVal = 42.f;
|
|
matthiasm@46
|
253 // while (currThreshInd != -1 && tau < maxTau)
|
|
matthiasm@46
|
254 // {
|
|
matthiasm@46
|
255 // if (yinBuffer[tau] < thresholds[currThreshInd])
|
|
matthiasm@46
|
256 // {
|
|
matthiasm@46
|
257 // while (tau + 1 < maxTau && yinBuffer[tau+1] < yinBuffer[tau])
|
|
matthiasm@46
|
258 // {
|
|
matthiasm@46
|
259 // tau++;
|
|
matthiasm@46
|
260 // }
|
|
matthiasm@46
|
261 // // tau is now local minimum
|
|
matthiasm@46
|
262 // // std::cerr << tau << " " << currThreshInd << " "<< thresholds[currThreshInd] << " " << distribution[currThreshInd] << std::endl;
|
|
matthiasm@46
|
263 // if (yinBuffer[tau] < minVal && tau > 2){
|
|
matthiasm@46
|
264 // minVal = yinBuffer[tau];
|
|
matthiasm@46
|
265 // minInd = tau;
|
|
matthiasm@46
|
266 // }
|
|
matthiasm@46
|
267 // peakProb[tau] += distribution[currThreshInd];
|
|
matthiasm@46
|
268 // currThreshInd--;
|
|
matthiasm@46
|
269 // } else {
|
|
matthiasm@46
|
270 // tau++;
|
|
matthiasm@46
|
271 // }
|
|
matthiasm@46
|
272 // }
|
|
matthiasm@46
|
273 // double nonPeakProb = 1;
|
|
matthiasm@46
|
274 // for (size_t i = minTau; i < maxTau; ++i)
|
|
matthiasm@46
|
275 // {
|
|
matthiasm@46
|
276 // nonPeakProb -= peakProb[i];
|
|
matthiasm@46
|
277 // }
|
|
matthiasm@46
|
278 //
|
|
matthiasm@46
|
279 // std::cerr << tau << " " << currThreshInd << " "<< thresholds[currThreshInd] << " " << distribution[currThreshInd] << std::endl;
|
|
matthiasm@46
|
280 float sumProb = 0;
|
|
Chris@62
|
281 while (tau+1 < maxTau)
|
|
matthiasm@0
|
282 {
|
|
matthiasm@46
|
283 if (yinBuffer[tau] < thresholds[thresholds.size()-1] && yinBuffer[tau+1] < yinBuffer[tau])
|
|
matthiasm@0
|
284 {
|
|
matthiasm@31
|
285 while (tau + 1 < maxTau && yinBuffer[tau+1] < yinBuffer[tau])
|
|
matthiasm@0
|
286 {
|
|
matthiasm@0
|
287 tau++;
|
|
matthiasm@0
|
288 }
|
|
matthiasm@0
|
289 // tau is now local minimum
|
|
matthiasm@0
|
290 // std::cerr << tau << " " << currThreshInd << " "<< thresholds[currThreshInd] << " " << distribution[currThreshInd] << std::endl;
|
|
matthiasm@0
|
291 if (yinBuffer[tau] < minVal && tau > 2){
|
|
matthiasm@0
|
292 minVal = yinBuffer[tau];
|
|
matthiasm@0
|
293 minInd = tau;
|
|
matthiasm@0
|
294 }
|
|
matthiasm@46
|
295 currThreshInd = nThresholdInt-1;
|
|
Chris@137
|
296 while (currThreshInd > -1 && thresholds[currThreshInd] > yinBuffer[tau]) {
|
|
matthiasm@116
|
297 // std::cerr << distribution[currThreshInd] << std::endl;
|
|
matthiasm@116
|
298 peakProb[tau] += distribution[currThreshInd];
|
|
matthiasm@116
|
299 currThreshInd--;
|
|
matthiasm@116
|
300 }
|
|
matthiasm@116
|
301 // peakProb[tau] = 1 - yinBuffer[tau];
|
|
matthiasm@46
|
302 sumProb += peakProb[tau];
|
|
matthiasm@46
|
303 tau++;
|
|
matthiasm@0
|
304 } else {
|
|
matthiasm@0
|
305 tau++;
|
|
matthiasm@0
|
306 }
|
|
matthiasm@0
|
307 }
|
|
matthiasm@46
|
308
|
|
matthiasm@58
|
309 if (peakProb[minInd] > 1) {
|
|
matthiasm@58
|
310 std::cerr << "WARNING: yin has prob > 1 ??? I'm returning all zeros instead." << std::endl;
|
|
Chris@136
|
311 return(std::vector<double>(m_yinBufferSize));
|
|
matthiasm@58
|
312 }
|
|
matthiasm@58
|
313
|
|
matthiasm@0
|
314 double nonPeakProb = 1;
|
|
matthiasm@46
|
315 if (sumProb > 0) {
|
|
matthiasm@46
|
316 for (size_t i = minTau; i < maxTau; ++i)
|
|
matthiasm@46
|
317 {
|
|
matthiasm@46
|
318 peakProb[i] = peakProb[i] / sumProb * peakProb[minInd];
|
|
matthiasm@46
|
319 nonPeakProb -= peakProb[i];
|
|
matthiasm@46
|
320 }
|
|
matthiasm@0
|
321 }
|
|
matthiasm@0
|
322 if (minInd > 0)
|
|
matthiasm@0
|
323 {
|
|
matthiasm@0
|
324 // std::cerr << "min set " << minVal << " " << minInd << " " << nonPeakProb << std::endl;
|
|
matthiasm@0
|
325 peakProb[minInd] += nonPeakProb * minWeight;
|
|
matthiasm@0
|
326 }
|
|
matthiasm@0
|
327
|
|
matthiasm@0
|
328 return peakProb;
|
|
matthiasm@0
|
329 }
|
|
matthiasm@0
|
330
|
|
matthiasm@0
|
331 double
|
|
Chris@136
|
332 YinUtil::parabolicInterpolation(const double *yinBuffer, const size_t tau)
|
|
matthiasm@0
|
333 {
|
|
matthiasm@0
|
334 // this is taken almost literally from Joren Six's Java implementation
|
|
Chris@136
|
335 if (tau == m_yinBufferSize) // not valid anyway.
|
|
matthiasm@0
|
336 {
|
|
matthiasm@0
|
337 return static_cast<double>(tau);
|
|
matthiasm@0
|
338 }
|
|
matthiasm@0
|
339
|
|
matthiasm@0
|
340 double betterTau = 0.0;
|
|
Chris@136
|
341 if (tau > 0 && tau < m_yinBufferSize-1) {
|
|
matthiasm@0
|
342 float s0, s1, s2;
|
|
matthiasm@46
|
343 s0 = yinBuffer[tau-1];
|
|
matthiasm@0
|
344 s1 = yinBuffer[tau];
|
|
matthiasm@46
|
345 s2 = yinBuffer[tau+1];
|
|
matthiasm@0
|
346
|
|
matthiasm@46
|
347 double adjustment = (s2 - s0) / (2 * (2 * s1 - s2 - s0));
|
|
matthiasm@0
|
348
|
|
matthiasm@46
|
349 if (abs(adjustment)>1) adjustment = 0;
|
|
matthiasm@46
|
350
|
|
matthiasm@46
|
351 betterTau = tau + adjustment;
|
|
matthiasm@46
|
352 } else {
|
|
matthiasm@118
|
353 // std::cerr << "WARNING: can't do interpolation at the edge (tau = " << tau << "), will return un-interpolated value.\n";
|
|
matthiasm@46
|
354 betterTau = tau;
|
|
matthiasm@0
|
355 }
|
|
matthiasm@0
|
356 return betterTau;
|
|
matthiasm@0
|
357 }
|
|
matthiasm@0
|
358
|
|
matthiasm@0
|
359 double
|
|
matthiasm@0
|
360 YinUtil::sumSquare(const double *in, const size_t start, const size_t end)
|
|
matthiasm@0
|
361 {
|
|
matthiasm@0
|
362 double out = 0;
|
|
matthiasm@0
|
363 for (size_t i = start; i < end; ++i)
|
|
matthiasm@0
|
364 {
|
|
matthiasm@0
|
365 out += in[i] * in[i];
|
|
matthiasm@0
|
366 }
|
|
matthiasm@0
|
367 return out;
|
|
matthiasm@0
|
368 }
|