]> git.sesse.net Git - pitch/blobdiff - pitchdetector.cpp
In glpitch, stretch the x axis a bit so that we have more precision around the intere...
[pitch] / pitchdetector.cpp
index cf0abe0d01fc313dd596aa44cdc956053c6b77cf..880584058808a0389a1e26c7acf8da9bf1734bc6 100644 (file)
@@ -1,4 +1,5 @@
 #include <stdio.h>
+#include <string.h>
 #include <stdlib.h>
 #include <unistd.h>
 #include <fcntl.h>
@@ -80,14 +81,25 @@ std::pair<double, double> PitchDetector::find_peak(double *in, unsigned num_samp
                        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),
@@ -97,34 +109,43 @@ std::pair<double, double> 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 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);
 }
 
@@ -244,7 +265,7 @@ std::pair<double, double> PitchDetector::interpolate_peak(double ym1, double y0,
        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);
 }