changeset 39:bfd9acbcfd7c

Add CENS features
author Chris Cannam
date Thu, 01 Oct 2015 11:51:54 +0100
parents ec93dacba3bd
children 14e0bbb06a9a
files Makefile.inc src/CENS.cpp src/CENS.h src/Quantize.h src/TipicVampPlugin.cpp src/TipicVampPlugin.h
diffstat 6 files changed, 214 insertions(+), 17 deletions(-) [+]
line wrap: on
line diff
--- a/Makefile.inc	Thu Oct 01 11:21:45 2015 +0100
+++ b/Makefile.inc	Thu Oct 01 11:51:54 2015 +0100
@@ -24,8 +24,34 @@
 
 PUBLIC_HEADERS	:=
 
-LIB_HEADERS	:= $(SRC_DIR)/delays.h $(SRC_DIR)/filter-a.h $(SRC_DIR)/filter-b.h $(SRC_DIR)/Filter.h $(SRC_DIR)/PitchFilterbank.h $(SRC_DIR)/DCT.h $(SRC_DIR)/Types.h $(SRC_DIR)/CRP.h $(SRC_DIR)/Normalise.h $(SRC_DIR)/LogCompress.h $(SRC_DIR)/OctaveFold.h $(SRC_DIR)/Resize.h $(SRC_DIR)/Chroma.h $(SRC_DIR)/FeatureDownsample.h
-LIB_SOURCES	:= $(SRC_DIR)/Filter.cpp $(SRC_DIR)/PitchFilterbank.cpp $(SRC_DIR)/DCT.cpp $(SRC_DIR)/CRP.cpp $(SRC_DIR)/Normalise.cpp $(SRC_DIR)/Chroma.cpp $(SRC_DIR)/FeatureDownsample.cpp
+LIB_HEADERS	:= \
+		$(SRC_DIR)/delays.h \
+		$(SRC_DIR)/filter-a.h \
+		$(SRC_DIR)/filter-b.h \
+		$(SRC_DIR)/Filter.h \
+		$(SRC_DIR)/PitchFilterbank.h \
+		$(SRC_DIR)/DCT.h \
+		$(SRC_DIR)/Types.h \
+		$(SRC_DIR)/CRP.h \
+		$(SRC_DIR)/Normalise.h \
+		$(SRC_DIR)/LogCompress.h \
+		$(SRC_DIR)/OctaveFold.h \
+		$(SRC_DIR)/Resize.h \
+		$(SRC_DIR)/Chroma.h \
+		$(SRC_DIR)/FeatureDownsample.h \
+		$(SRC_DIR)/Quantize.h \
+		$(SRC_DIR)/CENS.h
+
+LIB_SOURCES	:= \
+		$(SRC_DIR)/Filter.cpp \
+		$(SRC_DIR)/PitchFilterbank.cpp \
+		$(SRC_DIR)/DCT.cpp \
+		$(SRC_DIR)/CRP.cpp \
+		$(SRC_DIR)/Normalise.cpp \
+		$(SRC_DIR)/Chroma.cpp \
+		$(SRC_DIR)/FeatureDownsample.cpp \
+		$(SRC_DIR)/CENS.cpp
+		
 LIB_OBJECTS	:= $(LIB_SOURCES:.cpp=.o)
 LIB_OBJECTS	:= $(LIB_OBJECTS:.c=.o)
 
@@ -102,15 +128,17 @@
 src/CRP.o: src/CRP.h src/Types.h src/DCTReduce.h src/DCT.h src/Normalise.h
 src/CRP.o: src/LogCompress.h src/OctaveFold.h src/Resize.h
 src/Normalise.o: src/Normalise.h
-src/Chroma.o: src/Chroma.h src/Types.h src/FeatureDownsample.h
-src/Chroma.o: src/Normalise.h src/LogCompress.h src/OctaveFold.h src/Resize.h
+src/Chroma.o: src/Chroma.h src/Types.h src/Normalise.h src/LogCompress.h
+src/Chroma.o: src/OctaveFold.h src/Resize.h
 src/FeatureDownsample.o: src/FeatureDownsample.h src/Types.h src/Filter.h
-src/FeatureDownsample.o: bqvec/bqvec/Restrict.h
+src/FeatureDownsample.o: bqvec/bqvec/Restrict.h src/Normalise.h
+src/CENS.o: src/CENS.h src/Types.h src/Quantize.h src/Normalise.h
+src/CENS.o: src/OctaveFold.h src/Resize.h
 src/TipicVampPlugin.o: src/TipicVampPlugin.h src/Types.h
 src/TipicVampPlugin.o: src/PitchFilterbank.h src/CRP.h src/DCTReduce.h
-src/TipicVampPlugin.o: src/DCT.h src/Chroma.h src/FeatureDownsample.h
-src/TipicVampPlugin.o: bqvec/bqvec/Range.h bqvec/bqvec/VectorOps.h
-src/TipicVampPlugin.o: bqvec/bqvec/Restrict.h
+src/TipicVampPlugin.o: src/DCT.h src/Chroma.h src/CENS.h src/Quantize.h
+src/TipicVampPlugin.o: src/FeatureDownsample.h bqvec/bqvec/Range.h
+src/TipicVampPlugin.o: bqvec/bqvec/VectorOps.h bqvec/bqvec/Restrict.h
 src/libmain.o: src/TipicVampPlugin.h src/Types.h
 src/test-filter.o: src/Filter.h bqvec/bqvec/Restrict.h
 src/test-dct.o: src/DCT.h
