Revision 0:886f11e41417

View differences:

.hgtags
1
3a5840de4d5fae540d5f8302dd56a548fe21bb02 mirex2013
2
296404fd93c74f1ef065d74ffeb1b7d6d6ad166d v1.0
3
296404fd93c74f1ef065d74ffeb1b7d6d6ad166d v1.0
4
8d3716a5d7e775006ed13199c0d6890ca54ab4a8 v1.0
Agent.cpp
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()
Agent.h
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
#ifndef _AGENT_H_
17
#define _AGENT_H_
18

  
19
#include "Event.h"
20

  
21
#include <cmath>
22

  
23
#ifdef DEBUG_BEATROOT
24
#include <iostream>
25
#endif
26

  
27
class AgentList;
28

  
29
class AgentParameters
30
{
31
public:
32
    static const double DEFAULT_POST_MARGIN_FACTOR;
33
    static const double DEFAULT_PRE_MARGIN_FACTOR;
34
    static const double DEFAULT_MAX_CHANGE;
35
    static const double DEFAULT_EXPIRY_TIME;
36

  
37
    AgentParameters() :
38
        postMarginFactor(DEFAULT_POST_MARGIN_FACTOR),
39
        preMarginFactor(DEFAULT_PRE_MARGIN_FACTOR),
40
        maxChange(DEFAULT_MAX_CHANGE),
41
        expiryTime(DEFAULT_EXPIRY_TIME) { }
42

  
43
    /** The maximum amount by which a beat can be later than the
44
     *  predicted beat time, expressed as a fraction of the beat
45
     *  period. */
46
    double postMarginFactor;
47

  
48
    /** The maximum amount by which a beat can be earlier than the
49
     *  predicted beat time, expressed as a fraction of the beat
50
     *  period. */
51
    double preMarginFactor;
52

  
53
    /** The maximum allowed deviation from the initial tempo,
54
     * expressed as a fraction of the initial beat period. */
55
    double maxChange;
56

  
57
    /** The default value of expiryTime, which is the time (in
58
     *  seconds) after which an Agent that has no Event matching its
59
     *  beat predictions will be destroyed. */
60
    double expiryTime;
61
};
62

  
63
/** Agent is the central class for beat tracking.
64
 *  Each Agent object has a tempo hypothesis, a history of tracked beats, and
65
 *  a score evaluating the continuity, regularity and salience of its beat track.
66
 */
