Mercurial > hg > svcore
comparison data/model/FFTModel.cpp @ 500:83eae5239db6
* Permit viewing (though not editing) colour 3d plot layer data in
the spreadsheet data viewer dialog
* Add somewhat simplistic RDF export for layers
* Fix display of peak frequencies in spectrum layer
* Fix (I hope) sizing of plugin parameter dialog
author | Chris Cannam |
---|---|
date | Tue, 02 Dec 2008 17:17:25 +0000 |
parents | 115f60df1e4d |
children | 6066bde1c126 |
comparison
equal
deleted
inserted
replaced
499:b71116d3c180 | 500:83eae5239db6 |
---|---|
168 | 168 |
169 result.clear(); | 169 result.clear(); |
170 size_t h = getHeight(); | 170 size_t h = getHeight(); |
171 | 171 |
172 float magnitudes[h]; | 172 float magnitudes[h]; |
173 | |
173 if (m_server->getMagnitudesAt(x << m_xshift, magnitudes)) { | 174 if (m_server->getMagnitudesAt(x << m_xshift, magnitudes)) { |
175 | |
174 for (size_t y = 0; y < h; ++y) { | 176 for (size_t y = 0; y < h; ++y) { |
175 result.push_back(magnitudes[h]); | 177 result.push_back(magnitudes[y]); |
176 } | 178 } |
179 | |
177 } else { | 180 } else { |
178 for (size_t i = 0; i < h; ++i) result.push_back(0.f); | 181 for (size_t i = 0; i < h; ++i) result.push_back(0.f); |
179 } | 182 } |
180 } | 183 } |
181 | 184 |
257 return peaks; | 260 return peaks; |
258 } | 261 } |
259 | 262 |
260 getColumn(x, values); | 263 getColumn(x, values); |
261 | 264 |
265 float mean = 0.f; | |
266 for (int i =0; i < values.size(); ++i) mean += values[i]; | |
267 if (values.size() >0) mean /= values.size(); | |
268 | |
262 // For peak picking we use a moving median window, picking the | 269 // For peak picking we use a moving median window, picking the |
263 // highest value within each continuous region of values that | 270 // highest value within each continuous region of values that |
264 // exceed the median. For pitch adaptivity, we adjust the window | 271 // exceed the median. For pitch adaptivity, we adjust the window |
265 // size to a roughly constant pitch range (about four tones). | 272 // size to a roughly constant pitch range (about four tones). |
266 | 273 |
267 size_t sampleRate = getSampleRate(); | 274 size_t sampleRate = getSampleRate(); |
268 | 275 |
269 std::deque<float> window; | 276 std::deque<float> window; |
270 std::vector<size_t> inrange; | 277 std::vector<size_t> inrange; |
271 float dist = 0.5; | 278 float dist = 0.5; |
279 | |
272 size_t medianWinSize = getPeakPickWindowSize(type, sampleRate, ymin, dist); | 280 size_t medianWinSize = getPeakPickWindowSize(type, sampleRate, ymin, dist); |
273 size_t halfWin = medianWinSize/2; | 281 size_t halfWin = medianWinSize/2; |
274 | 282 |
275 size_t binmin; | 283 size_t binmin; |
276 if (ymin > halfWin) binmin = ymin - halfWin; | 284 if (ymin > halfWin) binmin = ymin - halfWin; |
278 | 286 |
279 size_t binmax; | 287 size_t binmax; |
280 if (ymax + halfWin < values.size()) binmax = ymax + halfWin; | 288 if (ymax + halfWin < values.size()) binmax = ymax + halfWin; |
281 else binmax = values.size()-1; | 289 else binmax = values.size()-1; |
282 | 290 |
291 size_t prevcentre = 0; | |
292 | |
283 for (size_t bin = binmin; bin <= binmax; ++bin) { | 293 for (size_t bin = binmin; bin <= binmax; ++bin) { |
284 | 294 |
285 float value = values[bin]; | 295 float value = values[bin]; |
286 | 296 |
287 window.push_back(value); | 297 window.push_back(value); |
288 | 298 |
289 // so-called median will actually be the dist*100'th percentile | 299 // so-called median will actually be the dist*100'th percentile |
290 medianWinSize = getPeakPickWindowSize(type, sampleRate, bin, dist); | 300 medianWinSize = getPeakPickWindowSize(type, sampleRate, bin, dist); |
291 halfWin = medianWinSize/2; | 301 halfWin = medianWinSize/2; |
292 | 302 |
293 while (window.size() > medianWinSize) window.pop_front(); | 303 while (window.size() > medianWinSize) { |
304 window.pop_front(); | |
305 } | |
306 | |
307 size_t actualSize = window.size(); | |
294 | 308 |
295 if (type == MajorPitchAdaptivePeaks) { | 309 if (type == MajorPitchAdaptivePeaks) { |
296 if (ymax + halfWin < values.size()) binmax = ymax + halfWin; | 310 if (ymax + halfWin < values.size()) binmax = ymax + halfWin; |
297 else binmax = values.size()-1; | 311 else binmax = values.size()-1; |
298 } | 312 } |
299 | 313 |
300 std::deque<float> sorted(window); | 314 std::deque<float> sorted(window); |
301 std::sort(sorted.begin(), sorted.end()); | 315 std::sort(sorted.begin(), sorted.end()); |
302 float median = sorted[int(sorted.size() * dist)]; | 316 float median = sorted[int(sorted.size() * dist)]; |
303 | 317 |
304 if (value > median) { | 318 size_t centrebin = 0; |
305 inrange.push_back(bin); | 319 if (bin > actualSize/2) centrebin = bin - actualSize/2; |
306 } | 320 |
307 | 321 while (centrebin > prevcentre || bin == binmin) { |
308 if (value <= median || bin+1 == values.size()) { | 322 |
309 size_t peakbin = 0; | 323 if (centrebin > prevcentre) ++prevcentre; |
310 float peakval = 0.f; | 324 |
311 if (!inrange.empty()) { | 325 float centre = values[prevcentre]; |
312 for (size_t i = 0; i < inrange.size(); ++i) { | 326 |
313 if (i == 0 || values[inrange[i]] > peakval) { | 327 if (centre > median) { |
314 peakval = values[inrange[i]]; | 328 inrange.push_back(centrebin); |
315 peakbin = inrange[i]; | 329 } |
330 | |
331 if (centre <= median || centrebin+1 == values.size()) { | |
332 if (!inrange.empty()) { | |
333 size_t peakbin = 0; | |
334 float peakval = 0.f; | |
335 for (size_t i = 0; i < inrange.size(); ++i) { | |
336 if (i == 0 || values[inrange[i]] > peakval) { | |
337 peakval = values[inrange[i]]; | |
338 peakbin = inrange[i]; | |
339 } | |
340 } | |
341 inrange.clear(); | |
342 if (peakbin >= ymin && peakbin <= ymax) { | |
343 peaks.insert(peakbin); | |
316 } | 344 } |
317 } | 345 } |
318 inrange.clear(); | |
319 if (peakbin >= ymin && peakbin <= ymax) { | |
320 peaks.insert(peakbin); | |
321 } | |
322 } | 346 } |
347 | |
348 if (bin == binmin) break; | |
323 } | 349 } |
324 } | 350 } |
325 | 351 |
326 return peaks; | 352 return peaks; |
327 } | 353 } |