To check out this repository please hg clone the following URL, or open the URL using EasyMercurial or your preferred Mercurial client.
root / AgentList.cpp
History | View | Annotate | Download (5.38 KB)
| 1 | 8:f04f87b5e643 | Chris | /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
|---|---|---|---|
| 2 | |||
| 3 | /*
|
||
| 4 | Vamp feature extraction plugin for the BeatRoot beat tracker.
|
||
| 5 | |||
| 6 | Centre for Digital Music, Queen Mary, University of London.
|
||
| 7 | This file copyright 2011 Simon Dixon, Chris Cannam and QMUL.
|
||
| 8 | |||
| 9 | This program is free software; you can redistribute it and/or
|
||
| 10 | modify it under the terms of the GNU General Public License as
|
||
| 11 | published by the Free Software Foundation; either version 2 of the
|
||
| 12 | License, or (at your option) any later version. See the file
|
||
| 13 | COPYING included with this distribution for more information.
|
||
| 14 | */
|
||
| 15 | |||
| 16 | #include "AgentList.h" |
||
| 17 | |||
| 18 | bool AgentList::useAverageSalience = false; |
||
| 19 | const double AgentList::DEFAULT_BI = 0.02; |
||
| 20 | const double AgentList::DEFAULT_BT = 0.04; |
||
| 21 | |||
| 22 | 15:887c629502a9 | Chris | void AgentList::removeDuplicates()
|
| 23 | {
|
||
| 24 | sort(); |
||
| 25 | for (iterator itr = begin(); itr != end(); ++itr) {
|
||
| 26 | 22:6afcb5edd7ab | Chris | #ifdef DEBUG_BEATROOT
|
| 27 | std::cerr << "removeDuplicates: considering agent " << (*itr)->idNumber << std::endl;
|
||
| 28 | #endif
|
||
| 29 | 16:33d0b18b2509 | Chris | if ((*itr)->phaseScore < 0.0) // already flagged for deletion |
| 30 | 15:887c629502a9 | Chris | continue;
|
| 31 | iterator itr2 = itr; |
||
| 32 | for (++itr2; itr2 != end(); ++itr2) {
|
||
| 33 | 16:33d0b18b2509 | Chris | if ((*itr2)->beatInterval - (*itr)->beatInterval > DEFAULT_BI)
|
| 34 | 15:887c629502a9 | Chris | break;
|
| 35 | 16:33d0b18b2509 | Chris | if (fabs((*itr)->beatTime - (*itr2)->beatTime) > DEFAULT_BT)
|
| 36 | 15:887c629502a9 | Chris | continue;
|
| 37 | 16:33d0b18b2509 | Chris | if ((*itr)->phaseScore < (*itr2)->phaseScore) {
|
| 38 | 22:6afcb5edd7ab | Chris | #ifdef DEBUG_BEATROOT
|
| 39 | std::cerr << "agent " << (*itr)->idNumber << " is similar to but lower-scoring than agent " << (*itr2)->idNumber << ", marking for deletion" << std::endl; |
||
| 40 | #endif
|
||
| 41 | 16:33d0b18b2509 | Chris | (*itr)->phaseScore = -1.0; // flag for deletion |
| 42 | if ((*itr2)->topScoreTime < (*itr)->topScoreTime)
|
||
| 43 | (*itr2)->topScoreTime = (*itr)->topScoreTime; |
||
| 44 | 15:887c629502a9 | Chris | break;
|
| 45 | } else {
|
||
| 46 | 22:6afcb5edd7ab | Chris | #ifdef DEBUG_BEATROOT
|
| 47 | std::cerr << "agent " << (*itr2)->idNumber << " is similar to but lower-scoring than agent " << (*itr)->idNumber << ", marking for deletion" << std::endl; |
||
| 48 | #endif
|
||
| 49 | 16:33d0b18b2509 | Chris | (*itr2)->phaseScore = -1.0; // flag for deletion |
| 50 | if ((*itr)->topScoreTime < (*itr2)->topScoreTime)
|
||
| 51 | (*itr)->topScoreTime = (*itr2)->topScoreTime; |
||
| 52 | 15:887c629502a9 | Chris | } |
| 53 | } |
||
| 54 | } |
||
| 55 | int removed = 0; |
||
| 56 | for (iterator itr = begin(); itr != end(); ) {
|
||
| 57 | 16:33d0b18b2509 | Chris | if ((*itr)->phaseScore < 0.0) { |
| 58 | 15:887c629502a9 | Chris | ++removed; |
| 59 | 16:33d0b18b2509 | Chris | delete *itr;
|
| 60 | 15:887c629502a9 | Chris | list.erase(itr); |
| 61 | } else {
|
||
| 62 | ++itr; |
||
| 63 | } |
||
| 64 | } |
||
| 65 | #ifdef DEBUG_BEATROOT
|
||
| 66 | if (removed > 0) { |
||
| 67 | std::cerr << "removeDuplicates: removed " << removed << ", have " |
||
| 68 | << list.size() << " agent(s) remaining" << std::endl;
|
||
| 69 | } |
||
| 70 | int n = 0; |
||
| 71 | for (Container::iterator i = list.begin(); i != list.end(); ++i) {
|
||
| 72 | 16:33d0b18b2509 | Chris | std::cerr << "agent " << n++ << ": time " << (*i)->beatTime << std::endl; |
| 73 | 15:887c629502a9 | Chris | } |
| 74 | #endif
|
||
| 75 | } // removeDuplicates()
|
||
| 76 | |||
| 77 | |||
| 78 | 23:633ec097fa56 | Chris | void AgentList::beatTrack(EventList el, AgentParameters params, double stop) |
| 79 | 15:887c629502a9 | Chris | {
|
| 80 | EventList::iterator ei = el.begin(); |
||
| 81 | 16:33d0b18b2509 | Chris | bool phaseGiven = !empty() && ((*begin())->beatTime >= 0); // if given for one, assume given for others |
| 82 | 15:887c629502a9 | Chris | while (ei != el.end()) {
|
| 83 | Event ev = *ei; |
||
| 84 | ++ei; |
||
| 85 | if ((stop > 0) && (ev.time > stop)) |
||
| 86 | break;
|
||
| 87 | bool created = phaseGiven;
|
||
| 88 | double prevBeatInterval = -1.0; |
||
| 89 | // cc: Duplicate our list of agents, and scan through the
|
||
| 90 | // copy. This means we can safely add agents to our own
|
||
| 91 | // list while scanning without disrupting our scan. Each
|
||
| 92 | // agent needs to be re-added to our own list explicitly
|
||
| 93 | // (since it is modified by e.g. considerAsBeat)
|
||
| 94 | Container currentAgents = list; |
||
| 95 | list.clear(); |
||
| 96 | for (Container::iterator ai = currentAgents.begin();
|
||
| 97 | ai != currentAgents.end(); ++ai) {
|
||
| 98 | 16:33d0b18b2509 | Chris | Agent *currentAgent = *ai; |
| 99 | if (currentAgent->beatInterval != prevBeatInterval) {
|
||
| 100 | 15:887c629502a9 | Chris | if ((prevBeatInterval>=0) && !created && (ev.time<5.0)) { |
| 101 | #ifdef DEBUG_BEATROOT
|
||
| 102 | std::cerr << "Creating a new agent" << std::endl;
|
||
| 103 | #endif
|
||
| 104 | // Create new agent with different phase
|
||
| 105 | 23:633ec097fa56 | Chris | Agent *newAgent = new Agent(params, prevBeatInterval);
|
| 106 | 15:887c629502a9 | Chris | // This may add another agent to our list as well
|
| 107 | 16:33d0b18b2509 | Chris | newAgent->considerAsBeat(ev, *this);
|
| 108 | 15:887c629502a9 | Chris | add(newAgent); |
| 109 | } |
||
| 110 | 16:33d0b18b2509 | Chris | prevBeatInterval = currentAgent->beatInterval; |
| 111 | 15:887c629502a9 | Chris | created = phaseGiven; |
| 112 | } |
||
| 113 | 16:33d0b18b2509 | Chris | if (currentAgent->considerAsBeat(ev, *this)) |
| 114 | 15:887c629502a9 | Chris | created = true;
|
| 115 | add(currentAgent); |
||
| 116 | } // loop for each agent
|
||
| 117 | removeDuplicates(); |
||
| 118 | } // loop for each event
|
||
| 119 | } // beatTrack()
|
||
| 120 | |||
| 121 | Agent *AgentList::bestAgent() |
||
| 122 | {
|
||
| 123 | double best = -1.0; |
||
| 124 | Agent *bestAg = 0;
|
||
| 125 | for (iterator itr = begin(); itr != end(); ++itr) {
|
||
| 126 | 16:33d0b18b2509 | Chris | if ((*itr)->events.empty()) continue; |
| 127 | double conf = ((*itr)->phaseScore + (*itr)->tempoScore) /
|
||
| 128 | (useAverageSalience? (double)(*itr)->beatCount: 1.0); |
||
| 129 | 15:887c629502a9 | Chris | if (conf > best) {
|
| 130 | 16:33d0b18b2509 | Chris | bestAg = *itr; |
| 131 | 15:887c629502a9 | Chris | best = conf; |
| 132 | } |
||
| 133 | } |
||
| 134 | #ifdef DEBUG_BEATROOT
|
||
| 135 | if (bestAg) {
|
||
| 136 | std::cerr << "Best agent: Ag#" << bestAg->idNumber << std::endl;
|
||
| 137 | std::cerr << " Av-salience = " << best << std::endl;
|
||
| 138 | } else {
|
||
| 139 | std::cerr << "No surviving agent - beat tracking failed" << std::endl;
|
||
| 140 | } |
||
| 141 | #endif
|
||
| 142 | return bestAg;
|
||
| 143 | } // bestAgent()
|