#include <stdio.h>
+#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
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 10dB)
+ // see if we might have hit an overtone (set a limit of 20dB)
for (unsigned i = 6; i >= 1; --i) {
- if (best_bin != best_bin / i &&
- 20.0 * log10(in[best_bin] / in[best_bin / i]) < 10.0f &&
- best_bin / i >= 5) {
+ 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);
}