Mercurial > hg > match-vamp
changeset 74:b9aa663a607b refactors
Pull out feature extractor calls from Matcher, remove MatchFeeder, have only the feeder-from-features and use that in MatchVampPlugin
author | Chris Cannam |
---|---|
date | Wed, 19 Nov 2014 11:59:03 +0000 |
parents | 7e3c1bc0984a |
children | e1a5f3095ba6 9be9182d4321 |
files | Makefile.inc src/FeatureExtractor.cpp src/FeatureExtractor.h src/MatchFeatureFeeder.cpp src/MatchFeatureFeeder.h src/MatchFeeder.cpp src/MatchFeeder.h src/MatchVampPlugin.cpp src/MatchVampPlugin.h src/Matcher.cpp src/Matcher.h |
diffstat | 11 files changed, 193 insertions(+), 491 deletions(-) [+] |
line wrap: on
line diff
--- a/Makefile.inc Wed Nov 19 10:48:27 2014 +0000 +++ b/Makefile.inc Wed Nov 19 11:59:03 2014 +0000 @@ -23,18 +23,17 @@ # DO NOT DELETE src/DistanceMetric.o: src/DistanceMetric.h -src/MatchFeeder.o: src/MatchFeeder.h src/Matcher.h src/DistanceMetric.h -src/MatchFeeder.o: src/Finder.h src/Path.o: src/Path.h src/MatchFeatureFeeder.o: src/MatchFeatureFeeder.h src/Matcher.h src/MatchFeatureFeeder.o: src/DistanceMetric.h src/Finder.h +src/FeatureExtractor.o: src/FeatureExtractor.h src/Finder.o: src/Finder.h src/Matcher.h src/DistanceMetric.h src/Path.h src/Matcher.o: src/Matcher.h src/DistanceMetric.h src/MatchVampPlugin.o: src/MatchVampPlugin.h src/Matcher.h -src/MatchVampPlugin.o: src/DistanceMetric.h src/MatchFeeder.h src/Finder.h -src/MatchVampPlugin.o: src/Path.h -src/MatchFeeder.o: src/Matcher.h src/DistanceMetric.h src/Finder.h +src/MatchVampPlugin.o: src/DistanceMetric.h src/FeatureExtractor.h +src/MatchVampPlugin.o: src/MatchFeatureFeeder.h src/Finder.h src/Path.h src/MatchFeatureFeeder.o: src/Matcher.h src/DistanceMetric.h src/Finder.h src/Finder.o: src/Matcher.h src/DistanceMetric.h src/Matcher.o: src/DistanceMetric.h src/MatchVampPlugin.o: src/Matcher.h src/DistanceMetric.h +src/MatchVampPlugin.o: src/FeatureExtractor.h
--- a/src/FeatureExtractor.cpp Wed Nov 19 10:48:27 2014 +0000 +++ b/src/FeatureExtractor.cpp Wed Nov 19 11:59:03 2014 +0000 @@ -28,17 +28,22 @@ m_params(parameters), m_ltAverage(0) { - if (m_params.useChromaFrequencyMap) { - m_featureSize = 13; - } else { - m_featureSize = 84; - } - + m_featureSize = getFeatureSizeFor(parameters); m_prevFrame = vector<double>(m_featureSize, 0.0); makeFreqMap(); } +int +FeatureExtractor::getFeatureSizeFor(Parameters parameters) +{ + if (parameters.useChromaFrequencyMap) { + return 13; + } else { + return 84; + } +} + void FeatureExtractor::makeFreqMap() { @@ -110,6 +115,28 @@ } rms = sqrt(rms / (m_params.fftSize/2)); + return postProcess(frame, rms); +} + +vector<double> +FeatureExtractor::process(const float *cframe) +{ + vector<double> frame(m_featureSize, 0.0); + + double rms = 0; + for (int i = 0; i <= m_params.fftSize/2; i++) { + double mag = cframe[i*2] * cframe[i*2] + cframe[i*2+1] * cframe[i*2+1]; + rms += mag; + frame[m_freqMap[i]] += mag; + } + rms = sqrt(rms / (m_params.fftSize/2)); + + return postProcess(frame, rms); +} + +vector<double> +FeatureExtractor::postProcess(const vector<double> &frame, double rms) +{ vector<double> feature(m_featureSize, 0.0); double totalEnergy = 0;
--- a/src/FeatureExtractor.h Wed Nov 19 10:48:27 2014 +0000 +++ b/src/FeatureExtractor.h Wed Nov 19 11:59:03 2014 +0000 @@ -103,6 +103,12 @@ * Return the feature vector size that will be returned from process(). */ int getFeatureSize() const { return m_featureSize; } + + /** + * Return the feature vector size that would be returned from + * process() with these parameters. + */ + static int getFeatureSizeFor(Parameters params); /** * Process one frequency-domain audio frame (provided as real & @@ -121,6 +127,21 @@ std::vector<double> process(const std::vector<double> &real, const std::vector<double> &imag); + /** + * Process one frequency-domain audio frame, provided as a single + * array of alternating real and imaginary components. Input array + * must have at least 2 * (params.fftSize/2 + 1) elements. + * + * Operates by mapping the frequency bins into a part-linear + * part-logarithmic array, then (optionally) computing the + * half-wave rectified spectral difference from the previous + * frame, then (optionally) normalising to a sum of 1. + * + * Return value is the frame (post-processed, with warping, + * rectification, and normalisation as appropriate). + */ + std::vector<double> process(const float *carray); + protected: /** Make either standard or chroma map, depending on m_params */ void makeFreqMap(); @@ -136,6 +157,8 @@ /** Creates a map of FFT frequency bins to semitone chroma bins. */ void makeChromaFrequencyMap(); + std::vector<double> postProcess(const std::vector<double> &, double rms); + /** Configuration parameters */ Parameters m_params;
--- a/src/MatchFeatureFeeder.cpp Wed Nov 19 10:48:27 2014 +0000 +++ b/src/MatchFeatureFeeder.cpp Wed Nov 19 11:59:03 2014 +0000 @@ -19,14 +19,14 @@ using std::vector; MatchFeatureFeeder::MatchFeatureFeeder(Matcher *m1, Matcher *m2) : - pm1(m1), pm2(m2) + m_pm1(m1), m_pm2(m2) { - finder = new Finder(m1); + m_finder = new Finder(m1); } MatchFeatureFeeder::~MatchFeatureFeeder() { - delete finder; + delete m_finder; } void @@ -39,14 +39,14 @@ // empty. Then it returns, to be called again with more data. if (!f1.empty()) { - q1.push(f1); + m_q1.push(f1); } if (!f2.empty()) { - q2.push(f2); + m_q2.push(f2); } - while (!q1.empty() && !q2.empty()) { + while (!m_q1.empty() && !m_q2.empty()) { feedBlock(); } } @@ -54,7 +54,7 @@ void MatchFeatureFeeder::finish() { - while (!q1.empty() || !q2.empty()) { + while (!m_q1.empty() || !m_q2.empty()) { feedBlock(); } } @@ -62,20 +62,20 @@ void MatchFeatureFeeder::feedBlock() { - if (q1.empty()) { // ended + if (m_q1.empty()) { // ended feed2(); - } else if (q2.empty()) { // ended + } else if (m_q2.empty()) { // ended feed1(); - } else if (pm1->m_frameCount < pm1->m_blockSize) { // fill initial block + } else if (m_pm1->m_frameCount < m_pm1->m_blockSize) { // fill initial block feed1(); feed2(); - } else if (pm1->m_runCount >= pm1->m_params.maxRunCount) { // slope constraints + } else if (m_pm1->m_runCount >= m_pm1->m_params.maxRunCount) { // slope constraints feed2(); - } else if (pm2->m_runCount >= pm2->m_params.maxRunCount) { + } else if (m_pm2->m_runCount >= m_pm2->m_params.maxRunCount) { feed1(); } else { - switch (finder->getExpandDirection - (pm1->m_frameCount-1, pm2->m_frameCount-1)) { + switch (m_finder->getExpandDirection + (m_pm1->m_frameCount-1, m_pm2->m_frameCount-1)) { case Matcher::AdvanceThis: feed1(); break; @@ -87,7 +87,7 @@ feed2(); break; case Matcher::AdvanceNone: - cerr << "finder says AdvanceNone!" << endl; + cerr << "m_finder says AdvanceNone!" << endl; break; } } @@ -96,14 +96,14 @@ void MatchFeatureFeeder::feed1() { - pm1->consumeFeatureVector(q1.front()); - q1.pop(); + m_pm1->consumeFeatureVector(m_q1.front()); + m_q1.pop(); } void MatchFeatureFeeder::feed2() { - pm2->consumeFeatureVector(q2.front()); - q2.pop(); + m_pm2->consumeFeatureVector(m_q2.front()); + m_q2.pop(); }
--- a/src/MatchFeatureFeeder.h Wed Nov 19 10:48:27 2014 +0000 +++ b/src/MatchFeatureFeeder.h Wed Nov 19 11:59:03 2014 +0000 @@ -48,19 +48,19 @@ */ void finish(); - Finder *getFinder() { return finder; } + Finder *getFinder() { return m_finder; } protected: void feedBlock(); void feed1(); void feed2(); - Finder *finder; - Matcher *pm1; - Matcher *pm2; + Finder *m_finder; + Matcher *m_pm1; + Matcher *m_pm2; - std::queue<std::vector<double> > q1; - std::queue<std::vector<double> > q2; + std::queue<std::vector<double> > m_q1; + std::queue<std::vector<double> > m_q2; }; #endif
--- a/src/MatchFeeder.cpp Wed Nov 19 10:48:27 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,215 +0,0 @@ -/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ - -/* - Vamp feature extraction plugin using the MATCH audio alignment - algorithm. - - Centre for Digital Music, Queen Mary, University of London. - This file copyright 2007 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 "MatchFeeder.h" - -using std::vector; - -MatchFeeder::MatchFeeder(Matcher *m1, Matcher *m2) : - pm1(m1), pm2(m2), n(0), lastIn1(0), lastIn2(0) -{ - fftSize = m1->m_params.fftSize; - finder = new Finder(m1); - reBuffer = new double[fftSize/2+1]; - imBuffer = new double[fftSize/2+1]; -} - -MatchFeeder::~MatchFeeder() -{ - delete[] imBuffer; - delete[] reBuffer; - while (!q1.empty()) { - delete[] q1.front(); - q1.pop(); - } - while (!q2.empty()) { - delete[] q2.front(); - q2.pop(); - } - delete finder; -} - -void -MatchFeeder::feed(const float *const *input) -{ - // We maintain two FIFO queues of audio data frame block pointers, - // one per input stream. When the match-feeder function is - // entered, it knows that it has at least one block in each queue. - // It loops, processing up to one block per matcher, until a queue - // is empty. Then it returns, to be called again with more data. - - prepare(input); - - while (!q1.empty() && !q2.empty()) { - (void)feedBlock(); - } -} - -MatchFeeder::Features -MatchFeeder::feedAndGetFeatures(const float *const *input) -{ - prepare(input); - - Features all; - - while (!q1.empty() && !q2.empty()) { - Features ff = feedBlock(); - all.f1.insert(all.f1.end(), ff.f1.begin(), ff.f1.end()); - all.f2.insert(all.f2.end(), ff.f2.begin(), ff.f2.end()); - } - - return all; -} - -void -MatchFeeder::finish() -{ - while (!q1.empty() || !q2.empty()) { - (void)feedBlock(); - } -} - -MatchFeeder::Features -MatchFeeder::finishAndGetFeatures() -{ - Features all; - - while (!q1.empty() || !q2.empty()) { - Features ff = feedBlock(); - all.f1.insert(all.f1.end(), ff.f1.begin(), ff.f1.end()); - all.f2.insert(all.f2.end(), ff.f2.begin(), ff.f2.end()); - } - - return all; -} - -void -MatchFeeder::prepare(const float *const *input) -{ - float threshold = 1e-5f; - - float *block = new float[fftSize+2]; - float rms = 0; - - for (size_t i = 0; i < fftSize+2; ++i) { - block[i] = input[0][i]; - rms += block[i] * block[i]; - } - rms = sqrtf(rms / (fftSize+2)); - if (rms > threshold) { - lastIn1 = n; - } - q1.push(block); - - block = new float[fftSize+2]; - rms = 0; - - for (size_t i = 0; i < fftSize+2; ++i) { - block[i] = input[1][i]; - rms += block[i] * block[i]; - } - rms = sqrtf(rms / (fftSize+2)); - if (rms > threshold) { - lastIn2 = n; - } - q2.push(block); - - ++n; - finder->setDurations(lastIn1, lastIn2); -} - -MatchFeeder::Features -MatchFeeder::feedBlock() -{ - Features ff; - vector<double> f1, f2; - - if (q1.empty()) { - cerr << "feedBlock: q1 empty, feeding 2" << endl; - f2 = feed2(); - } else if (q2.empty()) { - cerr << "feedBlock: q2 empty, feeding 1" << endl; - f1 = feed1(); - } else if (pm1->m_frameCount < pm1->m_blockSize) { // fill initial block - std::cerr << "feeding initial block" << std::endl; - f1 = feed1(); - f2 = feed2(); - } else if (pm1->m_runCount >= pm1->m_params.maxRunCount) { // slope constraints - std::cerr << "pm1 too slopey" << std::endl; - f2 = feed2(); - } else if (pm2->m_runCount >= pm2->m_params.maxRunCount) { - std::cerr << "pm2 too slopey" << std::endl; - f1 = feed1(); - } else { -// cerr << "run counts: " << pm1->m_runCount << ", " << pm2->m_runCount << endl; - switch (finder->getExpandDirection - (pm1->m_frameCount-1, pm2->m_frameCount-1)) { - case Matcher::AdvanceThis: -// cerr << "feeding 1" << endl; - f1 = feed1(); - break; - case Matcher::AdvanceOther: -// cerr << "feeding 2" << endl; - f2 = feed2(); - break; - case Matcher::AdvanceBoth: -// cerr << "feeding 1 and 2" << endl; - f1 = feed1(); - f2 = feed2(); - break; - case Matcher::AdvanceNone: - cerr << "finder says AdvanceNone!" << endl; - break; - } - } - - if (!f1.empty()) ff.f1.push_back(f1); - if (!f2.empty()) ff.f2.push_back(f2); - return ff; -} - -vector<double> -MatchFeeder::feed1() -{ -// std::cerr << "feed1" << std::endl; - float *block = q1.front(); - q1.pop(); - for (size_t i = 0; i <= fftSize/2; ++i) { - reBuffer[i] = block[i*2]; - } - for (size_t i = 0; i <= fftSize/2; ++i) { - imBuffer[i] = block[i*2+1]; - } - delete[] block; - return pm1->consumeFrame(reBuffer, imBuffer); -} - -vector<double> -MatchFeeder::feed2() -{ -// std::cerr << "feed2" << std::endl; - float *block = q2.front(); - q2.pop(); - for (size_t i = 0; i <= fftSize/2; ++i) { - reBuffer[i] = block[i*2]; - } - for (size_t i = 0; i <= fftSize/2; ++i) { - imBuffer[i] = block[i*2+1]; - } - delete[] block; - return pm2->consumeFrame(reBuffer, imBuffer); -} -
--- a/src/MatchFeeder.h Wed Nov 19 10:48:27 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,86 +0,0 @@ -/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ -/* - Vamp feature extraction plugin using the MATCH audio alignment - algorithm. - - Centre for Digital Music, Queen Mary, University of London. - This file copyright 2007 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 _MATCH_FEEDER_H_ -#define _MATCH_FEEDER_H_ - -#include "Matcher.h" -#include "Finder.h" - -#include <queue> -#include <vector> - -class MatchFeeder -{ -public: - MatchFeeder(Matcher *m1, Matcher *m2); - ~MatchFeeder(); - - /** - * Feed the two supplied channels of frequency-domain input data - * to feeders 1 and 2 respectively, as appropriate (depending on - * their advance status). - */ - void feed(const float *const *input); - - /** - * Indicate that the input has come to an end. - */ - void finish(); - - struct Features { - std::vector<std::vector<double> > f1; - std::vector<std::vector<double> > f2; - }; - - /** - * Feed the two supplied channels of frequency-domain input data - * to matchers 1 and 2 respectively, as appropriate (depending on - * their advance status) and return any new feature vectors - * calculated by the two feeders. - */ - Features feedAndGetFeatures(const float *const *input); - - /** - * Indicate that the input has come to an end, and return any - * remaining features. - */ - Features finishAndGetFeatures(); - - Finder *getFinder() { return finder; } - -protected: - void prepare(const float *const *input); - Features feedBlock(); - std::vector<double> feed1(); - std::vector<double> feed2(); - - Finder *finder; - Matcher *pm1; - Matcher *pm2; - - size_t fftSize; - double *reBuffer; - double *imBuffer; - - std::queue<float *> q1; - std::queue<float *> q2; - - int n; - int lastIn1; - int lastIn2; -}; - -#endif
--- a/src/MatchVampPlugin.cpp Wed Nov 19 10:48:27 2014 +0000 +++ b/src/MatchVampPlugin.cpp Wed Nov 19 11:59:03 2014 +0000 @@ -17,7 +17,8 @@ #include "MatchVampPlugin.h" #include "Matcher.h" -#include "MatchFeeder.h" +#include "MatchFeatureFeeder.h" +#include "FeatureExtractor.h" #include "Path.h" #include <vamp/vamp.h> @@ -56,6 +57,9 @@ m_begin(true), m_locked(false), m_smooth(true), + m_frameNo(0), + m_lastFrameIn1(0), + m_lastFrameIn2(0), m_params(inputSampleRate, defaultStepTime, m_blockSize), m_defaultParams(inputSampleRate, defaultStepTime, m_blockSize), m_feParams(inputSampleRate, m_blockSize), @@ -77,9 +81,11 @@ #endif } - pm1 = 0; - pm2 = 0; - feeder = 0; + m_pm1 = 0; + m_pm2 = 0; + m_fe1 = 0; + m_fe2 = 0; + m_feeder = 0; // std::cerr << "MatchVampPlugin::MatchVampPlugin(" << this << "): extant = " << ++extant << std::endl; } @@ -87,9 +93,11 @@ { // std::cerr << "MatchVampPlugin::~MatchVampPlugin(" << this << "): extant = " << --extant << std::endl; - delete feeder; - delete pm1; - delete pm2; + delete m_feeder; + delete m_fe1; + delete m_fe2; + delete m_pm1; + delete m_pm2; if (m_locked) { #ifdef _WIN32 @@ -303,10 +311,12 @@ m_params.hopTime = m_stepTime; m_params.fftSize = m_blockSize; m_feParams.fftSize = m_blockSize; - pm1 = new Matcher(m_params, m_feParams, 0); - pm2 = new Matcher(m_params, m_feParams, pm1); - pm1->setOtherMatcher(pm2); - feeder = new MatchFeeder(pm1, pm2); + m_fe1 = new FeatureExtractor(m_feParams); + m_fe2 = new FeatureExtractor(m_feParams); + m_pm1 = new Matcher(m_params, 0, m_fe1->getFeatureSize()); + m_pm2 = new Matcher(m_params, m_pm1, m_fe2->getFeatureSize()); + m_pm1->setOtherMatcher(m_pm2); + m_feeder = new MatchFeatureFeeder(m_pm1, m_pm2); } bool @@ -337,12 +347,21 @@ void MatchVampPlugin::reset() { - delete feeder; - delete pm1; - delete pm2; - feeder = 0; - pm1 = 0; - pm2 = 0; + delete m_feeder; + delete m_fe1; + delete m_fe2; + delete m_pm1; + delete m_pm2; + + m_feeder = 0; + m_fe1 = 0; + m_fe2 = 0; + m_pm1 = 0; + m_pm2 = 0; + + m_frameNo = 0; + m_lastFrameIn1 = 0; + m_lastFrameIn2 = 0; createMatchers(); m_begin = true; @@ -454,6 +473,18 @@ return list; } +bool +MatchVampPlugin::aboveThreshold(const float *frame) +{ + float threshold = 1e-5f; + float rms = 0.f; + for (int i = 0; i < m_blockSize/2 + 2; ++i) { + rms += frame[i] * frame[i]; + } + rms = sqrtf(rms / (m_blockSize/2 + 2)); + return (rms > threshold); +} + MatchVampPlugin::FeatureSet MatchVampPlugin::process(const float *const *inputBuffers, Vamp::RealTime timestamp) @@ -473,62 +504,47 @@ // std::cerr << timestamp.toString(); - MatchFeeder::Features ff = feeder->feedAndGetFeatures(inputBuffers); + if (aboveThreshold(inputBuffers[0])) m_lastFrameIn1 = m_frameNo; + if (aboveThreshold(inputBuffers[1])) m_lastFrameIn2 = m_frameNo; + + vector<double> f1 = m_fe1->process(inputBuffers[0]); + vector<double> f2 = m_fe2->process(inputBuffers[1]); + + m_feeder->feed(f1, f2); FeatureSet returnFeatures; Feature f; f.hasTimestamp = false; - for (int i = 0; i < (int)ff.f1.size(); ++i) { - f.values.clear(); - for (int j = 0; j < (int)ff.f1[i].size(); ++j) { - f.values.push_back(float(ff.f1[i][j])); - } - returnFeatures[m_aFeaturesOutNo].push_back(f); + f.values.clear(); + for (int j = 0; j < (int)f1.size(); ++j) { + f.values.push_back(float(f1[j])); } + returnFeatures[m_aFeaturesOutNo].push_back(f); - for (int i = 0; i < (int)ff.f2.size(); ++i) { - f.values.clear(); - for (int j = 0; j < (int)ff.f2[i].size(); ++j) { - f.values.push_back(float(ff.f2[i][j])); - } - returnFeatures[m_bFeaturesOutNo].push_back(f); + f.values.clear(); + for (int j = 0; j < (int)f2.size(); ++j) { + f.values.push_back(float(f2[j])); } + returnFeatures[m_bFeaturesOutNo].push_back(f); // std::cerr << "."; // std::cerr << std::endl; + ++m_frameNo; + return returnFeatures; } MatchVampPlugin::FeatureSet MatchVampPlugin::getRemainingFeatures() { + m_feeder->finish(); + FeatureSet returnFeatures; - MatchFeeder::Features ff = feeder->finishAndGetFeatures(); - - Feature f; - f.hasTimestamp = false; - - for (int i = 0; i < (int)ff.f1.size(); ++i) { - f.values.clear(); - for (int j = 0; j < (int)ff.f1[i].size(); ++j) { - f.values.push_back(float(ff.f1[i][j])); - } - returnFeatures[m_aFeaturesOutNo].push_back(f); - } - - for (int i = 0; i < (int)ff.f2.size(); ++i) { - f.values.clear(); - for (int j = 0; j < (int)ff.f2[i].size(); ++j) { - f.values.push_back(float(ff.f2[i][j])); - } - returnFeatures[m_bFeaturesOutNo].push_back(f); - } - - Finder *finder = feeder->getFinder(); + Finder *finder = m_feeder->getFinder(); std::vector<int> pathx; std::vector<int> pathy; int len = finder->retrievePath(m_smooth, pathx, pathy); @@ -594,12 +610,12 @@ prevy = y; } - delete feeder; - delete pm1; - delete pm2; - feeder = 0; - pm1 = 0; - pm2 = 0; + delete m_feeder; + delete m_pm1; + delete m_pm2; + m_feeder = 0; + m_pm1 = 0; + m_pm2 = 0; if (m_locked) { #ifdef _WIN32
--- a/src/MatchVampPlugin.h Wed Nov 19 10:48:27 2014 +0000 +++ b/src/MatchVampPlugin.h Wed Nov 19 11:59:03 2014 +0000 @@ -28,7 +28,7 @@ #include "Matcher.h" #include "FeatureExtractor.h" -class MatchFeeder; +class MatchFeatureFeeder; class MatchVampPlugin : public Vamp::Plugin { @@ -67,10 +67,13 @@ protected: void createMatchers(); + bool aboveThreshold(const float *); - Matcher *pm1; - Matcher *pm2; - MatchFeeder *feeder; + Matcher *m_pm1; + Matcher *m_pm2; + FeatureExtractor *m_fe1; + FeatureExtractor *m_fe2; + MatchFeatureFeeder *m_feeder; Vamp::RealTime m_startTime; int m_stepSize; @@ -81,6 +84,10 @@ bool m_locked; bool m_smooth; + int m_frameNo; + int m_lastFrameIn1; + int m_lastFrameIn2; + Matcher::Parameters m_params; Matcher::Parameters m_defaultParams;
--- a/src/Matcher.cpp Wed Nov 19 10:48:27 2014 +0000 +++ b/src/Matcher.cpp Wed Nov 19 11:59:03 2014 +0000 @@ -25,36 +25,9 @@ //#define DEBUG_MATCHER 1 -Matcher::Matcher(Parameters parameters, - FeatureExtractor::Parameters feParams, - Matcher *p) : - m_params(parameters), - m_featureExtractor(feParams), - m_metric(parameters.distanceNorm) -{ -#ifdef DEBUG_MATCHER - cerr << "Matcher::Matcher(" << m_params.sampleRate << ", " << p << ")" << endl; -#endif - - m_otherMatcher = p; // the first matcher will need this to be set later - m_firstPM = (!p); - m_frameCount = 0; - m_runCount = 0; - m_featureSize = m_featureExtractor.getFeatureSize(); - m_blockSize = 0; - - m_blockSize = lrint(m_params.blockTime / m_params.hopTime); -#ifdef DEBUG_MATCHER - cerr << "Matcher: m_blockSize = " << m_blockSize << endl; -#endif - - m_initialised = false; -} - Matcher::Matcher(Parameters parameters, Matcher *p, int m_featureSize_) : m_params(parameters), m_featureSize(m_featureSize_), - m_featureExtractor(FeatureExtractor::Parameters(m_params.sampleRate, m_params.fftSize)), // unused default config m_metric(parameters.distanceNorm) { #ifdef DEBUG_MATCHER @@ -111,21 +84,6 @@ m_last.resize(m_distXSize, 0); } -vector<double> -Matcher::consumeFrame(double *reBuffer, double *imBuffer) -{ - if (!m_initialised) init(); - - vector<double> real(reBuffer, reBuffer + m_params.fftSize/2 + 1); - vector<double> imag(imBuffer, imBuffer + m_params.fftSize/2 + 1); - vector<double> feature = m_featureExtractor.process(real, imag); - int frameIndex = m_frameCount % m_blockSize; - m_frames[frameIndex] = feature; - calcAdvance(); - - return feature; -} - void Matcher::consumeFeatureVector(vector<double> feature) {
--- a/src/Matcher.h Wed Nov 19 10:48:27 2014 +0000 +++ b/src/Matcher.h Wed Nov 19 11:59:03 2014 +0000 @@ -23,16 +23,15 @@ #include <cmath> #include "DistanceMetric.h" -#include "FeatureExtractor.h" using std::vector; using std::string; using std::cerr; using std::endl; -/** Represents an audio stream that can be matched to another audio - * stream of the same piece of music. The matching algorithm uses - * dynamic time warping. +/** Represents an audio feature stream that can be matched to another + * audio stream of the same piece of music. The matching algorithm + * uses dynamic time warping. */ class Matcher { @@ -87,28 +86,19 @@ }; /** Constructor for Matcher. - * - * @param p The Matcher representing the performance with which - * this one is going to be matched. Some information is shared - * between the two matchers (currently one possesses the distance - * matrix and optimal path matrix). - */ - Matcher(Parameters parameters, - FeatureExtractor::Parameters featureParams, - Matcher *p); - - /** Constructor for Matcher using externally supplied features. - * A Matcher made using this constructor will not carry out its - * own feature extraction from frequency-domain audio data, but - * instead will accept arbitrary feature frames calculated by - * some external code. + * + * A Matcher expects to be provided with feature vectors + * calculated by some external code (for example, a + * FeatureExtractor). Call consumeFeatureVector to provide each + * feature frame. * * @param p The Matcher representing the performance with which * this one is going to be matched. Some information is shared * between the two matchers (currently one possesses the distance * matrix and optimal path matrix). * - * @param featureSize Number of values in each feature vector. + * @param featureSize Number of values in each of the feature + * vectors that will be provided. */ Matcher(Parameters parameters, Matcher *p, int featureSize); @@ -121,7 +111,7 @@ */ void setOtherMatcher(Matcher *p) { m_otherMatcher = p; - } // setOtherMatcher() + } int getFrameCount() { return m_frameCount; @@ -130,6 +120,18 @@ int getOtherFrameCount() { return m_otherMatcher->getFrameCount(); } + + /** Processes a feature vector frame, presumably calculated from + * audio data by some external code such as a FeatureExtractor. + * Calculates the distance to all frames stored in the + * otherMatcher and stores in the distance matrix, before + * updating the optimal path matrix using the dynamic time + * warping algorithm. + * + * The supplied feature must be of the size that was passed as + * featureSize to the constructor. + */ + void consumeFeatureVector(std::vector<double> feature); /** Tests whether a location is in range in the minimum cost matrix. * @@ -217,34 +219,6 @@ /** The distXSize value has changed: resize internal buffers. */ void size(); - /** Process a frequency-domain frame of audio data using the - * built-in FeatureExtractor, then calculating the distance to - * all frames stored in the otherMatcher and storing them in the - * distance matrix, and finally updating the optimal path matrix - * using the dynamic time warping algorithm. - * - * Return value is the frame (post-processed, with warping, - * rectification, and normalisation as appropriate). - * - * The Matcher must have been constructed using the constructor - * without an external featureSize parameter in order to use this - * function. (Otherwise it will be expecting you to call - * consumeFeatureVector.) - */ - std::vector<double> consumeFrame(double *reBuffer, double *imBuffer); - - /** Processes a feature vector frame (presumably calculated from - * audio data by some external code). As consumeFrame, except - * that it does not calculate a feature from audio data but - * instead uses the supplied feature directly. - * - * The Matcher must have been constructed using the constructor - * that accepts an external featureSize parameter in order to - * use this function. The supplied feature must be of the size - * that was passed to the constructor. - */ - void consumeFeatureVector(std::vector<double> feature); - /** Updates an entry in the distance matrix and the optimal path matrix. * * @param i the frame number of this Matcher @@ -315,7 +289,6 @@ bool m_initialised; - FeatureExtractor m_featureExtractor; DistanceMetric m_metric; friend class MatchFeeder;