67
class Agent
68
{
69
public:
70
    /** The default value of innerMargin, which is the maximum time
71
     * 	(in seconds) that a beat can deviate from the predicted beat
72
     * 	time without a fork occurring. */
73
    static const double INNER_MARGIN;
74
	
75
    /** The slope of the penalty function for onsets which do not
76
     * coincide precisely with predicted beat times. */
77
    static const double CONF_FACTOR;
78
	
79
    /** The reactiveness/inertia balance, i.e. degree of change in the
80
     *  tempo, is controlled by the correctionFactor variable.  This
81
     *  constant defines its default value, which currently is not
82
     *  subsequently changed. The beat period is updated by the
83
     *  reciprocal of the correctionFactor multiplied by the
84
     *  difference between the predicted beat time and matching
85
     *  onset. */
86
    static const double DEFAULT_CORRECTION_FACTOR;
87
	
88
protected:
89
    /** The identity number of the next created Agent */
90
    static int idCounter;
91
	
92
    /** The maximum time (in seconds) that a beat can deviate from the
93
     *  predicted beat time without a fork occurring (i.e. a 2nd Agent
94
     *  being created). */
95
    double innerMargin;
96

  
97
    /** Controls the reactiveness/inertia balance, i.e. degree of
98
     *  change in the tempo.  The beat period is updated by the
99
     *  reciprocal of the correctionFactor multiplied by the
100
     *  difference between the predicted beat time and matching
101
     *  onset. */
102
    double correctionFactor;
103

  
104
    /** The time (in seconds) after which an Agent that has no Event
105
     *  matching its beat predictions will be destroyed. */
106
    double expiryTime;
107
	
108
    /** For scoring Agents in a (non-existent) real-time version
109
     * (otherwise not used). */
110
    double decayFactor;
111

  
112
public:
113
    /** The size of the outer half-window before the predicted beat time. */
114
    double preMargin;
115

  
116
    /** The size of the outer half-window after the predicted beat time. */
117
    double postMargin;
118
	
119
    /** The Agent's unique identity number. */
120
    int idNumber;
121
	
122
    /** To be used in real-time version?? */
123
    double tempoScore;
124
	
125
    /** Sum of salience values of the Events which have been
126
     *  interpreted as beats by this Agent, weighted by their nearness
127
     *  to the predicted beat times. */
128
    double phaseScore;
129
	
130
    /** How long has this agent been the best?  For real-time version;
131
     * otherwise not used. */
132
    double topScoreTime;
133
	
134
    /** The number of beats found by this Agent, including
135
     * interpolated beats. */
136
    int beatCount;
137
	
138
    /** The current tempo hypothesis of the Agent, expressed as the
139
     * beat period in seconds. */
140
    double beatInterval;
141

  
142
    /** The initial tempo hypothesis of the Agent, expressed as the
143
     * beat period in seconds. */
144
    double initialBeatInterval;
145
	
146
    /** The time of the most recent beat accepted by this Agent. */
147
    double beatTime;
148

  
149
    /** The maximum allowed deviation from the initial tempo,
150
     * expressed as a fraction of the initial beat period. */
151
    double maxChange;
152
	
153
    /** The list of Events (onsets) accepted by this Agent as beats,
154
     * plus interpolated beats. */
155
    EventList events;
156

  
157
    /** Constructor: the work is performed by init()
158
     *  @param ibi The beat period (inter-beat interval) of the Agent's tempo hypothesis.
159
     */
160
    Agent(AgentParameters params, double ibi) :
161
	innerMargin(INNER_MARGIN),
162
	correctionFactor(DEFAULT_CORRECTION_FACTOR),
163
	expiryTime(params.expiryTime),
164
	decayFactor(0),
165
	preMargin(ibi * params.preMarginFactor),
166
	postMargin(ibi * params.postMarginFactor),
167
	idNumber(idCounter++),
168
	tempoScore(0.0),
169
	phaseScore(0.0),
170
	topScoreTime(0.0),
171
	beatCount(0),
172
	beatInterval(ibi),
173
	initialBeatInterval(ibi),
174
	beatTime(-1.0),
175
        maxChange(params.maxChange) {
176
    } // constructor
177

  
178
    Agent *clone() const {
179
        Agent *a = new Agent(*this);
180
        a->idNumber = idCounter++;
181
        return a;
182
    }
183

  
184
protected:
185
    double threshold(double value, double min, double max) {
186
	if (value < min)
187
	    return min;
188
	if (value > max)
189
	    return max;
190
	return value;
191
    }
192

  
193
public:
194
    /** Accept a new Event as a beat time, and update the state of the Agent accordingly.
195
     *  @param e The Event which is accepted as being on the beat.
196
     *  @param err The difference between the predicted and actual beat times.
197
     *  @param beats The number of beats since the last beat that matched an Event.
198
     */
199
    void accept(Event e, double err, int beats);
200

  
201
    /** The given Event is tested for a possible beat time. The following situations can occur:
202
     *  1) The Agent has no beats yet; the Event is accepted as the first beat.
203
     *  2) The Event is beyond expiryTime seconds after the Agent's last 'confirming' beat; the Agent is terminated.
204
     *  3) The Event is within the innerMargin of the beat prediction; it is accepted as a beat.
205
     *  4) The Event is within the postMargin's of the beat prediction; it is accepted as a beat by this Agent,
206
     *     and a new Agent is created which doesn't accept it as a beat.
207
     *  5) The Event is ignored because it is outside the windows around the Agent's predicted beat time.
208
     * @param e The Event to be tested
209
     * @param a The list of all agents, which is updated if a new agent is created.
210
     * @return Indicate whether the given Event was accepted as a beat by this Agent.
211
     */
212
    bool considerAsBeat(Event e, AgentList &a);
213

  
214
    /** Interpolates missing beats in the Agent's beat track, starting from the beginning of the piece. */
215
    void fillBeats() {
216
	fillBeats(-1.0);
217
    } // fillBeats()/0
218

  
219
    /** Interpolates missing beats in the Agent's beat track.
220
     *  @param start Ignore beats earlier than this start time 
221
     */
222
    void fillBeats(double start);
223

  
224
}; // class Agent
225

  
226
#endif
AgentList.cpp
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 "AgentList.h"
17

  
18
bool AgentList::useAverageSalience = false;
19
const double AgentList::DEFAULT_BI = 0.02;
20
const double AgentList::DEFAULT_BT = 0.04;
21

  
22
void AgentList::removeDuplicates() 
23
{
24
    sort();
25
    for (iterator itr = begin(); itr != end(); ++itr) {
26
#ifdef DEBUG_BEATROOT
27
        std::cerr << "removeDuplicates: considering agent " << (*itr)->idNumber << std::endl;
28
#endif
29
        if ((*itr)->phaseScore < 0.0) // already flagged for deletion
30
            continue;
31
        iterator itr2 = itr;
32
        for (++itr2; itr2 != end(); ++itr2) {
33
            if ((*itr2)->beatInterval - (*itr)->beatInterval > DEFAULT_BI)
34
                break;
35
            if (fabs((*itr)->beatTime - (*itr2)->beatTime) > DEFAULT_BT)
36
                continue;
37
            if ((*itr)->phaseScore < (*itr2)->phaseScore) {
38
#ifdef DEBUG_BEATROOT
39
                std::cerr << "agent " << (*itr)->idNumber << " is similar to but lower-scoring than agent " << (*itr2)->idNumber << ", marking for deletion" << std::endl;
40
#endif
41
                (*itr)->phaseScore = -1.0;	// flag for deletion
42
                if ((*itr2)->topScoreTime < (*itr)->topScoreTime)
43
                    (*itr2)->topScoreTime = (*itr)->topScoreTime;
44
                break;
45
            } else {
46
#ifdef DEBUG_BEATROOT
47
                std::cerr << "agent " << (*itr2)->idNumber << " is similar to but lower-scoring than agent " << (*itr)->idNumber << ", marking for deletion" << std::endl;
48
#endif
49
                (*itr2)->phaseScore = -1.0;	// flag for deletion
50
                if ((*itr)->topScoreTime < (*itr2)->topScoreTime)
51
                    (*itr)->topScoreTime = (*itr2)->topScoreTime;
52
            }
53
        }
54
    }
55
    int removed = 0;
56
    for (iterator itr = begin(); itr != end(); ) {
57
        if ((*itr)->phaseScore < 0.0) {
58
            ++removed;
59
            delete *itr;
60
            list.erase(itr);
61
        } else {
62
            ++itr;
63
        }
64
    }
65
#ifdef DEBUG_BEATROOT
66
    if (removed > 0) {
67
        std::cerr << "removeDuplicates: removed " << removed << ", have "
68
                  << list.size() << " agent(s) remaining" << std::endl;
69
    }
70
    int n = 0;
71
    for (Container::iterator i = list.begin(); i != list.end(); ++i) {
72
        std::cerr << "agent " << n++ << ": time " << (*i)->beatTime << std::endl;
73
    }
74
#endif
75
} // removeDuplicates()
76

  
77

  
78
void AgentList::beatTrack(EventList el, AgentParameters params, double stop)
79
{
80
    EventList::iterator ei = el.begin();
81
    bool phaseGiven = !empty() && ((*begin())->beatTime >= 0); // if given for one, assume given for others
82
    while (ei != el.end()) {
83
        Event ev = *ei;
84
        ++ei;
85
        if ((stop > 0) && (ev.time > stop))
86
            break;
87
        bool created = phaseGiven;
88
        double prevBeatInterval = -1.0;
89
        // cc: Duplicate our list of agents, and scan through the
90
        // copy.  This means we can safely add agents to our own
91
        // list while scanning without disrupting our scan.  Each
92
        // agent needs to be re-added to our own list explicitly
93
        // (since it is modified by e.g. considerAsBeat)
94
        Container currentAgents = list;
95
        list.clear();
96
        for (Container::iterator ai = currentAgents.begin();
97
             ai != currentAgents.end(); ++ai) {
98
            Agent *currentAgent = *ai;
99
            if (currentAgent->beatInterval != prevBeatInterval) {
100
                if ((prevBeatInterval>=0) && !created && (ev.time<5.0)) {
101
#ifdef DEBUG_BEATROOT
102
                    std::cerr << "Creating a new agent" << std::endl;
103
#endif
104
                    // Create new agent with different phase
105
                    Agent *newAgent = new Agent(params, prevBeatInterval);
106
                    // This may add another agent to our list as well
107
                    newAgent->considerAsBeat(ev, *this);
108
                    add(newAgent);
109
                }
110
                prevBeatInterval = currentAgent->beatInterval;
111
                created = phaseGiven;
112
            }
113
            if (currentAgent->considerAsBeat(ev, *this))
114
                created = true;
115
            add(currentAgent);
116
        } // loop for each agent
117
        removeDuplicates();
118
    } // loop for each event
119
} // beatTrack()
120

  
121
Agent *AgentList::bestAgent()
122
{
123
    double best = -1.0;
124
    Agent *bestAg = 0;
125
    for (iterator itr = begin(); itr != end(); ++itr) {
126
        if ((*itr)->events.empty()) continue;
127
        double conf = ((*itr)->phaseScore + (*itr)->tempoScore) /
128
            (useAverageSalience? (double)(*itr)->beatCount: 1.0);
129
        if (conf > best) {
130
            bestAg = *itr;
131
            best = conf;
132
        }
133
    }
134
#ifdef DEBUG_BEATROOT
135
    if (bestAg) {
136
        std::cerr << "Best agent: Ag#" << bestAg->idNumber << std::endl;
137
        std::cerr << "  Av-salience = " << best << std::endl;
138
    } else {
139
        std::cerr << "No surviving agent - beat tracking failed" << std::endl;
140
    }
141
#endif
142
    return bestAg;
143
} // bestAgent()
144

  
AgentList.h
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
#ifndef _AGENT_LIST_H_
17
#define _AGENT_LIST_H_
18

  
19
#include "Agent.h"
20
#include "Event.h"
21

  
22
#include <vector>
23
#include <algorithm>
24

  
25
#ifdef DEBUG_BEATROOT
26
#include <iostream>
27
#endif
28

  
29
/** Class for maintaining the set of all Agents involved in beat tracking a piece of music.
30
 */
