-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathyin.cpp
More file actions
144 lines (125 loc) · 2.82 KB
/
yin.cpp
File metadata and controls
144 lines (125 loc) · 2.82 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
#include "yin.h"
#include "stdlib.h"
void Yin::initialize(float yinSampleRate, int yinBufferSize)
{
bufferSize = yinBufferSize;
sampleRate = yinSampleRate;
halfBufferSize = bufferSize / 2;
threshold = 0.15;
probability = 0.0;
//initialize array and set it to zero
yinBuffer = new float[halfBufferSize];
memset(yinBuffer, 0, halfBufferSize*sizeof(float));
}
Yin::Yin(float yinSampleRate, int yinBufferSize)
{
initialize(yinSampleRate, yinBufferSize);
}
float Yin::getProbability()
{
return probability;
}
float Yin::getPitch(WaveformPointsVector &buffer)
{
int tauEstimate = -1;
float pitchInHertz = -1;
difference(buffer);
cumulativeMeanNormalizedDifference();
tauEstimate = absoluteThreshold();
if(tauEstimate != -1){
pitchInHertz = sampleRate / parabolicInterpolation(tauEstimate);
}
return pitchInHertz;
}
float Yin::parabolicInterpolation(int tauEstimate)
{
float betterTau;
int x0;
int x2;
if (tauEstimate < 1)
x0 = tauEstimate;
else
x0 = tauEstimate - 1;
if (tauEstimate + 1 < halfBufferSize)
x2 = tauEstimate + 1;
else
x2 = tauEstimate;
if (x0 == tauEstimate)
{
if (yinBuffer[tauEstimate] <= yinBuffer[x2])
betterTau = tauEstimate;
else
betterTau = x2;
}
else if (x2 == tauEstimate)
{
if (yinBuffer[tauEstimate] <= yinBuffer[x0])
betterTau = tauEstimate;
else
betterTau = x0;
}
else
{
float s0, s1, s2;
s0 = yinBuffer[x0];
s1 = yinBuffer[tauEstimate];
s2 = yinBuffer[x2];
betterTau = tauEstimate + (s2 - s0) / (2 * (2 * s1 - s2 - s0));
}
return betterTau;
}
void Yin::cumulativeMeanNormalizedDifference()
{
int tau;
yinBuffer[0] = 1;
float runningSum = 0;
for (tau = 1; tau < halfBufferSize; tau++)
{
runningSum += yinBuffer[tau];
yinBuffer[tau] *= tau / runningSum;
}
}
void Yin::difference(WaveformPointsVector &buffer)
{
float delta;
for(int tau = 0; tau < halfBufferSize; tau++)
{
for(int i = 0; i < halfBufferSize; i++)
{
delta = buffer[i].y() - buffer[i + tau].y();
yinBuffer[tau] += delta * delta;
}
}
}
int Yin::absoluteThreshold(){
int tau;
// first two positions in yinBuffer are always 1
// So start at the third (index 2)
for (tau = 2; tau < halfBufferSize ; tau++)
{
if (yinBuffer[tau] < threshold)
{
while (tau + 1 < halfBufferSize && yinBuffer[tau + 1] < yinBuffer[tau])
{
tau++;
}
// found tau, exit loop and return
// store the probability
// From the YIN paper: The threshold determines the list of
// candidates admitted to the set, and can be interpreted as the
// proportion of aperiodic power tolerated
//
// Since we want the periodicity and and not aperiodicity:
// periodicity = 1 - aperiodicity
probability = 1 - yinBuffer[tau];
break;
}
}
// if no pitch found, tau => -1
if (tau == halfBufferSize || yinBuffer[tau] >= threshold)
{
tau = -1;
probability = 0;
}
return tau;
}