annotate Agent.h @ 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@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 #ifndef _AGENT_H_
Chris@6 17 #define _AGENT_H_
Chris@6 18
Chris@6 19 #include "Event.h"
Chris@6 20
Chris@9 21 #include <cmath>
Chris@9 22
Chris@12 23 #ifdef DEBUG_BEATROOT
Chris@12 24 #include <iostream>
Chris@12 25 #endif
Chris@12 26
Chris@8 27 class AgentList;
Chris@8 28
Chris@6 29 /** Agent is the central class for beat tracking.
Chris@6 30 * Each Agent object has a tempo hypothesis, a history of tracked beats, and
Chris@6 31 * a score evaluating the continuity, regularity and salience of its beat track.
Chris@6 32 */
Chris@6 33 class Agent
Chris@6 34 {
Chris@6 35 public:
Chris@6 36 /** The maximum amount by which a beat can be later than the predicted beat time,
Chris@6 37 * expressed as a fraction of the beat period. */
Chris@6 38 static double POST_MARGIN_FACTOR;
Chris@6 39
Chris@6 40 /** The maximum amount by which a beat can be earlier than the predicted beat time,
Chris@6 41 * expressed as a fraction of the beat period. */
Chris@6 42 static double PRE_MARGIN_FACTOR;
Chris@6 43
Chris@6 44 /** The default value of innerMargin, which is the maximum time (in seconds) that a
Chris@6 45 * beat can deviate from the predicted beat time without a fork occurring. */
Chris@6 46 static const double INNER_MARGIN;
Chris@6 47
Chris@6 48 /** The maximum allowed deviation from the initial tempo, expressed as a fraction of the initial beat period. */
Chris@6 49 static double MAX_CHANGE;
Chris@6 50
Chris@6 51 /** The slope of the penalty function for onsets which do not coincide precisely with predicted beat times. */
Chris@6 52 static double CONF_FACTOR;
Chris@6 53
Chris@6 54 /** The reactiveness/inertia balance, i.e. degree of change in the tempo, is controlled by the correctionFactor
Chris@6 55 * variable. This constant defines its default value, which currently is not subsequently changed. The
Chris@6 56 * beat period is updated by the reciprocal of the correctionFactor multiplied by the difference between the
Chris@6 57 * predicted beat time and matching onset. */
Chris@6 58 static const double DEFAULT_CORRECTION_FACTOR;
Chris@6 59
Chris@6 60 /** The default value of expiryTime, which is the time (in seconds) after which an Agent that
Chris@6 61 * has no Event matching its beat predictions will be destroyed. */
Chris@6 62 static const double DEFAULT_EXPIRY_TIME;
Chris@6 63
Chris@6 64 protected:
Chris@6 65 /** The identity number of the next created Agent */
Chris@6 66 static int idCounter;
Chris@6 67
Chris@6 68 /** The maximum time (in seconds) that a beat can deviate from the predicted beat time
Chris@6 69 * without a fork occurring (i.e. a 2nd Agent being created). */
Chris@6 70 static double innerMargin;
Chris@6 71
Chris@6 72 /** Controls the reactiveness/inertia balance, i.e. degree of change in the tempo. The
Chris@6 73 * beat period is updated by the reciprocal of the correctionFactor multiplied by the difference between the
Chris@6 74 * predicted beat time and matching onset. */
Chris@6 75 static double correctionFactor;
Chris@6 76
Chris@6 77 /** The time (in seconds) after which an Agent that
Chris@6 78 * has no Event matching its beat predictions will be destroyed. */
Chris@6 79 static double expiryTime;
Chris@6 80
Chris@6 81 /** For scoring Agents in a (non-existent) real-time version (otherwise not used). */
Chris@6 82 static double decayFactor;
Chris@6 83
Chris@6 84 public:
Chris@6 85 /** The size of the outer half-window before the predicted beat time. */
Chris@6 86 double preMargin;
Chris@6 87
Chris@6 88 /** The size of the outer half-window after the predicted beat time. */
Chris@6 89 double postMargin;
Chris@6 90
Chris@6 91 /** The Agent's unique identity number. */
Chris@6 92 int idNumber;
Chris@6 93
Chris@6 94 /** To be used in real-time version?? */
Chris@6 95 double tempoScore;
Chris@6 96
Chris@6 97 /** Sum of salience values of the Events which have been interpreted
Chris@6 98 * as beats by this Agent, weighted by their nearness to the predicted beat times. */
Chris@6 99 double phaseScore;
Chris@6 100
Chris@6 101 /** How long has this agent been the best? For real-time version; otherwise not used. */
Chris@6 102 double topScoreTime;
Chris@6 103
Chris@6 104 /** The number of beats found by this Agent, including interpolated beats. */
Chris@6 105 int beatCount;
Chris@6 106
Chris@6 107 /** The current tempo hypothesis of the Agent, expressed as the beat period in seconds. */
Chris@6 108 double beatInterval;
Chris@6 109
Chris@6 110 /** The initial tempo hypothesis of the Agent, expressed as the beat period in seconds. */
Chris@6 111 double initialBeatInterval;
Chris@6 112
Chris@6 113 /** The time of the most recent beat accepted by this Agent. */
Chris@6 114 double beatTime;
Chris@6 115
Chris@6 116 /** The list of Events (onsets) accepted by this Agent as beats, plus interpolated beats. */
Chris@6 117 EventList events;
Chris@6 118
Chris@6 119 /** Constructor: the work is performed by init()
Chris@6 120 * @param ibi The beat period (inter-beat interval) of the Agent's tempo hypothesis.
Chris@6 121 */
Chris@6 122 Agent(double ibi) {
Chris@6 123 innerMargin = INNER_MARGIN;
Chris@6 124 correctionFactor = DEFAULT_CORRECTION_FACTOR;
Chris@6 125 expiryTime = DEFAULT_EXPIRY_TIME;
Chris@6 126 decayFactor = 0;
Chris@6 127 beatInterval = ibi;
Chris@6 128 initialBeatInterval = ibi;
Chris@6 129 postMargin = ibi * POST_MARGIN_FACTOR;
Chris@6 130 preMargin = ibi * PRE_MARGIN_FACTOR;
Chris@6 131 idNumber = idCounter++;
Chris@6 132 phaseScore = 0.0;
Chris@6 133 tempoScore = 0.0;
Chris@6 134 topScoreTime = 0.0;
Chris@6 135 beatCount = 0;
Chris@6 136 beatTime = -1.0;
Chris@12 137 } // constructor
Chris@6 138
Chris@16 139 Agent *clone() const {
Chris@16 140 Agent *a = new Agent(*this);
Chris@16 141 a->idNumber = idCounter++;
Chris@12 142 return a;
Chris@12 143 }
Chris@6 144
Chris@12 145 protected:
Chris@6 146 double threshold(double value, double min, double max) {
Chris@6 147 if (value < min)
Chris@6 148 return min;
Chris@6 149 if (value > max)
Chris@6 150 return max;
Chris@6 151 return value;
Chris@6 152 }
Chris@6 153
Chris@8 154 public:
Chris@6 155 /** Accept a new Event as a beat time, and update the state of the Agent accordingly.
Chris@6 156 * @param e The Event which is accepted as being on the beat.
Chris@6 157 * @param err The difference between the predicted and actual beat times.
Chris@6 158 * @param beats The number of beats since the last beat that matched an Event.
Chris@6 159 */
Chris@15 160 void accept(Event e, double err, int beats);
Chris@6 161
Chris@6 162 /** The given Event is tested for a possible beat time. The following situations can occur:
Chris@6 163 * 1) The Agent has no beats yet; the Event is accepted as the first beat.
Chris@6 164 * 2) The Event is beyond expiryTime seconds after the Agent's last 'confirming' beat; the Agent is terminated.
Chris@6 165 * 3) The Event is within the innerMargin of the beat prediction; it is accepted as a beat.
Chris@9 166 * 4) The Event is within the postMargin's of the beat prediction; it is accepted as a beat by this Agent,
Chris@6 167 * and a new Agent is created which doesn't accept it as a beat.
Chris@6 168 * 5) The Event is ignored because it is outside the windows around the Agent's predicted beat time.
Chris@6 169 * @param e The Event to be tested
Chris@6 170 * @param a The list of all agents, which is updated if a new agent is created.
Chris@6 171 * @return Indicate whether the given Event was accepted as a beat by this Agent.
Chris@6 172 */
Chris@8 173 bool considerAsBeat(Event e, AgentList &a);
Chris@6 174
Chris@6 175 /** Interpolates missing beats in the Agent's beat track, starting from the beginning of the piece. */
Chris@6 176 void fillBeats() {
Chris@6 177 fillBeats(-1.0);
Chris@6 178 } // fillBeats()/0
Chris@6 179
Chris@6 180 /** Interpolates missing beats in the Agent's beat track.
Chris@6 181 * @param start Ignore beats earlier than this start time
Chris@6 182 */
Chris@6 183 void fillBeats(double start);
Chris@6 184
Chris@8 185 // for sorting AgentList
Chris@8 186 bool operator<(const Agent &a) const {
Chris@8 187 return beatInterval < a.beatInterval;
Chris@8 188 }
Chris@8 189
Chris@6 190 }; // class Agent
Chris@6 191
Chris@6 192 #endif