31
class AgentList
32
{
33
public:
34
    typedef std::vector<Agent *> Container;
35
    typedef Container::iterator iterator;
36

  
37
protected:
38
    Container list;
39

  
40
    static bool agentComparator(const Agent *a, const Agent *b) {
41
        if (a->beatInterval == b->beatInterval) {
42
            return a->idNumber < b->idNumber; // ensure stable ordering
43
        } else {
44
            return a->beatInterval < b->beatInterval;
45
        }
46
    }
47

  
48
public:
49
    // expose some vector methods
50
    //!!! can we remove these again once the rest of AgentList is implemented?
51
    bool empty() const { return list.empty(); }
52
    Container::iterator begin() { return list.begin(); }
53
    Container::iterator end() { return list.end(); }
54
    size_t size() { return list.size(); }
55
    void push_back(Agent *a) {
56
        list.push_back(a);
57
#ifdef DEBUG_BEATROOT
58
        std::cerr << "  Added Ag#" << a->idNumber << ", have " << list.size() << " agent(s)" << std::endl;
59
#endif
60
    }
61

  
62
    /** Flag for choice between sum and average beat salience values for Agent scores.
63
     *  The use of summed saliences favours faster tempi or lower metrical levels. */
64
    static bool useAverageSalience;
65
	
66
    /** For the purpose of removing duplicate agents, the default JND of IBI */
67
    static const double DEFAULT_BI;
68
	
69
    /** For the purpose of removing duplicate agents, the default JND of phase */
70
    static const double DEFAULT_BT;
71

  
72
    /** Inserts newAgent into the list in ascending order of beatInterval */
73
    void add(Agent *a) {
74
	add(a, true);
75
    } // add()/1
76

  
77
    /** Appends newAgent to list (sort==false), or inserts newAgent into the list
78
     *  in ascending order of beatInterval
79
     *  @param newAgent The agent to be added to the list
80
     *  @param sort Flag indicating whether the list is sorted or not
81
     */
82
    void add(Agent *newAgent, bool sort){
83
        push_back(newAgent);
84
	if (sort) this->sort();
85
    } // add()/2
86

  
87
    /** Sorts the AgentList by increasing beatInterval. */
88
    void sort() {
89
#ifdef DEBUG_BEATROOT
90
        std::cerr << "sort: before: ";
91
        for (iterator i = list.begin(); i != list.end(); ++i) {
92
            std::cerr << (*i)->idNumber << " ";
93
        }
94
        std::cerr << std::endl;
95
#endif
96
	std::sort(list.begin(), list.end(), agentComparator);
97
#ifdef DEBUG_BEATROOT
98
        std::cerr << "sort: after: ";
99
        for (iterator i = list.begin(); i != list.end(); ++i) {
100
            std::cerr << (*i)->idNumber << " ";
101
        }
102
        std::cerr << std::endl;
103
#endif
104
    } // sort()
105

  
106
    /** Removes the given item from the list.
107
     *  @param ptr Points to the Agent which is removed from the list
108
     */
109
    void remove(iterator itr) {
110
	list.erase(itr);
111
    } // remove()
112

  
113
protected:
114
    /** Removes Agents from the list which are duplicates of other Agents.
115
     *  A duplicate is defined by the tempo and phase thresholds
116
     *  thresholdBI and thresholdBT respectively.
117
     */
118
    void removeDuplicates();
119

  
120
public:
121
    /** Perform beat tracking on a list of events (onsets).
122
     *  @param el The list of onsets (or events or peaks) to beat track
123
     */
124
    void beatTrack(EventList el, AgentParameters params) {
125
	beatTrack(el, params, -1.0);
126
    } // beatTrack()/1
127
	
128
    /** Perform beat tracking on a list of events (onsets).
129
     *  @param el The list of onsets (or events or peaks) to beat track.
130
     *  @param stop Do not find beats after <code>stop</code> seconds.
131
     */
132
    void beatTrack(EventList el, AgentParameters params, double stop);
133

  
134
    /** Finds the Agent with the highest score in the list, or NULL if beat tracking has failed.
135
     *  @return The Agent with the highest score
136
     */
137
    Agent *bestAgent();
138

  
139
}; // class AgentList
140

  
141
#endif
142

  
BeatRootProcessor.cpp
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 "BeatRootProcessor.h"
17

  
18
bool
19
BeatRootProcessor::silent = true;
20

  
21
void BeatRootProcessor::processFrame(const float *const *inputBuffers) {
22
    double flux = 0;
23
    for (int i = 0; i <= fftSize/2; i++) {
24
        double mag = sqrt(inputBuffers[0][i*2] * inputBuffers[0][i*2] +
25
                          inputBuffers[0][i*2+1] * inputBuffers[0][i*2+1]);
26
        if (mag > prevFrame[i]) flux += mag - prevFrame[i];
27
        prevFrame[i] = mag;
28
    }
29
    
30
    spectralFlux.push_back(flux);
31
    
32
} // processFrame()
33

  
34
EventList BeatRootProcessor::beatTrack(EventList *unfilledReturn) {
35

  
36
#ifdef DEBUG_BEATROOT
37
    std::cerr << "Spectral flux:" << std::endl;
38
    for (int i = 0; i < spectralFlux.size(); ++i) {
39
        if ((i % 8) == 0) std::cerr << "\n";
40
        std::cerr << spectralFlux[i] << " ";
41
    }
42
#endif
43
		
44
    double hop = hopTime;
45
    Peaks::normalise(spectralFlux);
46
    vector<int> peaks = Peaks::findPeaks(spectralFlux, (int)lrint(0.06 / hop), 0.35, 0.84, true);
47
    onsets.clear();
48
    onsets.resize(peaks.size(), 0);
49
    vector<int>::iterator it = peaks.begin();
50
    onsetList.clear();
51
    double minSalience = Peaks::min(spectralFlux);
52
    for (int i = 0; i < (int)onsets.size(); i++) {
53
        int index = *it;
54
        ++it;
55
        onsets[i] = index * hop;
56
        Event e = BeatTracker::newBeat(onsets[i], 0);
57
//			if (debug)
58
//				System.err.printf("Onset: %8.3f  %8.3f  %8.3f\n",
59
//						onsets[i], energy[index], slope[index]);
60
//			e.salience = slope[index];	// or combination of energy + slope??
61
        // Note that salience must be non-negative or the beat tracking system fails!
62
        e.salience = spectralFlux[index] - minSalience;
63
        onsetList.push_back(e);
64
    }
65

  
66
#ifdef DEBUG_BEATROOT
67
    std::cerr << "Onsets: " << onsetList.size() << std::endl;
68
#endif
69

  
70
    return BeatTracker::beatTrack(agentParameters, onsetList, unfilledReturn);
71

  
72
} // processFile()
73

  
BeatRootProcessor.h
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
#ifndef _BEATROOT_PROCESSOR_H_
17
#define _BEATROOT_PROCESSOR_H_
18

  
19
#include "Peaks.h"
20
#include "Event.h"
21
#include "BeatTracker.h"
22

  
23
#include <vector>
24
#include <cmath>
25

  
26
#ifdef DEBUG_BEATROOT
27
#include <iostream>
28
#endif
29

  
30
using std::vector;
31

  
32
class BeatRootProcessor
33
{
34
public:
35
    int getFFTSize() const { return fftSize; }
36
    int getHopSize() const { return hopSize; }
37

  
38
protected:
39
    /** Sample rate of audio */
40
    float sampleRate;
41
	
42
    /** Spacing of audio frames (determines the amount of overlap or
43
     *  skip between frames). This value is expressed in
44
     *  seconds. (Default = 0.020s) */
45
    double hopTime;
46

  
47
    /** The approximate size of an FFT frame in seconds. (Default =
48
     *  0.04644s).  The value is adjusted so that <code>fftSize</code>
49
     *  is always power of 2. */
50
    double fftTime;
51

  
52
    /** Spacing of audio frames in samples (see <code>hopTime</code>) */
53
    int hopSize;
54

  
55
    /** The size of an FFT frame in samples (see <code>fftTime</code>) */
56
    int fftSize;
57

  
58
    /** Spectral flux onset detection function, indexed by frame. */
59
    vector<double> spectralFlux;
60
	
61
    /** A mapping function for mapping FFT bins to final frequency bins.
62
     *  The mapping is linear (1-1) until the resolution reaches 2 points per
63
     *  semitone, then logarithmic with a semitone resolution.  e.g. for
64
     *  44.1kHz sampling rate and fftSize of 2048 (46ms), bin spacing is
65
     *  21.5Hz, which is mapped linearly for bins 0-34 (0 to 732Hz), and
66
     *  logarithmically for the remaining bins (midi notes 79 to 127, bins 35 to
67
     *  83), where all energy above note 127 is mapped into the final bin. */
68
    vector<int> freqMap;
69

  
70
    /** The number of entries in <code>freqMap</code>. Note that the length of
71
     *  the array is greater, because its size is not known at creation time. */
72
    int freqMapSize;
73

  
74
    /** The magnitude spectrum of the most recent frame.  Used for
75
     *  calculating the spectral flux. */
76
    vector<double> prevFrame;
77

  
78
    /** The estimated onset times from peak-picking the onset
79
     * detection function(s). */
80
    vector<double> onsets;
81
	
82
    /** The estimated onset times and their saliences. */	
83
    EventList onsetList;
84
    
85
    /** User-specifiable processing parameters. */
86
    AgentParameters agentParameters;
87
	
88
    /** Flag for suppressing all standard output messages except results. */
89
    static bool silent;
90
	
91
public:
92

  
93
    /** Constructor: note that streams are not opened until the input
94
     *  file is set (see <code>setInputFile()</code>). */
95
    BeatRootProcessor(float sr, AgentParameters parameters) :
96
        sampleRate(sr),
97
        hopTime(0.010),
98
        fftTime(0.04644),
99
        hopSize(0),
100
        fftSize(0),
101
        agentParameters(parameters)
102
    {
103
        hopSize = lrint(sampleRate * hopTime);
104
        fftSize = lrint(pow(2, lrint( log(fftTime * sampleRate) / log(2))));
105
        init();
106
    } // constructor
107

  
108
    void reset() {
109
        init();
110
    }
111

  
112
    /** Processes a frame of frequency-domain audio data by mapping
113
     *  the frequency bins into a part-linear part-logarithmic array,
114
     *  then computing the spectral flux then (optionally) normalising
115
     *  and calculating onsets.
116
     */
117
    void processFrame(const float *const *inputBuffers);
118

  
119
    /** Tracks beats once all frames have been processed by processFrame
120
     */
121
    EventList beatTrack(EventList *optionalUnfilledBeatReturn);
122

  
123
protected:
124
    /** Allocates or re-allocates memory for arrays, based on parameter settings */
125
    void init() {
126
#ifdef DEBUG_BEATROOT
127
        std::cerr << "BeatRootProcessor::init()" << std::endl;
128
#endif
129
        makeFreqMap(fftSize, sampleRate);
130
        prevFrame.clear();
131
        for (int i = 0; i <= fftSize/2; i++) prevFrame.push_back(0);
132
        spectralFlux.clear();
133
        onsets.clear();
134
        onsetList.clear();
135
    } // init()
136

  
137
    /** Creates a map of FFT frequency bins to comparison bins.
138
     *  Where the spacing of FFT bins is less than 0.5 semitones, the mapping is
139
     *  one to one. Where the spacing is greater than 0.5 semitones, the FFT
140
     *  energy is mapped into semitone-wide bins. No scaling is performed; that
141
     *  is the energy is summed into the comparison bins. See also
142
     *  processFrame()
143
     */
144
    void makeFreqMap(int fftSize, float sampleRate) {
145
        freqMap.resize(fftSize/2+1);
146
        double binWidth = sampleRate / fftSize;
147
        int crossoverBin = (int)(2 / (pow(2, 1/12.0) - 1));
148
        int crossoverMidi = (int)lrint(log(crossoverBin*binWidth/440)/
149
                                       log(2) * 12 + 69);
150
        int i = 0;
151
        while (i <= crossoverBin && i <= fftSize/2) {
152
            freqMap[i] = i;
153
            ++i;
154
        }
155
        while (i <= fftSize/2) {
156
            double midi = log(i*binWidth/440) / log(2) * 12 + 69;
157
            if (midi > 127)
158
                midi = 127;
159
            freqMap[i] = crossoverBin + (int)lrint(midi) - crossoverMidi;
160
            ++i;
161
        }
162
        freqMapSize = freqMap[i-1] + 1;
163
    } // makeFreqMap()
164

  
165
}; // class AudioProcessor
166

  
167

  
168
#endif
BeatRootVampPlugin.cpp
14 14
*/
15 15

  
16 16
#include "BeatRootVampPlugin.h"
17
#include "BeatRootProcessor.h"
18 17

  
19
#include "Event.h"
20

  
21
#include <vamp-sdk/RealTime.h>
22
#include <vamp-sdk/PluginAdapter.h>
23 18

  
24 19
BeatRootVampPlugin::BeatRootVampPlugin(float inputSampleRate) :
25
    Plugin(inputSampleRate),
