#include <stdio.h>
+#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
std::pair<double, double> PitchDetector::detect_pitch(short *buf)
{
unsigned buf_len = fft_length / pad_factor / overlap;
- memmove(in, in + buf_len, (fft_length - buf_len) * sizeof(double));
+ memmove(in, in + buf_len, (fft_length / pad_factor - buf_len) * sizeof(double));
for (unsigned i = 0; i < buf_len; ++i)
in[i + (fft_length / pad_factor - buf_len)] = double(buf[i]);
best_peak = in[i];
best_bin = i;
}
+#if 0
+ if (20.0 * log10(in[i] / fft_length) > 0.0) {
+ printf("PEAK: %+4.2f dB %5.2f Hz\n",
+ 20.0 * log10(in[i] / fft_length),
+ bin_to_freq(i, num_samples));
+ }
+#endif
}
if (best_bin == 0 || best_bin == num_samples / 2) {
return std::make_pair(-1.0, 0.0);
}
+ std::pair<double, double> peak =
+ interpolate_peak(in[best_bin - 1],
+ in[best_bin],
+ in[best_bin + 1]);
#if 0
- printf("undertone strength: %+4.2f %+4.2f %+4.2f [%+4.2f] %+4.2f %+4.2f %+4.2f\n",
+ printf("undertone strength: %+6.2f %+6.2f %+6.2f [%+6.2f] %+6.2f %+6.2f %+6.2f\n",
20.0 * log10(in[best_bin*4] / fft_length),
20.0 * log10(in[best_bin*3] / fft_length),
20.0 * log10(in[best_bin*2] / fft_length),
20.0 * log10(in[best_bin/4] / fft_length));
#endif
- // see if we might have hit an overtone (set a limit of 5dB)
- for (unsigned i = 4; i >= 1; --i) {
- if (best_bin != best_bin / i &&
- 20.0 * log10(in[best_bin] / in[best_bin / i]) < 5.0f) {
+ // see if we might have hit an overtone (set a limit of 20dB)
+ for (unsigned i = 6; i >= 1; --i) {
+ unsigned candidate_bin = best_bin / i;
+ if (best_bin == candidate_bin ||
+ candidate_bin < 5 ||
+ candidate_bin >= num_samples / 2 - 1) {
+ continue;
+ }
+
+ // Check that we indeed have a peak in this area.
+ if (candidate_bin - 1 != best_bin &&
+ in[candidate_bin - 1] > in[candidate_bin] &&
+ in[candidate_bin - 1] > in[candidate_bin - 2]) {
+ --candidate_bin;
+ } else if (candidate_bin + 1 != best_bin &&
+ in[candidate_bin + 1] > in[candidate_bin] &&
+ in[candidate_bin + 1] > in[candidate_bin + 2]) {
+ ++candidate_bin;
+ } else if (in[candidate_bin] < in[candidate_bin - 1] ||
+ in[candidate_bin] < in[candidate_bin + 1]) {
+ continue;
+ }
+
+ std::pair<double, double> candidate_peak =
+ interpolate_peak(in[candidate_bin - 1],
+ in[candidate_bin],
+ in[candidate_bin + 1]);
+ if (candidate_peak.second + 20.0f > peak.second) {
#if 0
printf("Overtone of degree %u!\n", i);
#endif
- best_bin /= i;
-
- // consider sliding one bin up or down
- if (best_bin > 1 && in[best_bin - 1] > in[best_bin] && in[best_bin - 1] > in[best_bin - 2]) {
- --best_bin;
- } else if (best_bin < num_samples / 2 - 1 && in[best_bin + 1] > in[best_bin] && in[best_bin + 1] > in[best_bin + 2]) {
- ++best_bin;
- }
-
+ best_bin = candidate_bin;
+ peak = candidate_peak;
break;
}
}
- if (best_bin == 0 || best_bin == num_samples / 2) {
- return std::make_pair(-1.0, 0.0);
- }
- std::pair<double, double> peak =
- interpolate_peak(in[best_bin - 1],
- in[best_bin],
- in[best_bin + 1]);
-
return std::make_pair(bin_to_freq(double(best_bin) + peak.first, num_samples), peak.second);
}
double c = y0;
double xmax = (ym1 - y1) / (2.0 * (y1 + ym1 - 2.0 * y0));
- double ymax = 20.0 * (a * xmax * xmax + b * xmax + c) - 90.0;
+ double ymax = 20.0 * (a * xmax * xmax + b * xmax + c) - 70.0;
return std::make_pair(xmax, ymax);
}