changeset 1:ab0b04e1c56b

Implement the plugin!
author Chris Cannam
date Fri, 07 Mar 2014 15:51:20 +0000
parents f559ab000b67
children ee3cf00cfa4c
files ConstrainedHarmonicPeak.cpp ConstrainedHarmonicPeak.h Makefile.inc
diffstat 3 files changed, 108 insertions(+), 3 deletions(-) [+]
line wrap: on
line diff
--- a/ConstrainedHarmonicPeak.cpp	Fri Mar 07 14:34:50 2014 +0000
+++ b/ConstrainedHarmonicPeak.cpp	Fri Mar 07 15:51:20 2014 +0000
@@ -12,7 +12,8 @@
     Plugin(inputSampleRate),
     m_blockSize(0),
     m_minFreq(0),
-    m_maxFreq(inputSampleRate/2)
+    m_maxFreq(inputSampleRate/2),
+    m_harmonics(5)
 {
 }
 
@@ -113,6 +114,17 @@
     d.isQuantized = false;
     list.push_back(d);
 
+    d.identifier = "harmonics";
+    d.name = "Harmonics";
+    d.description = "Maximum number of harmonics to consider";
+    d.unit = "";
+    d.minValue = 1;
+    d.maxValue = 20;
+    d.defaultValue = 5;
+    d.isQuantized = true;
+    d.quantizeStep = 1;
+    list.push_back(d);
+
     return list;
 }
 
@@ -123,6 +135,8 @@
 	return m_minFreq;
     } else if (identifier == "maxfreq") {
 	return m_maxFreq;
+    } else if (identifier == "harmonics") {
+	return m_harmonics;
     }
     return 0;
 }
@@ -134,6 +148,8 @@
 	m_minFreq = value;
     } else if (identifier == "maxfreq") {
 	m_maxFreq = value;
+    } else if (identifier == "harmonics") {
+	m_harmonics = int(round(value));
     }
 }
 
@@ -193,11 +209,98 @@
 {
 }
 
+double
+ConstrainedHarmonicPeak::findInterpolatedPeak(const double *in, 
+					      int peakbin,
+					      int bins)
+{
+    // duplicate with SimpleCepstrum plugin
+    // after jos, 
+    // https://ccrma.stanford.edu/~jos/sasp/Quadratic_Interpolation_Spectral_Peaks.html
+
+    if (peakbin < 1 || peakbin > bins - 2) {
+        return peakbin;
+    }
+
+    double alpha = in[peakbin-1];
+    double beta  = in[peakbin];
+    double gamma = in[peakbin+1];
+
+    double denom = (alpha - 2*beta + gamma);
+
+    if (denom == 0) {
+        // flat
+        return peakbin;
+    }
+
+    double p = ((alpha - gamma) / denom) / 2.0;
+
+    return double(peakbin) + p;
+}
+
 ConstrainedHarmonicPeak::FeatureSet
 ConstrainedHarmonicPeak::process(const float *const *inputBuffers, Vamp::RealTime timestamp)
 {
     FeatureSet fs;
 
+    int hs = m_blockSize/2;
+
+    double *mags = new double[hs+1];
+    for (int i = 0; i <= hs; ++i) {
+	mags[i] = sqrtf(inputBuffers[0][i*2] * inputBuffers[0][i*2] +
+			inputBuffers[0][i*2+1] * inputBuffers[0][i*2+1]);
+    }
+
+    // bin freq is bin * samplerate / fftsize
+
+    int minbin = int(floor((m_minFreq * m_blockSize) / m_inputSampleRate));
+    int maxbin = int(ceil((m_maxFreq * m_blockSize) / m_inputSampleRate));
+    if (minbin > hs) minbin = hs;
+    if (maxbin > hs) maxbin = hs;
+    if (maxbin <= minbin) return fs;
+
+    double *hps = new double[maxbin - minbin + 1];
+
+    // HPS in dB after MzHarmonicSpectrum
+
+    for (int bin = minbin; bin <= maxbin; ++bin) {
+
+	int i = bin - minbin;
+	hps[i] = 1.0;
+
+	int contributing = 0;
+
+	for (int j = 1; j <= m_harmonics; ++j) {
+	    if (j * bin > hs) break;
+	    hps[i] *= mags[j * bin];
+	    ++contributing;
+	}
+
+	if (hps[i] <= 0.0) {
+	    hps[i] = -120.0;
+	} else {
+	    hps[i] = 20.0 / contributing * log10(hps[i]);
+	}
+    }
+
+    double maxdb = -120.0;
+    int maxidx = 0;
+    for (int i = 0; i <= maxbin - minbin; ++i) {
+	if (hps[i] > maxdb) {
+	    maxdb = hps[i];
+	    maxidx = i;
+	}
+    }
+
+    double interpolated = findInterpolatedPeak(hps, maxidx, maxbin - minbin + 1);
+    interpolated = interpolated + minbin;
+
+    double freq = interpolated * m_inputSampleRate / m_blockSize;
+
+    Feature f;
+    f.values.push_back(freq);
+    fs[0].push_back(f);
+
     return fs;
 }
 
@@ -205,7 +308,6 @@
 ConstrainedHarmonicPeak::getRemainingFeatures()
 {
     FeatureSet fs;
-
     return fs;
 }
 
--- a/ConstrainedHarmonicPeak.h	Fri Mar 07 14:34:50 2014 +0000
+++ b/ConstrainedHarmonicPeak.h	Fri Mar 07 15:51:20 2014 +0000
@@ -46,6 +46,9 @@
     int m_blockSize;
     float m_minFreq;
     float m_maxFreq;
+    int m_harmonics;
+
+    static double findInterpolatedPeak(const double *in, int peakbin, int bins);
 };
 
 
--- a/Makefile.inc	Fri Mar 07 14:34:50 2014 +0000
+++ b/Makefile.inc	Fri Mar 07 15:51:20 2014 +0000
@@ -7,7 +7,7 @@
 CFLAGS := $(CFLAGS) 
 CXXFLAGS := -I. $(CXXFLAGS)
 
-PLUGIN := chp(PLUGIN_EXT)
+PLUGIN := chp$(PLUGIN_EXT)
 
 SOURCES := ConstrainedHarmonicPeak.cpp