26
    m_firstFrame(true)
20
    Plugin(inputSampleRate)
27 21
{
28
    m_processor = new BeatRootProcessor(inputSampleRate, AgentParameters());
22
    m_processor = new BeatRootProcessor(inputSampleRate);
29 23
}
30 24

  
31 25
BeatRootVampPlugin::~BeatRootVampPlugin()
......
105 99
BeatRootVampPlugin::getParameterDescriptors() const
106 100
{
107 101
    ParameterList list;
108

  
109
    ParameterDescriptor desc;
110

  
111
    desc.identifier = "preMarginFactor";
112
    desc.name = "Pre-Margin Factor";
113
    desc.description = "The maximum amount by which a beat can be earlier than the predicted beat time, expressed as a fraction of the beat period.";
114
    desc.minValue = 0;
115
    desc.maxValue = 1;
116
    desc.defaultValue = AgentParameters::DEFAULT_PRE_MARGIN_FACTOR;
117
    desc.isQuantized = false;
118
    list.push_back(desc);
119
    
120
    desc.identifier = "postMarginFactor";
121
    desc.name = "Post-Margin Factor";
122
    desc.description = "The maximum amount by which a beat can be later than the predicted beat time, expressed as a fraction of the beat period.";
123
    desc.minValue = 0;
124
    desc.maxValue = 1;
125
    desc.defaultValue = AgentParameters::DEFAULT_POST_MARGIN_FACTOR;
126
    desc.isQuantized = false;
127
    list.push_back(desc);
128
    
129
    desc.identifier = "maxChange";
130
    desc.name = "Maximum Change";
131
    desc.description = "The maximum allowed deviation from the initial tempo, expressed as a fraction of the initial beat period.";
132
    desc.minValue = 0;
133
    desc.maxValue = 1;
134
    desc.defaultValue = AgentParameters::DEFAULT_MAX_CHANGE;
135
    desc.isQuantized = false;
136
    list.push_back(desc);
137
    
138
    desc.identifier = "expiryTime";
139
    desc.name = "Expiry Time";
140
    desc.description = "The default value of expiryTime, which is the time (in seconds) after which an Agent that has no Event matching its beat predictions will be destroyed.";
141
    desc.minValue = 2;
142
    desc.maxValue = 120;
143
    desc.defaultValue = AgentParameters::DEFAULT_EXPIRY_TIME;
144
    desc.isQuantized = false;
145
    list.push_back(desc);
146

  
147
    // Simon says...
148

  
149
    // These are the parameters that should be exposed (Agent.cpp):
150

  
151
    // If Pop, both margins should be lower (0.1).  If classical
152
    // music, post margin can be increased
153
    //
154
    // double Agent::POST_MARGIN_FACTOR = 0.3;
155
    // double Agent::PRE_MARGIN_FACTOR = 0.15;
156
    //
157
    // Max Change tells us how much tempo can change - so for
158
    // classical we should make it higher
159
    // 
160
    // double Agent::MAX_CHANGE = 0.2;
161
    // 
162
    // The EXPIRY TIME default should be defaulted to 100 (usual cause
163
    // of agents dying....)  it should also be exposed in order to
164
    // troubleshoot eventual problems in songs with big silences in
165
    // the beggining/end.
166
    // 
167
    // const double Agent::DEFAULT_EXPIRY_TIME = 10.0;
168

  
169 102
    return list;
170 103
}
171 104

  
172 105
float
173 106
BeatRootVampPlugin::getParameter(string identifier) const
174 107
{
175
    if (identifier == "preMarginFactor") {
176
        return m_parameters.preMarginFactor;
177
    } else if (identifier == "postMarginFactor") {
178
        return m_parameters.postMarginFactor;
179
    } else if (identifier == "maxChange") {
180
        return m_parameters.maxChange;
181
    } else if (identifier == "expiryTime") {
182
        return m_parameters.expiryTime;
183
    }
184
    
185 108
    return 0;
186 109
}
187 110

  
188 111
void
189 112
BeatRootVampPlugin::setParameter(string identifier, float value) 
190 113
{
191
    if (identifier == "preMarginFactor") {
192
        m_parameters.preMarginFactor = value;
193
    } else if (identifier == "postMarginFactor") {
194
        m_parameters.postMarginFactor = value;
195
    } else if (identifier == "maxChange") {
196
        m_parameters.maxChange = value;
197
    } else if (identifier == "expiryTime") {
198
        m_parameters.expiryTime = value;
199
    }
200 114
}
201 115

  
202 116
BeatRootVampPlugin::ProgramList
......
235 149
    d.hasKnownExtents = false;
