changeset 19:51eb8b1a1910

Add CRP (lacking some features)
author Chris Cannam
date Thu, 24 Sep 2015 16:35:48 +0100
parents c785eaaeac40
children 3bbdd3dada9f
files .hgsubstate Makefile.inc src/CRP.cpp src/CRP.h src/PitchFilterbank.cpp src/PitchFilterbank.h src/TipicVampPlugin.cpp src/TipicVampPlugin.h src/Types.h
diffstat 9 files changed, 175 insertions(+), 36 deletions(-) [+]
line wrap: on
line diff
--- a/.hgsubstate	Thu Sep 24 12:45:43 2015 +0100
+++ b/.hgsubstate	Thu Sep 24 16:35:48 2015 +0100
@@ -1,2 +1,2 @@
 5c47cf61c391c403a5d57ac0f7d8101ce129018b bqvec
-500416b7a651efa2a334ef0ee75fffde0d1f755d constant-q-cpp
+bc8033ed4c291e96202b32db94c9665724b2cb23 constant-q-cpp
--- a/Makefile.inc	Thu Sep 24 12:45:43 2015 +0100
+++ b/Makefile.inc	Thu Sep 24 16:35:48 2015 +0100
@@ -24,8 +24,8 @@
 
 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
-LIB_SOURCES	:= $(SRC_DIR)/Filter.cpp $(SRC_DIR)/PitchFilterbank.cpp $(SRC_DIR)/DCT.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
+LIB_SOURCES	:= $(SRC_DIR)/Filter.cpp $(SRC_DIR)/PitchFilterbank.cpp $(SRC_DIR)/DCT.cpp $(SRC_DIR)/CRP.cpp
 LIB_OBJECTS	:= $(LIB_SOURCES:.cpp=.o)
 LIB_OBJECTS	:= $(LIB_OBJECTS:.c=.o)
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/CRP.cpp	Thu Sep 24 16:35:48 2015 +0100
@@ -0,0 +1,69 @@
+/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
+
+#include "CRP.h"
+
+#include "DCT.h"
+
+#include <cmath>
+#include <iostream>
+
+using namespace std;
+
+CRP::~CRP()
+{
+    delete m_dct;
+}
+
+RealBlock
+CRP::process(const RealBlock &in)
+{
+    if (in.empty()) {
+	return in;
+    }
+    if (!m_dct) {
+	m_size = in[0].size();
+	m_dct = new DCT(m_size);
+    }
+
+    int bins = 12;
+    RealBlock out;
+    RealColumn dctOut(m_size);
+
+    for (RealColumn col: in) {
+
+	RealColumn crp(bins);
+
+	if (int(col.size()) != m_size) {
+	    cerr << "ERROR: Inconsistent value count in pitch column: found "
+		 << col.size() << " where previous column(s) have had " << m_size
+		 << endl;
+	    throw std::logic_error("Inconsistent value count in pitch column");
+	}
+    
+	if (m_params.applyLogCompression) {
+	    for (auto &v: col) {
+		//!!! These numbers are parameters in the MATLAB
+		v = log10(1.0 + 1000.0 * v);
+	    }
+	}
+
+	m_dct->forward(col.data(), dctOut.data());
+
+	for (int i = 0; i < m_params.coefficientsToDrop; ++i) {
+	    dctOut[i] = 0.0;
+	}
+
+	m_dct->inverse(dctOut.data(), col.data());
+
+	for (int i = 0; i < m_size; ++i) {
+	    crp[i % bins] += col[i];
+	}
+
+	//!!! normalise as in normalizeFeature.m
+	
+	out.push_back(crp);
+    }
+
+    return out;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/CRP.h	Thu Sep 24 16:35:48 2015 +0100
@@ -0,0 +1,33 @@
+/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
+
+#ifndef CRP_H
+#define CRP_H
+
+#include "Types.h"
+
+class DCT;
+
+//!!! Downsampling/temporal smoothing not yet implemented
+
+class CRP
+{
+public:
+    struct Parameters {
+	int coefficientsToDrop;
+	bool applyLogCompression;
+	Parameters() : coefficientsToDrop(54), applyLogCompression(true) { }
+    };
+	
+    CRP(Parameters params) : m_params(params), m_size(0), m_dct(0) { }
+    ~CRP();
+
+    RealBlock process(const RealBlock &in);
+    
+private:
+    Parameters m_params;
+    int m_size;
+    DCT *m_dct;
+};
+
+#endif
+
--- a/src/PitchFilterbank.cpp	Thu Sep 24 12:45:43 2015 +0100
+++ b/src/PitchFilterbank.cpp	Thu Sep 24 16:35:48 2015 +0100
@@ -63,15 +63,6 @@
 
     int getSampleRate() const { return m_sampleRate; }
     float getTuningFrequency() const { return m_tuningFrequency; }
-    
-    /// A series of real-valued samples ordered in time.
-    typedef vector<double> RealSequence;
-
-    /// A series of real-valued samples ordered by bin (frequency or similar).
-    typedef vector<double> RealColumn;
-
-    /// A matrix of real-valued samples, indexed by time then bin number.
-    typedef vector<RealColumn> RealBlock;
 
     RealBlock process(const RealSequence &in) {
 
@@ -277,13 +268,13 @@
     m_d = new D(rate, freq);
 }
 
-PitchFilterbank::RealBlock
+RealBlock
 PitchFilterbank::process(const RealSequence &in)
 {
     return m_d->process(in);
 }
 
-PitchFilterbank::RealBlock
+RealBlock
 PitchFilterbank::getRemainingOutput()
 {
     return m_d->getRemainingOutput();
--- a/src/PitchFilterbank.h	Thu Sep 24 12:45:43 2015 +0100
+++ b/src/PitchFilterbank.h	Thu Sep 24 16:35:48 2015 +0100
@@ -3,7 +3,7 @@
 #ifndef PITCH_FILTERBANK_H
 #define PITCH_FILTERBANK_H
 
-#include <vector>
+#include "Types.h"
 
 class PitchFilterbank
 {
@@ -11,15 +11,6 @@
     PitchFilterbank(int sampleRate, float tuningFrequency);
     ~PitchFilterbank();
 
-    /// A series of real-valued samples ordered in time.
-    typedef std::vector<double> RealSequence;
-
-    /// A series of real-valued samples ordered by bin (frequency or similar).
-    typedef std::vector<double> RealColumn;
-
-    /// A matrix of real-valued samples, indexed by time then bin number.
-    typedef std::vector<RealColumn> RealBlock;
-
     void reset();
     
     RealBlock process(const RealSequence &);
--- a/src/TipicVampPlugin.cpp	Thu Sep 24 12:45:43 2015 +0100
+++ b/src/TipicVampPlugin.cpp	Thu Sep 24 16:35:48 2015 +0100
@@ -1,6 +1,9 @@
 
 #include "TipicVampPlugin.h"
 
+#include "PitchFilterbank.h"
+#include "CRP.h"
+
 #include <bqvec/Range.h>
 #include <bqvec/VectorOps.h>
 
@@ -18,7 +21,9 @@
     m_blockSize(0),
     m_tuningFrequency(defaultTuningFrequency),
     m_filterbank(0),
-    m_pitchOutputNo(-1)
+    m_crp(0),
+    m_pitchOutputNo(-1),
+    m_crpOutputNo(-1)
 {
 }
 
@@ -177,21 +182,44 @@
     m_pitchOutputNo = list.size();
     list.push_back(d);
 
+    d.identifier = "crp";
+    d.name = "Chroma DCT-Reduced Log Pitch Features";
+    d.description = "";
+    d.unit = "";
+    d.hasFixedBinCount = true;
+    d.binCount = 12; //!!! make parameter in CRP
+    d.hasKnownExtents = false;
+    d.isQuantized = false;
+    d.sampleType = OutputDescriptor::FixedSampleRate;
+    d.sampleRate = 22050 / 2205; //!!! get block size & hop from filterbank
+    d.hasDuration = false;
+    m_crpOutputNo = list.size();
+    list.push_back(d);
+
     return list;
 }
 
 bool
 Tipic::initialise(size_t channels, size_t stepSize, size_t blockSize)
 {
+    if (m_inputSampleRate > 192000) {
+	cerr << "ERROR: Tipic::initialise: Max sample rate 192000 exceeded "
+	     << "(requested rate = " << m_inputSampleRate << ")" << endl;
+	return false;
+    }
+    
     if (m_pitchOutputNo < 0) {
 	// getOutputDescriptors has never been called, it sets up the
 	// outputNo members
 	(void)getOutputDescriptors();
     }
+    if (m_pitchOutputNo < 0 || m_crpOutputNo < 0) {
+	throw std::logic_error("setup went wrong");
+    }
     
     if (channels < getMinChannelCount() ||
 	channels > getMaxChannelCount()) {
-	cerr << "ERROR: initialise: wrong number of channels supplied (only 1 supported)" << endl;
+	cerr << "ERROR: Tipic::initialise: wrong number of channels supplied (only 1 supported)" << endl;
 	return false;
     }
 
@@ -213,6 +241,7 @@
 {
     if (!m_filterbank) {
 	m_filterbank = new PitchFilterbank(m_inputSampleRate, m_tuningFrequency);
+	m_crp = new CRP({});
     }
     m_filterbank->reset();
 }
@@ -220,36 +249,39 @@
 Tipic::FeatureSet
 Tipic::process(const float *const *inputBuffers, Vamp::RealTime timestamp)
 {
-    PitchFilterbank::RealSequence in;
+    RealSequence in;
     in.resize(m_blockSize);
     v_convert(in.data(), inputBuffers[0], m_blockSize);
     
-    PitchFilterbank::RealBlock pitchFiltered = m_filterbank->process(in);
+    RealBlock pitchFiltered = m_filterbank->process(in);
+    RealBlock crpReduced = m_crp->process(pitchFiltered);
 
     FeatureSet fs;
-    addPitchFeatures(fs, pitchFiltered);
+    addFeatures(fs, m_pitchOutputNo, pitchFiltered);
+    addFeatures(fs, m_crpOutputNo, crpReduced);
     return fs;
 }
 
 Tipic::FeatureSet
 Tipic::getRemainingFeatures()
 {
-    PitchFilterbank::RealBlock pitchFiltered = m_filterbank->getRemainingOutput();
+    RealBlock pitchFiltered = m_filterbank->getRemainingOutput();
+    RealBlock crpReduced = m_crp->process(pitchFiltered);
 
     FeatureSet fs;
-    addPitchFeatures(fs, pitchFiltered);
+    addFeatures(fs, m_pitchOutputNo, pitchFiltered);
+    addFeatures(fs, m_crpOutputNo, crpReduced);
     return fs;
 }
 
 void
-Tipic::addPitchFeatures(FeatureSet &fs, const PitchFilterbank::RealBlock &block)
+Tipic::addFeatures(FeatureSet &fs, int outputNo, const RealBlock &block)
 {
     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[m_pitchOutputNo].push_back(f);
+	fs[outputNo].push_back(f);
     }
 }
-
--- a/src/TipicVampPlugin.h	Thu Sep 24 12:45:43 2015 +0100
+++ b/src/TipicVampPlugin.h	Thu Sep 24 16:35:48 2015 +0100
@@ -3,7 +3,10 @@
 
 #include <vamp-sdk/Plugin.h>
 
-#include "PitchFilterbank.h"
+#include "Types.h"
+
+class PitchFilterbank;
+class CRP;
 
 using std::string;
 
@@ -49,9 +52,11 @@
     int m_blockSize;
     float m_tuningFrequency;
     PitchFilterbank *m_filterbank;
+    CRP *m_crp;
     mutable int m_pitchOutputNo;
+    mutable int m_crpOutputNo;
 
-    void addPitchFeatures(FeatureSet &, const PitchFilterbank::RealBlock &);
+    void addFeatures(FeatureSet &, int outputNo, const RealBlock &);
 };
 
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/Types.h	Thu Sep 24 16:35:48 2015 +0100
@@ -0,0 +1,18 @@
+/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
+
+#ifndef TIPIC_TYPES_H
+#define TIPIC_TYPES_H
+
+#include <vector>
+
+/// A series of real-valued samples ordered in time.
+typedef std::vector<double> RealSequence;
+
+/// A series of real-valued samples ordered by bin (frequency or similar).
+typedef std::vector<double> RealColumn;
+
+/// A matrix of real-valued samples, indexed by time then bin number.
+typedef std::vector<RealColumn> RealBlock;
+
+#endif
+