annotate AgentList.cpp @ 16:33d0b18b2509

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