To check out this repository please hg clone the following URL, or open the URL using EasyMercurial or your preferred Mercurial client.

Statistics Download as Zip
| Branch: | Tag: | Revision:

root / Induction.cpp @ 23:633ec097fa56

History | View | Annotate | Download (7.29 KB)

1
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
2

    
3
/*
4
  Vamp feature extraction plugin for the BeatRoot beat tracker.
5

6
  Centre for Digital Music, Queen Mary, University of London.
7
  This file copyright 2011 Simon Dixon, Chris Cannam and QMUL.
8
    
9
  This program is free software; you can redistribute it and/or
10
  modify it under the terms of the GNU General Public License as
11
  published by the Free Software Foundation; either version 2 of the
12
  License, or (at your option) any later version.  See the file
13
  COPYING included with this distribution for more information.
14
*/
15

    
16
#include "Induction.h"
17

    
18
double Induction::clusterWidth = 0.025;
19
double Induction::minIOI = 0.070;
20
double Induction::maxIOI = 2.500;
21
double Induction::minIBI = 0.3; 
22
double Induction::maxIBI = 1.0;
23
int Induction::topN = 10;
24

    
25

    
26
AgentList Induction::beatInduction(AgentParameters params, EventList events) {
27
    int i, j, b, bestCount;
28
    bool submult;
29
    int intervals = 0;                        // number of interval clusters
30
    vector<int> bestn;// count of high-scoring clusters
31
    bestn.resize(topN);
32

    
33
    double ratio, err;
34
    int degree;
35
    int maxClusterCount = (int) ceil((maxIOI - minIOI) / clusterWidth);
36
    vector<double> clusterMean;
37
    clusterMean.resize(maxClusterCount);
38
    vector<int> clusterSize;
39
    clusterSize.resize(maxClusterCount);
40
    vector<int> clusterScore;
41
    clusterScore.resize(maxClusterCount);
42
                
43
    EventList::iterator ptr1, ptr2;
44
    Event e1, e2;
45
    ptr1 = events.begin();
46
    while (ptr1 != events.end()) {
47
        e1 = *ptr1;
48
        ++ptr1;
49
        ptr2 = events.begin();
50
        e2 = *ptr2;
51
        ++ptr2;
52
        while (e2 != e1 && ptr2 != events.end()) {
53
            e2 = *ptr2;
54
            ++ptr2;
55
        }
56
        while (ptr2 != events.end()) {
57
            e2 = *ptr2;
58
            ++ptr2;
59
            double ioi = e2.time - e1.time;
60
            if (ioi < minIOI)                // skip short intervals
61
                continue;
62
            if (ioi > maxIOI)                // ioi too long
63
                break;
64
            for (b = 0; b < intervals; b++)                // assign to nearest cluster
65
                if (fabs(clusterMean[b] - ioi) < clusterWidth) {
66
                    if ((b < intervals - 1) && (
67
                            fabs(clusterMean[b+1] - ioi) <
68
                            fabs(clusterMean[b] - ioi)))
69
                        b++;                // next cluster is closer
70
                    clusterMean[b] = (clusterMean[b] * clusterSize[b] +ioi)/
71
                        (clusterSize[b] + 1);
72
                    clusterSize[b]++;
73
                    break;
74
                }
75
            if (b == intervals) {        // no suitable cluster; create new one
76
                if (intervals == maxClusterCount) {
77
//                        System.err.println("Warning: Too many clusters");
78
                    continue; // ignore this IOI
79
                }
80
                intervals++;
81
                for ( ; (b>0) && (clusterMean[b-1] > ioi); b--) {
82
                    clusterMean[b] = clusterMean[b-1];
83
                    clusterSize[b] = clusterSize[b-1];
84
                }
85
                clusterMean[b] = ioi;
86
                clusterSize[b] = 1;
87
            }
88
        }
89
    }
90
    for (b = 0; b < intervals; b++)        // merge similar intervals
91
        // TODO: they are now in order, so don't need the 2nd loop
92
        // TODO: check BOTH sides before averaging or upper gps don't work
93
        for (i = b+1; i < intervals; i++)
94
            if (fabs(clusterMean[b] - clusterMean[i]) < clusterWidth) {
95
                clusterMean[b] = (clusterMean[b] * clusterSize[b] +
96
                                  clusterMean[i] * clusterSize[i]) /
97
                    (clusterSize[b] + clusterSize[i]);
98
                clusterSize[b] = clusterSize[b] + clusterSize[i];
99
                --intervals;
100
                for (j = i+1; j <= intervals; j++) {
101
                    clusterMean[j-1] = clusterMean[j];
102
                    clusterSize[j-1] = clusterSize[j];
103
                }
104
            }
105
    if (intervals == 0)
106
        return AgentList();
107
    for (b = 0; b < intervals; b++)
108
        clusterScore[b] = 10 * clusterSize[b];
109
    bestn[0] = 0;
110
    bestCount = 1;
111
    for (b = 0; b < intervals; b++)
112
        for (i = 0; i <= bestCount; i++)
113
            if ((i < topN) && ((i == bestCount) ||
114
                               (clusterScore[b] > clusterScore[bestn[i]]))){
115
                if (bestCount < topN)
116
                    bestCount++;
117
                for (j = bestCount - 1; j > i; j--)
118
                    bestn[j] = bestn[j-1];
119
                bestn[i] = b;
120
                break;
121
            }
122
    for (b = 0; b < intervals; b++)        // score intervals
123
        for (i = b+1; i < intervals; i++) {
124
            ratio = clusterMean[b] / clusterMean[i];
125
            submult = ratio < 1;
126
            if (submult)
127
                degree = (int) nearbyint(1/ratio);
128
            else
129
                degree = (int) nearbyint(ratio);
130
            if ((degree >= 2) && (degree <= 8)) {
131
                if (submult)
132
                    err = fabs(clusterMean[b]*degree - clusterMean[i]);
133
                else
134
                    err = fabs(clusterMean[b] - clusterMean[i]*degree);
135
                if (err < (submult? clusterWidth : clusterWidth * degree)) {
136
                    if (degree >= 5)
137
                        degree = 1;
138
                    else
139
                        degree = 6 - degree;
140
                    clusterScore[b] += degree * clusterSize[i];
141
                    clusterScore[i] += degree * clusterSize[b];
142
                }
143
            }
144
        }
145

    
146
    AgentList a;
147
    for (int index = 0; index < bestCount; index++) {
148
        b = bestn[index];
149
        // Adjust it, using the size of super- and sub-intervals
150
        double newSum = clusterMean[b] * clusterScore[b];
151
        int newCount = clusterSize[b];
152
        int newWeight = clusterScore[b];
153
        for (i = 0; i < intervals; i++) {
154
            if (i == b)
155
                continue;
156
            ratio = clusterMean[b] / clusterMean[i];
157
            if (ratio < 1) {
158
                degree = (int) nearbyint(1 / ratio);
159
                if ((degree >= 2) && (degree <= 8)) {
160
                    err = fabs(clusterMean[b]*degree - clusterMean[i]);
161
                    if (err < clusterWidth) {
162
                        newSum += clusterMean[i] / degree * clusterScore[i];
163
                        newCount += clusterSize[i];
164
                        newWeight += clusterScore[i];
165
                    }
166
                }
167
            } else {
168
                degree = (int) nearbyint(ratio);
169
                if ((degree >= 2) && (degree <= 8)) {
170
                    err = fabs(clusterMean[b] - degree*clusterMean[i]);
171
                    if (err < clusterWidth * degree) {
172
                        newSum += clusterMean[i] * degree * clusterScore[i];
173
                        newCount += clusterSize[i];
174
                        newWeight += clusterScore[i];
175
                    }
176
                }
177
            }
178
        }
179
        double beat = newSum / newWeight;
180
        // Scale within range ... hope the grouping isn't ternary :(
181
        while (beat < minIBI)                // Maximum speed
182
            beat *= 2.0;
183
        while (beat > maxIBI)                // Minimum speed
184
            beat /= 2.0;
185
        if (beat >= minIBI) {
186
            a.push_back(new Agent(params, beat));
187
        }
188
    }
189
#ifdef DEBUG_BEATROOT
190
    std::cerr << "Induction complete, returning " << a.size() << " agent(s)" << std::endl;
191
#endif
192
    return a;
193
} // beatInduction()
194