236 150
    d.isQuantized = false;
237 151
    d.sampleType = OutputDescriptor::VariableSampleRate;
238
    d.sampleRate = m_inputSampleRate;
239 152
    d.hasDuration = false;
240 153
    list.push_back(d);
241 154

  
242
    d.identifier = "unfilled";
243
    d.name = "Un-interpolated beats";
244
    d.description = "Locations of detected beats, before agent interpolation occurs";
245
    list.push_back(d);
246

  
247 155
    return list;
248 156
}
249 157

  
......
273 181
	return false;
274 182
    }
275 183

  
276
    // Delete the processor that was created with default parameters
277
    // and used to determine the expected step and block size; replace
278
    // with one using the actual parameters we have
279
    delete m_processor;
280
    m_processor = new BeatRootProcessor(m_inputSampleRate, m_parameters);
184
    m_processor->initialise();
281 185

  
282 186
    return true;
283 187
}
......
286 190
BeatRootVampPlugin::reset()
287 191
{
288 192
    m_processor->reset();
289
    m_firstFrame = true;
290
    m_origin = Vamp::RealTime::zeroTime;
291 193
}
292 194

  
293 195
BeatRootVampPlugin::FeatureSet
294 196
BeatRootVampPlugin::process(const float *const *inputBuffers, Vamp::RealTime timestamp)
295 197
{
296
    if (m_firstFrame) {
297
        m_origin = timestamp;
298
        m_firstFrame = false;
299
    }
300

  
301
    m_processor->processFrame(inputBuffers);
198
    // Do actual work!
302 199
    return FeatureSet();
303 200
}
304 201

  
305 202
BeatRootVampPlugin::FeatureSet
306 203
BeatRootVampPlugin::getRemainingFeatures()
307 204
{
308
    EventList unfilled;
309
    EventList el = m_processor->beatTrack(&unfilled);
310

  
311
    Feature f;
312
    f.hasTimestamp = true;
313
    f.hasDuration = false;
314
    f.label = "";
315
    f.values.clear();
316

  
317
    FeatureSet fs;
318

  
319
    for (EventList::const_iterator i = el.begin(); i != el.end(); ++i) {
320
        f.timestamp = m_origin + Vamp::RealTime::fromSeconds(i->time);
321
        fs[0].push_back(f);
322
    }
323

  
324
    for (EventList::const_iterator i = unfilled.begin(); 
325
         i != unfilled.end(); ++i) {
326
        f.timestamp = m_origin + Vamp::RealTime::fromSeconds(i->time);
327
        fs[1].push_back(f);
328
    }
329

  
330
    return fs;
205
    return FeatureSet();
331 206
}
332 207

  
333 208

  
BeatRootVampPlugin.h
16 16
#ifndef _BEATROOT_VAMP_PLUGIN_H_
17 17
#define _BEATROOT_VAMP_PLUGIN_H_
18 18

  
19
#include "Agent.h"
20

  
21 19
#include <vamp-sdk/Plugin.h>
22 20

  
23 21
using std::string;
24 22

  
25
class BeatRootProcessor;
26

  
27 23
class BeatRootVampPlugin : public Vamp::Plugin
28 24
{
29 25
public:
......
63 59

  
64 60
protected:
65 61
    BeatRootProcessor *m_processor;
66
    AgentParameters m_parameters;
67
    Vamp::RealTime m_origin;
68
    bool m_firstFrame;
69 62
};
70 63

  
71 64

  
BeatTracker.cpp
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 "BeatTracker.h"
17

  
18
EventList BeatTracker::beatTrack(AgentParameters params,
19
                                 EventList events, EventList beats,
20
                                 EventList *unfilledReturn)
