changeset 0:02587f02ef41

First cut at extracting this from its previous home
author Chris Cannam
date Fri, 22 Jun 2012 13:38:51 +0100
parents
children ce41d2d066a1
files Makefile.inc Makefile.linux64 SimpleCepstrum.cpp SimpleCepstrum.h libmain.cpp
diffstat 5 files changed, 611 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Makefile.inc	Fri Jun 22 13:38:51 2012 +0100
@@ -0,0 +1,26 @@
+
+PLUGIN_EXT	?= .so
+PLUGIN	?= simple-cepstrum$(PLUGIN_EXT)
+CXX	?= g++
+CC	?= gcc
+
+CFLAGS		:= $(CFLAGS) 
+CXXFLAGS	:= $(CXXFLAGS) 
+LDFLAGS		:= $(LDFLAGS)
+
+HEADERS := SimpleCepstrum.h
+
+SOURCES := SimpleCepstrum.cpp \
+           libmain.cpp
+
+OBJECTS := $(SOURCES:.cpp=.o)
+OBJECTS := $(OBJECTS:.c=.o)
+
+$(PLUGIN):	$(OBJECTS)
+		$(CXX) -o $@ $^ $(LDFLAGS)
+
+clean:		
+		rm $(OBJECTS)
+
+distclean:	clean
+		rm $(PLUGIN)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Makefile.linux64	Fri Jun 22 13:38:51 2012 +0100
@@ -0,0 +1,10 @@
+
+CFLAGS := -Wall -g -fPIC 
+CXXFLAGS := $(CFLAGS)
+
+LDFLAGS := -shared -Wl,-Bstatic -lvamp-sdk -Wl,-Bdynamic 
+
+PLUGIN_EXT := .so
+
+include Makefile.inc
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SimpleCepstrum.cpp	Fri Jun 22 13:38:51 2012 +0100
@@ -0,0 +1,489 @@
+/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
+
+#include "SimpleCepstrum.h"
+
+#include <vector>
+#include <algorithm>
+
+#include <cstdio>
+#include <cmath>
+
+using std::string;
+
+SimpleCepstrum::SimpleCepstrum(float inputSampleRate) :
+    Plugin(inputSampleRate),
+    m_channels(0),
+    m_stepSize(256),
+    m_blockSize(1024),
+    m_fmin(50),
+    m_fmax(1000),
+    m_clamp(false)
+{
+}
+
+SimpleCepstrum::~SimpleCepstrum()
+{
+}
+
+string
+SimpleCepstrum::getIdentifier() const
+{
+    return "simple-cepstrum";
+}
+
+string
+SimpleCepstrum::getName() const
+{
+    return "Simple Cepstrum";
+}
+
+string
+SimpleCepstrum::getDescription() const
+{
+    return "Return simple cepstral data from DFT bins";
+}
+
+string
+SimpleCepstrum::getMaker() const
+{
+    // Your name here
+    return "";
+}
+
+int
+SimpleCepstrum::getPluginVersion() const
+{
+    // Increment this each time you release a version that behaves
+    // differently from the previous one
+    return 1;
+}
+
+string
+SimpleCepstrum::getCopyright() const
+{
+    // This function is not ideally named.  It does not necessarily
+    // need to say who made the plugin -- getMaker does that -- but it
+    // should indicate the terms under which it is distributed.  For
+    // example, "Copyright (year). All Rights Reserved", or "GPL"
+    return "";
+}
+
+SimpleCepstrum::InputDomain
+SimpleCepstrum::getInputDomain() const
+{
+    return FrequencyDomain;
+}
+
+size_t
+SimpleCepstrum::getPreferredBlockSize() const
+{
+    return 1024;
+}
+
+size_t 
+SimpleCepstrum::getPreferredStepSize() const
+{
+    return 256;
+}
+
+size_t
+SimpleCepstrum::getMinChannelCount() const
+{
+    return 1;
+}
+
+size_t
+SimpleCepstrum::getMaxChannelCount() const
+{
+    return 1;
+}
+
+SimpleCepstrum::ParameterList
+SimpleCepstrum::getParameterDescriptors() const
+{
+    ParameterList list;
+
+    ParameterDescriptor d;
+
+    d.identifier = "fmin";
+    d.name = "Minimum frequency";
+    d.description = "";
+    d.unit = "Hz";
+    d.minValue = m_inputSampleRate / m_blockSize;
+    d.maxValue = m_inputSampleRate / 2;
+    d.defaultValue = 50;
+    d.isQuantized = false;
+    list.push_back(d);
+
+    d.identifier = "fmax";
+    d.name = "Maximum frequency";
+    d.description = "";
+    d.unit = "Hz";
+    d.minValue = m_inputSampleRate / m_blockSize;
+    d.maxValue = m_inputSampleRate / 2;
+    d.defaultValue = 1000;
+    d.isQuantized = false;
+    list.push_back(d);
+
+    d.identifier = "clamp";
+    d.name = "Clamp negative values in cepstrum at zero";
+    d.unit = "";
+    d.minValue = 0;
+    d.maxValue = 1;
+    d.defaultValue = 0;
+    d.isQuantized = true;
+    d.quantizeStep = 1;
+    list.push_back(d);
+
+    return list;
+}
+
+float
+SimpleCepstrum::getParameter(string identifier) const
+{
+    if (identifier == "fmin") return m_fmin;
+    else if (identifier == "fmax") return m_fmax;
+    else if (identifier == "clamp") return (m_clamp ? 1 : 0);
+    else return 0.f;
+}
+
+void
+SimpleCepstrum::setParameter(string identifier, float value) 
+{
+    if (identifier == "fmin") m_fmin = value;
+    else if (identifier == "fmax") m_fmax = value;
+    else if (identifier == "clamp") m_clamp = (value > 0.5);
+}
+
+SimpleCepstrum::ProgramList
+SimpleCepstrum::getPrograms() const
+{
+    ProgramList list;
+    return list;
+}
+
+string
+SimpleCepstrum::getCurrentProgram() const
+{
+    return ""; // no programs
+}
+
+void
+SimpleCepstrum::selectProgram(string name)
+{
+}
+
+SimpleCepstrum::OutputList
+SimpleCepstrum::getOutputDescriptors() const
+{
+    OutputList outputs;
+
+    int n = 0;
+
+    OutputDescriptor d;
+    d.identifier = "f0";
+    d.name = "Estimated fundamental frequency";
+    d.description = "";
+    d.unit = "";
+    d.hasFixedBinCount = true;
+    d.binCount = 1;
+    d.hasKnownExtents = true;
+    d.minValue = m_fmin;
+    d.maxValue = m_fmax;
+    d.isQuantized = false;
+    d.sampleType = OutputDescriptor::OneSamplePerStep;
+    d.hasDuration = false;
+    m_f0Output = n++;
+    outputs.push_back(d);
+
+    d.identifier = "raw_cepstral_peak";
+    d.name = "Frequency corresponding to raw cepstral peak";
+    d.unit = "Hz";
+    m_rawOutput = n++;
+    outputs.push_back(d);
+
+    d.identifier = "variance";
+    d.name = "Variance of cepstral bins in range";
+    d.unit = "";
+    m_varOutput = n++;
+    outputs.push_back(d);
+
+    d.identifier = "peak";
+    d.name = "Peak value";
+    d.unit = "";
+    m_pvOutput = n++;
+    outputs.push_back(d);
+
+    d.identifier = "peak_to_mean";
+    d.name = "Peak-to-mean distance";
+    d.unit = "";
+    m_p2mOutput = n++;
+    outputs.push_back(d);
+
+    d.identifier = "cepstrum";
+    d.name = "Cepstrum";
+    d.unit = "";
+
+    int from = int(m_inputSampleRate / m_fmax);
+    int to = int(m_inputSampleRate / m_fmin);
+    if (to >= (int)m_blockSize / 2) {
+        to = m_blockSize / 2 - 1;
+    }
+    d.binCount = to - from + 1;
+    for (int i = from; i <= to; ++i) {
+        float freq = m_inputSampleRate / i;
+        char buffer[10];
+        sprintf(buffer, "%.2f", freq);
+        d.binNames.push_back(buffer);
+    }
+
+    d.hasKnownExtents = false;
+    m_cepOutput = n++;
+    outputs.push_back(d);
+
+    d.identifier = "am";
+    d.name = "Cepstrum bins relative to mean";
+    m_amOutput = n++;
+    outputs.push_back(d);
+
+    return outputs;
+}
+
+bool
+SimpleCepstrum::initialise(size_t channels, size_t stepSize, size_t blockSize)
+{
+    if (channels < getMinChannelCount() ||
+	channels > getMaxChannelCount()) return false;
+
+//    std::cerr << "SimpleCepstrum::initialise: channels = " << channels
+//	      << ", stepSize = " << stepSize << ", blockSize = " << blockSize
+//	      << std::endl;
+
+    m_channels = channels;
+    m_stepSize = stepSize;
+    m_blockSize = blockSize;
+
+    return true;
+}
+
+void
+SimpleCepstrum::reset()
+{
+}
+
+SimpleCepstrum::FeatureSet
+SimpleCepstrum::process(const float *const *inputBuffers, Vamp::RealTime timestamp)
+{
+    int bs = m_blockSize;
+    int hs = m_blockSize/2 + 1;
+
+    double *logmag = new double[bs];
+    for (int i = 0; i < hs; ++i) {
+        double mag = sqrt(inputBuffers[0][i*2  ] * inputBuffers[0][i*2  ] +
+                          inputBuffers[0][i*2+1] * inputBuffers[0][i*2+1]);
+        logmag[i] = log(mag + 0.000001);
+        if (i > 0) {
+            logmag[bs - i] = logmag[i];
+        }
+    }
+
+    double *cep = new double[bs];
+    double *discard0 = new double[bs];
+    double *discard1 = new double[bs];
+    for (int i = 0; i < bs; ++i) discard0[i] = 0.0;
+    fft(bs, true, logmag, discard0, cep, discard1);
+    delete[] discard0;
+    delete[] discard1;
+
+    if (m_clamp) {
+        for (int i = 0; i < bs; ++i) {
+            if (cep[i] < 0) cep[i] = 0;
+        }
+    }
+
+    FeatureSet fs;
+
+    int from = int(m_inputSampleRate / m_fmax);
+    int to = int(m_inputSampleRate / m_fmin);
+
+    if (to >= bs / 2) {
+        to = bs / 2 - 1;
+    }
+
+    Feature cf;
+    for (int i = from; i <= to; ++i) {
+        cf.values.push_back(cep[i]);
+    }
+    fs[m_cepOutput].push_back(cf);
+
+    float maxval = 0.f;
+    int maxbin = 0;
+
+    for (int i = from; i <= to; ++i) {
+        if (cep[i] > maxval) {
+            maxval = cep[i];
+            maxbin = i;
+        }
+    }
+
+    Feature rf;
+    if (maxbin > 0) {
+        rf.values.push_back(m_inputSampleRate / maxbin);
+    } else {
+        rf.values.push_back(0);
+    }
+    fs[m_rawOutput].push_back(rf);
+
+    float mean = 0;
+    for (int i = from; i <= to; ++i) {
+        mean += cep[i];
+    }
+    mean /= (to - from) + 1;
+
+    float variance = 0;
+    for (int i = from; i <= to; ++i) {
+        float dev = fabsf(cep[i] - mean);
+        variance += dev * dev;
+    }
+    variance /= (to - from) + 1;
+
+    Feature vf;
+    vf.values.push_back(variance);
+    fs[m_varOutput].push_back(vf);
+
+    Feature pf;
+    pf.values.push_back(maxval - mean);
+    fs[m_p2mOutput].push_back(pf);
+
+    Feature pv;
+    pv.values.push_back(maxval);
+    fs[m_pvOutput].push_back(pv);
+
+    Feature am;
+    for (int i = from; i <= to; ++i) {
+        if (cep[i] < mean) am.values.push_back(0);
+        else am.values.push_back(cep[i] - mean);
+    }
+    fs[m_amOutput].push_back(am);
+
+    delete[] logmag;
+    delete[] cep;
+
+    return fs;
+}
+
+SimpleCepstrum::FeatureSet
+SimpleCepstrum::getRemainingFeatures()
+{
+    FeatureSet fs;
+    return fs;
+}
+
+void
+SimpleCepstrum::fft(unsigned int n, bool inverse,
+                    double *ri, double *ii, double *ro, double *io)
+{
+    if (!ri || !ro || !io) return;
+
+    unsigned int bits;
+    unsigned int i, j, k, m;
+    unsigned int blockSize, blockEnd;
+
+    double tr, ti;
+
+    if (n < 2) return;
+    if (n & (n-1)) return;
+
+    double angle = 2.0 * M_PI;
+    if (inverse) angle = -angle;
+
+    for (i = 0; ; ++i) {
+	if (n & (1 << i)) {
+	    bits = i;
+	    break;
+	}
+    }
+
+    static unsigned int tableSize = 0;
+    static int *table = 0;
+
+    if (tableSize != n) {
+
+	delete[] table;
+
+	table = new int[n];
+
+	for (i = 0; i < n; ++i) {
+	
+	    m = i;
+
+	    for (j = k = 0; j < bits; ++j) {
+		k = (k << 1) | (m & 1);
+		m >>= 1;
+	    }
+
+	    table[i] = k;
+	}
+
+	tableSize = n;
+    }
+
+    if (ii) {
+	for (i = 0; i < n; ++i) {
+	    ro[table[i]] = ri[i];
+	    io[table[i]] = ii[i];
+	}
+    } else {
+	for (i = 0; i < n; ++i) {
+	    ro[table[i]] = ri[i];
+	    io[table[i]] = 0.0;
+	}
+    }
+
+    blockEnd = 1;
+
+    for (blockSize = 2; blockSize <= n; blockSize <<= 1) {
+
+	double delta = angle / (double)blockSize;
+	double sm2 = -sin(-2 * delta);
+	double sm1 = -sin(-delta);
+	double cm2 = cos(-2 * delta);
+	double cm1 = cos(-delta);
+	double w = 2 * cm1;
+	double ar[3], ai[3];
+
+	for (i = 0; i < n; i += blockSize) {
+
+	    ar[2] = cm2;
+	    ar[1] = cm1;
+
+	    ai[2] = sm2;
+	    ai[1] = sm1;
+
+	    for (j = i, m = 0; m < blockEnd; j++, m++) {
+
+		ar[0] = w * ar[1] - ar[2];
+		ar[2] = ar[1];
+		ar[1] = ar[0];
+
+		ai[0] = w * ai[1] - ai[2];
+		ai[2] = ai[1];
+		ai[1] = ai[0];
+
+		k = j + blockEnd;
+		tr = ar[0] * ro[k] - ai[0] * io[k];
+		ti = ar[0] * io[k] + ai[0] * ro[k];
+
+		ro[k] = ro[j] - tr;
+		io[k] = io[j] - ti;
+
+		ro[j] += tr;
+		io[j] += ti;
+	    }
+	}
+
+	blockEnd = blockSize;
+    }
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SimpleCepstrum.h	Fri Jun 22 13:38:51 2012 +0100
@@ -0,0 +1,65 @@
+/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
+
+#ifndef _SIMPLE_CEPSTRUM_H_
+#define _SIMPLE_CEPSTRUM_H_
+
+#include <vamp-sdk/Plugin.h>
+
+class SimpleCepstrum : public Vamp::Plugin
+{
+public:
+    SimpleCepstrum(float inputSampleRate);
+    virtual ~SimpleCepstrum();
+
+    std::string getIdentifier() const;
+    std::string getName() const;
+    std::string getDescription() const;
+    std::string getMaker() const;
+    int getPluginVersion() const;
+    std::string getCopyright() const;
+
+    InputDomain getInputDomain() const;
+    size_t getPreferredBlockSize() const;
+    size_t getPreferredStepSize() const;
+    size_t getMinChannelCount() const;
+    size_t getMaxChannelCount() const;
+
+    ParameterList getParameterDescriptors() const;
+    float getParameter(std::string identifier) const;
+    void setParameter(std::string identifier, float value);
+
+    ProgramList getPrograms() const;
+    std::string getCurrentProgram() const;
+    void selectProgram(std::string name);
+
+    OutputList getOutputDescriptors() const;
+
+    bool initialise(size_t channels, size_t stepSize, size_t blockSize);
+    void reset();
+
+    FeatureSet process(const float *const *inputBuffers,
+                       Vamp::RealTime timestamp);
+
+    FeatureSet getRemainingFeatures();
+
+protected:
+    size_t m_channels;
+    size_t m_stepSize;
+    size_t m_blockSize;
+    float m_fmin;
+    float m_fmax;
+    bool m_clamp;
+
+    mutable int m_f0Output;
+    mutable int m_rawOutput;
+    mutable int m_varOutput;
+    mutable int m_p2mOutput;
+    mutable int m_cepOutput;
+    mutable int m_pvOutput;
+    mutable int m_amOutput;
+
+    void fft(unsigned int n, bool inverse,
+             double *ri, double *ii, double *ro, double *io);
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libmain.cpp	Fri Jun 22 13:38:51 2012 +0100
@@ -0,0 +1,21 @@
+/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
+
+#include <vamp/vamp.h>
+#include <vamp-sdk/PluginAdapter.h>
+
+#include "SimpleCepstrum.h"
+
+static Vamp::PluginAdapter<SimpleCepstrum> cepPluginAdapter;
+
+const VampPluginDescriptor *
+vampGetPluginDescriptor(unsigned int version, unsigned int index)
+{
+    if (version < 1) return 0;
+
+    switch (index) {
+    case  0: return cepPluginAdapter.getDescriptor();
+    default: return 0;
+    }
+}
+
+