annotate Induction.cpp @ 37:1f175ae200a6 tip

Update RDF
author Chris Cannam
date Wed, 25 Jun 2014 13:48:49 +0100
parents 633ec097fa56
children
rev   line source
Chris@7 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@7 2
Chris@7 3 /*
Chris@7 4 Vamp feature extraction plugin for the BeatRoot beat tracker.
Chris@7 5
Chris@7 6 Centre for Digital Music, Queen Mary, University of London.
Chris@7 7 This file copyright 2011 Simon Dixon, Chris Cannam and QMUL.
Chris@7 8
Chris@7 9 This program is free software; you can redistribute it and/or
Chris@7 10 modify it under the terms of the GNU General Public License as
Chris@7 11 published by the Free Software Foundation; either version 2 of the
Chris@7 12 License, or (at your option) any later version. See the file
Chris@7 13 COPYING included with this distribution for more information.
Chris@7 14 */
Chris@7 15
Chris@9 16 #include "Induction.h"
Chris@9 17
Chris@7 18 double Induction::clusterWidth = 0.025;
Chris@7 19 double Induction::minIOI = 0.070;
Chris@7 20 double Induction::maxIOI = 2.500;
Chris@7 21 double Induction::minIBI = 0.3;
Chris@7 22 double Induction::maxIBI = 1.0;
Chris@7 23 int Induction::topN = 10;
Chris@7 24
Chris@15 25
Chris@23 26 AgentList Induction::beatInduction(AgentParameters params, EventList events) {
Chris@15 27 int i, j, b, bestCount;
Chris@15 28 bool submult;
Chris@15 29 int intervals = 0; // number of interval clusters
Chris@15 30 vector<int> bestn;// count of high-scoring clusters
Chris@15 31 bestn.resize(topN);
Chris@15 32
Chris@15 33 double ratio, err;
Chris@15 34 int degree;
Chris@15 35 int maxClusterCount = (int) ceil((maxIOI - minIOI) / clusterWidth);
Chris@15 36 vector<double> clusterMean;
Chris@15 37 clusterMean.resize(maxClusterCount);
Chris@15 38 vector<int> clusterSize;
Chris@15 39 clusterSize.resize(maxClusterCount);
Chris@15 40 vector<int> clusterScore;
Chris@15 41 clusterScore.resize(maxClusterCount);
Chris@15 42
Chris@15 43 EventList::iterator ptr1, ptr2;
Chris@15 44 Event e1, e2;
Chris@15 45 ptr1 = events.begin();
Chris@15 46 while (ptr1 != events.end()) {
Chris@15 47 e1 = *ptr1;
Chris@15 48 ++ptr1;
Chris@15 49 ptr2 = events.begin();
Chris@15 50 e2 = *ptr2;
Chris@15 51 ++ptr2;
Chris@15 52 while (e2 != e1 && ptr2 != events.end()) {
Chris@15 53 e2 = *ptr2;
Chris@15 54 ++ptr2;
Chris@15 55 }
Chris@15 56 while (ptr2 != events.end()) {
Chris@15 57 e2 = *ptr2;
Chris@15 58 ++ptr2;
Chris@15 59 double ioi = e2.time - e1.time;
Chris@15 60 if (ioi < minIOI) // skip short intervals
Chris@15 61 continue;
Chris@15 62 if (ioi > maxIOI) // ioi too long
Chris@15 63 break;
Chris@15 64 for (b = 0; b < intervals; b++) // assign to nearest cluster
Chris@15 65 if (fabs(clusterMean[b] - ioi) < clusterWidth) {
Chris@15 66 if ((b < intervals - 1) && (
Chris@15 67 fabs(clusterMean[b+1] - ioi) <
Chris@15 68 fabs(clusterMean[b] - ioi)))
Chris@15 69 b++; // next cluster is closer
Chris@15 70 clusterMean[b] = (clusterMean[b] * clusterSize[b] +ioi)/
Chris@15 71 (clusterSize[b] + 1);
Chris@15 72 clusterSize[b]++;
Chris@15 73 break;
Chris@15 74 }
Chris@15 75 if (b == intervals) { // no suitable cluster; create new one
Chris@15 76 if (intervals == maxClusterCount) {
Chris@15 77 // System.err.println("Warning: Too many clusters");
Chris@15 78 continue; // ignore this IOI
Chris@15 79 }
Chris@15 80 intervals++;
Chris@15 81 for ( ; (b>0) && (clusterMean[b-1] > ioi); b--) {
Chris@15 82 clusterMean[b] = clusterMean[b-1];
Chris@15 83 clusterSize[b] = clusterSize[b-1];
Chris@15 84 }
Chris@15 85 clusterMean[b] = ioi;
Chris@15 86 clusterSize[b] = 1;
Chris@15 87 }
Chris@15 88 }
Chris@15 89 }
Chris@15 90 for (b = 0; b < intervals; b++) // merge similar intervals
Chris@15 91 // TODO: they are now in order, so don't need the 2nd loop
Chris@15 92 // TODO: check BOTH sides before averaging or upper gps don't work
Chris@15 93 for (i = b+1; i < intervals; i++)
Chris@15 94 if (fabs(clusterMean[b] - clusterMean[i]) < clusterWidth) {
Chris@15 95 clusterMean[b] = (clusterMean[b] * clusterSize[b] +
Chris@15 96 clusterMean[i] * clusterSize[i]) /
Chris@15 97 (clusterSize[b] + clusterSize[i]);
Chris@15 98 clusterSize[b] = clusterSize[b] + clusterSize[i];
Chris@15 99 --intervals;
Chris@15 100 for (j = i+1; j <= intervals; j++) {
Chris@15 101 clusterMean[j-1] = clusterMean[j];
Chris@15 102 clusterSize[j-1] = clusterSize[j];
Chris@15 103 }
Chris@15 104 }
Chris@15 105 if (intervals == 0)
Chris@15 106 return AgentList();
Chris@15 107 for (b = 0; b < intervals; b++)
Chris@15 108 clusterScore[b] = 10 * clusterSize[b];
Chris@15 109 bestn[0] = 0;
Chris@15 110 bestCount = 1;
Chris@15 111 for (b = 0; b < intervals; b++)
Chris@15 112 for (i = 0; i <= bestCount; i++)
Chris@15 113 if ((i < topN) && ((i == bestCount) ||
Chris@15 114 (clusterScore[b] > clusterScore[bestn[i]]))){
Chris@15 115 if (bestCount < topN)
Chris@15 116 bestCount++;
Chris@15 117 for (j = bestCount - 1; j > i; j--)
Chris@15 118 bestn[j] = bestn[j-1];
Chris@15 119 bestn[i] = b;
Chris@15 120 break;
Chris@15 121 }
Chris@15 122 for (b = 0; b < intervals; b++) // score intervals
Chris@15 123 for (i = b+1; i < intervals; i++) {
Chris@15 124 ratio = clusterMean[b] / clusterMean[i];
Chris@15 125 submult = ratio < 1;
Chris@15 126 if (submult)
Chris@15 127 degree = (int) nearbyint(1/ratio);
Chris@15 128 else
Chris@15 129 degree = (int) nearbyint(ratio);
Chris@15 130 if ((degree >= 2) && (degree <= 8)) {
Chris@15 131 if (submult)
Chris@15 132 err = fabs(clusterMean[b]*degree - clusterMean[i]);
Chris@15 133 else
Chris@15 134 err = fabs(clusterMean[b] - clusterMean[i]*degree);
Chris@15 135 if (err < (submult? clusterWidth : clusterWidth * degree)) {
Chris@15 136 if (degree >= 5)
Chris@15 137 degree = 1;
Chris@15 138 else
Chris@15 139 degree = 6 - degree;
Chris@15 140 clusterScore[b] += degree * clusterSize[i];
Chris@15 141 clusterScore[i] += degree * clusterSize[b];
Chris@15 142 }
Chris@15 143 }
Chris@15 144 }
Chris@15 145
Chris@15 146 AgentList a;
Chris@15 147 for (int index = 0; index < bestCount; index++) {
Chris@15 148 b = bestn[index];
Chris@15 149 // Adjust it, using the size of super- and sub-intervals
Chris@15 150 double newSum = clusterMean[b] * clusterScore[b];
Chris@15 151 int newCount = clusterSize[b];
Chris@15 152 int newWeight = clusterScore[b];
Chris@15 153 for (i = 0; i < intervals; i++) {
Chris@15 154 if (i == b)
Chris@15 155 continue;
Chris@15 156 ratio = clusterMean[b] / clusterMean[i];
Chris@15 157 if (ratio < 1) {
Chris@15 158 degree = (int) nearbyint(1 / ratio);
Chris@15 159 if ((degree >= 2) && (degree <= 8)) {
Chris@15 160 err = fabs(clusterMean[b]*degree - clusterMean[i]);
Chris@15 161 if (err < clusterWidth) {
Chris@15 162 newSum += clusterMean[i] / degree * clusterScore[i];
Chris@15 163 newCount += clusterSize[i];
Chris@15 164 newWeight += clusterScore[i];
Chris@15 165 }
Chris@15 166 }
Chris@15 167 } else {
Chris@15 168 degree = (int) nearbyint(ratio);
Chris@15 169 if ((degree >= 2) && (degree <= 8)) {
Chris@15 170 err = fabs(clusterMean[b] - degree*clusterMean[i]);
Chris@15 171 if (err < clusterWidth * degree) {
Chris@15 172 newSum += clusterMean[i] * degree * clusterScore[i];
Chris@15 173 newCount += clusterSize[i];
Chris@15 174 newWeight += clusterScore[i];
Chris@15 175 }
Chris@15 176 }
Chris@15 177 }
Chris@15 178 }
Chris@15 179 double beat = newSum / newWeight;
Chris@15 180 // Scale within range ... hope the grouping isn't ternary :(
Chris@15 181 while (beat < minIBI) // Maximum speed
Chris@15 182 beat *= 2.0;
Chris@15 183 while (beat > maxIBI) // Minimum speed
Chris@15 184 beat /= 2.0;
Chris@15 185 if (beat >= minIBI) {
Chris@23 186 a.push_back(new Agent(params, beat));
Chris@15 187 }
Chris@15 188 }
Chris@15 189 #ifdef DEBUG_BEATROOT
Chris@15 190 std::cerr << "Induction complete, returning " << a.size() << " agent(s)" << std::endl;
Chris@15 191 #endif
Chris@15 192 return a;
Chris@15 193 } // beatInduction()
Chris@15 194