21
{
22
    AgentList agents;
23
    int count = 0;
24
    double beatTime = -1;
25
    if (!beats.empty()) {
26
	count = beats.size() - 1;
27
	EventList::iterator itr = beats.end();
28
	--itr;
29
	beatTime = itr->time;
30
    }
31
    if (count > 0) { // tempo given by mean of initial beats
32
	double ioi = (beatTime - beats.begin()->time) / count;
33
	agents.push_back(new Agent(params, ioi));
34
    } else // tempo not given; use tempo induction
35
	agents = Induction::beatInduction(params, events);
36
    if (!beats.empty())
37
	for (AgentList::iterator itr = agents.begin(); itr != agents.end();
38
	     ++itr) {
39
	    (*itr)->beatTime = beatTime;
40
	    (*itr)->beatCount = count;
41
	    (*itr)->events = beats;
42
	}
43
    agents.beatTrack(events, params, -1);
44
    Agent *best = agents.bestAgent();
45
    EventList results;
46
    if (best) {
47
        if (unfilledReturn) *unfilledReturn = best->events;
48
	best->fillBeats(beatTime);
49
	results = best->events;
50
    }
51
    for (AgentList::iterator ai = agents.begin(); ai != agents.end(); ++ai) {
52
	delete *ai;
53
    }
54
    return results;
55
} // beatTrack()/1
56
	
