Mercurial > hg > svgui
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(); |