Mercurial > hg > beatroot-vamp
changeset 4:c06cf6f7cb04
Bring in Peaks code from BeatRoot
author | Chris Cannam |
---|---|
date | Mon, 19 Sep 2011 15:48:26 +0100 |
parents | a821f49c42f0 |
children | 2150607d4726 |
files | BeatRootProcessor.h Makefile Peaks.cpp Peaks.h |
diffstat | 4 files changed, 250 insertions(+), 7 deletions(-) [+] |
line wrap: on
line diff
--- a/BeatRootProcessor.h Mon Jun 20 16:32:11 2011 +0100 +++ b/BeatRootProcessor.h Mon Sep 19 15:48:26 2011 +0100 @@ -16,6 +16,8 @@ #ifndef _BEATROOT_PROCESSOR_H_ #define _BEATROOT_PROCESSOR_H_ +#include "Peaks.h" + #include <vector> #include <cmath> @@ -53,7 +55,7 @@ double ltAverage; /** Spectral flux onset detection function, indexed by frame. */ - vector<int> spectralFlux; + vector<double> spectralFlux; /** A mapping function for mapping FFT bins to final frequency bins. * The mapping is linear (1-1) until the resolution reaches 2 points per @@ -277,18 +279,19 @@ // double[] slope = new double[energy.length]; // double hop = hopTime / energyOversampleFactor; // Peaks.getSlope(energy, hop, 15, slope); -// LinkedList<Integer> peaks = Peaks.findPeaks(slope, (int)lrint(0.06 / hop), 10); +// vector<Integer> peaks = Peaks.findPeaks(slope, (int)lrint(0.06 / hop), 10); double hop = hopTime; - Peaks.normalise(spectralFlux); - LinkedList<Integer> peaks = Peaks.findPeaks(spectralFlux, (int)lrint(0.06 / hop), 0.35, 0.84, true); + Peaks::normalise(spectralFlux); + vector<int> peaks = Peaks::findPeaks(spectralFlux, (int)lrint(0.06 / hop), 0.35, 0.84, true); onsets = new double[peaks.size()]; double[] y2 = new double[onsets.length]; - Iterator<Integer> it = peaks.iterator(); + vector<int>::iterator it = peaks.begin(); onsetList = new EventList(); double minSalience = Peaks.min(spectralFlux); for (int i = 0; i < onsets.length; i++) { - int index = it.next(); + int index = *it; + ++it; onsets[i] = index * hop; y2[i] = spectralFlux[index]; Event e = BeatTrackDisplay.newBeat(onsets[i], 0);
--- a/Makefile Mon Jun 20 16:32:11 2011 +0100 +++ b/Makefile Mon Sep 19 15:48:26 2011 +0100 @@ -1,7 +1,7 @@ CXXFLAGS := -g -beatroot-vamp.so: BeatRootProcessor.o BeatRootVampPlugin.o +beatroot-vamp.so: BeatRootProcessor.o BeatRootVampPlugin.o Peaks.o g++ -shared $^ -o $@ -Wl,-Bstatic -lvamp-sdk -Wl,-Bdynamic -lpthread -Wl,--version-script=vamp-plugin.map clean:
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Peaks.cpp Mon Sep 19 15:48:26 2011 +0100 @@ -0,0 +1,20 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Vamp feature extraction plugin for the BeatRoot beat tracker. + + Centre for Digital Music, Queen Mary, University of London. + This file copyright 2011 Simon Dixon, Chris Cannam and QMUL. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. See the file + COPYING included with this distribution for more information. +*/ + +#include "Peaks.h" + +static int Peaks::pre = 3; +static int Peaks::post = 1; +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Peaks.h Mon Sep 19 15:48:26 2011 +0100 @@ -0,0 +1,220 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Vamp feature extraction plugin for the BeatRoot beat tracker. + + Centre for Digital Music, Queen Mary, University of London. + This file copyright 2011 Simon Dixon, Chris Cannam and QMUL. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. See the file + COPYING included with this distribution for more information. +*/ + +#ifndef _BEATROOT_PEAKS_H_ +#define _BEATROOT_PEAKS_H_ + +#include <vector> +#include <cmath> + +using std::vector; + +class Peaks +{ +protected: + static int pre; + static int post; + +public: + /** General peak picking method for finding n local maxima in an array + * @param data input data + * @param peaks list of peak indexes + * @param width minimum distance between peaks + */ + static int findPeaks(const vector<double> &data, vector<int> peaks, int width) { + int peakCount = 0; + int maxp = 0; + int mid = 0; + int end = data.size(); + while (mid < end) { + int i = mid - width; + if (i < 0) + i = 0; + int stop = mid + width + 1; + if (stop > data.size()) + stop = data.size(); + maxp = i; + for (i++; i < stop; i++) + if (data[i] > data[maxp]) + maxp = i; + if (maxp == mid) { + int j; + for (j = peakCount; j > 0; j--) { + if (data[maxp] <= data[peaks[j-1]]) + break; + else if (j < peaks.size()) + peaks[j] = peaks[j-1]; + } + if (j != peaks.size()) + peaks[j] = maxp; + if (peakCount != peaks.size()) + peakCount++; + } + mid++; + } + return peakCount; + } // findPeaks() + + /** General peak picking method for finding local maxima in an array + * @param data input data + * @param width minimum distance between peaks + * @param threshold minimum value of peaks + * @return list of peak indexes + */ + static vector<int> findPeaks(const vector<double> &data, int width, + double threshold) { + return findPeaks(data, width, threshold, 0, false); + } // findPeaks() + + /** General peak picking method for finding local maxima in an array + * @param data input data + * @param width minimum distance between peaks + * @param threshold minimum value of peaks + * @param decayRate how quickly previous peaks are forgotten + * @param isRelative minimum value of peaks is relative to local average + * @return list of peak indexes + */ + static vector<int> findPeaks(const vector<double> &data, int width, + double threshold, double decayRate, bool isRelative) { + vector<int> peaks; + int maxp = 0; + int mid = 0; + int end = data.size(); + double av = data[0]; + while (mid < end) { + av = decayRate * av + (1 - decayRate) * data[mid]; + if (av < data[mid]) + av = data[mid]; + int i = mid - width; + if (i < 0) + i = 0; + int stop = mid + width + 1; + if (stop > data.size()) + stop = data.size(); + maxp = i; + for (i++; i < stop; i++) + if (data[i] > data[maxp]) + maxp = i; + if (maxp == mid) { + if (overThreshold(data, maxp, width, threshold, isRelative,av)){ + peaks.push_back(maxp); + } + } + mid++; + } + return peaks; + } // findPeaks() + + static double expDecayWithHold(double av, double decayRate, + const vector<double> &data, int start, int stop) { + while (start < stop) { + av = decayRate * av + (1 - decayRate) * data[start]; + if (av < data[start]) + av = data[start]; + start++; + } + return av; + } // expDecayWithHold() + + static bool overThreshold(const vector<double> &data, int index, int width, + double threshold, bool isRelative, + double av) { + if (data[index] < av) + return false; + if (isRelative) { + int iStart = index - pre * width; + if (iStart < 0) + iStart = 0; + int iStop = index + post * width; + if (iStop > data.size()) + iStop = data.size(); + double sum = 0; + int count = iStop - iStart; + while (iStart < iStop) + sum += data[iStart++]; + return (data[index] > sum / count + threshold); + } else + return (data[index] > threshold); + } // overThreshold() + + static void normalise(vector<double> &data) { + double sx = 0; + double sxx = 0; + for (int i = 0; i < data.size(); i++) { + sx += data[i]; + sxx += data[i] * data[i]; + } + double mean = sx / data.size(); + double sd = sqrt((sxx - sx * mean) / data.size()); + if (sd == 0) + sd = 1; // all data[i] == mean -> 0; avoids div by 0 + for (int i = 0; i < data.size(); i++) { + data[i] = (data[i] - mean) / sd; + } + } // normalise() + + /** Uses an n-point linear regression to estimate the slope of data. + * @param data input data + * @param hop spacing of data points + * @param n length of linear regression + * @param slope output data + */ + static void getSlope(const vector<double> &data, double hop, int n, + vector<double> &slope) { + int i = 0, j = 0; + double t; + double sx = 0, sxx = 0, sy = 0, sxy = 0; + for ( ; i < n; i++) { + t = i * hop; + sx += t; + sxx += t * t; + sy += data[i]; + sxy += t * data[i]; + } + double delta = n * sxx - sx * sx; + for ( ; j < n / 2; j++) + slope[j] = (n * sxy - sx * sy) / delta; + for ( ; j < data.size() - (n + 1) / 2; j++, i++) { + slope[j] = (n * sxy - sx * sy) / delta; + sy += data[i] - data[i - n]; + sxy += hop * (n * data[i] - sy); + } + for ( ; j < data.size(); j++) + slope[j] = (n * sxy - sx * sy) / delta; + } // getSlope() + + static double min(const vector<double> &arr) { return arr[imin(arr)]; } + + static double max(const vector<double> &arr) { return arr[imax(arr)]; } + + static int imin(const vector<double> &arr) { + int i = 0; + for (int j = 1; j < arr.size(); j++) + if (arr[j] < arr[i]) + i = j; + return i; + } // imin() + + static int imax(const vector<double> &arr) { + int i = 0; + for (int j = 1; j < arr.size(); j++) + if (arr[j] > arr[i]) + i = j; + return i; + } // imax() + +}; // class Peaks + +#endif