57

  
BeatTracker.h
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
#ifndef _BEAT_TRACKER_H_
17
#define _BEAT_TRACKER_H_
18

  
19
#include "Event.h"
20
#include "Agent.h"
21
#include "AgentList.h"
22
#include "Induction.h"
23

  
24
using std::vector;
25

  
26
class BeatTracker
27
{
28
protected:
29
    /** beat data encoded as a list of Events */
30
    EventList beats;
31
	
32
    /** a list of onset events for passing to the tempo induction and beat tracking methods */
33
    EventList onsetList;
34
	
35
    /** the times of onsets (in seconds) */
36
    vector<double> onsets;
37

  
38
public:
39
    /** Constructor:
40
     *  @param b The list of beats
41
     */
42
    BeatTracker(EventList b) {
43
	beats = b;
44
    } // BeatTracker constructor
45

  
46
    /** Creates a new Event object representing a beat.
47
     *  @param time The time of the beat in seconds
48
     *  @param beatNum The index of the beat
49
     *  @return The Event object representing the beat
50
     */
51
    static Event newBeat(double time, int beatNum) {
52
	return Event(time, beatNum, 0);
53
    } // newBeat()
54

  
55
    /** Perform beat tracking.
56
     *  @param events The onsets or peaks in a feature list
57
     *  @param unfilledReturn Pointer to list in which to return 
58
     *     un-interpolated beats, or NULL
59
     *  @return The list of beats, or an empty list if beat tracking fails
60
     */
61
    static EventList beatTrack(AgentParameters params, EventList events,
62
                               EventList *unfilledReturn) {
63
	return beatTrack(params, events, EventList(), unfilledReturn);
64
    }
65
	
66
    /** Perform beat tracking.
67
     *  @param events The onsets or peaks in a feature list
68
     *  @param beats The initial beats which are given, if any
69
     *  @param unfilledReturn Pointer to list in which to return
70
     *     un-interpolated beats, or NULL
71
     *  @return The list of beats, or an empty list if beat tracking fails
72
     */
73
    static EventList beatTrack(AgentParameters params,
74
                               EventList events, EventList beats,
75
                               EventList *unfilledReturn);
76
	
77
	
78
    // Various get and set methods
79
	
80
    /** @return the list of beats */
81
    EventList getBeats() {
82
	return beats;
83
    } // getBeats()
84

  
85
    /** @return the array of onset times */
86
    vector<double> getOnsets() {
87
	return onsets;
88
    } // getOnsets()
89

  
90
    /** Sets the onset times as a list of Events, for use by the beat tracking methods. 
91
     *  @param on The times of onsets in seconds
92
     */
93
    void setOnsetList(EventList on) {
94
	onsetList = on;
95
    } // setOnsetList()
96

  
97
    /** Sets the array of onset times, for displaying MIDI or audio input data.
98
     *  @param on The times of onsets in seconds
99
     */
100
    void setOnsets(vector<double> on) {
101
	onsets = on;
102
    } // setOnsets()
103

  
104
    /** Sets the list of beats.
105
     * @param b The list of beats
106
     */
107
    void setBeats(EventList b) {
108
	beats = b;
109
    } // setBeats()
110

  
111
}; // class BeatTrackDisplay
112

  
113

  
114
#endif
115

  
CITATION
1
@article{simon2001a,
2
  author = {Simon Dixon},
3
  title = {Automatic Extraction of Tempo and Beat from Expressive Performances},
4
  journal = {Journal of New Music Research},
5
  number = {1},
6
  pages = {39-58},
7
  volume = {30},
8
  year = {2001}
9
} 
10
@misc{chris2013a,
11
  author = {Chris Cannam and Matthias Mauch and Matthew E. P. Davies and Dixon, Simon and Christian Landone and Katy C. Noland and Mark Levy and Massimiliano Zanoni and Dan Stowell and Luís A. Figueira},
12
  title = {MIREX 2013 Entry: Vamp Plugins from the Centre for Digital Music},
13
  year = {2013}
14
} 
15

  
COPYING
1
		    GNU GENERAL PUBLIC LICENSE
2
		       Version 2, June 1991
3

  
4
 Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
5
 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
6
 Everyone is permitted to copy and distribute verbatim copies
7
 of this license document, but changing it is not allowed.
8

  
9
			    Preamble
10

  
11
  The licenses for most software are designed to take away your
12
freedom to share and change it.  By contrast, the GNU General Public
13
License is intended to guarantee your freedom to share and change free
14
software--to make sure the software is free for all its users.  This
15
General Public License applies to most of the Free Software
16
Foundation's software and to any other program whose authors commit to
17
using it.  (Some other Free Software Foundation software is covered by
18
the GNU Lesser General Public License instead.)  You can apply it to
19
your programs, too.
20

  
21
  When we speak of free software, we are referring to freedom, not
22
price.  Our General Public Licenses are designed to make sure that you
23
have the freedom to distribute copies of free software (and charge for
24
this service if you wish), that you receive source code or can get it
25
if you want it, that you can change the software or use pieces of it
26
in new free programs; and that you know you can do these things.
27

  
28
  To protect your rights, we need to make restrictions that forbid
