From 2acfa0424af341c8c2aa7446dfb720aa5e74db31 Mon Sep 17 00:00:00 2001 From: "sgunderson@bigfoot.com" <> Date: Tue, 20 Jul 2010 00:25:08 +0200 Subject: [PATCH] Lots of small but important changes to undertone detection: - When comparing peak amplitudes, compare interpolated peaks, not raw bins. - Find the best candidate bin _before_ sliding up or down one bin. - Verify that a candidate bin is indeed a local peak before testing it. - Remove some pointless out-of-bounds checks. - Formatting changes to undertone debug printouts. - Change the undertone limit from 10dB to 20dB. Seems to work quite a lot better, especially for the low E string. It's still not perfect, of course, and I'm sure there are regression situations, but I think it's a significant improvement. --- pitchdetector.cpp | 56 ++++++++++++++++++++++++++++------------------- 1 file changed, 34 insertions(+), 22 deletions(-) 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); } -- 2.39.2