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::outerMargin = 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@6: bool Agent::considerAsBeat(Event e, const 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@6: if (e.keyDown - events.l.getLast().keyDown > expiryTime) { Chris@6: phaseScore = -1.0; // flag agent to be deleted Chris@6: return false; Chris@6: } Chris@6: double beats = Math.round((e.keyDown - beatTime) / beatInterval); Chris@6: err = e.keyDown - beatTime - beats * beatInterval; Chris@6: if ((beats > 0) && (-preMargin <= err) && (err <= postMargin)) { Chris@6: if (Math.abs(err) > innerMargin) // Create new agent that skips this Chris@6: a.add(new 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@6: void fillBeats(double start) { Chris@6: double prevBeat = 0, nextBeat, currentInterval, beats; Chris@6: EventList::iterator list = events.begin(); Chris@6: if (list != events.end()) { Chris@6: ++list; Chris@6: prevBeat = list->time; Chris@6: --list; Chris@6: } Chris@6: for ( ; list != events.end(); ++list) { Chris@6: ++list; Chris@6: nextBeat = list->time; Chris@6: --list; 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@6: //!!! need to insert this event after current itr Chris@6: list.add(BeatTracker::newBeat(prevBeat, 0)); // more than once OK?? Chris@6: } Chris@6: prevBeat = nextBeat; Chris@6: } Chris@6: } // fillBeats()