To check out this repository please hg clone the following URL, or open the URL using EasyMercurial or your preferred Mercurial client.

Statistics Download as Zip
| Branch: | Tag: | Revision:

root / Agent.cpp

History | View | Annotate | Download (4.22 KB)

1 6:02d388f98c23 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 "Agent.h"
17
#include "BeatTracker.h"
18
19 23:633ec097fa56 Chris
const double AgentParameters::DEFAULT_POST_MARGIN_FACTOR = 0.3;
20
const double AgentParameters::DEFAULT_PRE_MARGIN_FACTOR = 0.15;
21
const double AgentParameters::DEFAULT_MAX_CHANGE = 0.2;
22
const double AgentParameters::DEFAULT_EXPIRY_TIME = 10.0;
23
24 6:02d388f98c23 Chris
const double Agent::INNER_MARGIN = 0.040;
25 23:633ec097fa56 Chris
const double Agent::CONF_FACTOR = 0.5;
26 6:02d388f98c23 Chris
const double Agent::DEFAULT_CORRECTION_FACTOR = 50.0;
27
28
int Agent::idCounter = 0;
29
30 15:887c629502a9 Chris
void Agent::accept(Event e, double err, int beats) {
31
    beatTime = e.time;
32
    events.push_back(e);
33
    if (fabs(initialBeatInterval - beatInterval -
34 23:633ec097fa56 Chris
             err / correctionFactor) < maxChange * initialBeatInterval)
35 15:887c629502a9 Chris
        beatInterval += err / correctionFactor;// Adjust tempo
36
    beatCount += beats;
37
    double conFactor = 1.0 - CONF_FACTOR * err /
38
        (err>0? postMargin: -preMargin);
39
    if (decayFactor > 0) {
40
        double memFactor = 1. - 1. / threshold((double)beatCount,1,decayFactor);
41
        phaseScore = memFactor * phaseScore +
42
            (1.0 - memFactor) * conFactor * e.salience;
43
    } else
44
        phaseScore += conFactor * e.salience;
45
46
#ifdef DEBUG_BEATROOT
47
    std::cerr << "Ag#" << idNumber << ": " << beatInterval << std::endl;
48
    std::cerr << "  Beat" << beatCount << "  Time=" << beatTime
49
              << "  Score=" << tempoScore << ":P" << phaseScore << ":"
50
              << topScoreTime << std::endl;
51
#endif
52
} // accept()
53
54 8:f04f87b5e643 Chris
bool Agent::considerAsBeat(Event e, AgentList &a) {
55 6:02d388f98c23 Chris
    double err;
56
    if (beatTime < 0) {        // first event
57 12:59520cd6abac Chris
#ifdef DEBUG_BEATROOT
58
        std::cerr << "Ag#" << idNumber << ": accepting first event trivially at " << e.time << std::endl;
59
#endif
60 6:02d388f98c23 Chris
        accept(e, 0, 1);
61
        return true;
62
    } else {                        // subsequent events
63 9:4f6626f9ffac Chris
        EventList::iterator last = events.end();
64
        --last;
65
        if (e.time - last->time > expiryTime) {
66 12:59520cd6abac Chris
#ifdef DEBUG_BEATROOT
67
            std::cerr << "Ag#" << idNumber << ": time " << e.time
68
                      << " too late relative to " << last->time << " (expiry "
69
                      << expiryTime << "), giving up" << std::endl;
70
#endif
71 6:02d388f98c23 Chris
            phaseScore = -1.0;        // flag agent to be deleted
72
            return false;
73
        }
74 8:f04f87b5e643 Chris
        double beats = nearbyint((e.time - beatTime) / beatInterval);
75
        err = e.time - beatTime - beats * beatInterval;
76 12:59520cd6abac Chris
#ifdef DEBUG_BEATROOT
77
        std::cerr << "Ag#" << idNumber << ": time " << e.time << ", err " << err << " for beats " << beats << std::endl;
78
#endif
79 6:02d388f98c23 Chris
        if ((beats > 0) && (-preMargin <= err) && (err <= postMargin)) {
80 16:33d0b18b2509 Chris
            if (fabs(err) > innerMargin) {
81 12:59520cd6abac Chris
#ifdef DEBUG_BEATROOT
82
                std::cerr << "Ag#" << idNumber << ": creating another new agent" << std::endl;
83
#endif
84 16:33d0b18b2509 Chris
                // Create new agent that skips this event (avoids
85
                // large phase jump)
86
                a.add(clone());
87 12:59520cd6abac Chris
            }
88 6:02d388f98c23 Chris
            accept(e, err, (int)beats);
89
            return true;
90
        }
91
    }
92
    return false;
93
} // considerAsBeat()
94
95
96 9:4f6626f9ffac Chris
void Agent::fillBeats(double start) {
97 6:02d388f98c23 Chris
    double prevBeat = 0, nextBeat, currentInterval, beats;
98 9:4f6626f9ffac Chris
    EventList::iterator ei = events.begin();
99
    if (ei != events.end()) {
100 13:0d4048bfadbb Chris
        EventList::iterator ni = ei;
101 18:55969570044e Chris
        if (++ni != events.end()) {
102
            prevBeat = ni->time;
103
        }
104 6:02d388f98c23 Chris
    }
105 16:33d0b18b2509 Chris
    while (ei != events.end()) {
106 13:0d4048bfadbb Chris
        EventList::iterator ni = ei;
107 18:55969570044e Chris
        if (ni == events.end() ||
108
            ++ni == events.end()) {
109
            break;
110
        }
111 16:33d0b18b2509 Chris
        nextBeat = ni->time;
112 6:02d388f98c23 Chris
        beats = nearbyint((nextBeat - prevBeat) / beatInterval - 0.01); //prefer slow
113
        currentInterval = (nextBeat - prevBeat) / beats;
114
        for ( ; (nextBeat > start) && (beats > 1.5); beats--) {
115
            prevBeat += currentInterval;
116 13:0d4048bfadbb Chris
            events.insert(ni, BeatTracker::newBeat(prevBeat, 0));
117 6:02d388f98c23 Chris
        }
118
        prevBeat = nextBeat;
119 13:0d4048bfadbb Chris
        ei = ni;
120 6:02d388f98c23 Chris
    }
121
} // fillBeats()