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
|
/**********************************************************************
Audacity: A Digital Audio Editor
Landmark.cpp
Dominic Mazzoni
Pitch detector based on "landmark" algorithm by Cooper and Ng,
University of Leeds SCS, Division of AI.
\cite{cooper94}
**********************************************************************/
#include <stdlib.h>
#ifndef SQ
#define SQ(X) ((X)*(X))
#endif
int GetLandmarkPeriod(int numSamples, double *sample)
{
const int max_zeros = 100;
const int numLandmarks = 6; // should be even
const int regionSizeThreshold = 10;
int numZeros;
int zeros[max_zeros];
double shape[max_zeros][numLandmarks];
int x, z, l;
// Find all (positive) zero-crossings
numZeros = 0;
for (x = 1; x < numSamples && numZeros < max_zeros; x++)
if (sample[x - 1] < 0.0 && sample[x] >= 0.0)
zeros[numZeros++] = x;
if (numZeros < 3)
return 0;
// Extract the "shape" of each region
for (z = 0; z < (numZeros - 1); z++) {
int len = (zeros[z + 1] - zeros[z]);
for (l = 0; l < (numLandmarks / 2); l++) {
x = zeros[z] + (l + 1) * len / (numLandmarks + 2);
shape[z][l] = sample[x];
x = zeros[z] + (l + 2 +
(numLandmarks / 2)) * len / (numLandmarks + 2);
shape[z][l + (numLandmarks / 2)] = sample[x];
}
}
/***PRINT
for(z=0; z<(numZeros-1); z++) {
for(l=0; l<numLandmarks; l++)
printf("%5.2lf ",shape[z][l]);
printf("\n");
}*/
// Find largest region
int largest = 0;
int largestSize = zeros[1] - zeros[0];
for (z = 1; z < (numZeros - 1); z++)
if (zeros[z + 1] - zeros[z] > largestSize) {
largest = z;
largestSize = zeros[z + 1] - zeros[z];
}
// Compare largest with all other regions
int best = largest;
double bestSimilarity = 0.0;
for (z = 0; z < (numZeros - 1); z++)
if (z != largest &&
abs((zeros[z + 1] - zeros[z]) -
(zeros[largest + 1] - zeros[largest]))
< regionSizeThreshold) {
double asq = 0.0, bsq = 0.0, ab = 0.0;
double score = 0.0;
for (l = 0; l < numLandmarks; l++) {
// Should move this line out of loop
asq += SQ(shape[largest][l]);
bsq += SQ(shape[z][l]);
ab += shape[largest][l] * shape[z][l];
}
score = ab / (asq + bsq - ab); // \cite{cooper94, Page 5}
if (score > bestSimilarity) {
best = z;
bestSimilarity = score;
}
}
int period = abs(zeros[best] - zeros[largest]);
return period;
}
|