Chris@105: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ Chris@105: /* Chris@105: Vamp feature extraction plugin using the MATCH audio alignment Chris@105: algorithm. Chris@105: Chris@105: Centre for Digital Music, Queen Mary, University of London. Chris@236: Copyright (c) 2007-2020 Simon Dixon, Chris Cannam, and Queen Mary Chris@230: University of London, Copyright (c) 2014-2015 Tido GmbH. Chris@105: Chris@105: This program is free software; you can redistribute it and/or Chris@105: modify it under the terms of the GNU General Public License as Chris@105: published by the Free Software Foundation; either version 2 of the Chris@105: License, or (at your option) any later version. See the file Chris@105: COPYING included with this distribution for more information. Chris@105: */ Chris@105: Chris@105: #include "MatchPipeline.h" Chris@105: Chris@140: //#define DEBUG_MATCH_PIPELINE 1 Chris@140: Chris@105: MatchPipeline::MatchPipeline(FeatureExtractor::Parameters feParams, Chris@105: FeatureConditioner::Parameters fcParams, Chris@143: DistanceMetric::Parameters dParams, Chris@160: Matcher::Parameters matchParams, Chris@160: double secondReferenceFrequency) : Chris@105: m_fe1(feParams), Chris@166: m_fe2(paramsWithFreq(feParams, secondReferenceFrequency)), Chris@105: m_fc1(fcParams), Chris@105: m_fc2(fcParams), Chris@143: m_pm1(matchParams, dParams, 0), Chris@143: m_pm2(matchParams, dParams, &m_pm1), Chris@105: m_feeder(&m_pm1, &m_pm2), Chris@105: m_lastFrameIn1(0), Chris@105: m_lastFrameIn2(0), Chris@105: m_frameNo(0) Chris@105: { Chris@105: m_pm1.setOtherMatcher(&m_pm2); Chris@105: } Chris@105: Chris@105: MatchPipeline::~MatchPipeline() Chris@105: { Chris@105: } Chris@105: Chris@166: FeatureExtractor::Parameters Chris@166: MatchPipeline::paramsWithFreq(FeatureExtractor::Parameters params, double freq) Chris@166: { Chris@166: if (freq == 0.0) return params; Chris@166: params.referenceFrequency = freq; Chris@166: return params; Chris@166: } Chris@166: Chris@105: void Chris@105: MatchPipeline::feedFrequencyDomainAudio(const float *arr1, const float *arr2) Chris@105: { Chris@105: feedFeatures(m_fe1.process(arr1), m_fe2.process(arr2)); Chris@105: } Chris@105: Chris@105: void Chris@183: MatchPipeline::feedFeatures(const feature_t &f1, const feature_t &f2) Chris@105: { Chris@106: m_f1 = f1; Chris@106: m_f2 = f2; Chris@106: Chris@140: #ifdef DEBUG_MATCH_PIPELINE Chris@140: if (m_lastFrameIn1 == 1) { Chris@140: cerr << "features 1 -> "; Chris@200: for (int i = 0; i < int(m_f1.size()); ++i) { Chris@140: cerr << m_f1[i] << " "; Chris@140: } Chris@140: cerr << endl; Chris@140: } Chris@140: #endif Chris@140: Chris@105: feedConditionedFeatures(m_fc1.process(f1), m_fc2.process(f2)); Chris@105: } Chris@105: Chris@105: void Chris@183: MatchPipeline::feedConditionedFeatures(const feature_t &c1, const feature_t &c2) Chris@105: { Chris@106: m_c1 = c1; Chris@106: m_c2 = c2; Chris@140: Chris@140: #ifdef DEBUG_MATCH_PIPELINE Chris@140: if (m_lastFrameIn1 == 1) { Chris@140: cerr << "conditioned features 1 -> "; Chris@200: for (int i = 0; i < int(m_c1.size()); ++i) { Chris@140: cerr << m_c1[i] << " "; Chris@140: } Chris@140: cerr << endl; Chris@140: } Chris@140: #endif Chris@106: Chris@106: m_feeder.feed(c1, c2); Chris@105: Chris@237: if (isAboveEndingThreshold(c1)) m_lastFrameIn1 = m_frameNo; Chris@237: if (isAboveEndingThreshold(c2)) m_lastFrameIn2 = m_frameNo; Chris@105: Chris@140: #ifdef DEBUG_MATCH_PIPELINE Chris@140: cerr << "last frames are " << m_lastFrameIn1 << ", " << m_lastFrameIn2 Chris@140: << endl; Chris@140: #endif Chris@140: Chris@105: ++m_frameNo; Chris@105: } Chris@105: Chris@106: void Chris@183: MatchPipeline::extractFeatures(feature_t &f1, feature_t &f2) Chris@106: { Chris@106: f1 = m_f1; Chris@106: f2 = m_f2; Chris@106: } Chris@106: Chris@106: void Chris@183: MatchPipeline::extractConditionedFeatures(feature_t &c1, feature_t &c2) Chris@106: { Chris@106: c1 = m_c1; Chris@106: c2 = m_c2; Chris@106: } Chris@106: Chris@105: bool Chris@237: MatchPipeline::isAboveEndingThreshold(const feature_t &f) Chris@105: { Chris@105: double threshold = 1e-4f; Chris@105: double sum = 0.f; Chris@105: for (int i = 0; i < int(f.size()); ++i) { Chris@105: sum += f[i] * f[i]; Chris@105: } Chris@140: #ifdef DEBUG_MATCH_PIPELINE Chris@237: cerr << "isAboveEndingThreshold: sum " << sum Chris@237: << ", threshold " << threshold Chris@140: << ", returning " << (sum >= threshold) << endl; Chris@140: #endif Chris@105: return (sum >= threshold); Chris@105: } Chris@105: Chris@105: void Chris@105: MatchPipeline::finish() Chris@105: { Chris@105: m_feeder.finish(); Chris@200: m_feeder.getFinder()->setDurations(m_lastFrameIn1 + 1, m_lastFrameIn2 + 1); Chris@105: } Chris@105: Chris@155: int Chris@155: MatchPipeline::retrievePath(bool smooth, std::vector &pathx, std::vector &pathy) Chris@135: { Chris@155: return m_feeder.getFinder()->retrievePath(smooth, pathx, pathy); Chris@135: } Chris@135: Chris@155: void Chris@155: MatchPipeline::retrieveForwardPath(std::vector &pathx, std::vector &pathy) { Chris@155: return m_feeder.retrieveForwardPath(pathx, pathy); Chris@105: } Chris@105: Chris@173: double Chris@173: MatchPipeline::getOverallCost() Chris@173: { Chris@173: return m_feeder.getFinder()->getOverallCost(); Chris@173: } Chris@105: