X-Git-Url: https://git.sesse.net/?p=pitch;a=blobdiff_plain;f=pitchdetector.cpp;h=880584058808a0389a1e26c7acf8da9bf1734bc6;hp=a73fb8632579824a1e603f3a01d73c0d1b8e9d05;hb=a500a1c540da51bdb686bdb9657b354c4238bcb2;hpb=fa1b9cdf79b7688a8fec21e3a13eb8d8e6505391 diff --git a/pitchdetector.cpp b/pitchdetector.cpp index a73fb86..8805840 100644 --- a/pitchdetector.cpp +++ b/pitchdetector.cpp @@ -93,9 +93,13 @@ std::pair PitchDetector::find_peak(double *in, unsigned num_samp if (best_bin == 0 || best_bin == num_samples / 2) { return std::make_pair(-1.0, 0.0); } + std::pair 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), @@ -105,35 +109,43 @@ std::pair PitchDetector::find_peak(double *in, unsigned num_samp 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 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 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); }