annotate BeatTracker.h @ 8:f04f87b5e643

Add agent list class, and continue plodding through
author Chris Cannam
date Fri, 30 Sep 2011 11:37:25 +0100
parents 3c11becfc81a
children 887c629502a9
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 _BEAT_TRACKER_H_
Chris@6 17 #define _BEAT_TRACKER_H_
Chris@6 18
Chris@6 19 #include "Event.h"
Chris@6 20 #include "Agent.h"
Chris@8 21 #include "AgentList.h"
Chris@7 22 #include "Induction.h"
Chris@6 23
Chris@6 24 using std::vector;
Chris@6 25
Chris@6 26 class BeatTracker
Chris@6 27 {
Chris@6 28 protected:
Chris@6 29 /** beat data encoded as a list of Events */
Chris@6 30 EventList beats;
Chris@6 31
Chris@6 32 /** a list of onset events for passing to the tempo induction and beat tracking methods */
Chris@6 33 EventList onsetList;
Chris@6 34
Chris@6 35 /** the times of onsets (in seconds) */
Chris@6 36 vector<double> onsets;
Chris@6 37
Chris@6 38 public:
Chris@6 39 /** Constructor:
Chris@6 40 * @param b The list of beats
Chris@6 41 */
Chris@6 42 BeatTracker(EventList b) {
Chris@6 43 beats = b;
Chris@6 44 } // BeatTracker constructor
Chris@6 45
Chris@6 46 /** Creates a new Event object representing a beat.
Chris@6 47 * @param time The time of the beat in seconds
Chris@6 48 * @param beatNum The index of the beat
Chris@6 49 * @return The Event object representing the beat
Chris@6 50 */
Chris@6 51 static Event newBeat(double time, int beatNum) {
Chris@6 52 return Event(time, beatNum, 0);
Chris@6 53 } // newBeat()
Chris@6 54
Chris@6 55 /** Perform beat tracking.
Chris@6 56 * @param events The onsets or peaks in a feature list
Chris@6 57 * @return The list of beats, or an empty list if beat tracking fails
Chris@6 58 */
Chris@6 59 static EventList beatTrack(EventList events) {
Chris@6 60 return beatTrack(events, EventList());
Chris@6 61 }
Chris@6 62
Chris@6 63 /** Perform beat tracking.
Chris@6 64 * @param events The onsets or peaks in a feature list
Chris@6 65 * @param beats The initial beats which are given, if any
Chris@6 66 * @return The list of beats, or an empty list if beat tracking fails
Chris@6 67 */
Chris@6 68 static EventList beatTrack(EventList events, EventList beats) {
Chris@7 69 AgentList agents;
Chris@6 70 int count = 0;
Chris@6 71 double beatTime = -1;
Chris@6 72 if (!beats.empty()) {
Chris@6 73 count = beats.size() - 1;
Chris@7 74 EventList::iterator itr = beats.end();
Chris@7 75 --itr;
Chris@7 76 beatTime = itr->time;
Chris@6 77 }
Chris@6 78 if (count > 0) { // tempo given by mean of initial beats
Chris@8 79 double ioi = (beatTime - beats.begin()->time) / count;
Chris@8 80 agents.push_back(Agent(ioi));
Chris@8 81 } else // tempo not given; use tempo induction
Chris@8 82 agents = Induction::beatInduction(events);
Chris@8 83 if (!beats.empty())
Chris@8 84 for (AgentList::iterator itr = agents.begin(); itr != agents.end();
Chris@8 85 ++itr) {
Chris@8 86 itr->beatTime = beatTime;
Chris@8 87 itr->beatCount = count;
Chris@8 88 itr->events = beats;
Chris@6 89 }
Chris@6 90 agents.beatTrack(events, -1);
Chris@8 91 Agent *best = agents.bestAgent();
Chris@8 92 if (best) {
Chris@8 93 best->fillBeats(beatTime);
Chris@8 94 return best->events;
Chris@6 95 }
Chris@8 96 return EventList();
Chris@6 97 } // beatTrack()/1
Chris@6 98
Chris@6 99 /** Finds the mean tempo (as inter-beat interval) from an array of beat times
Chris@6 100 * @param d An array of beat times
Chris@6 101 * @return The average inter-beat interval
Chris@6 102 */
Chris@6 103 static double getAverageIBI(vector<double> d) {
Chris@8 104 if (d.size() < 2)
Chris@6 105 return -1.0;
Chris@8 106 return (d[d.size() - 1] - d[0]) / (d.size() - 1);
Chris@6 107 } // getAverageIBI()
Chris@6 108
Chris@6 109 /** Finds the median tempo (as inter-beat interval) from an array of beat times
Chris@6 110 * @param d An array of beat times
Chris@6 111 * @return The median inter-beat interval
Chris@6 112 */
Chris@6 113 static double getMedianIBI(vector<double> d) {
Chris@8 114 if (d.size() < 2)
Chris@6 115 return -1.0;
Chris@8 116 vector<double> ibi;
Chris@8 117 ibi.resize(d.size()-1);
Chris@8 118 for (int i = 1; i < d.size(); i++)
Chris@6 119 ibi[i-1] = d[i] - d[i-1];
Chris@8 120 std::sort(ibi.begin(), ibi.end());
Chris@8 121 if (ibi.size() % 2 == 0)
Chris@8 122 return (ibi[ibi.size() / 2] + ibi[ibi.size() / 2 - 1]) / 2;
Chris@6 123 else
Chris@8 124 return ibi[ibi.size() / 2];
Chris@6 125 } // getAverageIBI()
Chris@6 126
Chris@6 127
Chris@6 128 // Various get and set methods
Chris@6 129
Chris@6 130 /** @return the list of beats */
Chris@6 131 EventList getBeats() {
Chris@6 132 return beats;
Chris@6 133 } // getBeats()
Chris@6 134
Chris@6 135 /** @return the array of onset times */
Chris@6 136 vector<double> getOnsets() {
Chris@6 137 return onsets;
Chris@6 138 } // getOnsets()
Chris@6 139
Chris@6 140 /** Sets the onset times as a list of Events, for use by the beat tracking methods.
Chris@6 141 * @param on The times of onsets in seconds
Chris@6 142 */
Chris@6 143 void setOnsetList(EventList on) {
Chris@6 144 onsetList = on;
Chris@6 145 } // setOnsetList()
Chris@6 146
Chris@6 147 /** Sets the array of onset times, for displaying MIDI or audio input data.
Chris@6 148 * @param on The times of onsets in seconds
Chris@6 149 */
Chris@6 150 void setOnsets(vector<double> on) {
Chris@6 151 onsets = on;
Chris@6 152 } // setOnsets()
Chris@6 153
Chris@6 154 /** Sets the list of beats.
Chris@6 155 * @param b The list of beats
Chris@6 156 */
Chris@6 157 void setBeats(EventList b) {
Chris@6 158 beats = b;
Chris@6 159 } // setBeats()
Chris@6 160
Chris@6 161 }; // class BeatTrackDisplay
Chris@6 162
Chris@6 163
Chris@6 164 #endif
Chris@6 165