@@ -118,6 +146,7 @@
 src/Filter.o: bqvec/bqvec/Restrict.h
 src/PitchFilterbank.o: src/Types.h
 src/CRP.o: src/Types.h src/DCTReduce.h src/DCT.h
-src/Chroma.o: src/Types.h src/FeatureDownsample.h
+src/Chroma.o: src/Types.h
 src/FeatureDownsample.o: src/Types.h
+src/CENS.o: src/Types.h src/Quantize.h
 src/TipicVampPlugin.o: src/Types.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/CENS.cpp	Thu Oct 01 11:51:54 2015 +0100
@@ -0,0 +1,53 @@
+/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
+
+#include "CENS.h"
+
+#include "Normalise.h"
+#include "OctaveFold.h"
+#include "Resize.h"
+
+#include <cmath>
+#include <iostream>
+
+using namespace std;
+
+static Quantize::Parameters
+qparams(CENS::Parameters params)
+{
+    Quantize::Parameters qp;
+    qp.steps = params.quantSteps;
+    qp.weights = params.quantWeights;
+    return qp;
+}
+
+CENS::CENS(Parameters params) :
+    m_params(params),
+    m_quantize(qparams(params))
+{
+}
+
+CENS::~CENS()
+{
+}
+
+RealBlock
+CENS::process(const RealBlock &in)
+{
+    if (in.empty()) {
+	return in;
+    }
+
+    RealBlock out;
+
+    for (RealColumn col: in) {
+
+        out.push_back(m_quantize.process
+		      (Normalise::normalise
+		       (OctaveFold::process
+			(Resize::process(col)),
+			m_params.normP, m_params.normThresh)));
+    }        
+
+    return out;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/CENS.h	Thu Oct 01 11:51:54 2015 +0100
@@ -0,0 +1,37 @@
+/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
+
+#ifndef CENS_H
+#define CENS_H
+
+#include "Types.h"
+#include "Quantize.h"
+
+class CENS
+{
+public:
+    struct Parameters {
+    public:
+	std::vector<double> quantSteps;
+	std::vector<double> quantWeights;
+        int normP; // 0 = no normalisation, 1 = L^1, 2 = L^2
+        double normThresh;
+	Parameters() :
+	    quantSteps({ 0.4, 0.2, 0.1, 0.05 }),
+	    quantWeights({ 0.25, 0.25, 0.25, 0.25 }),
+            normP(1),
+            normThresh(1e-3)
+        { }
+    };
+
+    CENS(Parameters params);
+    ~CENS();
+
+    RealBlock process(const RealBlock &in);
+
+private:
+    Parameters m_params;
+    Quantize m_quantize;
+};
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/Quantize.h	Thu Oct 01 11:51:54 2015 +0100
@@ -0,0 +1,49 @@
+/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
+
+#ifndef QUANTIZE_H
+#define QUANTIZE_H
+
+#include <vector>
+#include <stdexcept>
+
+class Quantize
+{
+public:
+    class Parameters {
+    public:
+	std::vector<double> steps;
+	std::vector<double> weights;
+	Parameters() :
+	    steps({ 0.4, 0.2, 0.1, 0.05 }),
+	    weights({ 0.25, 0.25, 0.25, 0.25 }) { }
+    };
+
+    Quantize(Parameters params) : m_params(params) {
+	if (params.steps.empty()) {
+	    throw std::invalid_argument("Quantize steps must not be empty");
+	}
+	if (params.steps.size() != params.weights.size()) {
+	    throw std::invalid_argument("Must have same number of quantize steps and weights");
+	}
+    }
+    ~Quantize() { }
+
+    std::vector<double> process(const std::vector<double> &in) {
+	int n = in.size();
+	int m = m_params.steps.size();
+	std::vector<double> out(n, 0.0);
+	for (int i = 0; i < n; ++i) {
+	    for (int j = 0; j < m; ++j) {
+		if (in[i] > m_params.steps[j]) {
+		    out[i] += m_params.weights[j];
+		}
+	    }
+	}
+	return out;
+    }
+
+private:
+    Parameters m_params;
+};
+
+#endif
--- a/src/TipicVampPlugin.cpp	Thu Oct 01 11:21:45 2015 +0100
+++ b/src/TipicVampPlugin.cpp	Thu Oct 01 11:51:54 2015 +0100
@@ -4,6 +4,7 @@
 #include "PitchFilterbank.h"
 #include "CRP.h"
 #include "Chroma.h"
+#include "CENS.h"
 #include "FeatureDownsample.h"
 
 #include <bqvec/Range.h>
@@ -27,9 +28,11 @@
     m_crp(0),
     m_chroma(0),
     m_logChroma(0),
+    m_cens(0),
     m_pitchOutputNo(-1),
     m_cpOutputNo(-1),
     m_clpOutputNo(-1),
+    m_censOutputNo(-1),
     m_crpOutputNo(-1)
 {
 }
@@ -40,6 +43,7 @@
     delete m_crp;
     delete m_chroma;
     delete m_logChroma;
+    delete m_cens;
 
     for (auto &d: m_downsamplers) delete d.second;
 }
