annotate Agent.cpp @ 37:1f175ae200a6 tip

Update RDF
author Chris Cannam
date Wed, 25 Jun 2014 13:48:49 +0100
parents 633ec097fa56
children
rev   line source
Chris@6 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@6 2
Chris@6 3 /*
Chris@6 4 Vamp feature extraction plugin for the BeatRoot beat tracker.
Chris@6 5
Chris@6 6 Centre for Digital Music, Queen Mary, University of London.
Chris@6 7 This file copyright 2011 Simon Dixon, Chris Cannam and QMUL.
Chris@6 8
Chris@6 9 This program is free software; you can redistribute it and/or
Chris@6 10 modify it under the terms of the GNU General Public License as
Chris@6 11 published by the Free Software Foundation; either version 2 of the
Chris@6 12 License, or (at your option) any later version. See the file
Chris@6 13 COPYING included with this distribution for more information.
Chris@6 14 */
Chris@6 15
Chris@6 16 #include "Agent.h"
Chris@6 17 #include "BeatTracker.h"
Chris@6 18
Chris@23 19 const double AgentParameters::DEFAULT_POST_MARGIN_FACTOR = 0.3;
Chris@23 20 const double AgentParameters::DEFAULT_PRE_MARGIN_FACTOR = 0.15;
Chris@23 21 const double AgentParameters::DEFAULT_MAX_CHANGE = 0.2;
Chris@23 22 const double AgentParameters::DEFAULT_EXPIRY_TIME = 10.0;
Chris@23 23
Chris@6 24 const double Agent::INNER_MARGIN = 0.040;
Chris@23 25 const double Agent::CONF_FACTOR = 0.5;
Chris@6 26 const double Agent::DEFAULT_CORRECTION_FACTOR = 50.0;
Chris@6 27
Chris@6 28 int Agent::idCounter = 0;
Chris@6 29
Chris@15 30 void Agent::accept(Event e, double err, int beats) {
Chris@15 31 beatTime = e.time;
Chris@15 32 events.push_back(e);
Chris@15 33 if (fabs(initialBeatInterval - beatInterval -
Chris@23 34 err / correctionFactor) < maxChange * initialBeatInterval)
Chris@15 35 beatInterval += err / correctionFactor;// Adjust tempo
Chris@15 36 beatCount += beats;
Chris@15 37 double conFactor = 1.0 - CONF_FACTOR * err /
Chris@15 38 (err>0? postMargin: -preMargin);
Chris@15 39 if (decayFactor > 0) {
Chris@15 40 double memFactor = 1. - 1. / threshold((double)beatCount,1,decayFactor);
Chris@15 41 phaseScore = memFactor * phaseScore +
Chris@15 42 (1.0 - memFactor) * conFactor * e.salience;
Chris@15 43 } else
Chris@15 44 phaseScore += conFactor * e.salience;
Chris@15 45
Chris@15 46 #ifdef DEBUG_BEATROOT
Chris@15 47 std::cerr << "Ag#" << idNumber << ": " << beatInterval << std::endl;
Chris@15 48 std::cerr << " Beat" << beatCount << " Time=" << beatTime
Chris@15 49 << " Score=" << tempoScore << ":P" << phaseScore << ":"
Chris@15 50 << topScoreTime << std::endl;
Chris@15 51 #endif
Chris@15 52 } // accept()
Chris@15 53
Chris@8 54 bool Agent::considerAsBeat(Event e, AgentList &a) {
Chris@6 55 double err;
Chris@6 56 if (beatTime < 0) { // first event
Chris@12 57 #ifdef DEBUG_BEATROOT
Chris@12 58 std::cerr << "Ag#" << idNumber << ": accepting first event trivially at " << e.time << std::endl;
Chris@12 59 #endif
Chris@6 60 accept(e, 0, 1);
Chris@6 61 return true;
Chris@6 62 } else { // subsequent events
Chris@9 63 EventList::iterator last = events.end();
Chris@9 64 --last;
Chris@9 65 if (e.time - last->time > expiryTime) {
Chris@12 66 #ifdef DEBUG_BEATROOT
Chris@12 67 std::cerr << "Ag#" << idNumber << ": time " << e.time
Chris@12 68 << " too late relative to " << last->time << " (expiry "
Chris@12 69 << expiryTime << "), giving up" << std::endl;
Chris@12 70 #endif
Chris@6 71 phaseScore = -1.0; // flag agent to be deleted
Chris@6 72 return false;
Chris@6 73 }
Chris@8 74 double beats = nearbyint((e.time - beatTime) / beatInterval);
Chris@8 75 err = e.time - beatTime - beats * beatInterval;
Chris@12 76 #ifdef DEBUG_BEATROOT
Chris@12 77 std::cerr << "Ag#" << idNumber << ": time " << e.time << ", err " << err << " for beats " << beats << std::endl;
Chris@12 78 #endif
Chris@6 79 if ((beats > 0) && (-preMargin <= err) && (err <= postMargin)) {
Chris@16 80 if (fabs(err) > innerMargin) {
Chris@12 81 #ifdef DEBUG_BEATROOT
Chris@12 82 std::cerr << "Ag#" << idNumber << ": creating another new agent" << std::endl;
Chris@12 83 #endif
Chris@16 84 // Create new agent that skips this event (avoids
Chris@16 85 // large phase jump)
Chris@16 86 a.add(clone());
Chris@12 87 }
Chris@6 88 accept(e, err, (int)beats);
Chris@6 89 return true;
Chris@6 90 }
Chris@6 91 }
Chris@6 92 return false;
Chris@6 93 } // considerAsBeat()
Chris@6 94
Chris@6 95
Chris@9 96 void Agent::fillBeats(double start) {
Chris@6 97 double prevBeat = 0, nextBeat, currentInterval, beats;
Chris@9 98 EventList::iterator ei = events.begin();
Chris@9 99 if (ei != events.end()) {
Chris@13 100 EventList::iterator ni = ei;
Chris@18 101 if (++ni != events.end()) {
Chris@18 102 prevBeat = ni->time;
Chris@18 103 }
Chris@6 104 }
Chris@16 105 while (ei != events.end()) {
Chris@13 106 EventList::iterator ni = ei;
Chris@18 107 if (ni == events.end() ||
Chris@18 108 ++ni == events.end()) {
Chris@18 109 break;
Chris@18 110 }
Chris@16 111 nextBeat = ni->time;
Chris@6 112 beats = nearbyint((nextBeat - prevBeat) / beatInterval - 0.01); //prefer slow
Chris@6 113 currentInterval = (nextBeat - prevBeat) / beats;
Chris@6 114 for ( ; (nextBeat > start) && (beats > 1.5); beats--) {
Chris@6 115 prevBeat += currentInterval;
Chris@13 116 events.insert(ni, BeatTracker::newBeat(prevBeat, 0));
Chris@6 117 }
Chris@6 118 prevBeat = nextBeat;
Chris@13 119 ei = ni;
Chris@6 120 }
Chris@6 121 } // fillBeats()