Krotos Modules 3
Loading...
Searching...
No Matches
SWIPE_PitchEstimation.cpp
Go to the documentation of this file.
1//=====================================================================================
7//=====================================================================================
8namespace krotos
9{
10 SWIPE_PitchEstimation::SWIPE_PitchEstimation(const float sampleRate, const float timeStep,
11 const float log2PitchStep, const float ERBStep,
12 const float normOverlap, const float strenThresh)
13 {
14 // TODO: If they are not passed as arguments then resort to these values
15 m_sampleRate = sampleRate;
16 m_timeStep = timeStep;
17 m_log2PitchStep = log2PitchStep;
18 m_ERBStep = ERBStep;
19 m_normOverlap = normOverlap;
20 m_strenThresh = strenThresh;
21
22 // initialize vectors with pitch candidates, winSizes and ERBs for pitch estimation calc
24 }
25
27 {
28 m_pitchLims << 50.0f, 500.0f;
29
30 // Define pitch candidates
31 Eigen::VectorXf log2PitchCands = calculateLog2PitchCands(m_log2PitchStep);
32 m_pitchCands = calculatePitchCands(log2PitchCands);
33
34 // Determine P2-Winsizes
35 Eigen::Vector2f logWinSizeLimsEigen;
36 logWinSizeLimsEigen[0] = std::round(std::log2(8.0f * m_sampleRate / m_pitchLims[0]));
37 logWinSizeLimsEigen[1] = std::round(std::log2(8.0f * m_sampleRate / m_pitchLims[1]));
38
39 size_t vectorSize = static_cast<size_t>(logWinSizeLimsEigen[0] - logWinSizeLimsEigen[1]) + 1;
40 m_winSizes.resize(vectorSize);
41 for (size_t i = 0; i < vectorSize; i++)
42 {
43 m_winSizes[i] = std::pow(2.0f, logWinSizeLimsEigen[0] - i);
44 }
45
46 // Calculate winSizeOptPitches
47 Eigen::VectorXf winSizeOptPitchesEigen(m_winSizes.size());
48 for (size_t i = 0; i < m_winSizes.size(); ++i)
49 {
50 winSizeOptPitchesEigen[i] = 8.0f * m_sampleRate / m_winSizes[i];
51 }
52
53 // Determine window sizes used by each pitch candidate
54 m_log2DistWin1OptPitchAndPitchCands.resize(log2PitchCands.size());
55 for (size_t i = 0; i < log2PitchCands.size(); ++i)
56 {
57 m_log2DistWin1OptPitchAndPitchCands[i] = log2PitchCands[i] - std::log2(winSizeOptPitchesEigen[0]) + 1.0f;
58 }
59
60 // Create ERB - scale uniformly - spaced frequencies(in Hertz)
61 float start = krotos::ERB_FFTSpectrogram::hz2Erbs(m_pitchCands.minCoeff() / 4.0f);
63 size_t size = static_cast<size_t>((end - start) / m_ERBStep) + 1;
64 Eigen::VectorXf erbsRangeEigen = Eigen::VectorXf::LinSpaced(size, start, end);
65
66 // Calculate corresponding Hz values using erbs2Hz function
68 }
69
70 std::pair<Eigen::VectorXf, Eigen::VectorXf> SWIPE_PitchEstimation::calculatePitchStrengthPairs(
71 std::vector<float>& signalSTL)
72 {
73 // At this point everything needs to be intialized
74 jassert(m_sampleRate != -1.0f && m_timeStep != -1.0f && m_log2PitchStep != -1.0f && m_ERBStep != -1.0f &&
75 m_normOverlap != -1.0f && m_strenThresh != -1.0f);
76
77 // TODO:: There is a copy here, need to go one level above and pass VectorXf when called!!!!
78 Eigen::VectorXf signal = Eigen::VectorXf::Map(&signalSTL[0], signalSTL.size());
79
80 // Calculate time vector
81 m_times = Eigen::VectorXf::LinSpaced(signal.size() / m_sampleRate / m_timeStep + 1, 0.0f,
82 signal.size() / m_sampleRate);
83
84 // Initialize pitch strength matrix
85 Eigen::MatrixXf globStrenMtrx(m_pitchCands.size(), m_times.size());
86 globStrenMtrx.setZero();
87
88 // Vectors holding the STFT results
89 Eigen::MatrixXf distr;
90 // Frequency bins axis and time frame axis, will be used for interpolation later
91 Eigen::VectorXf fSupport, tSupport;
92
93 // optPitchCandsIdcs and imperfectFitIdcs vectors
94 std::pair<Eigen::VectorXf, Eigen::VectorXf> candidates;
95
96 // Main loop
97 for (size_t winSizeIdx = 0; winSizeIdx < m_winSizes.size(); winSizeIdx++)
98 {
99 // Hop size
100 float hopSize = std::max(1.0f, (std::round((1.0f - m_normOverlap) * m_winSizes[winSizeIdx])));
101
102 // Zero Pad signal
103 // Calculate the zero-padding size
104 size_t padSize = static_cast<size_t>(m_winSizes[winSizeIdx] / 2);
105 // Append zeros to the beginning using Eigen - the end zeros are handled from the STFT algorithm
106 Eigen::VectorXf paddedSignal(signal.size() + padSize);
107 paddedSignal << Eigen::VectorXf::Zero(padSize), signal;
108
109 // -- Compute spectrum --
110 // Init stft again
111 std::unique_ptr<ShortTimeFourierTransform> stftObj = std::make_unique<ShortTimeFourierTransform>(
112 static_cast<int>(m_winSizes[winSizeIdx]), static_cast<int>(m_winSizes[winSizeIdx]),
114 static_cast<int>(m_sampleRate));
115
116 // Perform stft
117 distr = stftObj->processSignal(paddedSignal);
118
119 // Get the frequency and time vectors
120 fSupport = stftObj->getBins(ShortTimeFourierTransform::FrequencyRange::Half);
121 // TODO: Check why diff from MATLAB -> Problem here!!
122 tSupport = stftObj->getColumns();
123
124 // Select candidates that use this window size
125 candidates = selectCandidatesForWindowSize(winSizeIdx + 1);
126
127 // Compute loudness at ERBs uniformly-spaced frequencies
128 auto ERBsSubset = getERBsSubset(candidates.first);
129
130 // Interpolate abs stft matrix at ERB frequency axis and square
131 auto ERBsDistrValues = ShapePreservingCubicInterpolator::interpolate2DEigen(fSupport, distr, ERBsSubset);
132 ERBsDistrValues = ERBsDistrValues.unaryExpr([](float val) { return std::sqrt(std::max(0.0f, val)); });
133
134 // Compute pitch strength
135 // Collect pitchCands at specified indices
136 Eigen::VectorXf selectedPitchCands;
137 for (int i = 0; i < candidates.first.size(); ++i)
138 {
139 int index = static_cast<int>(candidates.first[i]);
140
141 // to get the right output shapes for all window sizes we need <=
142 if (index > 0 && index <= m_pitchCands.size())
143 {
144 selectedPitchCands.conservativeResize(selectedPitchCands.size() + 1);
145 selectedPitchCands(selectedPitchCands.size() - 1) = m_pitchCands[index - 1];
146 }
147 }
148
149 Eigen::MatrixXf locStrenMtrxEigen =
150 pitchStrengthAllCandidates(ERBsSubset, ERBsDistrValues, selectedPitchCands);
151
152 // Interpolate pitch strength at desired times
153 Eigen::MatrixXf locStrenMtrxInterpEigen;
154 if (locStrenMtrxEigen.size() > 1)
155 {
156 locStrenMtrxEigen.transposeInPlace();
157 locStrenMtrxInterpEigen = LinearInterpolator::interpolate2DEigen(tSupport, locStrenMtrxEigen, m_times);
158 locStrenMtrxInterpEigen.transposeInPlace();
159 }
160 else
161 {
162 locStrenMtrxInterpEigen.resize(candidates.first.size(), m_times.size());
163 locStrenMtrxInterpEigen.setConstant(std::numeric_limits<float>::quiet_NaN());
164 }
165
166 // Add pitch strength to combination
167 Eigen::VectorXf currWinRelStrenEigen(candidates.first.size());
168 currWinRelStrenEigen.setOnes();
169 Eigen::VectorXf log2DistCurrWinOptPitchAndOptPitchCandsEigen;
170
171 auto optPitchCandsIdcs = candidates.first.cast<int>().array() - 1;
172 auto imperfectFitIdcs = candidates.second.cast<int>().array() - 1;
173 auto log2DistCurrWinOptPitchAndOptPitchCands =
174 m_log2DistWin1OptPitchAndPitchCands(optPitchCandsIdcs(imperfectFitIdcs)).array() - (winSizeIdx + 1);
175
176 currWinRelStrenEigen(imperfectFitIdcs) = (1 - log2DistCurrWinOptPitchAndOptPitchCands.abs().array());
177
178 // vectorise accumulating into globStrenMtrxEigen
179 globStrenMtrx(optPitchCandsIdcs, Eigen::all) =
180 globStrenMtrx(optPitchCandsIdcs, Eigen::all).array() +
181 (currWinRelStrenEigen.replicate(1, locStrenMtrxInterpEigen.cols()).array() *
182 locStrenMtrxInterpEigen.array());
183 }
184
185 return fineTunePitch(globStrenMtrx);
186 }
187
188 Eigen::VectorXf SWIPE_PitchEstimation::calculateLog2PitchCands(float log2PitchStep)
189 {
190 // Calculate the size of the resulting vector
191 int vectorSize = static_cast<int>((std::log2(m_pitchLims[1]) - std::log2(m_pitchLims[0])) / log2PitchStep) + 1;
192
193 // Initialize Eigen vector with the calculated size
194 Eigen::VectorXf log2PitchCands(vectorSize);
195
196 // Populate the vector using Eigen's sequence generation
197 for (int i = 0; i < vectorSize; ++i)
198 {
199 log2PitchCands(i) = std::log2(m_pitchLims[0]) + (float)i * log2PitchStep;
200 }
201
202 return log2PitchCands;
203 }
204
205 Eigen::VectorXf SWIPE_PitchEstimation::calculatePitchCands(const Eigen::VectorXf& log2PitchCands)
206 {
207 Eigen::VectorXf pitchCands(log2PitchCands.size());
208
209 // Perform an element-wise power of 2
210 pitchCands = Eigen::pow(2.0f, log2PitchCands.array());
211
212 return pitchCands;
213 }
214
215 std::pair<Eigen::VectorXf, Eigen::VectorXf> SWIPE_PitchEstimation::selectCandidatesForWindowSize(size_t winSizeIDx)
216 {
217 Eigen::VectorXf optPitchCandsIdcs;
218 Eigen::VectorXf imperfectFitIdcs;
219
220 if (m_winSizes.size() == 1)
221 {
222 optPitchCandsIdcs =
223 Eigen::VectorXf::LinSpaced(m_pitchCands.size(), 1.0f, static_cast<float>(m_pitchCands.size()));
224 }
225 else if (winSizeIDx == m_winSizes.size())
226 {
227 for (size_t j = 0; j < m_log2DistWin1OptPitchAndPitchCands.size(); ++j)
228 {
229 if (m_log2DistWin1OptPitchAndPitchCands[j] - static_cast<float>(winSizeIDx) > -1.0f)
230 {
231 optPitchCandsIdcs.conservativeResize(optPitchCandsIdcs.size() + 1);
232 optPitchCandsIdcs(optPitchCandsIdcs.size() - 1) = j + 1.0f;
233 }
234 }
235
236 for (size_t j = 0; j < optPitchCandsIdcs.size(); ++j)
237 {
238 if (m_log2DistWin1OptPitchAndPitchCands[static_cast<size_t>(optPitchCandsIdcs(j)) - 1.0f] -
239 static_cast<float>(winSizeIDx) <
240 0.0f)
241 {
242 imperfectFitIdcs.conservativeResize(imperfectFitIdcs.size() + 1);
243 imperfectFitIdcs(imperfectFitIdcs.size() - 1) = j + 1.0f;
244 }
245 }
246 }
247 else if (winSizeIDx == 1)
248 {
249 for (size_t j = 0; j < m_log2DistWin1OptPitchAndPitchCands.size(); ++j)
250 {
251 if (m_log2DistWin1OptPitchAndPitchCands[j] - static_cast<float>(winSizeIDx) < 1.0f)
252 {
253 optPitchCandsIdcs.conservativeResize(optPitchCandsIdcs.size() + 1);
254 optPitchCandsIdcs(optPitchCandsIdcs.size() - 1) = j + 1.0f;
255 }
256 }
257
258 for (size_t j = 0; j < optPitchCandsIdcs.size(); ++j)
259 {
260 if (m_log2DistWin1OptPitchAndPitchCands[static_cast<size_t>(optPitchCandsIdcs(j)) - 1.0f] -
261 static_cast<float>(winSizeIDx) >
262 0.0f)
263 {
264 imperfectFitIdcs.conservativeResize(imperfectFitIdcs.size() + 1);
265 imperfectFitIdcs(imperfectFitIdcs.size() - 1) = j + 1.0f;
266 }
267 }
268 }
269 else
270 {
271 for (Eigen::Index j = 0; j < m_log2DistWin1OptPitchAndPitchCands.size(); ++j)
272 {
273 if (std::abs(m_log2DistWin1OptPitchAndPitchCands[j] - static_cast<float>(winSizeIDx)) < 1.0f)
274 {
275 optPitchCandsIdcs.conservativeResize(optPitchCandsIdcs.size() + 1);
276 optPitchCandsIdcs(optPitchCandsIdcs.size() - 1) = j + 1.0f;
277 }
278 }
279 imperfectFitIdcs = Eigen::VectorXf::LinSpaced(optPitchCandsIdcs.size(), 1.0f,
280 static_cast<float>(optPitchCandsIdcs.size()));
281 }
282
283 return {optPitchCandsIdcs, imperfectFitIdcs};
284 }
285
286 Eigen::VectorXf SWIPE_PitchEstimation::getERBsSubset(const Eigen::VectorXf& pitchCandsSubset)
287 {
288 float threshold = m_pitchCands[static_cast<int>(pitchCandsSubset[0])] / 4.0f;
289
290 // Find the index of the first element greater than the threshold
291 Eigen::VectorXf::Index startIndex = -1;
292 for (Eigen::VectorXf::Index i = 0; i < m_ERBs.size(); ++i)
293 {
294 if (m_ERBs(i) > threshold)
295 {
296 startIndex = i;
297 break;
298 }
299 }
300
301 // Extract the subset from the found position to the end
302 Eigen::VectorXf ERBsSubset;
303 if (startIndex != -1)
304 {
305 ERBsSubset = m_ERBs.segment(startIndex, m_ERBs.size() - startIndex);
306 }
307
308 return ERBsSubset;
309 }
310
311 Eigen::MatrixXf SWIPE_PitchEstimation::pitchStrengthAllCandidates(const Eigen::VectorXf& _ERBs,
312 Eigen::MatrixXf& _ERBsDistrValues,
313 const Eigen::VectorXf& _pitchCands)
314 {
315 // Create pitch strength matrix
316 Eigen::MatrixXf locStrenMtrx(_pitchCands.size(), _ERBsDistrValues.cols());
317 locStrenMtrx.setZero();
318
319 // Define integration regions
320 Eigen::VectorXf k(_pitchCands.size() + 1);
321 k.setZero();
322
323 for (int j = 0; j < k.size() - 1; ++j)
324 {
325 // Find index
326 auto startIdx = static_cast<size_t>(k[j]);
327 auto it = std::find_if(_ERBs.data() + startIdx, _ERBs.data() + _ERBs.size(),
328 [&](float erb) { return erb > _pitchCands[j] / 4.0f; });
329
330 // Update k based on the found index
331 if (it != _ERBs.data() + _ERBs.size())
332 {
333 float dist = static_cast<float>(std::distance(_ERBs.data(), it));
334 k(j + 1) = dist;
335 }
336 else
337 {
338 k(j + 1) = k(j);
339 }
340 }
341
342 // Remove the first element of k
343 Eigen::VectorXf kKeep = k.segment(1, k.size() - 1);
344
345 // Create loudness normalization matrix
346 auto N = computeN(_ERBsDistrValues);
347
348 for (size_t j = 0; j < _pitchCands.size(); j++)
349 {
350 // Normalize loudness
351 auto n = N.row(kKeep[j]).transpose(); // Extract row k(j). Do I transpose ??
352 // Make zero-loudness equal zero after normalization
353 std::replace_if(
354 n.begin(), n.end(), [](float val) { return val == 0; }, INFINITY);
355 // NL = ERBsDistrValues(k(j):end, :) ./ repmat(n, size(ERBsDistrValues, 1)-k(j)+1, 1)
356 Eigen::MatrixXf NL = _ERBsDistrValues.bottomRows(_ERBsDistrValues.rows() - kKeep[j]);
357 NL.array().rowwise() /= n.transpose().array();
358
359 // Compute pitch strength
360 locStrenMtrx.row(j) = pitchStrengthOneCandidate(_ERBs.segment(kKeep[j], _ERBs.size() - kKeep[j]), NL,
361 _pitchCands[j]); // sliiiightly different;
362 }
363
364 return locStrenMtrx;
365 }
366
367 Eigen::VectorXf SWIPE_PitchEstimation::pitchStrengthOneCandidate(const Eigen::VectorXf& ERBS,
368 const Eigen::MatrixXf& normERBsDistrValues,
369 float pitchCand)
370 {
371 int n = static_cast<int>(std::floor(ERBS[ERBS.size() - 1] / pitchCand - 0.75)); // Number of harmonics
372
373 if (n == 0)
374 {
375 return Eigen::VectorXf::Constant(normERBsDistrValues.cols(), std::numeric_limits<float>::quiet_NaN());
376 }
377
378 Eigen::VectorXf k = Eigen::VectorXf::Zero(ERBS.size()); // Kernel
379
380 // Normalize frequency w.r.t. candidate
381 Eigen::VectorXf q = ERBS.array() / pitchCand;
382
383 auto primesVec = primes(n);
384 // Create Kernel
385 for (int i : primesVec) // primes up to 17
386 {
387 Eigen::VectorXf a = (q.array() - static_cast<float>(i)).cwiseAbs();
388
389 // Peak's weight
390 for (size_t p = 0; p < a.size(); ++p)
391 {
392 if (a[p] < 0.25f)
393 {
394 k[p] = std::cos(2.0f * M_PI * q[p]);
395 }
396 }
397
398 // Valleys' weights
399 for (size_t v = 0; v < a.size(); ++v)
400 {
401 if (a[v] > 0.25f && a[v] < 0.75f)
402 {
403 k[v] += std::cos(2.0f * M_PI * q[v]) / 2.0f;
404 }
405 }
406 }
407
408 // Apply envelope
409 k.array() *= (1.0f / ERBS.array()).array().sqrt();
410
411 // K+-normalize kernel
412 Eigen::VectorXf nonZeroElements;
413 for (size_t i = 0; i < k.size(); i++)
414 {
415 if (k[i] > 0.0f)
416 {
417 nonZeroElements.conservativeResize(nonZeroElements.size() + 1);
418 nonZeroElements(nonZeroElements.size() - 1) = k[i];
419 }
420 }
421 float normNonZero = nonZeroElements.norm();
422 k.array() /= normNonZero;
423
424 // Compute pitch strength
425 Eigen::VectorXf locStrenLine = k.transpose() * normERBsDistrValues;
426 return locStrenLine;
427 }
428
429 std::pair<Eigen::VectorXf, Eigen::VectorXf> SWIPE_PitchEstimation::fineTunePitch(Eigen::MatrixXf globStrMatrix)
430 {
431 size_t numTimes = globStrMatrix.cols();
432 size_t numPitches = globStrMatrix.rows();
433
434 Eigen::VectorXf pitches(numTimes);
435 pitches.setConstant(std::numeric_limits<float>::quiet_NaN());
436
437 Eigen::VectorXf strengths(numTimes);
438 strengths.setConstant(std::numeric_limits<float>::quiet_NaN());
439
440 for (size_t timeIdx = 0; timeIdx < numTimes; ++timeIdx)
441 {
442 // Find the pitch with maximum strength
443 // Extract the column
444 Eigen::VectorXf column = globStrMatrix.col(timeIdx);
445 // Find the maximum and it's index
446 // Eigen::Index maxStrenPitchIdx;
447 // auto maxStrength = column.maxCoeff(&maxStrenPitchIdx);
448
449 float maxStrength = std::numeric_limits<float>::quiet_NaN();
450 Eigen::Index maxStrenPitchIdx = 0;
451 for (Eigen::Index i = 0; i < column.size(); ++i)
452 {
453 if (!std::isnan(column[i]))
454 {
455 if (std::isnan(maxStrength) || column[i] > maxStrength)
456 {
457 maxStrength = column[i];
458 maxStrenPitchIdx = i;
459 }
460 }
461 }
462
463 strengths[timeIdx] = maxStrength;
464
465 // Check strength threshold
466 if (strengths[timeIdx] < m_strenThresh)
467 continue;
468
469 // Check conditions for pitch assignment
470 if (maxStrenPitchIdx == 0 || maxStrenPitchIdx == numPitches - 1)
471 {
472 pitches[timeIdx] = m_pitchCands[maxStrenPitchIdx];
473 }
474 else
475 {
476 // Perform polyfit for pitch assignment
477 Eigen::VectorXf maxStrenPitchLocIdcs(3);
478 maxStrenPitchLocIdcs << maxStrenPitchIdx - 1.0f, maxStrenPitchIdx, maxStrenPitchIdx + 1.0f;
479
480 Eigen::VectorXf tc(maxStrenPitchLocIdcs.size());
481 Eigen::VectorXf ntc(tc.size());
482
483 for (size_t i = 0; i < tc.size(); ++i)
484 {
485 tc[i] = 1.0f / m_pitchCands[maxStrenPitchLocIdcs[i]];
486 }
487
488 for (size_t i = 0; i < tc.size(); ++i)
489 {
490 ntc[i] = ((tc[i] / tc[1]) - 1.0f) * (2.0f * static_cast<float>(M_PI));
491 }
492
493 // Perform polyfit
494 Eigen::VectorXf y;
495 for (size_t i = 0; i < maxStrenPitchLocIdcs.size(); i++)
496 {
497 y.conservativeResize(y.size() + 1);
498 y(y.size() - 1) = globStrMatrix.row(maxStrenPitchLocIdcs[i])[timeIdx];
499 }
500 Eigen::VectorXf c = polyfit(ntc, y, 2);
501
502 // Calculate ftcs
503 float startVal = std::log2(m_pitchCands[maxStrenPitchLocIdcs[0]]);
504 float endVal = std::log2(m_pitchCands[maxStrenPitchLocIdcs[2]]);
505 int numSteps = static_cast<int>((endVal - startVal) / (1.0f / 12.0f / 100.0f) + 1);
506 Eigen::VectorXf ftc = Eigen::VectorXf::LinSpaced(numSteps, startVal, endVal);
507 ftc = Eigen::pow(2.0f, ftc.array());
508 ftc = 1.0f / ftc.array();
509
510 // Calculate ftcs
511 Eigen::VectorXf nftc(ftc.size());
512 nftc = (ftc.array() / tc(1) - 1.0f) * 2.0f * M_PI;
513
514 // Evaluate polynomial
515 Eigen::VectorXf polyValRes(nftc.size());
516 for (int i = 0; i < nftc.size(); i++)
517 {
518 polyValRes[i] = Eigen::poly_eval(c, nftc[i]);
519 }
520
521 // Find the maximum value and its index
522 auto maxIt = std::max_element(polyValRes.begin(), polyValRes.end());
523 strengths[timeIdx] = *maxIt;
524 size_t maxPolyFitIdcs = std::distance(polyValRes.begin(), maxIt);
525
526 float pitchValue = m_pitchCands[static_cast<size_t>(maxStrenPitchLocIdcs[0])];
527 float maxPolyFitValue = static_cast<float>(maxPolyFitIdcs) / 12.0f / 100.0f;
528
529 pitches[timeIdx] = std::pow(2.0f, (std::log2(pitchValue) + maxPolyFitValue));
530 }
531 }
532
533 return {pitches, strengths};
534 }
535
536 Eigen::MatrixXf SWIPE_PitchEstimation::computeN(const Eigen::MatrixXf& ERBsDistrValues)
537 {
538 // Step 1: Element-wise square
539 Eigen::MatrixXf squaredValues = ERBsDistrValues.array().square();
540
541 // Step 2: Flip rows upside down
542 Eigen::MatrixXf flipSquaredValues = squaredValues.colwise().reverse().eval();
543
544 // Step 3: Cumulative sum across columns
545 Eigen::MatrixXf cumSumFlipSquaredValues = cumsum(flipSquaredValues);
546
547 // Step 4: Flip again
548 Eigen::MatrixXf flipCumSumFlipSquaredValues = cumSumFlipSquaredValues.colwise().reverse().eval();
549
550 // Step 5: Calculate square root
551 Eigen::MatrixXf rootValues = flipCumSumFlipSquaredValues.array().sqrt();
552
553 return rootValues;
554 }
555
556 Eigen::VectorXi SWIPE_PitchEstimation::primes(int n)
557 {
558 Eigen::VectorXi primesList(2);
559 primesList << 1, 2;
560
561 for (int i = 3; i <= n; ++i)
562 {
563 Eigen::VectorXi range = Eigen::VectorXi::LinSpaced(i - 2, 2, i - 1);
564 Eigen::VectorXi remainder = range.unaryExpr([&](int x) { return i % x; });
565
566 bool isPrime = remainder.all();
567
568 if (isPrime)
569 {
570 primesList.conservativeResize(primesList.size() + 1);
571 primesList(primesList.size() - 1) = i;
572 }
573 }
574
575 return primesList;
576 }
577
578 Eigen::VectorXf SWIPE_PitchEstimation::polyfit(const Eigen::VectorXf& x, const Eigen::VectorXf& y, int n)
579 {
580 jassert(x.size() == y.size());
581
582 Eigen::MatrixXf xs(x.size(), n + 1);
583 xs.col(0).setOnes();
584 for (int i = 1; i <= n; ++i)
585 {
586 xs.col(i).array() = xs.col(i - 1).array() * x.array();
587 }
588
589 Eigen::VectorXf result(n + 1);
590 // Use QR decomposition via Householder reflections. List of other decompositions in:
591 // https://eigen.tuxfamily.org/dox/group__TutorialLinearAlgebra.html and
592 // https://eigen.tuxfamily.org/dox/group__TopicLinearAlgebraDecompositions.html
593 auto decomposition = xs.householderQr();
594 result = decomposition.solve(y);
595
596 // Careful: Returns the vector of coef in the opposite order of MATLABs polyfit, but
597 // combines correctly with Eigen::poly_eval to produce the same value!!
598 return result;
599 }
600
601 Eigen::MatrixXf SWIPE_PitchEstimation::cumsum(const Eigen::MatrixXf& input)
602 {
603 Eigen::MatrixXf result(input.rows(), input.cols());
604
605 for (int col = 0; col < input.cols(); ++col)
606 {
607 result(0, col) = input(0, col);
608 for (int row = 1; row < input.rows(); ++row)
609 {
610 result(row, col) = result(row - 1, col) + input(row, col);
611 }
612 }
613
614 return result;
615 }
616} // namespace krotos
static std::vector< float > hz2Erbs(const std::vector< float > &hzVector)
Definition ERB_FFTSpectrogram.cpp:403
static std::vector< float > erbs2Hz(const std::vector< float > &erbsVector)
Definition ERB_FFTSpectrogram.cpp:388
static Eigen::MatrixXf interpolate2DEigen(const Eigen::VectorXf &xValues, const Eigen::MatrixXf &yValues, const Eigen::VectorXf &vals)
Definition KrotosIntrepolators.cpp:413
float m_normOverlap
Definition SWIPE_PitchEstimation.h:101
Eigen::VectorXf getERBsSubset(const Eigen::VectorXf &pitchCandsSubset)
Definition SWIPE_PitchEstimation.cpp:286
Eigen::MatrixXf cumsum(const Eigen::MatrixXf &input)
Definition SWIPE_PitchEstimation.cpp:601
Eigen::VectorXf m_times
Definition SWIPE_PitchEstimation.h:106
Eigen::VectorXf m_ERBs
Definition SWIPE_PitchEstimation.h:110
std::pair< Eigen::VectorXf, Eigen::VectorXf > calculatePitchStrengthPairs(std::vector< float > &signal)
Definition SWIPE_PitchEstimation.cpp:70
Eigen::VectorXf polyfit(const Eigen::VectorXf &x, const Eigen::VectorXf &y, int n)
Definition SWIPE_PitchEstimation.cpp:578
Eigen::Vector2f m_pitchLims
Definition SWIPE_PitchEstimation.h:105
Eigen::VectorXi primes(int n)
Definition SWIPE_PitchEstimation.cpp:556
void initVectors()
Definition SWIPE_PitchEstimation.cpp:26
Eigen::VectorXf calculateLog2PitchCands(float log2PitchStep)
Definition SWIPE_PitchEstimation.cpp:188
float m_log2PitchStep
Definition SWIPE_PitchEstimation.h:101
Eigen::VectorXf m_log2DistWin1OptPitchAndPitchCands
Definition SWIPE_PitchEstimation.h:109
std::pair< Eigen::VectorXf, Eigen::VectorXf > fineTunePitch(Eigen::MatrixXf globStrMatrix)
Definition SWIPE_PitchEstimation.cpp:429
float m_strenThresh
Definition SWIPE_PitchEstimation.h:102
Eigen::MatrixXf pitchStrengthAllCandidates(const Eigen::VectorXf &ERBs, Eigen::MatrixXf &ERBsDistrValues, const Eigen::VectorXf &pitchCands)
Definition SWIPE_PitchEstimation.cpp:311
Eigen::MatrixXf computeN(const Eigen::MatrixXf &ERBsDistrValues)
Definition SWIPE_PitchEstimation.cpp:536
Eigen::VectorXf m_winSizes
Definition SWIPE_PitchEstimation.h:108
SWIPE_PitchEstimation(const float sampleRate, const float timeStep, const float log2PitchStep, const float ERBStep, const float normOverlap, const float strenThresh)
Definition SWIPE_PitchEstimation.cpp:10
Eigen::VectorXf calculatePitchCands(const Eigen::VectorXf &log2PitchCands)
Definition SWIPE_PitchEstimation.cpp:205
std::pair< Eigen::VectorXf, Eigen::VectorXf > selectCandidatesForWindowSize(size_t winSizeIDx)
Definition SWIPE_PitchEstimation.cpp:215
float m_timeStep
Definition SWIPE_PitchEstimation.h:101
float m_sampleRate
Definition SWIPE_PitchEstimation.h:101
Eigen::VectorXf m_pitchCands
Definition SWIPE_PitchEstimation.h:107
Eigen::VectorXf pitchStrengthOneCandidate(const Eigen::VectorXf &ERBS, const Eigen::MatrixXf &normERBsDistrValues, float pitchCand)
Definition SWIPE_PitchEstimation.cpp:367
float m_ERBStep
Definition SWIPE_PitchEstimation.h:101
static Eigen::MatrixXf interpolate2DEigen(const Eigen::VectorXf &xValues, const Eigen::MatrixXf yValues, const Eigen::VectorXf &vals)
Definition KrotosIntrepolators.cpp:133
@ freqMagOnly
Definition ShortTimeFourierTransform.h:20
Definition AirAbsorptionFilter.cpp:2
#define M_PI
Definition windowing.h:9