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 @ 18:55969570044e

History | View | Annotate | Download (4.26 KB)

1
/* -*- 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
double Agent::POST_MARGIN_FACTOR = 0.3;
20
double Agent::PRE_MARGIN_FACTOR = 0.15;
21
const double Agent::INNER_MARGIN = 0.040;
22
double Agent::MAX_CHANGE = 0.2;
23
double Agent::CONF_FACTOR = 0.5;
24
const double Agent::DEFAULT_CORRECTION_FACTOR = 50.0;
25
const double Agent::DEFAULT_EXPIRY_TIME = 10.0;
26

    
27
int Agent::idCounter = 0;
28

    
29
double Agent::innerMargin = 0.0;
30
double Agent::correctionFactor = 0.0;
31
double Agent::expiryTime = 0.0;
32
double Agent::decayFactor = 0.0;
33

    
34
void Agent::accept(Event e, double err, int beats) {
35
    beatTime = e.time;
36
    events.push_back(e);
37
    if (fabs(initialBeatInterval - beatInterval -
38
             err / correctionFactor) < MAX_CHANGE * initialBeatInterval)
39
        beatInterval += err / correctionFactor;// Adjust tempo
40
    beatCount += beats;
41
    double conFactor = 1.0 - CONF_FACTOR * err /
42
        (err>0? postMargin: -preMargin);
43
    if (decayFactor > 0) {
44
        double memFactor = 1. - 1. / threshold((double)beatCount,1,decayFactor);
45
        phaseScore = memFactor * phaseScore +
46
            (1.0 - memFactor) * conFactor * e.salience;
47
    } else
48
        phaseScore += conFactor * e.salience;
49

    
50
#ifdef DEBUG_BEATROOT
51
    std::cerr << "Ag#" << idNumber << ": " << beatInterval << std::endl;
52
    std::cerr << "  Beat" << beatCount << "  Time=" << beatTime
53
              << "  Score=" << tempoScore << ":P" << phaseScore << ":"
54
              << topScoreTime << std::endl;
55
#endif
56
} // accept()
57

    
58
bool Agent::considerAsBeat(Event e, AgentList &a) {
59
    double err;
60
    if (beatTime < 0) {        // first event
61
#ifdef DEBUG_BEATROOT
62
        std::cerr << "Ag#" << idNumber << ": accepting first event trivially at " << e.time << std::endl;
63
#endif
64
        accept(e, 0, 1);
65
        return true;
66
    } else {                        // subsequent events
67
        EventList::iterator last = events.end();
68
        --last;
69
        if (e.time - last->time > expiryTime) {
70
#ifdef DEBUG_BEATROOT
71
            std::cerr << "Ag#" << idNumber << ": time " << e.time 
72
                      << " too late relative to " << last->time << " (expiry "
73
                      << expiryTime << "), giving up" << std::endl;
74
#endif
75
            phaseScore = -1.0;        // flag agent to be deleted
76
            return false;
77
        }
78
        double beats = nearbyint((e.time - beatTime) / beatInterval);
79
        err = e.time - beatTime - beats * beatInterval;
80
#ifdef DEBUG_BEATROOT
81
        std::cerr << "Ag#" << idNumber << ": time " << e.time << ", err " << err << " for beats " << beats << std::endl;
82
#endif
83
        if ((beats > 0) && (-preMargin <= err) && (err <= postMargin)) {
84
            if (fabs(err) > innerMargin) {
85
#ifdef DEBUG_BEATROOT
86
                std::cerr << "Ag#" << idNumber << ": creating another new agent" << std::endl;
87
#endif
88
                // Create new agent that skips this event (avoids
89
                // large phase jump)
90
                a.add(clone());
91
            }
92
            accept(e, err, (int)beats);
93
            return true;
94
        }
95
    }
96
    return false;
97
} // considerAsBeat()
98

    
99

    
100
void Agent::fillBeats(double start) {
101
    double prevBeat = 0, nextBeat, currentInterval, beats;
102
    EventList::iterator ei = events.begin();
103
    if (ei != events.end()) {
104
        EventList::iterator ni = ei;
105
        if (++ni != events.end()) {
106
            prevBeat = ni->time;
107
        }
108
    }
109
    while (ei != events.end()) {
110
        EventList::iterator ni = ei;
111
        if (ni == events.end() ||
112
            ++ni == events.end()) {
113
            break;
114
        }
115
        nextBeat = ni->time;
116
        beats = nearbyint((nextBeat - prevBeat) / beatInterval - 0.01); //prefer slow
117
        currentInterval = (nextBeat - prevBeat) / beats;
118
        for ( ; (nextBeat > start) && (beats > 1.5); beats--) {
119
            prevBeat += currentInterval;
120
            events.insert(ni, BeatTracker::newBeat(prevBeat, 0));
121
        }
122
        prevBeat = nextBeat;
123
        ei = ni;
124
    }
125
} // fillBeats()