Chris@6: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ Chris@6: Chris@6: /* Chris@6: Vamp feature extraction plugin for the BeatRoot beat tracker. Chris@6: Chris@6: Centre for Digital Music, Queen Mary, University of London. Chris@6: This file copyright 2011 Simon Dixon, Chris Cannam and QMUL. Chris@6: Chris@6: This program is free software; you can redistribute it and/or Chris@6: modify it under the terms of the GNU General Public License as Chris@6: published by the Free Software Foundation; either version 2 of the Chris@6: License, or (at your option) any later version. See the file Chris@6: COPYING included with this distribution for more information. Chris@6: */ Chris@6: Chris@6: #ifndef _BEAT_TRACKER_H_ Chris@6: #define _BEAT_TRACKER_H_ Chris@6: Chris@6: #include "Event.h" Chris@6: #include "Agent.h" Chris@8: #include "AgentList.h" Chris@7: #include "Induction.h" Chris@6: Chris@6: using std::vector; Chris@6: Chris@6: class BeatTracker Chris@6: { Chris@6: protected: Chris@6: /** beat data encoded as a list of Events */ Chris@6: EventList beats; Chris@6: Chris@6: /** a list of onset events for passing to the tempo induction and beat tracking methods */ Chris@6: EventList onsetList; Chris@6: Chris@6: /** the times of onsets (in seconds) */ Chris@6: vector onsets; Chris@6: Chris@6: public: Chris@6: /** Constructor: Chris@6: * @param b The list of beats Chris@6: */ Chris@6: BeatTracker(EventList b) { Chris@6: beats = b; Chris@6: } // BeatTracker constructor Chris@6: Chris@6: /** Creates a new Event object representing a beat. Chris@6: * @param time The time of the beat in seconds Chris@6: * @param beatNum The index of the beat Chris@6: * @return The Event object representing the beat Chris@6: */ Chris@6: static Event newBeat(double time, int beatNum) { Chris@6: return Event(time, beatNum, 0); Chris@6: } // newBeat() Chris@6: Chris@6: /** Perform beat tracking. Chris@6: * @param events The onsets or peaks in a feature list Chris@6: * @return The list of beats, or an empty list if beat tracking fails Chris@6: */ Chris@6: static EventList beatTrack(EventList events) { Chris@6: return beatTrack(events, EventList()); Chris@6: } Chris@6: Chris@6: /** Perform beat tracking. Chris@6: * @param events The onsets or peaks in a feature list Chris@6: * @param beats The initial beats which are given, if any Chris@6: * @return The list of beats, or an empty list if beat tracking fails Chris@6: */ Chris@6: static EventList beatTrack(EventList events, EventList beats) { Chris@7: AgentList agents; Chris@6: int count = 0; Chris@6: double beatTime = -1; Chris@6: if (!beats.empty()) { Chris@6: count = beats.size() - 1; Chris@7: EventList::iterator itr = beats.end(); Chris@7: --itr; Chris@7: beatTime = itr->time; Chris@6: } Chris@6: if (count > 0) { // tempo given by mean of initial beats Chris@8: double ioi = (beatTime - beats.begin()->time) / count; Chris@8: agents.push_back(Agent(ioi)); Chris@8: } else // tempo not given; use tempo induction Chris@8: agents = Induction::beatInduction(events); Chris@8: if (!beats.empty()) Chris@8: for (AgentList::iterator itr = agents.begin(); itr != agents.end(); Chris@8: ++itr) { Chris@8: itr->beatTime = beatTime; Chris@8: itr->beatCount = count; Chris@8: itr->events = beats; Chris@6: } Chris@6: agents.beatTrack(events, -1); Chris@8: Agent *best = agents.bestAgent(); Chris@8: if (best) { Chris@8: best->fillBeats(beatTime); Chris@8: return best->events; Chris@6: } Chris@8: return EventList(); Chris@6: } // beatTrack()/1 Chris@6: Chris@6: /** Finds the mean tempo (as inter-beat interval) from an array of beat times Chris@6: * @param d An array of beat times Chris@6: * @return The average inter-beat interval Chris@6: */ Chris@6: static double getAverageIBI(vector d) { Chris@8: if (d.size() < 2) Chris@6: return -1.0; Chris@8: return (d[d.size() - 1] - d[0]) / (d.size() - 1); Chris@6: } // getAverageIBI() Chris@6: Chris@6: /** Finds the median tempo (as inter-beat interval) from an array of beat times Chris@6: * @param d An array of beat times Chris@6: * @return The median inter-beat interval Chris@6: */ Chris@6: static double getMedianIBI(vector d) { Chris@8: if (d.size() < 2) Chris@6: return -1.0; Chris@8: vector ibi; Chris@8: ibi.resize(d.size()-1); Chris@8: for (int i = 1; i < d.size(); i++) Chris@6: ibi[i-1] = d[i] - d[i-1]; Chris@8: std::sort(ibi.begin(), ibi.end()); Chris@8: if (ibi.size() % 2 == 0) Chris@8: return (ibi[ibi.size() / 2] + ibi[ibi.size() / 2 - 1]) / 2; Chris@6: else Chris@8: return ibi[ibi.size() / 2]; Chris@6: } // getAverageIBI() Chris@6: Chris@6: Chris@6: // Various get and set methods Chris@6: Chris@6: /** @return the list of beats */ Chris@6: EventList getBeats() { Chris@6: return beats; Chris@6: } // getBeats() Chris@6: Chris@6: /** @return the array of onset times */ Chris@6: vector getOnsets() { Chris@6: return onsets; Chris@6: } // getOnsets() Chris@6: Chris@6: /** Sets the onset times as a list of Events, for use by the beat tracking methods. Chris@6: * @param on The times of onsets in seconds Chris@6: */ Chris@6: void setOnsetList(EventList on) { Chris@6: onsetList = on; Chris@6: } // setOnsetList() Chris@6: Chris@6: /** Sets the array of onset times, for displaying MIDI or audio input data. Chris@6: * @param on The times of onsets in seconds Chris@6: */ Chris@6: void setOnsets(vector on) { Chris@6: onsets = on; Chris@6: } // setOnsets() Chris@6: Chris@6: /** Sets the list of beats. Chris@6: * @param b The list of beats Chris@6: */ Chris@6: void setBeats(EventList b) { Chris@6: beats = b; Chris@6: } // setBeats() Chris@6: Chris@6: }; // class BeatTrackDisplay Chris@6: Chris@6: Chris@6: #endif Chris@6: