Krotos Modules 3
Loading...
Searching...
No Matches
McLeod.cpp
Go to the documentation of this file.
1/*
2 ==============================================================================
3
4 McLeod.cpp
5 Created: 4 Nov 2016 4:02:48pm
6 Author: KrotosMacMini
7
8 ==============================================================================
9*/
10
11#include "McLeod.h"
12
14
15krotos::McLeod::McLeod(double sampRate, int bufSize) { initialise(sampRate, bufSize); }
16
18//======================
19//~±~±~±~±~±~±~±~±~±~±~±
20void krotos::McLeod::initialise(double newSampleRate, int newBufferSize)
21{
22 sampleRate = newSampleRate;
23 bufferSize = newBufferSize;
24
25 mcLeodBuffer.resize(bufferSize);
26 peakPositions.resize(bufferSize);
27 periodEstimates.resize(bufferSize);
28 amplitudeEstimates.resize(bufferSize);
29 window.resize(bufferSize);
30
31 for (int i = 0; i < bufferSize; ++i)
32 {
33 mcLeodBuffer[i] = 0.0f;
34 peakPositions[i] = 0;
35 periodEstimates[i] = 0.0f;
36 amplitudeEstimates[i] = 0.0f;
37 window[i] = static_cast<float>(0.5 * (1.0 - std::cos(TWO_PI * double(i) / double(bufferSize))));
38 }
39}
40//~±~±~±~±~±~±~±~±~±~±~±
41float krotos::McLeod::getPitch(std::vector<float> InputBuffer)
42{
43 for (int i = 0; i < InputBuffer.size(); ++i)
44 {
45 mcLeodBuffer[i] = InputBuffer[i] * window[i]; // added the window option!
46 }
47
48 return getPitchInternal();
49}
50
51float krotos::McLeod::getPitch(const float* InputBuffer, int numSamples)
52{
53 for (int i = 0; i < numSamples; ++i)
54 {
55 mcLeodBuffer[i] = InputBuffer[i] * window[i]; // added the window option!
56 }
57
58 return getPitchInternal();
59}
60
62{
63 int tauEstimation = -1;
64 float pitchEstimation = -1.0f;
65#ifdef JUCE_WINDOWS
66 float maxAmplitude = -FLT_MAX;
67#else
68 float maxAmplitude = -__FLT_MAX__;
69#endif
70
71 peakPositionsIndex = 0;
72 periodEstimatesIndex = 0;
73 amplitudeEstimatesIndex = 0;
74 //
75 calculateNormalisedSquareDifferenceFunction(mcLeodBuffer);
76 //
77 peakPicking();
78 //
79 for (int i = 0; i < peakPositionsIndex; ++i)
80 {
81 tauEstimation = peakPositions[i];
82 maxAmplitude = jmax(maxAmplitude, mcLeodBuffer[i]);
83
84 if (mcLeodBuffer[i] > SMALL_CUTOFF)
85 {
86 parabolicInterpolation(tauEstimation);
87 amplitudeEstimates[amplitudeEstimatesIndex++] = interpolatedY;
88 periodEstimates[periodEstimatesIndex++] = interpolatedX;
89 maxAmplitude = jmax(maxAmplitude, interpolatedY);
90 }
91 }
92 //
93 if (periodEstimatesIndex != 0)
94 {
95 const float threshold = float(CUTOFF) * maxAmplitude;
96
97 int periodIndex = 0;
98 for (int i = 0; i < amplitudeEstimatesIndex; ++i)
99 {
100 if (amplitudeEstimates[i] > threshold)
101 {
102 periodIndex = i;
103 break;
104 }
105 }
106 pitchEstimation = float(sampleRate) / periodEstimates[periodIndex];
107 if (pitchEstimation < LOWER_PITCH_CUTOFF)
108 pitchEstimation = -1;
109 }
110
111 return pitchEstimation;
112}
113
114//~±~±~±~±~±~±~±~±~±~±~±
116{
117 for (int tau = 0; tau < bufferSize; ++tau)
118 {
119 float autocorrelationSum = 0;
120 float squareDifferenceSum = 0;
121
122 for (int index = 0; index < bufferSize - tau; ++index)
123 {
124 autocorrelationSum += buffer[index] * buffer[index + tau];
125 squareDifferenceSum += buffer[index] * buffer[index] + buffer[index + tau] * buffer[index + tau];
126 }
127
128 mcLeodBuffer[tau] = 2 * autocorrelationSum / squareDifferenceSum;
129 }
130}
131//~±~±~±~±~±~±~±~±~±~±~±
133{
134 int position = 0;
135 int currentMaxPosition = 0;
136
137 while (position < (bufferSize - 1) / 3 && mcLeodBuffer[position] > 0.0f) // Initial area until we find the first
138 // zero crossing (positive -> negative)
139 {
140 position++;
141 }
142
143 while (position < (bufferSize - 1) &&
144 mcLeodBuffer[position] <= 0.0f) // Find second zero-crossing (negative -> positive)
145 {
146 position++;
147 }
148
149 if (position == 0)
150 position = 1;
151
152 while (position < bufferSize - 1) // We have found the first positively sloped
153 // zero-crossing so now we'll look for local maxima
154 {
155 if (mcLeodBuffer[position] > mcLeodBuffer[position - 1] &&
156 mcLeodBuffer[position] >= mcLeodBuffer[position + 1]) // if a local maximum, ...
157 {
158 if (currentMaxPosition == 0)
159 currentMaxPosition = position;
160 else if (mcLeodBuffer[position] > mcLeodBuffer[currentMaxPosition])
161 currentMaxPosition = position;
162 }
163
164 position++;
165
166 // Find the next zero-crossing
167 if (position < bufferSize - 1 && mcLeodBuffer[position] <= 0.0f)
168 {
169 if (currentMaxPosition > 0) // If we found the next zero-crossing (now negatively sloped) and
170 // we have found a maximum, we register it as a candidate and reset
171 // the current position
172 {
173 peakPositions[peakPositionsIndex++] = currentMaxPosition;
174 currentMaxPosition = 0;
175 }
176
177 while (position < bufferSize - 1 &&
178 mcLeodBuffer[position] <= 0.0f) // "Skip" to the next z.c. (positively sloped) to start
179 // looking for candidate peaks again
180 {
181 position++;
182 }
183 }
184 }
185
186 if (currentMaxPosition > 0)
187 peakPositions[peakPositionsIndex++] = currentMaxPosition; // Register the very last candidate peak
188}
189//~±~±~±~±~±~±~±~±~±~±~±
191{
192 // In the McLeod method we need to implement the parabolic estimation
193 // differently since we need to keep track of the abscissas and ordinates at
194 // the interpolation points so that we register them as period and max
195 // amplitude candidates
196
197 float previous = mcLeodBuffer[tauEstimation - 1];
198 float current = mcLeodBuffer[tauEstimation];
199 float next = mcLeodBuffer[tauEstimation + 1];
200
201 float divisor = next + previous - 2 * current;
202
203 if (divisor == 0.0f)
204 {
205 interpolatedX = float(tauEstimation);
206 interpolatedY = mcLeodBuffer[tauEstimation];
207 }
208 else
209 {
210 interpolatedX = tauEstimation + (previous - next) / (2 * divisor);
211 interpolatedY = mcLeodBuffer[tauEstimation] - ((previous - next) * (previous - next)) / (8 * divisor);
212 }
213}
~McLeod()
Definition McLeod.cpp:17
float getPitch(std::vector< float > InputBuffer)
Definition McLeod.cpp:41
void initialise(double newSampleRate, int newBufferSize)
Definition McLeod.cpp:20
void peakPicking()
Definition McLeod.cpp:132
const float DEFAULT_SAMPLE_RATE
Definition McLeod.h:38
McLeod()
Definition McLeod.cpp:13
void parabolicInterpolation(int tauEstimation)
Definition McLeod.cpp:190
float getPitchInternal()
Definition McLeod.cpp:61
const int MAX_BUFFER_SIZE
Definition McLeod.h:39
void calculateNormalisedSquareDifferenceFunction(std::vector< float > buffer)
Definition McLeod.cpp:115