annotate BeatTracker.h @ 7:3c11becfc81a

Add tempo induction class as well
author Chris Cannam
date Tue, 27 Sep 2011 19:05:27 +0100
parents 02d388f98c23
children f04f87b5e643
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@7 21 #include "Induction.h"
Chris@6 22
Chris@6 23 using std::vector;
Chris@6 24
Chris@6 25 class BeatTracker
Chris@6 26 {
Chris@6 27 protected:
Chris@6 28 /** beat data encoded as a list of Events */
Chris@6 29 EventList beats;
Chris@6 30
Chris@6 31 /** a list of onset events for passing to the tempo induction and beat tracking methods */
Chris@6 32 EventList onsetList;
Chris@6 33
Chris@6 34 /** the times of onsets (in seconds) */
Chris@6 35 vector<double> onsets;
Chris@6 36
Chris@6 37 /** the times corresponding to each point in the <code>magnitudes</code> array */
Chris@6 38 vector<double> env;
Chris@6 39
Chris@6 40 /** smoothed amplitude envelope of audio signal */
Chris@6 41 vector<int> magnitudes;
Chris@6 42
Chris@6 43 public:
Chris@6 44 /** Constructor:
Chris@6 45 * @param b The list of beats
Chris@6 46 */
Chris@6 47 BeatTracker(EventList b) {
Chris@6 48 beats = b;
Chris@6 49 } // BeatTracker constructor
Chris@6 50
Chris@6 51 /** Creates a new Event object representing a beat.
Chris@6 52 * @param time The time of the beat in seconds
Chris@6 53 * @param beatNum The index of the beat
Chris@6 54 * @return The Event object representing the beat
Chris@6 55 */
Chris@6 56 static Event newBeat(double time, int beatNum) {
Chris@6 57 return Event(time, beatNum, 0);
Chris@6 58 } // newBeat()
Chris@6 59
Chris@6 60 /** Perform beat tracking.
Chris@6 61 * @param events The onsets or peaks in a feature list
Chris@6 62 * @return The list of beats, or an empty list if beat tracking fails
Chris@6 63 */
Chris@6 64 static EventList beatTrack(EventList events) {
Chris@6 65 return beatTrack(events, EventList());
Chris@6 66 }
Chris@6 67
Chris@6 68 /** Perform beat tracking.
Chris@6 69 * @param events The onsets or peaks in a feature list
Chris@6 70 * @param beats The initial beats which are given, if any
Chris@6 71 * @return The list of beats, or an empty list if beat tracking fails
Chris@6 72 */
Chris@6 73 static EventList beatTrack(EventList events, EventList beats) {
Chris@7 74 AgentList agents;
Chris@6 75 int count = 0;
Chris@6 76 double beatTime = -1;
Chris@6 77 if (!beats.empty()) {
Chris@6 78 count = beats.size() - 1;
Chris@7 79 EventList::iterator itr = beats.end();
Chris@7 80 --itr;
Chris@7 81 beatTime = itr->time;
Chris@6 82 }
Chris@6 83 if (count > 0) { // tempo given by mean of initial beats
Chris@6 84 double ioi = (beatTime - beats.l.getFirst().keyDown) / count;
Chris@6 85 agents = new AgentList(new Agent(ioi), null);
Chris@6 86 } else // tempo not given; use tempo induction
Chris@6 87 agents = Induction.beatInduction(events);
Chris@6 88 if (beats != null)
Chris@6 89 for (AgentList ptr = agents; ptr.ag != null; ptr = ptr.next) {
Chris@6 90 ptr.ag.beatTime = beatTime;
Chris@6 91 ptr.ag.beatCount = count;
Chris@6 92 ptr.ag.events = new EventList(beats);
Chris@6 93 }
Chris@6 94 agents.beatTrack(events, -1);
Chris@6 95 Agent best = agents.bestAgent();
Chris@6 96 if (best != null) {
Chris@6 97 best.fillBeats(beatTime);
Chris@6 98 return best.events;
Chris@6 99 }
Chris@6 100 return new EventList();
Chris@6 101 } // beatTrack()/1
Chris@6 102
Chris@6 103 /** Finds the mean tempo (as inter-beat interval) from an array of beat times
Chris@6 104 * @param d An array of beat times
Chris@6 105 * @return The average inter-beat interval
Chris@6 106 */
Chris@6 107 static double getAverageIBI(vector<double> d) {
Chris@6 108 if ((d == null) || (d.length < 2))
Chris@6 109 return -1.0;
Chris@6 110 return (d[d.length - 1] - d[0]) / (d.length - 1);
Chris@6 111 } // getAverageIBI()
Chris@6 112
Chris@6 113 /** Finds the median tempo (as inter-beat interval) from an array of beat times
Chris@6 114 * @param d An array of beat times
Chris@6 115 * @return The median inter-beat interval
Chris@6 116 */
Chris@6 117 static double getMedianIBI(vector<double> d) {
Chris@6 118 if ((d == null) || (d.length < 2))
Chris@6 119 return -1.0;
Chris@6 120 vector<double> ibi = new double[d.length-1];
Chris@6 121 for (int i = 1; i < d.length; i++)
Chris@6 122 ibi[i-1] = d[i] - d[i-1];
Chris@6 123 Arrays.sort(ibi);
Chris@6 124 if (ibi.length % 2 == 0)
Chris@6 125 return (ibi[ibi.length / 2] + ibi[ibi.length / 2 - 1]) / 2;
Chris@6 126 else
Chris@6 127 return ibi[ibi.length / 2];
Chris@6 128 } // getAverageIBI()
Chris@6 129
Chris@6 130
Chris@6 131 // Various get and set methods
Chris@6 132
Chris@6 133 /** @return the list of beats */
Chris@6 134 EventList getBeats() {
Chris@6 135 return beats;
Chris@6 136 } // getBeats()
Chris@6 137
Chris@6 138 /** @return the array of onset times */
Chris@6 139 vector<double> getOnsets() {
Chris@6 140 return onsets;
Chris@6 141 } // getOnsets()
Chris@6 142
Chris@6 143 /** @return the array of offset times */
Chris@6 144 vector<double> getOffsets() {
Chris@6 145 return offsets;
Chris@6 146 } // getOffsets()
Chris@6 147
Chris@6 148 /** @return the array of MIDI pitches */
Chris@6 149 vector<int> getPitches() {
Chris@6 150 return pitches;
Chris@6 151 } // getPitches()
Chris@6 152
Chris@6 153 /** Sets the onset times as a list of Events, for use by the beat tracking methods.
Chris@6 154 * @param on The times of onsets in seconds
Chris@6 155 */
Chris@6 156 void setOnsetList(EventList on) {
Chris@6 157 onsetList = on;
Chris@6 158 } // setOnsetList()
Chris@6 159
Chris@6 160 /** Sets the array of onset times, for displaying MIDI or audio input data.
Chris@6 161 * @param on The times of onsets in seconds
Chris@6 162 */
Chris@6 163 void setOnsets(vector<double> on) {
Chris@6 164 onsets = on;
Chris@6 165 } // setOnsets()
Chris@6 166
Chris@6 167 /** Sets the array of offset times, for displaying MIDI input data.
Chris@6 168 * @param off The array of MIDI offset times
Chris@6 169 */
Chris@6 170 void setOffsets(vector<double> off) {
Chris@6 171 offsets = off;
Chris@6 172 // setMode(SHOW_MIDI, SHOW_AUDIO | SHOW_SPECTRO);
Chris@6 173 } // setOffsets()
Chris@6 174
Chris@6 175 /** Sets the array of times of amplitude envelope points, for displaying.
Chris@6 176 * @param envTimes The array of times in seconds corresponding to the values in <code>magnitudes</code>
Chris@6 177 */
Chris@6 178 void setEnvTimes(vector<double> envTimes) {
Chris@6 179 env = envTimes;
Chris@6 180 setMode(SHOW_AUDIO, SHOW_MIDI);
Chris@6 181 } // setEnvTimes()
Chris@6 182
Chris@6 183 /** Sets the array of magnitude values, for displaying.
Chris@6 184 * @param mag The array of amplitude envelope values
Chris@6 185 */
Chris@6 186 void setMagnitudes(vector<int> mag) {
Chris@6 187 magnitudes = mag;
Chris@6 188 } // setMagnitudes()
Chris@6 189
Chris@6 190 /** Sets the array of pitch values, for displaying MIDI input data.
Chris@6 191 * @param p The array of MIDI pitch values
Chris@6 192 */
Chris@6 193 void setPitches(vector<int> p) {
Chris@6 194 pitches = p;
Chris@6 195 } // setPitches()
Chris@6 196
Chris@6 197 /** Sets the list of beats.
Chris@6 198 * @param b The list of beats
Chris@6 199 */
Chris@6 200 void setBeats(EventList b) {
Chris@6 201 beats = b;
Chris@6 202 selectedBeat = null;
Chris@6 203 beatPtr = beats.listIterator();
Chris@6 204 } // setBeats()
Chris@6 205
Chris@6 206 }; // class BeatTrackDisplay
Chris@6 207
Chris@6 208
Chris@6 209 #endif
Chris@6 210