cannam@0: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ cannam@0: cannam@0: /* cannam@0: Vamp feature extraction plugin using the MATCH audio alignment cannam@0: algorithm. cannam@0: cannam@0: Centre for Digital Music, Queen Mary, University of London. cannam@0: This file copyright 2007 Simon Dixon, Chris Cannam and QMUL. cannam@0: cannam@0: This program is free software; you can redistribute it and/or cannam@0: modify it under the terms of the GNU General Public License as cannam@0: published by the Free Software Foundation; either version 2 of the cannam@0: License, or (at your option) any later version. See the file cannam@0: COPYING included with this distribution for more information. cannam@0: */ cannam@0: cannam@0: #include "MatchFeeder.h" cannam@0: Chris@14: using std::vector; Chris@14: cannam@0: MatchFeeder::MatchFeeder(Matcher *m1, Matcher *m2) : cannam@0: pm1(m1), pm2(m2) cannam@0: { cannam@0: fftSize = m1->fftSize; cannam@0: finder = new Finder(m1, m2); cannam@0: reBuffer = new double[fftSize/2+1]; cannam@0: imBuffer = new double[fftSize/2+1]; cannam@0: } cannam@0: cannam@0: MatchFeeder::~MatchFeeder() cannam@0: { cannam@0: delete[] imBuffer; cannam@0: delete[] reBuffer; cannam@0: while (!q1.empty()) { cannam@0: delete[] q1.front(); cannam@0: q1.pop(); cannam@0: } cannam@0: while (!q2.empty()) { cannam@0: delete[] q2.front(); cannam@0: q2.pop(); cannam@0: } cannam@0: delete finder; cannam@0: } cannam@0: cannam@0: void cannam@0: MatchFeeder::feed(const float *const *input) cannam@0: { cannam@0: // We maintain two FIFO queues of audio data frame block pointers, cannam@0: // one per input stream. When the match-feeder function is cannam@0: // entered, it knows that it has at least one block in each queue. cannam@0: // It loops, processing up to one block per matcher, until a queue cannam@0: // is empty. Then it returns, to be called again with more data. cannam@0: Chris@14: prepare(input); Chris@14: Chris@14: while (!q1.empty() && !q2.empty()) { Chris@14: // std::cerr << "MatchFeeder::feed: q1 " << q1.size() << " q2 " << q2.size() << std::endl; Chris@14: (void)feedBlock(); Chris@14: } Chris@14: } Chris@14: Chris@14: MatchFeeder::Features Chris@14: MatchFeeder::feedAndGetFeatures(const float *const *input) Chris@14: { Chris@14: prepare(input); Chris@14: Chris@14: Features all; Chris@14: Chris@14: while (!q1.empty() && !q2.empty()) { Chris@14: Features ff = feedBlock(); Chris@14: all.f1.insert(all.f1.end(), ff.f1.begin(), ff.f1.end()); Chris@14: all.f2.insert(all.f2.end(), ff.f2.begin(), ff.f2.end()); Chris@14: } Chris@14: Chris@14: return all; Chris@14: } Chris@14: Chris@14: void Chris@14: MatchFeeder::prepare(const float *const *input) Chris@14: { cannam@0: float *block = new float[fftSize+2]; cannam@0: for (size_t i = 0; i < fftSize+2; ++i) { cannam@0: block[i] = input[0][i]; cannam@0: } cannam@0: q1.push(block); cannam@0: cannam@0: block = new float[fftSize+2]; cannam@0: for (size_t i = 0; i < fftSize+2; ++i) { cannam@0: block[i] = input[1][i]; cannam@0: } cannam@0: q2.push(block); cannam@0: } cannam@0: Chris@14: MatchFeeder::Features cannam@0: MatchFeeder::feedBlock() cannam@0: { Chris@14: Features ff; Chris@14: vector f1, f2; Chris@14: cannam@0: if (pm1->frameCount < pm1->blockSize) { // fill initial block cannam@0: // std::cerr << "feeding initial block" << std::endl; Chris@14: f1 = feed1(); Chris@14: f2 = feed2(); cannam@0: } cannam@0: //!!! } else if (pm1->atEnd) { cannam@0: // feed2(); cannam@0: //!!! } else if (pm2->atEnd) cannam@0: // feed1(); cannam@0: else if (pm1->runCount >= Matcher::MAX_RUN_COUNT) { // slope constraints cannam@0: // std::cerr << "pm1 too slopey" << std::endl; Chris@14: f2 = feed2(); cannam@0: } else if (pm2->runCount >= Matcher::MAX_RUN_COUNT) { cannam@0: // std::cerr << "pm2 too slopey" << std::endl; Chris@14: f1 = feed1(); cannam@0: } else { cannam@0: switch (finder->getExpandDirection cannam@0: (pm1->frameCount-1, pm2->frameCount-1)) { cannam@0: case ADVANCE_THIS: cannam@0: // std::cerr << "finder says ADVANCE_THIS" << std::endl; Chris@14: f1 = feed1(); cannam@0: break; cannam@0: case ADVANCE_OTHER: cannam@0: // std::cerr << "finder says ADVANCE_OTHER" << std::endl; Chris@14: f2 = feed2(); cannam@0: break; cannam@0: case ADVANCE_BOTH: cannam@0: // std::cerr << "finder says ADVANCE_BOTH" << std::endl; Chris@14: f1 = feed1(); Chris@14: f2 = feed2(); cannam@0: break; cannam@0: } cannam@0: } Chris@14: Chris@14: if (!f1.empty()) ff.f1.push_back(f1); Chris@14: if (!f2.empty()) ff.f2.push_back(f2); Chris@14: return ff; cannam@0: } cannam@0: Chris@14: vector cannam@0: MatchFeeder::feed1() cannam@0: { cannam@0: // std::cerr << "feed1" << std::endl; cannam@0: float *block = q1.front(); cannam@0: q1.pop(); cannam@0: for (size_t i = 0; i <= fftSize/2; ++i) { cannam@0: reBuffer[i] = block[i*2]; cannam@0: } cannam@0: for (size_t i = 0; i <= fftSize/2; ++i) { cannam@0: imBuffer[i] = block[i*2+1]; cannam@0: } cannam@0: delete[] block; Chris@14: return pm1->processFrame(reBuffer, imBuffer); cannam@0: } cannam@0: Chris@14: vector cannam@0: MatchFeeder::feed2() cannam@0: { cannam@0: // std::cerr << "feed2" << std::endl; cannam@0: float *block = q2.front(); cannam@0: q2.pop(); cannam@0: for (size_t i = 0; i <= fftSize/2; ++i) { cannam@0: reBuffer[i] = block[i*2]; cannam@0: } cannam@0: for (size_t i = 0; i <= fftSize/2; ++i) { cannam@0: imBuffer[i] = block[i*2+1]; cannam@0: } cannam@0: delete[] block; Chris@14: return pm2->processFrame(reBuffer, imBuffer); cannam@0: } cannam@0: