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 @ 23:633ec097fa56

History | View | Annotate | Download (4.22 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
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
const double Agent::INNER_MARGIN = 0.040;
25
const double Agent::CONF_FACTOR = 0.5;
26
const double Agent::DEFAULT_CORRECTION_FACTOR = 50.0;
27

    
28
int Agent::idCounter = 0;
29

    
30
void Agent::accept(Event e, double err, int beats) {
31
    beatTime = e.time;
32
    events.push_back(e);
33
    if (fabs(initialBeatInterval - beatInterval -
34
             err / correctionFactor) < maxChange * initialBeatInterval)
35
        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
bool Agent::considerAsBeat(Event e, AgentList &a) {
55
    double err;
56
    if (beatTime < 0) {        // first event
57
#ifdef DEBUG_BEATROOT
58
        std::cerr << "Ag#" << idNumber << ": accepting first event trivially at " << e.time << std::endl;
59
#endif
60
        accept(e, 0, 1);
61
        return true;
62
    } else {                        // subsequent events
63
        EventList::iterator last = events.end();
64
        --last;
65
        if (e.time - last->time > expiryTime) {
66
#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
            phaseScore = -1.0;        // flag agent to be deleted
72
            return false;
73
        }
74
        double beats = nearbyint((e.time - beatTime) / beatInterval);
75
        err = e.time - beatTime - beats * beatInterval;
76
#ifdef DEBUG_BEATROOT
77
        std::cerr << "Ag#" << idNumber << ": time " << e.time << ", err " << err << " for beats " << beats << std::endl;
78
#endif
79
        if ((beats > 0) && (-preMargin <= err) && (err <= postMargin)) {
80
            if (fabs(err) > innerMargin) {
81
#ifdef DEBUG_BEATROOT
82
                std::cerr << "Ag#" << idNumber << ": creating another new agent" << std::endl;
83
#endif
84
                // Create new agent that skips this event (avoids
85
                // large phase jump)
86
                a.add(clone());
87
            }
88
            accept(e, err, (int)beats);
89
            return true;
90
        }
91
    }
92
    return false;
93
} // considerAsBeat()
94

    
95

    
96
void Agent::fillBeats(double start) {
97
    double prevBeat = 0, nextBeat, currentInterval, beats;
98
    EventList::iterator ei = events.begin();
99
    if (ei != events.end()) {
100
        EventList::iterator ni = ei;
101
        if (++ni != events.end()) {
102
            prevBeat = ni->time;
103
        }
104
    }
105
    while (ei != events.end()) {
106
        EventList::iterator ni = ei;
107
        if (ni == events.end() ||
108
            ++ni == events.end()) {
109
            break;
110
        }
111
        nextBeat = ni->time;
112
        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
            events.insert(ni, BeatTracker::newBeat(prevBeat, 0));
117
        }
118
        prevBeat = nextBeat;
119
        ei = ni;
120
    }
121
} // fillBeats()