Mercurial > hg > beatroot-vamp
comparison Peaks.h @ 4:c06cf6f7cb04
Bring in Peaks code from BeatRoot
author | Chris Cannam |
---|---|
date | Mon, 19 Sep 2011 15:48:26 +0100 |
parents | |
children | 887c629502a9 |
comparison
equal
deleted
inserted
replaced
3:a821f49c42f0 | 4:c06cf6f7cb04 |
---|---|
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 #ifndef _BEATROOT_PEAKS_H_ | |
17 #define _BEATROOT_PEAKS_H_ | |
18 | |
19 #include <vector> | |
20 #include <cmath> | |
21 | |
22 using std::vector; | |
23 | |
24 class Peaks | |
25 { | |
26 protected: | |
27 static int pre; | |
28 static int post; | |
29 | |
30 public: | |
31 /** General peak picking method for finding n local maxima in an array | |
32 * @param data input data | |
33 * @param peaks list of peak indexes | |
34 * @param width minimum distance between peaks | |
35 */ | |
36 static int findPeaks(const vector<double> &data, vector<int> peaks, int width) { | |
37 int peakCount = 0; | |
38 int maxp = 0; | |
39 int mid = 0; | |
40 int end = data.size(); | |
41 while (mid < end) { | |
42 int i = mid - width; | |
43 if (i < 0) | |
44 i = 0; | |
45 int stop = mid + width + 1; | |
46 if (stop > data.size()) | |
47 stop = data.size(); | |
48 maxp = i; | |
49 for (i++; i < stop; i++) | |
50 if (data[i] > data[maxp]) | |
51 maxp = i; | |
52 if (maxp == mid) { | |
53 int j; | |
54 for (j = peakCount; j > 0; j--) { | |
55 if (data[maxp] <= data[peaks[j-1]]) | |
56 break; | |
57 else if (j < peaks.size()) | |
58 peaks[j] = peaks[j-1]; | |
59 } | |
60 if (j != peaks.size()) | |
61 peaks[j] = maxp; | |
62 if (peakCount != peaks.size()) | |
63 peakCount++; | |
64 } | |
65 mid++; | |
66 } | |
67 return peakCount; | |
68 } // findPeaks() | |
69 | |
70 /** General peak picking method for finding local maxima in an array | |
71 * @param data input data | |
72 * @param width minimum distance between peaks | |
73 * @param threshold minimum value of peaks | |
74 * @return list of peak indexes | |
75 */ | |
76 static vector<int> findPeaks(const vector<double> &data, int width, | |
77 double threshold) { | |
78 return findPeaks(data, width, threshold, 0, false); | |
79 } // findPeaks() | |
80 | |
81 /** General peak picking method for finding local maxima in an array | |
82 * @param data input data | |
83 * @param width minimum distance between peaks | |
84 * @param threshold minimum value of peaks | |
85 * @param decayRate how quickly previous peaks are forgotten | |
86 * @param isRelative minimum value of peaks is relative to local average | |
87 * @return list of peak indexes | |
88 */ | |
89 static vector<int> findPeaks(const vector<double> &data, int width, | |
90 double threshold, double decayRate, bool isRelative) { | |
91 vector<int> peaks; | |
92 int maxp = 0; | |
93 int mid = 0; | |
94 int end = data.size(); | |
95 double av = data[0]; | |
96 while (mid < end) { | |
97 av = decayRate * av + (1 - decayRate) * data[mid]; | |
98 if (av < data[mid]) | |
99 av = data[mid]; | |
100 int i = mid - width; | |
101 if (i < 0) | |
102 i = 0; | |
103 int stop = mid + width + 1; | |
104 if (stop > data.size()) | |
105 stop = data.size(); | |
106 maxp = i; | |
107 for (i++; i < stop; i++) | |
108 if (data[i] > data[maxp]) | |
109 maxp = i; | |
110 if (maxp == mid) { | |
111 if (overThreshold(data, maxp, width, threshold, isRelative,av)){ | |
112 peaks.push_back(maxp); | |
113 } | |
114 } | |
115 mid++; | |
116 } | |
117 return peaks; | |
118 } // findPeaks() | |
119 | |
120 static double expDecayWithHold(double av, double decayRate, | |
121 const vector<double> &data, int start, int stop) { | |
122 while (start < stop) { | |
123 av = decayRate * av + (1 - decayRate) * data[start]; | |
124 if (av < data[start]) | |
125 av = data[start]; | |
126 start++; | |
127 } | |
128 return av; | |
129 } // expDecayWithHold() | |
130 | |
131 static bool overThreshold(const vector<double> &data, int index, int width, | |
132 double threshold, bool isRelative, | |
133 double av) { | |
134 if (data[index] < av) | |
135 return false; | |
136 if (isRelative) { | |
137 int iStart = index - pre * width; | |
138 if (iStart < 0) | |
139 iStart = 0; | |
140 int iStop = index + post * width; | |
141 if (iStop > data.size()) | |
142 iStop = data.size(); | |
143 double sum = 0; | |
144 int count = iStop - iStart; | |
145 while (iStart < iStop) | |
146 sum += data[iStart++]; | |
147 return (data[index] > sum / count + threshold); | |
148 } else | |
149 return (data[index] > threshold); | |
150 } // overThreshold() | |
151 | |
152 static void normalise(vector<double> &data) { | |
153 double sx = 0; | |
154 double sxx = 0; | |
155 for (int i = 0; i < data.size(); i++) { | |
156 sx += data[i]; | |
157 sxx += data[i] * data[i]; | |
158 } | |
159 double mean = sx / data.size(); | |
160 double sd = sqrt((sxx - sx * mean) / data.size()); | |
161 if (sd == 0) | |
162 sd = 1; // all data[i] == mean -> 0; avoids div by 0 | |
163 for (int i = 0; i < data.size(); i++) { | |
164 data[i] = (data[i] - mean) / sd; | |
165 } | |
166 } // normalise() | |
167 | |
168 /** Uses an n-point linear regression to estimate the slope of data. | |
169 * @param data input data | |
170 * @param hop spacing of data points | |
171 * @param n length of linear regression | |
172 * @param slope output data | |
173 */ | |
174 static void getSlope(const vector<double> &data, double hop, int n, | |
175 vector<double> &slope) { | |
176 int i = 0, j = 0; | |
177 double t; | |
178 double sx = 0, sxx = 0, sy = 0, sxy = 0; | |
179 for ( ; i < n; i++) { | |
180 t = i * hop; | |
181 sx += t; | |
182 sxx += t * t; | |
183 sy += data[i]; | |
184 sxy += t * data[i]; | |
185 } | |
186 double delta = n * sxx - sx * sx; | |
187 for ( ; j < n / 2; j++) | |
188 slope[j] = (n * sxy - sx * sy) / delta; | |
189 for ( ; j < data.size() - (n + 1) / 2; j++, i++) { | |
190 slope[j] = (n * sxy - sx * sy) / delta; | |
191 sy += data[i] - data[i - n]; | |
192 sxy += hop * (n * data[i] - sy); | |
193 } | |
194 for ( ; j < data.size(); j++) | |
195 slope[j] = (n * sxy - sx * sy) / delta; | |
196 } // getSlope() | |
197 | |
198 static double min(const vector<double> &arr) { return arr[imin(arr)]; } | |
199 | |
200 static double max(const vector<double> &arr) { return arr[imax(arr)]; } | |
201 | |
202 static int imin(const vector<double> &arr) { | |
203 int i = 0; | |
204 for (int j = 1; j < arr.size(); j++) | |
205 if (arr[j] < arr[i]) | |
206 i = j; | |
207 return i; | |
208 } // imin() | |
209 | |
210 static int imax(const vector<double> &arr) { | |
211 int i = 0; | |
212 for (int j = 1; j < arr.size(); j++) | |
213 if (arr[j] > arr[i]) | |
214 i = j; | |
215 return i; | |
216 } // imax() | |
217 | |
218 }; // class Peaks | |
219 | |
220 #endif |