@@ -249,6 +253,13 @@
     d.sampleRate /= 10.0;
     list.push_back(d);
 
+    d.identifier = "cens";
+    d.name = "Chroma Energy Normalised Statistics Features";
+    d.description = "";
+    d.sampleRate = PitchFilterbank::getOutputSampleRate() / 10.0;
+    m_censOutputNo = list.size();
+    list.push_back(d);
+
     d.identifier = "crp";
     d.name = "Chroma DCT-Reduced Log Pitch Features";
     d.description = "";
@@ -281,6 +292,7 @@
     if (m_pitchOutputNo < 0 ||
 	m_cpOutputNo < 0 ||
 	m_clpOutputNo < 0 ||
+	m_censOutputNo < 0 ||
 	m_crpOutputNo < 0) {
 	throw std::logic_error("setup went wrong");
     }
@@ -318,6 +330,8 @@
 	Chroma::Parameters params;
 	params.applyLogCompression = true;
 	m_logChroma = new Chroma(params);
+
+	m_cens = new CENS({});
     }
     
     m_filterbank->reset();
@@ -336,12 +350,14 @@
 
     RealBlock cp = m_chroma->process(pitchFiltered);
     RealBlock clp = m_logChroma->process(pitchFiltered);
+    RealBlock cens = m_cens->process(pitchFiltered);
     RealBlock crp = m_crp->process(pitchFiltered);
 
     FeatureSet fs;
     addFeatures(fs, m_pitchOutputNo, pitchFiltered, false);
     addFeatures(fs, m_cpOutputNo, cp, false);
     addFeatures(fs, m_clpOutputNo, clp, false);
+    addFeatures(fs, m_censOutputNo, cens, false);
     addFeatures(fs, m_crpOutputNo, crp, false);
     return fs;
 }
@@ -353,12 +369,14 @@
 
     RealBlock cp = m_chroma->process(pitchFiltered);
     RealBlock clp = m_logChroma->process(pitchFiltered);
+    RealBlock cens = m_cens->process(pitchFiltered);
     RealBlock crp = m_crp->process(pitchFiltered);
 
     FeatureSet fs;
     addFeatures(fs, m_pitchOutputNo, pitchFiltered, true);
     addFeatures(fs, m_cpOutputNo, cp, true);
     addFeatures(fs, m_clpOutputNo, clp, true);
+    addFeatures(fs, m_censOutputNo, cens, true);
     addFeatures(fs, m_crpOutputNo, crp, true);
     return fs;
 }
@@ -367,13 +385,21 @@
 Tipic::addFeatures(FeatureSet &fs, int outputNo, const RealBlock &block, bool final)
 {
     if (block.empty()) return;
-    
-    for (int i = 0; in_range_for(block, i); ++i) {
-	Feature f;
-	int h = block[i].size();
-	f.values.resize(h);
-	v_convert(f.values.data(), block[i].data(), h);
-	fs[outputNo].push_back(f);
+
+    int downsampledOutputNo = outputNo + 1;
+    if (outputNo == m_censOutputNo) {
+	// CENS exists only in downsampled form
+	downsampledOutputNo = outputNo;
+    }
+
+    if (outputNo != downsampledOutputNo) {
+	for (int i = 0; in_range_for(block, i); ++i) {
+	    Feature f;
+	    int h = block[i].size();
+	    f.values.resize(h);
+	    v_convert(f.values.data(), block[i].data(), h);
+	    fs[outputNo].push_back(f);
+	}
     }
     
     if (m_downsamplers.find(outputNo) == m_downsamplers.end()) {
@@ -394,6 +420,6 @@
 	int h = downsampled[i].size();
 	f.values.resize(h);
 	v_convert(f.values.data(), downsampled[i].data(), h);
-	fs[outputNo + 1].push_back(f);
+	fs[downsampledOutputNo].push_back(f);
     }
 }
--- a/src/TipicVampPlugin.h	Thu Oct 01 11:21:45 2015 +0100
+++ b/src/TipicVampPlugin.h	Thu Oct 01 11:51:54 2015 +0100
@@ -8,6 +8,7 @@
 class PitchFilterbank;
 class CRP;
 class Chroma;
+class CENS;
 class FeatureDownsample;
 
 using std::string;
@@ -57,9 +58,11 @@
     CRP *m_crp;
     Chroma *m_chroma;
     Chroma *m_logChroma;
+    CENS *m_cens;
     mutable int m_pitchOutputNo;
     mutable int m_cpOutputNo;
     mutable int m_clpOutputNo;
+    mutable int m_censOutputNo;
     mutable int m_crpOutputNo;
     std::map<int, FeatureDownsample *> m_downsamplers;