Mercurial > hg > match-vamp
changeset 108:4b263ef50c9b adaptive_diagonals
Merge from branch feature_conditioner, but leave the confidence calculation unfinished (need to move this)
author | Chris Cannam |
---|---|
date | Thu, 04 Dec 2014 13:54:05 +0000 |
parents | 2e6144da14af (diff) a07b962e9f03 (current diff) |
children | fef3160ff0e2 |
files | src/MatchVampPlugin.cpp src/MatchVampPlugin.h |
diffstat | 6 files changed, 332 insertions(+), 39 deletions(-) [+] |
line wrap: on
line diff
--- a/Makefile.linux Thu Dec 04 13:48:17 2014 +0000 +++ b/Makefile.linux Thu Dec 04 13:54:05 2014 +0000 @@ -1,6 +1,6 @@ -#CXXFLAGS += -fPIC -ffast-math -O3 -Wall -Werror -Wfloat-conversion -CXXFLAGS += -fPIC -g -Wall -Werror -DPERFORM_ERROR_CHECKS=1 +CXXFLAGS += -fPIC -ffast-math -O3 -Wall -Werror +#CXXFLAGS += -fPIC -g -Wall -Werror -Wfloat-conversion -DPERFORM_ERROR_CHECKS=1 LDFLAGS += -shared -Wl,-Bstatic -lvamp-sdk -Wl,-Bdynamic -Wl,-Bsymbolic -Wl,-z,defs -lpthread -Wl,--version-script=vamp-plugin.map
--- a/src/Finder.cpp Thu Dec 04 13:48:17 2014 +0000 +++ b/src/Finder.cpp Thu Dec 04 13:54:05 2014 +0000 @@ -88,11 +88,16 @@ } void -Finder::recalculatePathCostMatrix(int r1, int c1, int r2, int c2) +Finder::recalculatePathCostMatrix(int r1, int c1, int r2, int c2) +{ + recalculatePathCostMatrix(r1, c1, r2, c2, m_m->getDiagonalWeight()); +} + +void +Finder::recalculatePathCostMatrix(int r1, int c1, int r2, int c2, + float diagonalWeight) { int prevRowStart = 0, prevRowStop = 0; - - float diagonalWeight = m_m->getDiagonalWeight(); for (int r = r1; r <= r2; r++) { @@ -366,7 +371,7 @@ y = ey; } - recalculatePathCostMatrix(0, 0, y, x); +// recalculatePathCostMatrix(0, 0, y, x); // cerr << "start: x = " << x << ", y = " << y << endl; @@ -418,4 +423,33 @@ } } +void +Finder::smoothWithPinPoints(const map<int, int> &pinpoints) +{ + cerr << "Pin points are:" << endl; + typedef map<int, int> PPMap; + + for (PPMap::const_iterator i = pinpoints.begin(); i != pinpoints.end(); ++i) { + cerr << "[" << i->first << "," << i->second << "] "; + } + + cerr << endl; + + if (pinpoints.size() < 2) return; + + pair<int, int> prev = *pinpoints.begin(); + + for (PPMap::const_iterator i = pinpoints.begin(); i != pinpoints.end(); ++i) { + if (i == pinpoints.begin()) continue; + + pair<int, int> curr = *i; + + recalculatePathCostMatrix(prev.second, prev.first, + curr.second, curr.first, 1.0); + + prev = curr; + } +} + +
--- a/src/Finder.h Thu Dec 04 13:48:17 2014 +0000 +++ b/src/Finder.h Thu Dec 04 13:54:05 2014 +0000 @@ -18,6 +18,7 @@ #define _FINDER_H_ #include <vector> +#include <map> #include <iostream> #include "Matcher.h" @@ -65,6 +66,8 @@ */ int retrievePath(bool smooth, std::vector<int> &pathx, std::vector<int> &pathy); + void smoothWithPinPoints(const std::map<int, int> &); + protected: #ifdef PERFORM_ERROR_CHECKS struct ErrorPosition { @@ -83,6 +86,9 @@ ErrorPosition checkPathCostMatrix(); void checkAndReport(); #endif + + void recalculatePathCostMatrix(int r1, int c1, int r2, int c2, + float diagonalWeight); Matcher *m_m; int m_duration1;
--- a/src/MatchVampPlugin.cpp Thu Dec 04 13:48:17 2014 +0000 +++ b/src/MatchVampPlugin.cpp Thu Dec 04 13:54:05 2014 +0000 @@ -27,6 +27,9 @@ #include <vector> #include <algorithm> +#include <map> + +using namespace std; //static int extant = 0; @@ -66,10 +69,10 @@ m_defaultFcParams() { if (inputSampleRate < sampleRateMin) { - std::cerr << "MatchVampPlugin::MatchVampPlugin: input sample rate " + cerr << "MatchVampPlugin::MatchVampPlugin: input sample rate " << inputSampleRate << " < min supported rate " << sampleRateMin << ", plugin will refuse to initialise" - << std::endl; + << endl; } if (!m_serialisingMutexInitialised) { @@ -82,12 +85,11 @@ } m_pipeline = 0; -// std::cerr << "MatchVampPlugin::MatchVampPlugin(" << this << "): extant = " << ++extant << std::endl; } MatchVampPlugin::~MatchVampPlugin() { -// std::cerr << "MatchVampPlugin::~MatchVampPlugin(" << this << "): extant = " << --extant << std::endl; +// cerr << "MatchVampPlugin::~MatchVampPlugin(" << this << "): extant = " << --extant << endl; delete m_pipeline; @@ -250,7 +252,7 @@ } float -MatchVampPlugin::getParameter(std::string name) const +MatchVampPlugin::getParameter(string name) const { if (name == "serialise") { return m_serialise ? 1.0 : 0.0; @@ -276,7 +278,7 @@ } void -MatchVampPlugin::setParameter(std::string name, float value) +MatchVampPlugin::setParameter(string name, float value) { if (name == "serialise") { m_serialise = (value > 0.5); @@ -325,9 +327,9 @@ MatchVampPlugin::initialise(size_t channels, size_t stepSize, size_t blockSize) { if (m_inputSampleRate < sampleRateMin) { - std::cerr << "MatchVampPlugin::MatchVampPlugin: input sample rate " + cerr << "MatchVampPlugin::MatchVampPlugin: input sample rate " << m_inputSampleRate << " < min supported rate " - << sampleRateMin << std::endl; + << sampleRateMin << endl; return false; } if (channels < getMinChannelCount() || @@ -352,6 +354,10 @@ delete m_pipeline; m_pipeline = 0; m_frameNo = 0; + + m_mag1.clear(); + m_mag2.clear(); + createMatchers(); m_begin = true; m_locked = false; @@ -459,6 +465,45 @@ m_bFeaturesOutNo = list.size(); list.push_back(desc); + desc.identifier = "feature_distance"; + desc.name = "Feature Distance"; + desc.description = "Value of distance metric between features at each point-in-A along the chosen alignment path"; + desc.unit = ""; + desc.hasFixedBinCount = true; + desc.binCount = 1; + desc.hasKnownExtents = false; + desc.isQuantized = false; + desc.sampleType = OutputDescriptor::VariableSampleRate; + desc.sampleRate = outRate; + m_distOutNo = list.size(); + list.push_back(desc); + + desc.identifier = "confidence"; + desc.name = "Confidence"; + desc.description = "Confidence metric for the quality of match at each point-in-A along the chosen alignment path"; + desc.unit = ""; + desc.hasFixedBinCount = true; + desc.binCount = 1; + desc.hasKnownExtents = false; + desc.isQuantized = false; + desc.sampleType = OutputDescriptor::FixedSampleRate; + desc.sampleRate = outRate; + m_confidenceOutNo = list.size(); + list.push_back(desc); + + desc.identifier = "confidence_peaks"; + desc.name = "Confidence Peaks"; + desc.description = "Peak locations for the confidence metric"; + desc.unit = ""; + desc.hasFixedBinCount = true; + desc.binCount = 0; + desc.hasKnownExtents = false; + desc.isQuantized = false; + desc.sampleType = OutputDescriptor::FixedSampleRate; + desc.sampleRate = outRate; + m_confPeakOutNo = list.size(); + list.push_back(desc); + return list; } @@ -479,7 +524,7 @@ m_begin = false; } -// std::cerr << timestamp.toString(); +// cerr << timestamp.toString(); m_pipeline->feedFrequencyDomainAudio(inputBuffers[0], inputBuffers[1]); @@ -492,19 +537,27 @@ f.hasTimestamp = false; f.values.clear(); + double mag1 = 0.0; for (int j = 0; j < (int)f1.size(); ++j) { f.values.push_back(float(f1[j])); + mag1 += f1[j] * f1[j]; } + mag1 = sqrt(mag1); + m_mag1.push_back(float(mag1)); returnFeatures[m_aFeaturesOutNo].push_back(f); f.values.clear(); + double mag2 = 0.0; for (int j = 0; j < (int)f2.size(); ++j) { f.values.push_back(float(f2[j])); + mag2 += f1[j] * f1[j]; } + mag2 = sqrt(mag2); + m_mag2.push_back(float(mag2)); returnFeatures[m_bFeaturesOutNo].push_back(f); -// std::cerr << "."; -// std::cerr << std::endl; +// cerr << "."; +// cerr << endl; ++m_frameNo; @@ -519,18 +572,69 @@ FeatureSet returnFeatures; Finder *finder = m_pipeline->getFinder(); - std::vector<int> pathx; - std::vector<int> pathy; - int len = finder->retrievePath(m_smooth, pathx, pathy); + vector<int> pathx; + vector<int> pathy; + int len = finder->retrievePath(false, pathx, pathy); //!!! smooth int prevx = 0; int prevy = 0; + if (m_smooth) { + + vector<float> confidence; + + for (int i = 0; i < len; ++i) { + int x = pathx[i]; + int y = pathy[i]; + if (x != prevx) { + double magSum = m_mag1[y] + m_mag2[x]; +// double distance = m_pm1->getDistance(y, x); + double distance = 0;///!!! + float c = magSum - distance; + confidence.push_back(c); + } + } + + if (!confidence.empty()) { + + map<int, int> pinpoints; + + vector<float> csorted = confidence; + sort(csorted.begin(), csorted.end()); + float thresh = csorted[int(csorted.size() * 0.7)]; // 70th percentile + for (int i = 1; i + 1 < int(confidence.size()); ++i) { + + int x = pathx[i]; + int y = pathy[i]; + + if (confidence[i] > thresh && + confidence[i] > confidence[i-1] && + confidence[i] >= confidence[i+1]) { + + pinpoints[x] = y; + + Vamp::RealTime xt = Vamp::RealTime::frame2RealTime + (x * m_stepSize, lrintf(m_inputSampleRate)); + Feature feature; + feature.hasTimestamp = true; + feature.timestamp = m_startTime + xt; + returnFeatures[m_confPeakOutNo].push_back(feature); + } + } + + finder->smoothWithPinPoints(pinpoints); + } + + pathx.clear(); + pathy.clear(); + len = finder->retrievePath(false, pathx, pathy); //!!! smooth + } + for (int i = 0; i < len; ++i) { int x = pathx[i]; int y = pathy[i]; - + Vamp::RealTime xt = Vamp::RealTime::frame2RealTime (x * m_stepSize, lrintf(m_inputSampleRate)); Vamp::RealTime yt = Vamp::RealTime::frame2RealTime @@ -556,6 +660,19 @@ feature.values.push_back(float(diff.sec + diff.msec()/1000.0)); returnFeatures[m_abDivOutNo].push_back(feature); + double magSum = m_mag1[y] + m_mag2[x]; +// double distance = m_pm1->getDistance(y, x); + double distance = 0;///!!! + + feature.values.clear(); + feature.values.push_back(distance); + returnFeatures[m_distOutNo].push_back(feature); + + feature.values.clear(); + float c = magSum - distance; + feature.values.push_back(c); + returnFeatures[m_confidenceOutNo].push_back(feature); + if (i > 0) { int lookback = 100; //!!! arbitrary if (lookback > i) lookback = i; @@ -601,31 +718,31 @@ /* for (int i = 0; i < len; ++i) { - std::cerr << i << ": [" << pathx[i] << "," << pathy[i] << "]" << std::endl; + cerr << i << ": [" << pathx[i] << "," << pathy[i] << "]" << endl; } - std::cerr << std::endl; - std::cerr << "File: A" << std::endl; - std::cerr << "Marks: -1" << std::endl; - std::cerr << "FixedPoints: true 0" << std::endl; - std::cerr << "0" << std::endl; - std::cerr << "0" << std::endl; - std::cerr << "0" << std::endl; - std::cerr << "0" << std::endl; - std::cerr << "File: B" << std::endl; - std::cerr << "Marks: 0" << std::endl; - std::cerr << "FixedPoints: true 0" << std::endl; - std::cerr << "0.02" << std::endl; - std::cerr << "0.02" << std::endl; + cerr << endl; + cerr << "File: A" << endl; + cerr << "Marks: -1" << endl; + cerr << "FixedPoints: true 0" << endl; + cerr << "0" << endl; + cerr << "0" << endl; + cerr << "0" << endl; + cerr << "0" << endl; + cerr << "File: B" << endl; + cerr << "Marks: 0" << endl; + cerr << "FixedPoints: true 0" << endl; + cerr << "0.02" << endl; + cerr << "0.02" << endl; - std::cerr << len << std::endl; + cerr << len << endl; for (int i = 0; i < len; ++i) { - std::cerr << pathx[i] << std::endl; + cerr << pathx[i] << endl; } - std::cerr << len << std::endl; + cerr << len << endl; for (int i = 0; i < len; ++i) { - std::cerr << pathy[i] << std::endl; + cerr << pathy[i] << endl; } */ }
--- a/src/MatchVampPlugin.h Thu Dec 04 13:48:17 2014 +0000 +++ b/src/MatchVampPlugin.h Thu Dec 04 13:54:05 2014 +0000 @@ -90,6 +90,9 @@ FeatureConditioner::Parameters m_fcParams; FeatureConditioner::Parameters m_defaultFcParams; + std::vector<float> m_mag1; + std::vector<float> m_mag2; + mutable int m_pathOutNo; mutable int m_abOutNo; mutable int m_baOutNo; @@ -97,6 +100,9 @@ mutable int m_abRatioOutNo; mutable int m_aFeaturesOutNo; mutable int m_bFeaturesOutNo; + mutable int m_distOutNo; + mutable int m_confidenceOutNo; + mutable int m_confPeakOutNo; #ifdef _WIN32 static HANDLE m_serialisingMutex;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/MedianFilter.h Thu Dec 04 13:54:05 2014 +0000 @@ -0,0 +1,130 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + QM DSP Library + + Centre for Digital Music, Queen Mary, University of London. + This file Copyright 2010 Chris Cannam. + + 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 MEDIAN_FILTER_H +#define MEDIAN_FILTER_H + +#include <algorithm> +#include <cassert> +#include <cmath> +#include <iostream> +#include <vector> + +template <typename T> +class MedianFilter +{ +public: + MedianFilter(int size, float percentile = 50.f) : + m_size(size), + m_frame(new T[size]), + m_sorted(new T[size]), + m_sortend(m_sorted + size - 1) { + setPercentile(percentile); + reset(); + } + + ~MedianFilter() { + delete[] m_frame; + delete[] m_sorted; + } + + void setPercentile(float p) { + m_index = int((m_size * p) / 100.f); + if (m_index >= m_size) m_index = m_size-1; + if (m_index < 0) m_index = 0; + } + + void push(T value) { + if (value != value) { + std::cerr << "WARNING: MedianFilter::push: attempt to push NaN" << std::endl; + return; // nan + } + drop(m_frame[0]); + const int sz1 = m_size-1; + for (int i = 0; i < sz1; ++i) m_frame[i] = m_frame[i+1]; + m_frame[m_size-1] = value; + put(value); + } + + T get() const { + return m_sorted[m_index]; + } + + int getSize() const { + return m_size; + } + + T getAt(float percentile) { + int ix = int((m_size * percentile) / 100.f); + if (ix >= m_size) ix = m_size-1; + if (ix < 0) ix = 0; + return m_sorted[ix]; + } + + void reset() { + for (int i = 0; i < m_size; ++i) m_frame[i] = 0; + for (int i = 0; i < m_size; ++i) m_sorted[i] = 0; + } + + static std::vector<T> filter(int size, const std::vector<T> &in) { + std::vector<T> out; + MedianFilter<T> f(size); + for (int i = 0; i < int(in.size()); ++i) { + f.push(in[i]); + T median = f.get(); + if (i >= size/2) out.push_back(median); + } + while (out.size() < in.size()) { + f.push(T()); + out.push_back(f.get()); + } + return out; + } + +private: + const int m_size; + T *const m_frame; + T *const m_sorted; + T *const m_sortend; + int m_index; + + void put(T value) { + // precondition: m_sorted contains m_size-1 values, packed at start + // postcondition: m_sorted contains m_size values, one of which is value + T *point = std::lower_bound(m_sorted, m_sortend, value); + const int n = m_sortend - point; + for (int i = n; i > 0; --i) point[i] = point[i-1]; + *point = value; + } + + void drop(T value) { + // precondition: m_sorted contains m_size values, one of which is value + // postcondition: m_sorted contains m_size-1 values, packed at start + T *point = std::lower_bound(m_sorted, m_sortend + 1, value); + if (*point != value) { + std::cerr << "WARNING: MedianFilter::drop: *point is " << *point + << ", expected " << value << std::endl; + } + const int n = m_sortend - point; + for (int i = 0; i < n; ++i) point[i] = point[i+1]; + *m_sortend = T(0); + } + + MedianFilter(const MedianFilter &); // not provided + MedianFilter &operator=(const MedianFilter &); // not provided +}; + +#endif +