Mercurial > hg > svgui
comparison layer/SpectrumLayer.cpp @ 944:78c152e4db95
Merge from branch tonioni
author | Chris Cannam |
---|---|
date | Mon, 20 Apr 2015 09:12:17 +0100 |
parents | 4a578a360011 |
children | 94e4952a6774 b8187c83b93a |
comparison
equal
deleted
inserted
replaced
896:78e041e45ff0 | 944:78c152e4db95 |
---|---|
299 return; | 299 return; |
300 } | 300 } |
301 } | 301 } |
302 | 302 |
303 bool | 303 bool |
304 SpectrumLayer::getValueExtents(float &, float &, bool &, QString &) const | 304 SpectrumLayer::getValueExtents(double &, double &, bool &, QString &) const |
305 { | 305 { |
306 return false; | 306 return false; |
307 } | 307 } |
308 | 308 |
309 float | 309 double |
310 SpectrumLayer::getXForBin(int bin, int totalBins, float w) const | 310 SpectrumLayer::getXForBin(int bin, int totalBins, double w) const |
311 { | 311 { |
312 if (!m_sliceableModel) return SliceLayer::getXForBin(bin, totalBins, w); | 312 if (!m_sliceableModel) return SliceLayer::getXForBin(bin, totalBins, w); |
313 | 313 |
314 float sampleRate = m_sliceableModel->getSampleRate(); | 314 sv_samplerate_t sampleRate = m_sliceableModel->getSampleRate(); |
315 float binfreq = (sampleRate * bin) / (totalBins * 2); | 315 double binfreq = (sampleRate * bin) / (totalBins * 2); |
316 | 316 |
317 return getXForFrequency(binfreq, w); | 317 return getXForFrequency(binfreq, w); |
318 } | 318 } |
319 | 319 |
320 int | 320 int |
321 SpectrumLayer::getBinForX(float x, int totalBins, float w) const | 321 SpectrumLayer::getBinForX(double x, int totalBins, double w) const |
322 { | 322 { |
323 if (!m_sliceableModel) return SliceLayer::getBinForX(x, totalBins, w); | 323 if (!m_sliceableModel) return SliceLayer::getBinForX(x, totalBins, w); |
324 | 324 |
325 float sampleRate = m_sliceableModel->getSampleRate(); | 325 sv_samplerate_t sampleRate = m_sliceableModel->getSampleRate(); |
326 float binfreq = getFrequencyForX(x, w); | 326 double binfreq = getFrequencyForX(x, w); |
327 | 327 |
328 return int((binfreq * totalBins * 2) / sampleRate); | 328 return int((binfreq * totalBins * 2) / sampleRate); |
329 } | 329 } |
330 | 330 |
331 float | 331 double |
332 SpectrumLayer::getFrequencyForX(float x, float w) const | 332 SpectrumLayer::getFrequencyForX(double x, double w) const |
333 { | 333 { |
334 float freq = 0; | 334 double freq = 0; |
335 if (!m_sliceableModel) return 0; | 335 if (!m_sliceableModel) return 0; |
336 | 336 |
337 int sampleRate = m_sliceableModel->getSampleRate(); | 337 sv_samplerate_t sampleRate = m_sliceableModel->getSampleRate(); |
338 | 338 |
339 float maxfreq = float(sampleRate) / 2; | 339 double maxfreq = double(sampleRate) / 2; |
340 | 340 |
341 switch (m_binScale) { | 341 switch (m_binScale) { |
342 | 342 |
343 case LinearBins: | 343 case LinearBins: |
344 freq = ((x * maxfreq) / w); | 344 freq = ((x * maxfreq) / w); |
345 break; | 345 break; |
346 | 346 |
347 case LogBins: | 347 case LogBins: |
348 freq = powf(10.f, (x * log10f(maxfreq)) / w); | 348 freq = pow(10.0, (x * log10(maxfreq)) / w); |
349 break; | 349 break; |
350 | 350 |
351 case InvertedLogBins: | 351 case InvertedLogBins: |
352 freq = maxfreq - powf(10.f, ((w - x) * log10f(maxfreq)) / w); | 352 freq = maxfreq - pow(10.0, ((w - x) * log10(maxfreq)) / w); |
353 break; | 353 break; |
354 } | 354 } |
355 | 355 |
356 return freq; | 356 return freq; |
357 } | 357 } |
358 | 358 |
359 float | 359 double |
360 SpectrumLayer::getXForFrequency(float freq, float w) const | 360 SpectrumLayer::getXForFrequency(double freq, double w) const |
361 { | 361 { |
362 float x = 0; | 362 double x = 0; |
363 if (!m_sliceableModel) return x; | 363 if (!m_sliceableModel) return x; |
364 | 364 |
365 int sampleRate = m_sliceableModel->getSampleRate(); | 365 sv_samplerate_t sampleRate = m_sliceableModel->getSampleRate(); |
366 | 366 |
367 float maxfreq = float(sampleRate) / 2; | 367 double maxfreq = double(sampleRate) / 2; |
368 | 368 |
369 switch (m_binScale) { | 369 switch (m_binScale) { |
370 | 370 |
371 case LinearBins: | 371 case LinearBins: |
372 x = (freq * w) / maxfreq; | 372 x = (freq * w) / maxfreq; |
373 break; | 373 break; |
374 | 374 |
375 case LogBins: | 375 case LogBins: |
376 x = (log10f(freq) * w) / log10f(maxfreq); | 376 x = (log10(freq) * w) / log10(maxfreq); |
377 break; | 377 break; |
378 | 378 |
379 case InvertedLogBins: | 379 case InvertedLogBins: |
380 if (maxfreq == freq) x = w; | 380 if (maxfreq == freq) x = w; |
381 else x = w - (log10f(maxfreq - freq) * w) / log10f(maxfreq); | 381 else x = w - (log10(maxfreq - freq) * w) / log10(maxfreq); |
382 break; | 382 break; |
383 } | 383 } |
384 | 384 |
385 return x; | 385 return x; |
386 } | 386 } |
387 | 387 |
388 bool | 388 bool |
389 SpectrumLayer::getXScaleValue(const View *v, int x, | 389 SpectrumLayer::getXScaleValue(const View *v, int x, |
390 float &value, QString &unit) const | 390 double &value, QString &unit) const |
391 { | 391 { |
392 if (m_xorigins.find(v) == m_xorigins.end()) return false; | 392 if (m_xorigins.find(v) == m_xorigins.end()) return false; |
393 int xorigin = m_xorigins.find(v)->second; | 393 int xorigin = m_xorigins.find(v)->second; |
394 value = getFrequencyForX(x - xorigin, v->width() - xorigin - 1); | 394 value = getFrequencyForX(x - xorigin, v->width() - xorigin - 1); |
395 unit = "Hz"; | 395 unit = "Hz"; |
396 return true; | 396 return true; |
397 } | 397 } |
398 | 398 |
399 bool | 399 bool |
400 SpectrumLayer::getYScaleValue(const View *v, int y, | 400 SpectrumLayer::getYScaleValue(const View *v, int y, |
401 float &value, QString &unit) const | 401 double &value, QString &unit) const |
402 { | 402 { |
403 value = getValueForY(y, v); | 403 value = getValueForY(y, v); |
404 | 404 |
405 if (m_energyScale == dBScale || m_energyScale == MeterScale) { | 405 if (m_energyScale == dBScale || m_energyScale == MeterScale) { |
406 | 406 |
407 if (value > 0.f) { | 407 if (value > 0.0) { |
408 value = 10.f * log10f(value); | 408 value = 10.0 * log10(value); |
409 if (value < m_threshold) value = m_threshold; | 409 if (value < m_threshold) value = m_threshold; |
410 } else value = m_threshold; | 410 } else value = m_threshold; |
411 | 411 |
412 unit = "dBV"; | 412 unit = "dBV"; |
413 | 413 |
418 return true; | 418 return true; |
419 } | 419 } |
420 | 420 |
421 bool | 421 bool |
422 SpectrumLayer::getYScaleDifference(const View *v, int y0, int y1, | 422 SpectrumLayer::getYScaleDifference(const View *v, int y0, int y1, |
423 float &diff, QString &unit) const | 423 double &diff, QString &unit) const |
424 { | 424 { |
425 bool rv = SliceLayer::getYScaleDifference(v, y0, y1, diff, unit); | 425 bool rv = SliceLayer::getYScaleDifference(v, y0, y1, diff, unit); |
426 if (rv && (unit == "dBV")) unit = "dB"; | 426 if (rv && (unit == "dBV")) unit = "dB"; |
427 return rv; | 427 return rv; |
428 } | 428 } |
490 int w = v->width() - xorigin - 1; | 490 int w = v->width() - xorigin - 1; |
491 | 491 |
492 paint.drawLine(xorigin, cursorPos.y(), v->width(), cursorPos.y()); | 492 paint.drawLine(xorigin, cursorPos.y(), v->width(), cursorPos.y()); |
493 paint.drawLine(cursorPos.x(), cursorPos.y(), cursorPos.x(), v->height()); | 493 paint.drawLine(cursorPos.x(), cursorPos.y(), cursorPos.x(), v->height()); |
494 | 494 |
495 float fundamental = getFrequencyForX(cursorPos.x() - xorigin, w); | 495 double fundamental = getFrequencyForX(cursorPos.x() - xorigin, w); |
496 | 496 |
497 int hoffset = 2; | 497 int hoffset = 2; |
498 if (m_binScale == LogBins) hoffset = 13; | 498 if (m_binScale == LogBins) hoffset = 13; |
499 | 499 |
500 v->drawVisibleText(paint, | 500 v->drawVisibleText(paint, |
510 v->height() - 2 - hoffset, | 510 v->height() - 2 - hoffset, |
511 pitchLabel, | 511 pitchLabel, |
512 View::OutlinedText); | 512 View::OutlinedText); |
513 } | 513 } |
514 | 514 |
515 float value = getValueForY(cursorPos.y(), v); | 515 double value = getValueForY(cursorPos.y(), v); |
516 float thresh = m_threshold; | 516 double thresh = m_threshold; |
517 float db = thresh; | 517 double db = thresh; |
518 if (value > 0.f) db = 10.f * log10f(value); | 518 if (value > 0.0) db = 10.0 * log10(value); |
519 if (db < thresh) db = thresh; | 519 if (db < thresh) db = thresh; |
520 | 520 |
521 v->drawVisibleText(paint, | 521 v->drawVisibleText(paint, |
522 xorigin + 2, | 522 xorigin + 2, |
523 cursorPos.y() - 2, | 523 cursorPos.y() - 2, |
532 | 532 |
533 int harmonic = 2; | 533 int harmonic = 2; |
534 | 534 |
535 while (harmonic < 100) { | 535 while (harmonic < 100) { |
536 | 536 |
537 float hx = lrintf(getXForFrequency(fundamental * harmonic, w)); | 537 int hx = int(lrint(getXForFrequency(fundamental * harmonic, w))); |
538 hx += xorigin; | 538 hx += xorigin; |
539 | 539 |
540 if (hx < xorigin || hx > v->width()) break; | 540 if (hx < xorigin || hx > v->width()) break; |
541 | 541 |
542 int len = 7; | 542 int len = 7; |
547 } else { | 547 } else { |
548 len = 10; | 548 len = 10; |
549 } | 549 } |
550 } | 550 } |
551 | 551 |
552 paint.drawLine(int(hx), | 552 paint.drawLine(hx, |
553 cursorPos.y(), | 553 cursorPos.y(), |
554 int(hx), | 554 hx, |
555 cursorPos.y() + len); | 555 cursorPos.y() + len); |
556 | 556 |
557 ++harmonic; | 557 ++harmonic; |
558 } | 558 } |
559 | 559 |
569 QString genericDesc = SliceLayer::getFeatureDescriptionAux | 569 QString genericDesc = SliceLayer::getFeatureDescriptionAux |
570 (v, p, false, minbin, maxbin, range); | 570 (v, p, false, minbin, maxbin, range); |
571 | 571 |
572 if (genericDesc == "") return ""; | 572 if (genericDesc == "") return ""; |
573 | 573 |
574 float minvalue = 0.f; | 574 double minvalue = 0.f; |
575 if (minbin < int(m_values.size())) minvalue = m_values[minbin]; | 575 if (minbin < int(m_values.size())) minvalue = m_values[minbin]; |
576 | 576 |
577 float maxvalue = minvalue; | 577 double maxvalue = minvalue; |
578 if (maxbin < int(m_values.size())) maxvalue = m_values[maxbin]; | 578 if (maxbin < int(m_values.size())) maxvalue = m_values[maxbin]; |
579 | 579 |
580 if (minvalue > maxvalue) std::swap(minvalue, maxvalue); | 580 if (minvalue > maxvalue) std::swap(minvalue, maxvalue); |
581 | 581 |
582 QString binstr; | 582 QString binstr; |
583 QString hzstr; | 583 QString hzstr; |
584 int minfreq = lrintf((minbin * m_sliceableModel->getSampleRate()) / | 584 int minfreq = int(lrint((minbin * m_sliceableModel->getSampleRate()) / |
585 m_windowSize); | 585 m_windowSize)); |
586 int maxfreq = lrintf((std::max(maxbin, minbin+1) | 586 int maxfreq = int(lrint((std::max(maxbin, minbin+1) |
587 * m_sliceableModel->getSampleRate()) / | 587 * m_sliceableModel->getSampleRate()) / |
588 m_windowSize); | 588 m_windowSize)); |
589 | 589 |
590 if (maxbin != minbin) { | 590 if (maxbin != minbin) { |
591 binstr = tr("%1 - %2").arg(minbin+1).arg(maxbin+1); | 591 binstr = tr("%1 - %2").arg(minbin+1).arg(maxbin+1); |
592 } else { | 592 } else { |
593 binstr = QString("%1").arg(minbin+1); | 593 binstr = QString("%1").arg(minbin+1); |
604 } else { | 604 } else { |
605 valuestr = QString("%1").arg(minvalue); | 605 valuestr = QString("%1").arg(minvalue); |
606 } | 606 } |
607 | 607 |
608 QString dbstr; | 608 QString dbstr; |
609 float mindb = AudioLevel::multiplier_to_dB(minvalue); | 609 double mindb = AudioLevel::multiplier_to_dB(minvalue); |
610 float maxdb = AudioLevel::multiplier_to_dB(maxvalue); | 610 double maxdb = AudioLevel::multiplier_to_dB(maxvalue); |
611 QString mindbstr; | 611 QString mindbstr; |
612 QString maxdbstr; | 612 QString maxdbstr; |
613 if (mindb == AudioLevel::DB_FLOOR) { | 613 if (mindb == AudioLevel::DB_FLOOR) { |
614 mindbstr = tr("-Inf"); | 614 mindbstr = tr("-Inf"); |
615 } else { | 615 } else { |
616 mindbstr = QString("%1").arg(lrintf(mindb)); | 616 mindbstr = QString("%1").arg(lrint(mindb)); |
617 } | 617 } |
618 if (maxdb == AudioLevel::DB_FLOOR) { | 618 if (maxdb == AudioLevel::DB_FLOOR) { |
619 maxdbstr = tr("-Inf"); | 619 maxdbstr = tr("-Inf"); |
620 } else { | 620 } else { |
621 maxdbstr = QString("%1").arg(lrintf(maxdb)); | 621 maxdbstr = QString("%1").arg(lrint(maxdb)); |
622 } | 622 } |
623 if (lrintf(mindb) != lrintf(maxdb)) { | 623 if (lrint(mindb) != lrint(maxdb)) { |
624 dbstr = tr("%1 - %2").arg(mindbstr).arg(maxdbstr); | 624 dbstr = tr("%1 - %2").arg(mindbstr).arg(maxdbstr); |
625 } else { | 625 } else { |
626 dbstr = tr("%1").arg(mindbstr); | 626 dbstr = tr("%1").arg(mindbstr); |
627 } | 627 } |
628 | 628 |
664 } | 664 } |
665 | 665 |
666 FFTModel *fft = dynamic_cast<FFTModel *> | 666 FFTModel *fft = dynamic_cast<FFTModel *> |
667 (const_cast<DenseThreeDimensionalModel *>(m_sliceableModel)); | 667 (const_cast<DenseThreeDimensionalModel *>(m_sliceableModel)); |
668 | 668 |
669 float thresh = (powf(10, -6) / m_gain) * (m_windowSize / 2.f); // -60dB adj | 669 double thresh = (pow(10, -6) / m_gain) * (m_windowSize / 2.0); // -60dB adj |
670 | 670 |
671 int xorigin = getVerticalScaleWidth(v, false, paint) + 1; | 671 int xorigin = getVerticalScaleWidth(v, false, paint) + 1; |
672 int w = v->width() - xorigin - 1; | 672 int w = v->width() - xorigin - 1; |
673 | 673 |
674 int pkh = 0; | 674 int pkh = 0; |
682 | 682 |
683 // draw peak lines | 683 // draw peak lines |
684 | 684 |
685 // SVDEBUG << "Showing peaks..." << endl; | 685 // SVDEBUG << "Showing peaks..." << endl; |
686 | 686 |
687 int col = v->getCentreFrame() / fft->getResolution(); | 687 int col = int(v->getCentreFrame() / fft->getResolution()); |
688 | 688 |
689 paint.save(); | 689 paint.save(); |
690 paint.setRenderHint(QPainter::Antialiasing, false); | 690 paint.setRenderHint(QPainter::Antialiasing, false); |
691 paint.setPen(QColor(160, 160, 160)); //!!! | 691 paint.setPen(QColor(160, 160, 160)); //!!! |
692 | 692 |
693 int peakminbin = 0; | 693 int peakminbin = 0; |
694 int peakmaxbin = fft->getHeight() - 1; | 694 int peakmaxbin = fft->getHeight() - 1; |
695 float peakmaxfreq = Pitch::getFrequencyForPitch(128); | 695 double peakmaxfreq = Pitch::getFrequencyForPitch(128); |
696 peakmaxbin = ((peakmaxfreq * fft->getHeight() * 2) / fft->getSampleRate()); | 696 peakmaxbin = int(((peakmaxfreq * fft->getHeight() * 2) / fft->getSampleRate())); |
697 | 697 |
698 FFTModel::PeakSet peaks = fft->getPeakFrequencies | 698 FFTModel::PeakSet peaks = fft->getPeakFrequencies |
699 (FFTModel::MajorPitchAdaptivePeaks, col, peakminbin, peakmaxbin); | 699 (FFTModel::MajorPitchAdaptivePeaks, col, peakminbin, peakmaxbin); |
700 | 700 |
701 ColourMapper mapper(ColourMapper::BlackOnWhite, 0, 1); | 701 ColourMapper mapper(ColourMapper::BlackOnWhite, 0, 1); |
702 | 702 |
703 BiasCurve curve; | 703 BiasCurve curve; |
704 getBiasCurve(curve); | 704 getBiasCurve(curve); |
705 int cs = curve.size(); | 705 int cs = int(curve.size()); |
706 | 706 |
707 std::vector<float> values; | 707 std::vector<double> values; |
708 | 708 |
709 for (int bin = 0; bin < fft->getHeight(); ++bin) { | 709 for (int bin = 0; bin < fft->getHeight(); ++bin) { |
710 float value = m_sliceableModel->getValueAt(col, bin); | 710 double value = m_sliceableModel->getValueAt(col, bin); |
711 if (bin < cs) value *= curve[bin]; | 711 if (bin < cs) value *= curve[bin]; |
712 values.push_back(value); | 712 values.push_back(value); |
713 } | 713 } |
714 | 714 |
715 for (FFTModel::PeakSet::iterator i = peaks.begin(); | 715 for (FFTModel::PeakSet::iterator i = peaks.begin(); |
717 | 717 |
718 int bin = i->first; | 718 int bin = i->first; |
719 | 719 |
720 // cerr << "bin = " << bin << ", thresh = " << thresh << ", value = " << fft->getMagnitudeAt(col, bin) << endl; | 720 // cerr << "bin = " << bin << ", thresh = " << thresh << ", value = " << fft->getMagnitudeAt(col, bin) << endl; |
721 | 721 |
722 if (!fft->isOverThreshold(col, bin, thresh)) continue; | 722 if (!fft->isOverThreshold(col, bin, float(thresh))) continue; |
723 | 723 |
724 float freq = i->second; | 724 double freq = i->second; |
725 | 725 |
726 int x = lrintf(getXForFrequency(freq, w)); | 726 int x = int(lrint(getXForFrequency(freq, w))); |
727 | 727 |
728 float norm = 0.f; | 728 double norm = 0.f; |
729 (void)getYForValue(values[bin], v, norm); // don't need return value, need norm | 729 (void)getYForValue(values[bin], v, norm); // don't need return value, need norm |
730 | 730 |
731 paint.setPen(mapper.map(norm)); | 731 paint.setPen(mapper.map(norm)); |
732 paint.drawLine(xorigin + x, 0, xorigin + x, v->height() - pkh - 1); | 732 paint.drawLine(xorigin + x, 0, xorigin + x, v->height() - pkh - 1); |
733 } | 733 } |
760 int px = xorigin, ppx = xorigin; | 760 int px = xorigin, ppx = xorigin; |
761 paint.setBrush(paint.pen().color()); | 761 paint.setBrush(paint.pen().color()); |
762 | 762 |
763 for (int i = 0; i < 128; ++i) { | 763 for (int i = 0; i < 128; ++i) { |
764 | 764 |
765 float f = Pitch::getFrequencyForPitch(i); | 765 double f = Pitch::getFrequencyForPitch(i); |
766 int x = lrintf(getXForFrequency(f, w)); | 766 int x = int(lrint(getXForFrequency(f, w))); |
767 | 767 |
768 x += xorigin; | 768 x += xorigin; |
769 | 769 |
770 if (i == 0) { | 770 if (i == 0) { |
771 px = ppx = x; | 771 px = ppx = x; |
803 } | 803 } |
804 | 804 |
805 if (n == 1 || n == 3 || n == 6 || n == 8 || n == 10) { | 805 if (n == 1 || n == 3 || n == 6 || n == 8 || n == 10) { |
806 // black notes | 806 // black notes |
807 paint.drawLine(x, h - pkh, x, h); | 807 paint.drawLine(x, h - pkh, x, h); |
808 int rw = lrintf(float(x - px) / 4) * 2; | 808 int rw = int(lrint(double(x - px) / 4) * 2); |
809 if (rw < 2) rw = 2; | 809 if (rw < 2) rw = 2; |
810 paint.drawRect(x - rw/2, h - pkh, rw, pkh/2); | 810 paint.drawRect(x - rw/2, h - pkh, rw, pkh/2); |
811 } else if (n == 0 || n == 5) { | 811 } else if (n == 0 || n == 5) { |
812 // C, F | 812 // C, F |
813 if (px < w) { | 813 if (px < w) { |