comparison layer/SpectrogramLayer.cpp @ 1058:9a13bc339fa9 spectrogram-minor-refactor

Mid-refactor to pull out the bulk of paintDrawBuffer into chunks
author Chris Cannam
date Mon, 13 Jun 2016 16:17:44 +0100
parents b4fd6c67fce5
children e1c2dcc7790e
comparison
equal deleted inserted replaced
1057:218be6cf2d4f 1058:9a13bc339fa9
2350 } 2350 }
2351 2351
2352 return columnCount; 2352 return columnCount;
2353 } 2353 }
2354 2354
2355 void
2356 SpectrogramLayer::normalise(vector<float> &values, Normalization norm) const
2357 {
2358 if (norm == NormalizeColumns ||
2359 norm == NormalizeHybrid) {
2360
2361 float max = 0.f;
2362 for (int i = 0; in_range_for(i, values); ++i) {
2363 if (i == 0 || values[i] > max) {
2364 max = values[i];
2365 }
2366 }
2367 if (max > 0.f) {
2368 float scale = 1.f / max;
2369 if (norm == NormalizeHybrid) {
2370 scale = scale * log10f(max + 1.f);
2371 }
2372 for (int i = 0; in_range_for(i, values); ++i) {
2373 values[i] *= scale;
2374 }
2375 }
2376 }
2377 }
2378
2379 vector<float>
2380 SpectrogramLayer::getColumnFromFFTModel(FFTModel *fft,
2381 int sx, // column number in model
2382 int minbin,
2383 int bincount) const
2384 {
2385 vector<float> values(bincount, 0.f);
2386
2387 if (m_colourScale == PhaseColourScale) {
2388 fft->getPhasesAt(sx, values.data(), minbin, bincount);
2389 } else {
2390 fft->getMagnitudesAt(sx, values.data(), minbin, bincount);
2391 }
2392
2393 return move(values);
2394 }
2395
2396 vector<float>
2397 SpectrogramLayer::getColumnFromGenericModel(DenseThreeDimensionalModel *model,
2398 int sx, // column number in model
2399 int minbin,
2400 int bincount) const
2401 {
2402 if (m_colourScale == PhaseColourScale) {
2403 throw std::logic_error("can't use phase scale with generic 3d model");
2404 }
2405
2406 auto col = model->getColumn(sx);
2407
2408 return move(vector<float>(col.data() + minbin,
2409 col.data() + minbin + bincount));
2410 }
2411
2412 void
2413 SpectrogramLayer::scaleColumn(vector<float> &col)
2414 {
2415 if (m_normalization != NormalizeColumns &&
2416 m_normalization != NormalizeHybrid) {
2417 float scale = 2.f / float(m_fftSize);
2418 int n = int(col.size());
2419 for (int i = 0; i < n; ++i) {
2420 col[i] *= scale;
2421 }
2422 }
2423 }
2424
2425 static bool
2426 is_peak(const vector<float> &values, int ix)
2427 {
2428 if (!in_range_for(ix-1, values)) return false;
2429 if (!in_range_for(ix+1, values)) return false;
2430 if (values[ix] < values[ix+1]) return false;
2431 if (values[ix] < values[ix-1]) return false;
2432 return true;
2433 }
2434
2435 vector<float>
2436 SpectrogramLayer::distributeColumn(const vector<float> &in,
2437 int h,
2438 const vector<double> &binfory,
2439 int minbin,
2440 bool interpolate)
2441 {
2442 vector<float> out(h, 0.f);
2443 int bins = int(in.size());
2444
2445 for (int y = 0; y < h; ++y) {
2446
2447 double sy0 = binfory[y] - minbin;
2448 double sy1 = sy0 + 1;
2449 if (y+1 < h) {
2450 sy1 = binfory[y+1] - minbin;
2451 }
2452
2453 if (interpolate && fabs(sy1 - sy0) < 1.0) {
2454
2455 double centre = (sy0 + sy1) / 2;
2456 double dist = (centre - 0.5) - rint(centre - 0.5);
2457 int bin = int(centre);
2458
2459 int other = (dist < 0 ? (bin-1) : (bin+1));
2460
2461 if (bin < 0) bin = 0;
2462 if (bin >= bins) bin = bins-1;
2463
2464 if (other < 0 || other >= bins) {
2465 other = bin;
2466 }
2467
2468 if (m_binDisplay == PeakBins) {
2469
2470 if (is_peak(in, bin)) {
2471 out[y] = in[bin];
2472 } else if (other != bin && is_peak(in, other)) {
2473 out[y] = in[other];
2474 }
2475
2476 } else {
2477
2478 double prop = 1.0 - fabs(dist);
2479
2480 double v0 = in[bin];
2481 double v1 = in[other];
2482
2483 out[y] = float(prop * v0 + (1.0 - prop) * v1);
2484 }
2485
2486 } else { // not interpolating this one
2487
2488 int by0 = int(sy0 + 0.0001);
2489 int by1 = int(sy1 + 0.0001);
2490 if (by1 < by0 + 1) by1 = by0 + 1;
2491
2492 for (int bin = by0; bin < by1; ++bin) {
2493
2494 if (m_binDisplay == PeakBins && !is_peak(in, bin)) {
2495 continue;
2496 }
2497
2498 float value = in[bin];
2499
2500 if (value > out[y] || m_colourScale == PhaseColourScale) {
2501 out[y] = value;
2502 }
2503 }
2504 }
2505 }
2506
2507 return out;
2508 }
2509
2510 void
2511 SpectrogramLayer::recordColumnExtents(const vector<float> &col,
2512 int sx, // column index, for m_columnMags
2513 MagnitudeRange &overallMag,
2514 bool &overallMagChanged)
2515 {
2516 //!!! this differs from previous logic when in peak mode - as the
2517 //!!! zeros between peaks are now sampled, where they were not
2518 //!!! before
2519
2520 if (!in_range_for(sx, m_columnMags)) {
2521 throw logic_error("sx out of range for m_columnMags");
2522 }
2523 MagnitudeRange mr;
2524 for (auto v: col) {
2525 mr.sample(v);
2526 }
2527 m_columnMags[sx] = mr;
2528 if (overallMag.sample(mr)) {
2529 overallMagChanged = true;
2530 }
2531 }
2532
2533 // order:
2534 // get column -> scale -> distribute/interpolate -> record extents -> normalise -> apply display gain
2535
2355 int 2536 int
2356 SpectrogramLayer::paintDrawBuffer(LayerGeometryProvider *v, 2537 SpectrogramLayer::paintDrawBuffer(LayerGeometryProvider *v,
2357 int w, 2538 int w,
2358 int h, 2539 int h,
2359 const vector<int> &binforx, 2540 const vector<int> &binforx,