comparison layer/SpectrogramLayer.cpp @ 477:92f4d88241b8

* some preparatory reorganisation
author Chris Cannam
date Tue, 03 Feb 2009 11:19:39 +0000
parents 4f4f943bfdfc
children 0990b95140e3
comparison
equal deleted inserted replaced
476:2613bc1b2823 477:92f4d88241b8
40 #include <iostream> 40 #include <iostream>
41 41
42 #include <cassert> 42 #include <cassert>
43 #include <cmath> 43 #include <cmath>
44 44
45 //#define DEBUG_SPECTROGRAM_REPAINT 1 45 #define DEBUG_SPECTROGRAM_REPAINT 1
46 46
47 SpectrogramLayer::SpectrogramLayer(Configuration config) : 47 SpectrogramLayer::SpectrogramLayer(Configuration config) :
48 m_model(0), 48 m_model(0),
49 m_channel(0), 49 m_channel(0),
50 m_windowSize(1024), 50 m_windowSize(1024),
1779 } 1779 }
1780 1780
1781 PixmapCache &cache = m_pixmapCaches[v]; 1781 PixmapCache &cache = m_pixmapCaches[v];
1782 1782
1783 #ifdef DEBUG_SPECTROGRAM_REPAINT 1783 #ifdef DEBUG_SPECTROGRAM_REPAINT
1784 std::cerr << "SpectrogramLayer::paint(): pixmap cache valid area " << cache.validArea.x() << ", " << cache.validArea.y() << ", " << cache.validArea.width() << "x" << cache.validArea.height() << std::endl; 1784 std::cerr << "SpectrogramLayer::paint(): pixmap cache valid area " << cache.
1785
1786 validArea.x() << ", " << cache.validArea.y() << ", " << cache.validArea.width() << "x" << cache.validArea.height() << std::endl;
1785 #endif 1787 #endif
1786 1788
1787 #ifdef DEBUG_SPECTROGRAM_REPAINT 1789 #ifdef DEBUG_SPECTROGRAM_REPAINT
1788 bool stillCacheing = (m_updateTimer != 0); 1790 bool stillCacheing = (m_updateTimer != 0);
1789 std::cerr << "SpectrogramLayer::paint(): Still cacheing = " << stillCacheing << std::endl; 1791 std::cerr << "SpectrogramLayer::paint(): Still cacheing = " << stillCacheing << std::endl;
2112 displayMaxFreq = getEffectiveMaxFrequency(); 2114 displayMaxFreq = getEffectiveMaxFrequency();
2113 } 2115 }
2114 2116
2115 // std::cerr << "(giving actual minFreq " << minFreq << " and display minFreq " << displayMinFreq << ")" << std::endl; 2117 // std::cerr << "(giving actual minFreq " << minFreq << " and display minFreq " << displayMinFreq << ")" << std::endl;
2116 2118
2117 float ymag[h]; 2119 float yforbin[maxbin - minbin + 1];
2118 float ydiv[h]; 2120 float yval[h];
2119
2120 float yval[maxbin - minbin + 1];
2121 float values[maxbin - minbin + 1];
2122 2121
2123 size_t increment = getWindowIncrement(); 2122 size_t increment = getWindowIncrement();
2124 2123
2125 bool logarithmic = (m_frequencyScale == LogFrequencyScale); 2124 bool logarithmic = (m_frequencyScale == LogFrequencyScale);
2126 2125
2127 for (size_t q = minbin; q <= maxbin; ++q) { 2126 for (size_t q = minbin; q <= maxbin; ++q) {
2128 float f0 = (float(q) * sr) / fftSize; 2127 float f0 = (float(q) * sr) / fftSize;
2129 yval[q - minbin] = 2128 yforbin[q - minbin] =
2130 v->getYForFrequency(f0, displayMinFreq, displayMaxFreq, 2129 v->getYForFrequency(f0, displayMinFreq, displayMaxFreq,
2131 logarithmic); 2130 logarithmic);
2132 } 2131 }
2133 2132
2134 MagnitudeRange overallMag = m_viewMags[v]; 2133 MagnitudeRange overallMag = m_viewMags[v];
2135 bool overallMagChanged = false; 2134 bool overallMagChanged = false;
2136 2135
2137 bool fftSuspended = false; 2136 bool fftSuspended = false;
2138 2137
2139 bool interpolate = false;
2140 Preferences::SpectrogramSmoothing smoothing =
2141 Preferences::getInstance()->getSpectrogramSmoothing();
2142 if (smoothing == Preferences::SpectrogramInterpolated ||
2143 smoothing == Preferences::SpectrogramZeroPaddedAndInterpolated) {
2144 if (m_binDisplay != PeakBins &&
2145 m_binDisplay != PeakFrequencies) {
2146 interpolate = true;
2147 }
2148 }
2149
2150 #ifdef DEBUG_SPECTROGRAM_REPAINT 2138 #ifdef DEBUG_SPECTROGRAM_REPAINT
2151 std::cerr << ((float(v->getFrameForX(1) - v->getFrameForX(0))) / increment) << " bin(s) per pixel" << std::endl; 2139 std::cerr << ((float(v->getFrameForX(1) - v->getFrameForX(0))) / increment) << " bin(s) per pixel" << std::endl;
2152 #endif 2140 #endif
2153 2141
2154 bool runOutOfData = false; 2142 bool runOutOfData = false;
2160 #ifdef DEBUG_SPECTROGRAM_REPAINT 2148 #ifdef DEBUG_SPECTROGRAM_REPAINT
2161 size_t pixels = 0; 2149 size_t pixels = 0;
2162 #endif 2150 #endif
2163 2151
2164 Profiler outerprof("SpectrogramLayer::paint: all cols"); 2152 Profiler outerprof("SpectrogramLayer::paint: all cols");
2165 FFTModel::PeakSet peaks;
2166 2153
2167 for (int x = 0; x < w; ++x) { 2154 for (int x = 0; x < w; ++x) {
2168 2155
2169 Profiler innerprof("SpectrogramLayer::paint: 1 pixel column"); 2156 Profiler innerprof("SpectrogramLayer::paint: 1 pixel column");
2170 2157
2158 runOutOfData = !getColumnValues(v, fft, x0, x,
2159 minbin, maxbin,
2160 displayMinFreq, displayMaxFreq,
2161 h, yforbin, yval);
2162
2171 if (runOutOfData) { 2163 if (runOutOfData) {
2172 #ifdef DEBUG_SPECTROGRAM_REPAINT 2164 #ifdef DEBUG_SPECTROGRAM_REPAINT
2173 std::cerr << "Run out of data -- dropping out of loop" << std::endl; 2165 std::cerr << "Run out of data -- dropping out of loop" << std::endl;
2174 #endif 2166 #endif
2175 break; 2167 break;
2176 } 2168 }
2177 2169
2170 Profiler drawbufferprof("SpectrogramLayer::paint: set buffer pixels");
2171
2178 for (int y = 0; y < h; ++y) { 2172 for (int y = 0; y < h; ++y) {
2179 ymag[y] = 0.f; 2173
2180 ydiv[y] = 0.f; 2174 unsigned char pixel = 0;
2181 } 2175
2182 2176 pixel = getDisplayValue(v, yval[y]);
2183 float s0 = 0, s1 = 0; 2177
2184 2178 assert(x <= m_drawBuffer.width());
2185 if (!getXBinRange(v, x0 + x, s0, s1)) { 2179 QColor c = m_palette.getColour(pixel);
2186 #ifdef DEBUG_SPECTROGRAM_REPAINT 2180 m_drawBuffer.setPixel(x, y,
2187 std::cerr << "Out of range at " << x0 + x << std::endl; 2181 qRgb(c.red(), c.green(), c.blue()));
2188 #endif 2182 #ifdef DEBUG_SPECTROGRAM_REPAINT
2189 assert(x <= m_drawBuffer.width()); 2183 ++pixels;
2190 continue; 2184 #endif
2191 }
2192
2193 int s0i = int(s0 + 0.001);
2194 int s1i = int(s1);
2195
2196 if (s1i >= int(fft->getWidth())) {
2197 if (s0i >= int(fft->getWidth())) {
2198 #ifdef DEBUG_SPECTROGRAM_REPAINT
2199 std::cerr << "Column " << s0i << " out of range" << std::endl;
2200 #endif
2201 continue;
2202 } else {
2203 s1i = s0i;
2204 }
2205 }
2206
2207 for (int s = s0i; s <= s1i; ++s) {
2208
2209 if (!m_synchronous) {
2210 if (!fft->isColumnAvailable(s)) {
2211 #ifdef DEBUG_SPECTROGRAM_REPAINT
2212 std::cerr << "Met unavailable column at col " << s << std::endl;
2213 #endif
2214 runOutOfData = true;
2215 break;
2216 }
2217 }
2218 /*!!!
2219 if (!fftSuspended) {
2220 fft->suspendWrites();
2221 fftSuspended = true;
2222 }
2223 */
2224 Profiler innerprof2("SpectrogramLayer::paint: 1 data column");
2225
2226 MagnitudeRange mag;
2227
2228 if (m_binDisplay == PeakFrequencies) {
2229 if (s < int(fft->getWidth()) - 1) {
2230 peaks = fft->getPeakFrequencies(FFTModel::AllPeaks,
2231 s,
2232 minbin, maxbin - 1);
2233 } else {
2234 peaks.clear();
2235 }
2236 }
2237
2238 if (m_colourScale == PhaseColourScale) {
2239 fft->getPhasesAt(s, values, minbin, maxbin - minbin + 1);
2240 } else if (m_normalizeColumns) {
2241 fft->getNormalizedMagnitudesAt(s, values, minbin, maxbin - minbin + 1);
2242 } else {
2243 fft->getMagnitudesAt(s, values, minbin, maxbin - minbin + 1);
2244 }
2245
2246 for (size_t q = minbin; q < maxbin; ++q) {
2247
2248 Profiler innerprof3("SpectrogramLayer::paint: 1 bin");
2249
2250 float y0 = yval[q + 1 - minbin];
2251 float y1 = yval[q - minbin];
2252
2253 if (m_binDisplay == PeakBins) {
2254 if (!fft->isLocalPeak(s, q)) continue;
2255 }
2256 if (m_binDisplay == PeakFrequencies) {
2257 if (peaks.find(q) == peaks.end()) continue;
2258 }
2259
2260 if (m_threshold != 0.f &&
2261 !fft->isOverThreshold(s, q, m_threshold * (m_fftSize/2))) {
2262 continue;
2263 }
2264
2265 float sprop = 1.f;
2266 if (s == s0i) sprop *= (s + 1) - s0;
2267 if (s == s1i) sprop *= s1 - s;
2268
2269 if (m_binDisplay == PeakFrequencies) {
2270 y0 = y1 = v->getYForFrequency
2271 (peaks[q], displayMinFreq, displayMaxFreq, logarithmic);
2272 }
2273
2274 int y0i = int(y0 + 0.001f);
2275 int y1i = int(y1);
2276
2277 float value = values[q - minbin];
2278
2279 if (m_colourScale != PhaseColourScale) {
2280 if (!m_normalizeColumns) {
2281 value /= (m_fftSize/2.f);
2282 }
2283 mag.sample(value);
2284 value *= m_gain;
2285 }
2286
2287 if (interpolate) {
2288
2289 int ypi = y0i;
2290 if (q < maxbin - 1) ypi = int(yval[q + 2 - minbin]);
2291
2292 for (int y = ypi; y <= y1i; ++y) {
2293
2294 if (y < 0 || y >= h) continue;
2295
2296 float yprop = sprop;
2297 float iprop = yprop;
2298
2299 if (ypi < y0i && y <= y0i) {
2300
2301 float half = float(y0i - ypi) / 2.f;
2302 float dist = y - (ypi + half);
2303
2304 if (dist >= 0) {
2305 iprop = (iprop * dist) / half;
2306 ymag[y] += iprop * value;
2307 }
2308 } else {
2309 if (y1i > y0i) {
2310
2311 float half = float(y1i - y0i) / 2.f;
2312 float dist = y - (y0i + half);
2313
2314 if (dist >= 0) {
2315 iprop = (iprop * (half - dist)) / half;
2316 }
2317 }
2318
2319 ymag[y] += iprop * value;
2320 ydiv[y] += yprop;
2321 }
2322 }
2323
2324 } else {
2325
2326 for (int y = y0i; y <= y1i; ++y) {
2327
2328 if (y < 0 || y >= h) continue;
2329
2330 float yprop = sprop;
2331 if (y == y0i) yprop *= (y + 1) - y0;
2332 if (y == y1i) yprop *= y1 - y;
2333
2334 for (int y = y0i; y <= y1i; ++y) {
2335
2336 if (y < 0 || y >= h) continue;
2337
2338 float yprop = sprop;
2339 if (y == y0i) yprop *= (y + 1.f) - y0;
2340 if (y == y1i) yprop *= y1 - y;
2341 ymag[y] += yprop * value;
2342 ydiv[y] += yprop;
2343 }
2344 }
2345 }
2346 }
2347
2348 if (mag.isSet()) {
2349
2350 if (s >= int(m_columnMags.size())) {
2351 std::cerr << "INTERNAL ERROR: " << s << " >= "
2352 << m_columnMags.size() << " at SpectrogramLayer.cpp:2087" << std::endl;
2353 }
2354
2355 m_columnMags[s].sample(mag);
2356
2357 if (overallMag.sample(mag)) {
2358 //!!! scaling would change here
2359 overallMagChanged = true;
2360 #ifdef DEBUG_SPECTROGRAM_REPAINT
2361 std::cerr << "Overall mag changed (again?) at column " << s << ", to [" << overallMag.getMin() << "->" << overallMag.getMax() << "]" << std::endl;
2362 #endif
2363 }
2364 }
2365 }
2366
2367 Profiler drawbufferprof("SpectrogramLayer::paint: set buffer pixels");
2368
2369 for (int y = 0; y < h; ++y) {
2370
2371 if (ydiv[y] > 0.0) {
2372
2373 unsigned char pixel = 0;
2374
2375 float avg = ymag[y] / ydiv[y];
2376 pixel = getDisplayValue(v, avg);
2377
2378 assert(x <= m_drawBuffer.width());
2379 QColor c = m_palette.getColour(pixel);
2380 m_drawBuffer.setPixel(x, y,
2381 qRgb(c.red(), c.green(), c.blue()));
2382 #ifdef DEBUG_SPECTROGRAM_REPAINT
2383 ++pixels;
2384 #endif
2385 }
2386 } 2185 }
2387 } 2186 }
2388 2187
2389 #ifdef DEBUG_SPECTROGRAM_REPAINT 2188 #ifdef DEBUG_SPECTROGRAM_REPAINT
2390 std::cerr << pixels << " pixels drawn" << std::endl; 2189 std::cerr << pixels << " pixels drawn" << std::endl;
2487 m_lastPaintTime = RealTime::fromTimeval(tv) - mainPaintStart; 2286 m_lastPaintTime = RealTime::fromTimeval(tv) - mainPaintStart;
2488 } 2287 }
2489 2288
2490 //!!! if (fftSuspended) fft->resume(); 2289 //!!! if (fftSuspended) fft->resume();
2491 } 2290 }
2291
2292
2293 bool
2294 SpectrogramLayer::getColumnValues(View *v,
2295 FFTModel *fft,
2296 int x0,
2297 int x,
2298 int minbin,
2299 int maxbin,
2300 float displayMinFreq,
2301 float displayMaxFreq,
2302 const int h,
2303 const float *yforbin,
2304 float *yval) const
2305 {
2306 float ymag[h];
2307 float ydiv[h];
2308 float values[maxbin - minbin + 1];
2309
2310 bool logarithmic = (m_frequencyScale == LogFrequencyScale);
2311
2312 bool interpolate = false;
2313 Preferences::SpectrogramSmoothing smoothing =
2314 Preferences::getInstance()->getSpectrogramSmoothing();
2315 if (smoothing == Preferences::SpectrogramInterpolated ||
2316 smoothing == Preferences::SpectrogramZeroPaddedAndInterpolated) {
2317 if (m_binDisplay != PeakBins &&
2318 m_binDisplay != PeakFrequencies) {
2319 interpolate = true;
2320 }
2321 }
2322
2323 for (int y = 0; y < h; ++y) {
2324 ymag[y] = 0.f;
2325 ydiv[y] = 0.f;
2326 }
2327
2328 float s0 = 0, s1 = 0;
2329
2330 if (!getXBinRange(v, x0 + x, s0, s1)) {
2331 #ifdef DEBUG_SPECTROGRAM_REPAINT
2332 std::cerr << "Out of range at " << x0 + x << std::endl;
2333 #endif
2334 assert(x <= m_drawBuffer.width());
2335 return false;
2336 }
2337
2338 int s0i = int(s0 + 0.001);
2339 int s1i = int(s1);
2340
2341 if (s1i >= int(fft->getWidth())) {
2342 if (s0i >= int(fft->getWidth())) {
2343 #ifdef DEBUG_SPECTROGRAM_REPAINT
2344 std::cerr << "Column " << s0i << " out of range" << std::endl;
2345 #endif
2346 return false;
2347 } else {
2348 s1i = s0i;
2349 }
2350 }
2351
2352 FFTModel::PeakSet peaks;
2353
2354 for (int s = s0i; s <= s1i; ++s) {
2355
2356 if (!m_synchronous) {
2357 if (!fft->isColumnAvailable(s)) {
2358 #ifdef DEBUG_SPECTROGRAM_REPAINT
2359 std::cerr << "Met unavailable column at col " << s << std::endl;
2360 #endif
2361 return false;
2362 }
2363 }
2364 /*!!!
2365 if (!fftSuspended) {
2366 fft->suspendWrites();
2367 fftSuspended = true;
2368 }
2369 */
2370 Profiler innerprof2("SpectrogramLayer::paint: 1 data column");
2371
2372 MagnitudeRange mag;
2373
2374 if (m_binDisplay == PeakFrequencies) {
2375 if (s < int(fft->getWidth()) - 1) {
2376 peaks = fft->getPeakFrequencies(FFTModel::AllPeaks,
2377 s,
2378 minbin, maxbin - 1);
2379 } else {
2380 peaks.clear();
2381 }
2382 }
2383
2384 if (m_colourScale == PhaseColourScale) {
2385 fft->getPhasesAt(s, values, minbin, maxbin - minbin + 1);
2386 } else if (m_normalizeColumns) {
2387 fft->getNormalizedMagnitudesAt(s, values, minbin, maxbin - minbin + 1);
2388 } else {
2389 fft->getMagnitudesAt(s, values, minbin, maxbin - minbin + 1);
2390 }
2391
2392 for (size_t q = minbin; q < maxbin; ++q) {
2393
2394 Profiler innerprof3("SpectrogramLayer::paint: 1 bin");
2395
2396 float y0 = yforbin[q + 1 - minbin];
2397 float y1 = yforbin[q - minbin];
2398
2399 if (m_binDisplay == PeakBins) {
2400 if (!fft->isLocalPeak(s, q)) continue;
2401 }
2402 if (m_binDisplay == PeakFrequencies) {
2403 if (peaks.find(q) == peaks.end()) continue;
2404 }
2405
2406 if (m_threshold != 0.f &&
2407 !fft->isOverThreshold(s, q, m_threshold * (m_fftSize/2))) {
2408 continue;
2409 }
2410
2411 float sprop = 1.f;
2412 if (s == s0i) sprop *= (s + 1) - s0;
2413 if (s == s1i) sprop *= s1 - s;
2414
2415 if (m_binDisplay == PeakFrequencies) {
2416 y0 = y1 = v->getYForFrequency
2417 (peaks[q], displayMinFreq, displayMaxFreq, logarithmic);
2418 }
2419
2420 int y0i = int(y0 + 0.001f);
2421 int y1i = int(y1);
2422
2423 float value = values[q - minbin];
2424
2425 if (m_colourScale != PhaseColourScale) {
2426 if (!m_normalizeColumns) {
2427 value /= (m_fftSize/2.f);
2428 }
2429 mag.sample(value);
2430 value *= m_gain;
2431 }
2432
2433 if (interpolate) {
2434
2435 int ypi = y0i;
2436 if (q < maxbin - 1) ypi = int(yforbin[q + 2 - minbin]);
2437
2438 for (int y = ypi; y <= y1i; ++y) {
2439
2440 if (y < 0 || y >= h) continue;
2441
2442 float yprop = sprop;
2443 float iprop = yprop;
2444
2445 if (ypi < y0i && y <= y0i) {
2446
2447 float half = float(y0i - ypi) / 2.f;
2448 float dist = y - (ypi + half);
2449
2450 if (dist >= 0) {
2451 iprop = (iprop * dist) / half;
2452 ymag[y] += iprop * value;
2453 }
2454 } else {
2455 if (y1i > y0i) {
2456
2457 float half = float(y1i - y0i) / 2.f;
2458 float dist = y - (y0i + half);
2459
2460 if (dist >= 0) {
2461 iprop = (iprop * (half - dist)) / half;
2462 }
2463 }
2464
2465 ymag[y] += iprop * value;
2466 ydiv[y] += yprop;
2467 }
2468 }
2469
2470 } else {
2471
2472 for (int y = y0i; y <= y1i; ++y) {
2473
2474 if (y < 0 || y >= h) continue;
2475
2476 float yprop = sprop;
2477 if (y == y0i) yprop *= (y + 1) - y0;
2478 if (y == y1i) yprop *= y1 - y;
2479
2480 for (int y = y0i; y <= y1i; ++y) {
2481
2482 if (y < 0 || y >= h) continue;
2483
2484 float yprop = sprop;
2485 if (y == y0i) yprop *= (y + 1.f) - y0;
2486 if (y == y1i) yprop *= y1 - y;
2487 ymag[y] += yprop * value;
2488 ydiv[y] += yprop;
2489 }
2490 }
2491 }
2492 }
2493
2494 if (mag.isSet()) {
2495
2496 if (s >= int(m_columnMags.size())) {
2497 std::cerr << "INTERNAL ERROR: " << s << " >= "
2498 << m_columnMags.size() << " at SpectrogramLayer.cpp:2087" << std::endl;
2499 }
2500
2501 m_columnMags[s].sample(mag);
2502 /*!!!
2503 if (overallMag.sample(mag)) {
2504 //!!! scaling would change here
2505 overallMagChanged = true;
2506 #ifdef DEBUG_SPECTROGRAM_REPAINT
2507 std::cerr << "Overall mag changed (again?) at column " << s << ", to [" << overallMag.getMin() << "->" << overallMag.getMax() << "]" << std::endl;
2508 #endif
2509 }
2510 */
2511 }
2512 }
2513
2514 for (int y = 0; y < h; ++y) {
2515
2516 if (ydiv[y] > 0.0) {
2517 yval[y] = ymag[y] / ydiv[y];
2518 } else {
2519 yval[y] = 0;
2520 }
2521 }
2522
2523 return true;
2524 }
2525
2492 2526
2493 void 2527 void
2494 SpectrogramLayer::illuminateLocalFeatures(View *v, QPainter &paint) const 2528 SpectrogramLayer::illuminateLocalFeatures(View *v, QPainter &paint) const
2495 { 2529 {
2496 Profiler profiler("SpectrogramLayer::illuminateLocalFeatures"); 2530 Profiler profiler("SpectrogramLayer::illuminateLocalFeatures");