comparison layer/SpectrogramLayer.cpp @ 1064:77564d4fff43 spectrogram-minor-refactor

Extend column logic to peak frequency display as well, and correct some scopes according to whether values are per source column or per target pixel
author Chris Cannam
date Mon, 20 Jun 2016 12:00:32 +0100
parents a0f234acd6e7
children 85e49aa7fe77
comparison
equal deleted inserted replaced
1063:a0f234acd6e7 1064:77564d4fff43
2210 2210
2211 FFTModel *fft = getFFTModel(v); 2211 FFTModel *fft = getFFTModel(v);
2212 if (!fft) return 0; 2212 if (!fft) return 0;
2213 2213
2214 FFTModel::PeakSet peakfreqs; 2214 FFTModel::PeakSet peakfreqs;
2215 2215 vector<float> preparedColumn;
2216
2216 int psx = -1; 2217 int psx = -1;
2217
2218 #ifdef __GNUC__
2219 float values[maxbin - minbin + 1];
2220 #else
2221 float *values = (float *)alloca((maxbin - minbin + 1) * sizeof(float));
2222 #endif
2223 2218
2224 int minColumns = 4; 2219 int minColumns = 4;
2225 bool haveTimeLimits = (softTimeLimit > 0.0); 2220 bool haveTimeLimits = (softTimeLimit > 0.0);
2226 double hardTimeLimit = softTimeLimit * 2.0; 2221 double hardTimeLimit = softTimeLimit * 2.0;
2227 bool overridingSoftLimit = false; 2222 bool overridingSoftLimit = false;
2250 if (x+1 < w) sx1 = binforx[x+1]; 2245 if (x+1 < w) sx1 = binforx[x+1];
2251 if (sx0 < 0) sx0 = sx1 - 1; 2246 if (sx0 < 0) sx0 = sx1 - 1;
2252 if (sx0 < 0) continue; 2247 if (sx0 < 0) continue;
2253 if (sx1 <= sx0) sx1 = sx0 + 1; 2248 if (sx1 <= sx0) sx1 = sx0 + 1;
2254 2249
2250 vector<float> pixelPeakColumn;
2251
2255 for (int sx = sx0; sx < sx1; ++sx) { 2252 for (int sx = sx0; sx < sx1; ++sx) {
2256 2253
2257 if (sx < 0 || sx >= int(fft->getWidth())) continue; 2254 if (sx < 0 || sx >= int(fft->getWidth())) {
2258 2255 continue;
2259 MagnitudeRange mag; 2256 }
2260 2257
2261 if (sx != psx) { 2258 if (sx != psx) {
2259
2260 ColumnOp::Column column;
2261
2262 column = getColumnFromFFTModel(fft,
2263 sx,
2264 minbin,
2265 maxbin - minbin + 1);
2266
2267 if (m_colourScale != PhaseColourScale) {
2268 column = ColumnOp::fftScale(column, m_fftSize);
2269 }
2270
2271 recordColumnExtents(column,
2272 sx,
2273 overallMag,
2274 overallMagChanged);
2275
2276 if (m_colourScale != PhaseColourScale) {
2277 column = ColumnOp::normalize(column, m_normalization);
2278 }
2279
2280 preparedColumn = ColumnOp::applyGain(column, m_gain);
2281
2282 psx = sx;
2283 }
2284
2285 if (sx == sx0) {
2286 pixelPeakColumn = preparedColumn;
2262 peakfreqs = fft->getPeakFrequencies(FFTModel::AllPeaks, sx, 2287 peakfreqs = fft->getPeakFrequencies(FFTModel::AllPeaks, sx,
2263 minbin, maxbin - 1); 2288 minbin, maxbin - 1);
2264 if (m_colourScale == PhaseColourScale) { 2289 } else {
2265 fft->getPhasesAt(sx, values, minbin, maxbin - minbin + 1); 2290 for (int i = 0; in_range_for(pixelPeakColumn, i); ++i) {
2266 /*!!! 2291 pixelPeakColumn[i] = std::max(pixelPeakColumn[i],
2267 } else if (m_normalization == ColumnOp::NormalizeColumns) { 2292 preparedColumn[i]);
2268 fft->getNormalizedMagnitudesAt(sx, values, minbin, maxbin - minbin + 1);
2269 } else if (m_normalization == ColumnOp::NormalizeHybrid) {
2270 float max = fft->getNormalizedMagnitudesAt
2271 (sx, values, minbin, maxbin - minbin + 1);
2272 float scale = log10f(max + 1.f);
2273 for (int i = minbin; i <= maxbin; ++i) {
2274 values[i - minbin] *= scale;
2275 }*/
2276 } else {
2277 fft->getMagnitudesAt(sx, values, minbin, maxbin - minbin + 1);
2278 }
2279 psx = sx;
2280 }
2281
2282 for (FFTModel::PeakSet::const_iterator pi = peakfreqs.begin();
2283 pi != peakfreqs.end(); ++pi) {
2284
2285 int bin = pi->first;
2286 double freq = pi->second;
2287
2288 if (bin < minbin) continue;
2289 if (bin > maxbin) break;
2290
2291 double value = values[bin - minbin];
2292
2293 if (m_colourScale != PhaseColourScale) {
2294 if (m_normalization != ColumnOp::NormalizeColumns) {
2295 value /= (m_fftSize/2.0);
2296 }
2297 mag.sample(float(value));
2298 value *= m_gain;
2299 }
2300
2301 double y = v->getYForFrequency
2302 (freq, displayMinFreq, displayMaxFreq, logarithmic);
2303
2304 int iy = int(y + 0.5);
2305 if (iy < 0 || iy >= h) continue;
2306
2307 m_drawBuffer.setPixel(x, iy, getDisplayValue(v, value));
2308 }
2309
2310 if (mag.isSet()) {
2311 if (sx >= int(m_columnMags.size())) {
2312 #ifdef DEBUG_SPECTROGRAM
2313 cerr << "INTERNAL ERROR: " << sx << " >= "
2314 << m_columnMags.size()
2315 << " at SpectrogramLayer.cpp::paintDrawBuffer"
2316 << endl;
2317 #endif
2318 } else {
2319 m_columnMags[sx].sample(mag);
2320 if (overallMag.sample(mag)) overallMagChanged = true;
2321 } 2293 }
2322 } 2294 }
2295 }
2296
2297 for (FFTModel::PeakSet::const_iterator pi = peakfreqs.begin();
2298 pi != peakfreqs.end(); ++pi) {
2299
2300 int bin = pi->first;
2301 double freq = pi->second;
2302
2303 if (bin < minbin) continue;
2304 if (bin > maxbin) break;
2305
2306 double value = pixelPeakColumn[bin - minbin];
2307
2308 double y = v->getYForFrequency
2309 (freq, displayMinFreq, displayMaxFreq, logarithmic);
2310
2311 int iy = int(y + 0.5);
2312 if (iy < 0 || iy >= h) continue;
2313
2314 m_drawBuffer.setPixel(x, iy, getDisplayValue(v, value));
2323 } 2315 }
2324 2316
2325 if (haveTimeLimits) { 2317 if (haveTimeLimits) {
2326 if (columnCount >= minColumns) { 2318 if (columnCount >= minColumns) {
2327 auto t = chrono::steady_clock::now(); 2319 auto t = chrono::steady_clock::now();
2489 2481
2490 ++columnCount; 2482 ++columnCount;
2491 2483
2492 if (binforx[x] < 0) continue; 2484 if (binforx[x] < 0) continue;
2493 2485
2494 float columnMax = 0.f;
2495
2496 int sx0 = binforx[x] / divisor; 2486 int sx0 = binforx[x] / divisor;
2497 int sx1 = sx0; 2487 int sx1 = sx0;
2498 if (x+1 < w) sx1 = binforx[x+1] / divisor; 2488 if (x+1 < w) sx1 = binforx[x+1] / divisor;
2499 if (sx0 < 0) sx0 = sx1 - 1; 2489 if (sx0 < 0) sx0 = sx1 - 1;
2500 if (sx0 < 0) continue; 2490 if (sx0 < 0) continue;
2501 if (sx1 <= sx0) sx1 = sx0 + 1; 2491 if (sx1 <= sx0) sx1 = sx0 + 1;
2502 2492
2493 vector<float> pixelPeakColumn;
2494
2503 for (int sx = sx0; sx < sx1; ++sx) { 2495 for (int sx = sx0; sx < sx1; ++sx) {
2504 2496
2505 #ifdef DEBUG_SPECTROGRAM_REPAINT 2497 #ifdef DEBUG_SPECTROGRAM_REPAINT
2506 // cerr << "sx = " << sx << endl; 2498 // cerr << "sx = " << sx << endl;
2507 #endif 2499 #endif
2508 2500
2509 if (sx < 0 || sx >= sourceModel->getWidth()) continue; 2501 if (sx < 0 || sx >= sourceModel->getWidth()) {
2510 2502 continue;
2511 MagnitudeRange mag; 2503 }
2512 2504
2513 if (sx != psx) { 2505 if (sx != psx) {
2514 2506
2515 // order: get column -> scale -> record extents -> 2507 // order:
2508 // get column -> scale -> record extents ->
2516 // normalise -> peak pick -> apply display gain -> 2509 // normalise -> peak pick -> apply display gain ->
2517 // distribute/interpolate 2510 // distribute/interpolate
2518 2511
2519 ColumnOp::Column column; 2512 ColumnOp::Column column;
2520 2513
2528 sx, 2521 sx,
2529 minbin, 2522 minbin,
2530 maxbin - minbin + 1); 2523 maxbin - minbin + 1);
2531 } 2524 }
2532 2525
2533 column = ColumnOp::fftScale(column, m_fftSize); 2526 if (m_colourScale != PhaseColourScale) {
2527 column = ColumnOp::fftScale(column, m_fftSize);
2528 }
2534 2529
2535 recordColumnExtents(column, 2530 recordColumnExtents(column,
2536 sx, 2531 sx,
2537 overallMag, 2532 overallMag,
2538 overallMagChanged); 2533 overallMagChanged);
2539 2534
2540 column = ColumnOp::normalize(column, m_normalization); 2535 if (m_colourScale != PhaseColourScale) {
2536 column = ColumnOp::normalize(column, m_normalization);
2537 }
2541 2538
2542 if (m_binDisplay == PeakBins) { 2539 if (m_binDisplay == PeakBins) {
2543 column = ColumnOp::peakPick(column); 2540 column = ColumnOp::peakPick(column);
2544 } 2541 }
2545 2542
2546 preparedColumn = 2543 preparedColumn =
2547 ColumnOp::distribute 2544 ColumnOp::distribute(ColumnOp::applyGain(column, m_gain),
2548 (ColumnOp::applyGain(column, m_gain), 2545 h,
2549 h, 2546 binfory,
2550 binfory, 2547 minbin,
2551 minbin, 2548 interpolate);
2552 interpolate);
2553 2549
2554 psx = sx; 2550 psx = sx;
2555 } 2551 }
2556 2552
2557 //!!! now peak of all preparedColumns for this pixel 2553 if (sx == sx0) {
2554 pixelPeakColumn = preparedColumn;
2555 } else {
2556 for (int i = 0; in_range_for(pixelPeakColumn, i); ++i) {
2557 pixelPeakColumn[i] = std::max(pixelPeakColumn[i],
2558 preparedColumn[i]);
2559 }
2560 }
2558 } 2561 }
2559 2562
2560 for (int y = 0; y < h; ++y) { 2563 for (int y = 0; y < h; ++y) {
2561 unsigned char pixel = getDisplayValue(v, preparedColumn[y]); 2564 m_drawBuffer.setPixel(x,
2562 m_drawBuffer.setPixel(x, h-y-1, pixel); 2565 h-y-1,
2566 getDisplayValue(v, pixelPeakColumn[y]));
2563 } 2567 }
2564 2568
2565 if (haveTimeLimits) { 2569 if (haveTimeLimits) {
2566 if (columnCount >= minColumns) { 2570 if (columnCount >= minColumns) {
2567 auto t = chrono::steady_clock::now(); 2571 auto t = chrono::steady_clock::now();