29
anyone to deny you these rights or to ask you to surrender the rights.
30
These restrictions translate to certain responsibilities for you if you
31
distribute copies of the software, or if you modify it.
32

  
33
  For example, if you distribute copies of such a program, whether
34
gratis or for a fee, you must give the recipients all the rights that
35
you have.  You must make sure that they, too, receive or can get the
36
source code.  And you must show them these terms so they know their
37
rights.
38

  
39
  We protect your rights with two steps: (1) copyright the software, and
40
(2) offer you this license which gives you legal permission to copy,
41
distribute and/or modify the software.
42

  
43
  Also, for each author's protection and ours, we want to make certain
44
that everyone understands that there is no warranty for this free
45
software.  If the software is modified by someone else and passed on, we
46
want its recipients to know that what they have is not the original, so
47
that any problems introduced by others will not reflect on the original
48
authors' reputations.
49

  
50
  Finally, any free program is threatened constantly by software
51
patents.  We wish to avoid the danger that redistributors of a free
52
program will individually obtain patent licenses, in effect making the
53
program proprietary.  To prevent this, we have made it clear that any
54
patent must be licensed for everyone's free use or not licensed at all.
55

  
56
  The precise terms and conditions for copying, distribution and
57
modification follow.
58

  
59
		    GNU GENERAL PUBLIC LICENSE
60
   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
61

  
62
  0. This License applies to any program or other work which contains
63
a notice placed by the copyright holder saying it may be distributed
64
under the terms of this General Public License.  The "Program", below,
65
refers to any such program or work, and a "work based on the Program"
66
means either the Program or any derivative work under copyright law:
67
that is to say, a work containing the Program or a portion of it,
68
either verbatim or with modifications and/or translated into another
69
language.  (Hereinafter, translation is included without limitation in
70
the term "modification".)  Each licensee is addressed as "you".
71

  
72
Activities other than copying, distribution and modification are not
73
covered by this License; they are outside its scope.  The act of
74
running the Program is not restricted, and the output from the Program
75
is covered only if its contents constitute a work based on the
76
Program (independent of having been made by running the Program).
77
Whether that is true depends on what the Program does.
78

  
79
  1. You may copy and distribute verbatim copies of the Program's
80
source code as you receive it, in any medium, provided that you
81
conspicuously and appropriately publish on each copy an appropriate
82
copyright notice and disclaimer of warranty; keep intact all the
83
notices that refer to this License and to the absence of any warranty;
84
and give any other recipients of the Program a copy of this License
85
along with the Program.
86

  
87
You may charge a fee for the physical act of transferring a copy, and
88
you may at your option offer warranty protection in exchange for a fee.
89

  
90
  2. You may modify your copy or copies of the Program or any portion
91
of it, thus forming a work based on the Program, and copy and
92
distribute such modifications or work under the terms of Section 1
93
above, provided that you also meet all of these conditions:
94

  
95
    a) You must cause the modified files to carry prominent notices
96
    stating that you changed the files and the date of any change.
97

  
98
    b) You must cause any work that you distribute or publish, that in
99
    whole or in part contains or is derived from the Program or any
100
    part thereof, to be licensed as a whole at no charge to all third
101
    parties under the terms of this License.
102

  
103
    c) If the modified program normally reads commands interactively
104
    when run, you must cause it, when started running for such
105
    interactive use in the most ordinary way, to print or display an
106
    announcement including an appropriate copyright notice and a
107
    notice that there is no warranty (or else, saying that you provide
108
    a warranty) and that users may redistribute the program under
109
    these conditions, and telling the user how to view a copy of this
110
    License.  (Exception: if the Program itself is interactive but
111
    does not normally print such an announcement, your work based on
112
    the Program is not required to print an announcement.)
113

  
114
These requirements apply to the modified work as a whole.  If
115
identifiable sections of that work are not derived from the Program,
116
and can be reasonably considered independent and separate works in
117
themselves, then this License, and its terms, do not apply to those
118
sections when you distribute them as separate works.  But when you
119
distribute the same sections as part of a whole which is a work based
120
on the Program, the distribution of the whole must be on the terms of
121
this License, whose permissions for other licensees extend to the
122
entire whole, and thus to each and every part regardless of who wrote it.
123

  
124
Thus, it is not the intent of this section to claim rights or contest
125
your rights to work written entirely by you; rather, the intent is to
126
exercise the right to control the distribution of derivative or
127
collective works based on the Program.
128

  
129
In addition, mere aggregation of another work not based on the Program
130
with the Program (or with a work based on the Program) on a volume of
131
a storage or distribution medium does not bring the other work under
132
the scope of this License.
133

  
134
  3. You may copy and distribute the Program (or a work based on it,
135
under Section 2) in object code or executable form under the terms of
136
Sections 1 and 2 above provided that you also do one of the following:
137

  
138
    a) Accompany it with the complete corresponding machine-readable
139
    source code, which must be distributed under the terms of Sections
140
    1 and 2 above on a medium customarily used for software interchange; or,
141

  
142
    b) Accompany it with a written offer, valid for at least three
143
    years, to give any third party, for a charge no more than your
144
    cost of physically performing source distribution, a complete
145
    machine-readable copy of the corresponding source code, to be
146
    distributed under the terms of Sections 1 and 2 above on a medium
147
    customarily used for software interchange; or,
148

  
149
    c) Accompany it with the information you received as to the offer
150
    to distribute corresponding source code.  (This alternative is
151
    allowed only for noncommercial distribution and only if you
152
    received the program in object code or executable form with such
153
    an offer, in accord with Subsection b above.)
154

  
155
The source code for a work means the preferred form of the work for
156
making modifications to it.  For an executable work, complete source
157
code means all the source code for all modules it contains, plus any
158
associated interface definition files, plus the scripts used to
159
control compilation and installation of the executable.  However, as a
160
special exception, the source code distributed need not include
161
anything that is normally distributed (in either source or binary
... This diff was truncated because it exceeds the maximum size that can be displayed.

Also available in: Unified diff