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: #include "Agent.h" Chris@6: #include "BeatTracker.h" Chris@6: Chris@6: double Agent::POST_MARGIN_FACTOR = 0.3; Chris@6: double Agent::PRE_MARGIN_FACTOR = 0.15; Chris@6: const double Agent::INNER_MARGIN = 0.040; Chris@6: double Agent::MAX_CHANGE = 0.2; Chris@6: double Agent::CONF_FACTOR = 0.5; Chris@6: const double Agent::DEFAULT_CORRECTION_FACTOR = 50.0; Chris@6: const double Agent::DEFAULT_EXPIRY_TIME = 10.0; Chris@6: Chris@6: int Agent::idCounter = 0; Chris@6: Chris@6: double Agent::innerMargin = 0.0; Chris@6: double Agent::correctionFactor = 0.0; Chris@6: double Agent::expiryTime = 0.0; Chris@6: double Agent::decayFactor = 0.0; Chris@6: Chris@8: bool Agent::considerAsBeat(Event e, AgentList &a) { Chris@6: double err; Chris@6: if (beatTime < 0) { // first event Chris@6: accept(e, 0, 1); Chris@6: return true; Chris@6: } else { // subsequent events Chris@9: EventList::iterator last = events.end(); Chris@9: --last; Chris@9: if (e.time - last->time > expiryTime) { Chris@6: phaseScore = -1.0; // flag agent to be deleted Chris@6: return false; Chris@6: } Chris@8: double beats = nearbyint((e.time - beatTime) / beatInterval); Chris@8: err = e.time - beatTime - beats * beatInterval; Chris@6: if ((beats > 0) && (-preMargin <= err) && (err <= postMargin)) { Chris@8: if (fabs(err) > innerMargin) // Create new agent that skips this Chris@9: a.add(Agent(*this)); // event (avoids large phase jump) Chris@6: accept(e, err, (int)beats); Chris@6: return true; Chris@6: } Chris@6: } Chris@6: return false; Chris@6: } // considerAsBeat() Chris@6: Chris@6: Chris@9: void Agent::fillBeats(double start) { Chris@6: double prevBeat = 0, nextBeat, currentInterval, beats; Chris@9: EventList::iterator ei = events.begin(); Chris@9: if (ei != events.end()) { Chris@9: ++ei; Chris@9: prevBeat = ei->time; Chris@9: --ei; Chris@6: } Chris@9: for ( ; ei != events.end(); ++ei) { Chris@9: ++ei; Chris@9: nextBeat = ei->time; Chris@9: --ei; // so as to insert before nextBeat Chris@6: beats = nearbyint((nextBeat - prevBeat) / beatInterval - 0.01); //prefer slow Chris@6: currentInterval = (nextBeat - prevBeat) / beats; Chris@6: for ( ; (nextBeat > start) && (beats > 1.5); beats--) { Chris@6: prevBeat += currentInterval; Chris@9: events.insert(ei, BeatTracker::newBeat(prevBeat, 0)); Chris@9: ++ei; Chris@6: } Chris@6: prevBeat = nextBeat; Chris@6: } Chris@6: } // fillBeats()