19 #include "base/Profiler.h"    20 #include "base/AudioLevel.h"    21 #include "base/Window.h"    22 #include "base/Pitch.h"    23 #include "base/Preferences.h"    24 #include "base/RangeMapper.h"    25 #include "base/LogRange.h"    26 #include "base/ColumnOp.h"    27 #include "base/Strings.h"    28 #include "base/StorageAdviser.h"    29 #include "base/Exceptions.h"    31 #include "data/model/Dense3DModelPeakCache.h"    43 #include <QApplication>    44 #include <QMessageBox>    45 #include <QMouseEvent>    46 #include <QTextStream>    62     m_windowType(HanningWindow),
    68     m_initialThreshold(1.0e-8f),
    73     m_initialMaxFrequency(8000),
    74     m_verticallyFixed(false),
    76     m_colourScaleMultiple(1.0),
    78     m_colourInverted(false),
    81     m_normalization(ColumnNormalization::None),
    82     m_normalizeVisibleArea(false),
    83     m_lastEmittedZoomStep(-1),
    85     m_haveDetailedScale(false),
    89     QString colourConfigName = 
"spectrogram-colour";
   104         colourConfigName = 
"spectrogram-melodic-colour";
   117         colourConfigName = 
"spectrogram-melodic-colour";
   122     settings.beginGroup(
"Preferences");
   123     setColourMap(settings.value(colourConfigName, colourConfigDefault).toInt());
   126     Preferences *prefs = Preferences::getInstance();
   127     connect(prefs, SIGNAL(propertyChanged(PropertyContainer::PropertyName)),
   174     ModelId exporter = ModelById::add
   175         (std::make_shared<Colour3DPlotExporter>(sources, params));
   189             ModelById::getAs<Colour3DPlotExporter>(exporterId)) {
   190             exporter->discardSources();
   192         ModelById::release(exporterId);
   201 pair<ColourScaleType, double>
   228 std::pair<ColumnNormalization, bool>
   233     case 0: 
return { ColumnNormalization::None, 
false };
   234     case 1: 
return { ColumnNormalization::Max1, 
false };
   235     case 2: 
return { ColumnNormalization::None, 
true }; 
   236     case 3: 
return { ColumnNormalization::Hybrid, 
false };
   243     if (visible) 
return 2;
   245     case ColumnNormalization::None: 
return 0;
   246     case ColumnNormalization::Max1: 
return 1;
   247     case ColumnNormalization::Hybrid: 
return 3;
   249     case ColumnNormalization::Sum1:
   250     case ColumnNormalization::Range01:
   258     auto newModel = ModelById::getAs<DenseTimeValueModel>(modelId);
   259     if (!modelId.isNone() && !newModel) {
   260         throw std::logic_error(
"Not a DenseTimeValueModel");
   263     if (modelId == 
m_model) 
return;
   271         connect(newModel.get(),
   274         connect(newModel.get(),
   276                 this, SLOT(
cacheInvalid(ModelId, sv_frame_t, sv_frame_t)));
   286     list.push_back(
"Colour");
   287     list.push_back(
"Colour Scale");
   288     list.push_back(
"Window Size");
   289     list.push_back(
"Window Increment");
   290     list.push_back(
"Oversampling");
   291     list.push_back(
"Normalization");
   292     list.push_back(
"Bin Display");
   293     list.push_back(
"Threshold");
   294     list.push_back(
"Gain");
   295     list.push_back(
"Colour Rotation");
   298     list.push_back(
"Frequency Scale");
   305     if (name == 
"Colour") 
return tr(
"Colour");
   306     if (name == 
"Colour Scale") 
return tr(
"Colour Scale");
   307     if (name == 
"Window Size") 
return tr(
"Window Size");
   308     if (name == 
"Window Increment") 
return tr(
"Window Overlap");
   309     if (name == 
"Oversampling") 
return tr(
"Oversampling");
   310     if (name == 
"Normalization") 
return tr(
"Normalization");
   311     if (name == 
"Bin Display") 
return tr(
"Bin Display");
   312     if (name == 
"Threshold") 
return tr(
"Threshold");
   313     if (name == 
"Gain") 
return tr(
"Gain");
   314     if (name == 
"Colour Rotation") 
return tr(
"Colour Rotation");
   315     if (name == 
"Min Frequency") 
return tr(
"Min Frequency");
   316     if (name == 
"Max Frequency") 
return tr(
"Max Frequency");
   317     if (name == 
"Frequency Scale") 
return tr(
"Frequency Scale");
   330     if (name == 
"Gain") 
return RangeProperty;
   331     if (name == 
"Colour Rotation") 
return RangeProperty;
   332     if (name == 
"Threshold") 
return RangeProperty;
   333     if (name == 
"Colour") 
return ColourMapProperty;
   334     return ValueProperty;
   340     if (name == 
"Bin Display" ||
   341         name == 
"Frequency Scale") 
return tr(
"Bins");
   342     if (name == 
"Window Size" ||
   343         name == 
"Window Increment" ||
   344         name == 
"Oversampling") 
return tr(
"Window");
   345     if (name == 
"Colour" ||
   346         name == 
"Threshold" ||
   347         name == 
"Colour Rotation") 
return tr(
"Colour");
   348     if (name == 
"Normalization" ||
   350         name == 
"Colour Scale") 
return tr(
"Scale");
   356                                            int *min, 
int *max, 
int *deflt)
 const   360     int garbage0, garbage1, garbage2;
   361     if (!min) min = &garbage0;
   362     if (!max) max = &garbage1;
   363     if (!deflt) deflt = &garbage2;
   365     if (name == 
"Gain") {
   371         if (*deflt < *min) *deflt = *min;
   372         if (*deflt > *max) *deflt = *max;
   374         val = int(lrint(log10(
m_gain) * 20.0));
   375         if (val < *min) val = *min;
   376         if (val > *max) val = *max;
   378     } 
else if (name == 
"Threshold") {
   384         if (*deflt < *min) *deflt = *min;
   385         if (*deflt > *max) *deflt = *max;
   387         val = int(lrint(AudioLevel::multiplier_to_dB(
m_threshold)));
   388         if (val < *min) val = *min;
   389         if (val > *max) val = *max;
   391     } 
else if (name == 
"Colour Rotation") {
   399     } 
else if (name == 
"Colour Scale") {
   408     } 
else if (name == 
"Colour") {
   416     } 
else if (name == 
"Window Size") {
   424         while (ws > 32) { ws >>= 1; val ++; }
   426     } 
else if (name == 
"Window Increment") {
   434     } 
else if (name == 
"Oversampling") {
   442         while (ov > 1) { ov >>= 1; val ++; }
   444     } 
else if (name == 
"Min Frequency") {
   451         case 0: 
default: val = 0; 
break;
   452         case 10: val = 1; 
break;
   453         case 20: val = 2; 
break;
   454         case 40: val = 3; 
break;
   455         case 100: val = 4; 
break;
   456         case 250: val = 5; 
break;
   457         case 500: val = 6; 
break;
   458         case 1000: val = 7; 
break;
   459         case 4000: val = 8; 
break;
   460         case 10000: val = 9; 
break;
   463     } 
else if (name == 
"Max Frequency") {
   470         case 500: val = 0; 
break;
   471         case 1000: val = 1; 
break;
   472         case 1500: val = 2; 
break;
   473         case 2000: val = 3; 
break;
   474         case 4000: val = 4; 
break;
   475         case 6000: val = 5; 
break;
   476         case 8000: val = 6; 
break;
   477         case 12000: val = 7; 
break;
   478         case 16000: val = 8; 
break;
   479         default: val = 9; 
break;
   482     } 
else if (name == 
"Frequency Scale") {
   489     } 
else if (name == 
"Bin Display") {
   496     } 
else if (name == 
"Normalization") {
   505         val = Layer::getPropertyRangeAndValue(name, min, max, deflt);
   515     if (name == 
"Colour") {
   518     if (name == 
"Colour Scale") {
   521         case 0: 
return tr(
"Linear");
   522         case 1: 
return tr(
"Meter");
   523         case 2: 
return tr(
"dBV^2");
   524         case 3: 
return tr(
"dBV");
   525         case 4: 
return tr(
"Phase");
   528     if (name == 
"Normalization") {
   531         case 0: 
return tr(
"None");
   532         case 1: 
return tr(
"Col");
   533         case 2: 
return tr(
"View");
   534         case 3: 
return tr(
"Hybrid");
   538     if (name == 
"Window Size") {
   539         return QString(
"%1").arg(32 << value);
   541     if (name == 
"Window Increment") {
   544         case 0: 
return tr(
"None");
   545         case 1: 
return tr(
"25 %");
   546         case 2: 
return tr(
"50 %");
   547         case 3: 
return tr(
"75 %");
   548         case 4: 
return tr(
"87.5 %");
   549         case 5: 
return tr(
"93.75 %");
   552     if (name == 
"Oversampling") {
   555         case 0: 
return tr(
"1x");
   556         case 1: 
return tr(
"2x");
   557         case 2: 
return tr(
"4x");
   558         case 3: 
return tr(
"8x");
   561     if (name == 
"Min Frequency") {
   564         case 0: 
return tr(
"No min");
   565         case 1: 
return tr(
"10 Hz");
   566         case 2: 
return tr(
"20 Hz");
   567         case 3: 
return tr(
"40 Hz");
   568         case 4: 
return tr(
"100 Hz");
   569         case 5: 
return tr(
"250 Hz");
   570         case 6: 
return tr(
"500 Hz");
   571         case 7: 
return tr(
"1 KHz");
   572         case 8: 
return tr(
"4 KHz");
   573         case 9: 
return tr(
"10 KHz");
   576     if (name == 
"Max Frequency") {
   579         case 0: 
return tr(
"500 Hz");
   580         case 1: 
return tr(
"1 KHz");
   581         case 2: 
return tr(
"1.5 KHz");
   582         case 3: 
return tr(
"2 KHz");
   583         case 4: 
return tr(
"4 KHz");
   584         case 5: 
return tr(
"6 KHz");
   585         case 6: 
return tr(
"8 KHz");
   586         case 7: 
return tr(
"12 KHz");
   587         case 8: 
return tr(
"16 KHz");
   588         case 9: 
return tr(
"No max");
   591     if (name == 
"Frequency Scale") {
   594         case 0: 
return tr(
"Linear");
   595         case 1: 
return tr(
"Log");
   598     if (name == 
"Bin Display") {
   601         case 0: 
return tr(
"All Bins");
   602         case 1: 
return tr(
"Peak Bins");
   603         case 2: 
return tr(
"Frequencies");
   606     return tr(
"<unknown>");
   613     if (name == 
"Normalization") {
   616         case 0: 
return "normalise-none";
   617         case 1: 
return "normalise-columns";
   618         case 2: 
return "normalise";
   619         case 3: 
return "normalise-hybrid";
   628     if (name == 
"Gain") {
   629         return new LinearRangeMapper(-50, 50, -25, 25, tr(
"dB"));
   631     if (name == 
"Threshold") {
   632         return new LinearRangeMapper(-81, -1, -81, -1, tr(
"dB"), 
false,
   633                                      { { -81, Strings::minus_infinity } });
   641     if (name == 
"Gain") {
   642         setGain(
float(pow(10, 
float(value)/20.0)));
   643     } 
else if (name == 
"Threshold") {
   645         else setThreshold(
float(AudioLevel::dB_to_multiplier(value)));
   646     } 
else if (name == 
"Colour Rotation") {
   648     } 
else if (name == 
"Colour") {
   650     } 
else if (name == 
"Window Size") {
   652     } 
else if (name == 
"Window Increment") {
   654     } 
else if (name == 
"Oversampling") {
   656     } 
else if (name == 
"Min Frequency") {
   675     } 
else if (name == 
"Max Frequency") {
   694     } 
else if (name == 
"Colour Scale") {
   707     } 
else if (name == 
"Frequency Scale") {
   713     } 
else if (name == 
"Bin Display") {
   720     } 
else if (name == 
"Normalization") {
   730 #ifdef DEBUG_SPECTROGRAM   731     cerr << 
"SpectrogramLayer::invalidateRenderers called" << endl;
   734     for (ViewRendererMap::iterator i = 
m_renderers.begin();
   744     SVDEBUG << 
"SpectrogramLayer::preferenceChanged(" << name << 
")" << endl;
   746     if (name == 
"Window Type") {
   750     if (name == 
"Spectrogram Y Smoothing") {
   755     if (name == 
"Spectrogram X Smoothing") {
   760     if (name == 
"Tuning Frequency") {
   863     if (
m_gain == gain) 
return;
   902         throw std::logic_error(
"setMinFrequency called with value differing from the default, on SpectrogramLayer with verticallyFixed true");
   927         throw std::logic_error(
"setMaxFrequency called with value differing from the default, on SpectrogramLayer with verticallyFixed true");
   950     if (r > 256) r = 256;
   954         m_colourRotation = r;
  1095 #ifdef DEBUG_SPECTROGRAM_REPAINT  1096         cerr << 
"SpectrogramLayer::setLayerDormant(" << dormant << 
")"  1126 #ifdef DEBUG_SPECTROGRAM_REPAINT  1127     cerr << 
"SpectrogramLayer::cacheInvalid()" << endl;
  1137 #ifdef DEBUG_SPECTROGRAM_REPAINT
  1138     sv_frame_t from, sv_frame_t to
  1140     sv_frame_t     , sv_frame_t
  1144 #ifdef DEBUG_SPECTROGRAM_REPAINT  1145     cerr << 
"SpectrogramLayer::cacheInvalid(" << from << 
", " << to << 
")" << endl;
  1168     auto model = ModelById::getAs<DenseTimeValueModel>(
m_model);
  1169     if (!model) 
return 0.0;
  1171     sv_samplerate_t sr = model->getSampleRate();
  1176         if (minbin < 1) minbin = 1;
  1186     auto model = ModelById::getAs<DenseTimeValueModel>(
m_model);
  1187     if (!model) 
return 0.0;
  1189     sv_samplerate_t sr = model->getSampleRate();
  1190     double maxf = double(sr) / 2;
  1204     Profiler profiler(
"SpectrogramLayer::getYBinRange");
  1206     if (y < 0 || y >= h) 
return false;
  1215     auto model = ModelById::getAs<DenseTimeValueModel>(
m_model);
  1216     if (!model) 
return 0.0;
  1221     sv_samplerate_t sr = model->getSampleRate();
  1233     auto model = ModelById::getAs<DenseTimeValueModel>(
m_model);
  1234     if (!model) 
return 0.0;
  1236     sv_samplerate_t sr = model->getSampleRate();
  1253     auto model = ModelById::getAs<DenseTimeValueModel>(
m_model);
  1254     if (!model) 
return false;
  1256     sv_frame_t modelStart = model->getStartFrame();
  1257     sv_frame_t modelEnd = model->getEndFrame();
  1261     sv_frame_t f1 = v->
getFrameForX(x + 1) - modelStart - 1;
  1263     if (f1 < 
int(modelStart) || f0 > 
int(modelEnd)) {
  1271     s0 = double(f0) / windowIncrement;
  1272     s1 = double(f1) / windowIncrement;
  1280     auto model = ModelById::getAs<DenseTimeValueModel>(
m_model);
  1281     if (!model) 
return false;
  1283     double s0 = 0, s1 = 0;
  1286     int s0i = int(s0 + 0.001);
  1290     int w0 = s0i * windowIncrement - (
m_windowSize - windowIncrement)/2;
  1291     int w1 = s1i * windowIncrement + windowIncrement +
  1294     min = RealTime::frame2RealTime(w0, model->getSampleRate());
  1295     max = RealTime::frame2RealTime(w1, model->getSampleRate());
  1303     auto model = ModelById::getAs<DenseTimeValueModel>(
m_model);
  1304     if (!model) 
return false;
  1306     double q0 = 0, q1 = 0;
  1309     int q0i = int(q0 + 0.001);
  1312     sv_samplerate_t sr = model->getSampleRate();
  1314     for (
int q = q0i; q <= q1i; ++q) {
  1315         if (q == q0i) freqMin = (sr * q) / 
getFFTSize();
  1316         if (q == q1i) freqMax = (sr * (q+1)) / 
getFFTSize();
  1323                                              double &freqMin, 
double &freqMax,
  1324                                              double &adjFreqMin, 
double &adjFreqMax)
  1327     auto model = ModelById::getAs<DenseTimeValueModel>(
m_model);
  1328     if (!model || !model->isOK() || !model->isReady()) {
  1332     auto fft = ModelById::getAs<FFTModel>(
m_fftModel);
  1333     if (!fft) 
return false;
  1335     double s0 = 0, s1 = 0;
  1338     double q0 = 0, q1 = 0;
  1341     int s0i = int(s0 + 0.001);
  1344     int q0i = int(q0 + 0.001);
  1347     sv_samplerate_t sr = model->getSampleRate();
  1349     bool haveAdj = 
false;
  1354     for (
int q = q0i; q <= q1i; ++q) {
  1356         for (
int s = s0i; s <= s1i; ++s) {
  1358             double binfreq = (double(sr) * q) / 
getFFTSize();
  1359             if (q == q0i) freqMin = binfreq;
  1360             if (q == q1i) freqMax = binfreq;
  1362             if (peaksOnly && !fft->isLocalPeak(s, q)) 
continue;
  1364             if (!fft->isOverThreshold
  1369             double freq = binfreq;
  1371             if (s < 
int(fft->getWidth()) - 1) {
  1373                 fft->estimateStableFrequency(s, q, freq);
  1375                 if (!haveAdj || freq < adjFreqMin) adjFreqMin = freq;
  1376                 if (!haveAdj || freq > adjFreqMax) adjFreqMax = freq;
  1384         adjFreqMin = adjFreqMax = 0.0;
  1392                                       double &min, 
double &max,
  1393                                       double &phaseMin, 
double &phaseMax)
 const  1395     auto model = ModelById::getAs<DenseTimeValueModel>(
m_model);
  1396     if (!model || !model->isOK() || !model->isReady()) {
  1400     double q0 = 0, q1 = 0;
  1403     double s0 = 0, s1 = 0;
  1406     int q0i = int(q0 + 0.001);
  1409     int s0i = int(s0 + 0.001);
  1414     auto fft = ModelById::getAs<FFTModel>(
m_fftModel);
  1418         int cw = fft->getWidth();
  1419         int ch = fft->getHeight();
  1427         for (
int q = q0i; q <= q1i; ++q) {
  1428             for (
int s = s0i; s <= s1i; ++s) {
  1429                 if (s >= 0 && q >= 0 && s < cw && q < ch) {
  1433                     value = fft->getPhaseAt(s, q);
  1434                     if (!have || value < phaseMin) { phaseMin = value; }
  1435                     if (!have || value > phaseMax) { phaseMax = value; }
  1437                     value = fft->getMagnitudeAt(s, q) / (
getFFTSize()/2.0);
  1438                     if (!have || value < min) { min = value; }
  1439                     if (!have || value > max) { max = value; }
  1457     SVDEBUG << 
"SpectrogramLayer::recreateFFTModel called" << endl;
  1460         auto model = ModelById::getAs<DenseTimeValueModel>(
m_model);
  1461         if (!model || !model->isOK()) {
  1469     auto newFFTModel = std::make_shared<FFTModel>(
m_model,
  1476     if (!newFFTModel->isOK()) {
  1477         QMessageBox::critical
  1478             (
nullptr, tr(
"FFT cache failed"),
  1479              tr(
"Failed to create the FFT model for this spectrogram.\n"  1480                 "There may be insufficient memory or disc space to continue."));
  1490     bool createWholeCache = 
false;
  1493     if (createWholeCache) {
  1495         auto whole = std::make_shared<Dense3DModelPeakCache>(
m_fftModel, 1);
  1498         auto peaks = std::make_shared<Dense3DModelPeakCache>(
m_fftModel,
  1504         auto peaks = std::make_shared<Dense3DModelPeakCache>(
m_fftModel,
  1512                                   bool *createWholeCache)
 const  1514     *suggestedPeakDivisor = 8;
  1515     *createWholeCache = 
false;
  1517     auto fftModel = ModelById::getAs<FFTModel>(
m_fftModel);
  1518     if (!fftModel) 
return;
  1521         size_t(fftModel->getWidth()) *
  1522         size_t(fftModel->getHeight()) *
  1526         SVDEBUG << 
"Requesting advice from StorageAdviser on whether to create whole-model cache" << endl;
  1532         StorageAdviser::Recommendation recommendation =
  1533             StorageAdviser::recommend
  1534             (StorageAdviser::Criteria(StorageAdviser::SpeedCritical |
  1535                                       StorageAdviser::PrecisionCritical |
  1536                                       StorageAdviser::FrequentLookupLikely),
  1537              (sz / 8) / 1024, sz / 1024);
  1538         if (recommendation & StorageAdviser::UseDisc) {
  1539             SVDEBUG << 
"Seems inadvisable to create whole-model cache" << endl;
  1540         } 
else if (recommendation & StorageAdviser::ConserveSpace) {
  1541             SVDEBUG << 
"Seems inadvisable to create whole-model cache but acceptable to use the slightly higher-resolution peak cache" << endl;
  1542             *suggestedPeakDivisor = 4;
  1544             SVDEBUG << 
"Seems fine to create whole-model cache" << endl;
  1545             *createWholeCache = 
true;
  1547     } 
catch (
const InsufficientDiscSpace &) {
  1548         SVDEBUG << 
"Seems like a terrible idea to create whole-model cache" << endl;
  1561 #ifdef DEBUG_SPECTROGRAM  1562     cerr << 
"SpectrogramLayer::invalidateMagnitudes called" << endl;
  1576     int viewId = v->
getId();
  1597         double minValue = 0.0f;
  1598         double maxValue = 1.0f;
  1608         if (maxValue <= minValue) {
  1609             maxValue = minValue + 0.1f;
  1636         Preferences::SpectrogramSmoothing smoothing = 
  1637             Preferences::getInstance()->getSpectrogramSmoothing();
  1639             (smoothing != Preferences::NoSpectrogramSmoothing);
  1657     MagnitudeRange magRange;
  1658     int viewId = v->
getId();
  1662     if (continuingPaint) {
  1668         result = renderer->
render(v, paint, rect);
  1674 #ifdef DEBUG_SPECTROGRAM_REPAINT  1675         cerr << 
"rect width from this paint: " << result.
rendered.width()
  1676              << 
", mag range in this paint: " << result.
range.getMin() << 
" -> "  1677              << result.
range.getMax() << endl;
  1681         if (uncached.width() > 0) {
  1686     magRange.sample(result.
range);
  1688     if (magRange.isSet()) {
  1691 #ifdef DEBUG_SPECTROGRAM_REPAINT  1692             cerr << 
"mag range in this view has changed: "  1693                  << magRange.getMin() << 
" -> " << magRange.getMax() << endl;
  1700 #ifdef DEBUG_SPECTROGRAM_REPAINT  1701         cerr << 
"mag range has changed from last rendered range: re-rendering"  1713     Profiler profiler(
"SpectrogramLayer::paint", 
false);
  1715 #ifdef DEBUG_SPECTROGRAM_REPAINT  1716     cerr << 
"SpectrogramLayer::paint() entering: m_model is " << 
m_model << 
", zoom level is " << v->
getZoomLevel() << endl;
  1718     cerr << 
"SpectrogramLayer::paint(): rect is " << rect.x() << 
"," << rect.y() << 
" " << rect.width() << 
"x" << rect.height() << endl;
  1721     auto model = ModelById::getAs<DenseTimeValueModel>(
m_model);
  1722     if (!model || !model->isOK() || !model->isReady()) {
  1734     Profiler profiler(
"SpectrogramLayer::illuminateLocalFeatures");
  1736     auto model = ModelById::getAs<DenseTimeValueModel>(
m_model);
  1743 #ifdef DEBUG_SPECTROGRAM_REPAINT  1744     cerr << 
"SpectrogramLayer: illuminateLocalFeatures("  1745               << localPos.x() << 
"," << localPos.y() << 
")" << endl;
  1754         int s0i = int(s0 + 0.001);
  1763 #ifdef DEBUG_SPECTROGRAM_REPAINT  1764         cerr << 
"SpectrogramLayer: illuminate "  1765                   << x0 << 
"," << y1 << 
" -> " << x1 << 
"," << y0 << endl;
  1772         paint.drawRect(x0, y1, x1 - x0 + 1, y0 - y1 + 1);
  1797     auto fftModel = ModelById::getAs<FFTModel>(
m_fftModel);
  1798     if (!fftModel) 
return 100;
  1799     int completion = fftModel->getCompletion();
  1800 #ifdef DEBUG_SPECTROGRAM_REPAINT  1801     cerr << 
"SpectrogramLayer::getCompletion: completion = " << completion << endl;
  1809     auto fftModel = ModelById::getAs<FFTModel>(
m_fftModel);
  1810     if (!fftModel) 
return "";
  1811     return fftModel->getError();
  1816                                   bool &logarithmic, QString &unit)
 const  1818     auto model = ModelById::getAs<DenseTimeValueModel>(
m_model);
  1819     if (!model) 
return false;
  1821     sv_samplerate_t sr = model->getSampleRate();
  1823     max = double(sr) / 2;
  1843     auto model = ModelById::getAs<DenseTimeValueModel>(
m_model);
  1844     if (!model) 
return false;
  1848     if (min < 0) min = 0;
  1849     if (max > model->getSampleRate()/2.0) max = model->getSampleRate()/2.0;
  1851     int minf = int(lrint(min));
  1852     int maxf = int(lrint(max));
  1861         throw std::logic_error(
"setDisplayExtents called with values differing from the defaults, on SpectrogramLayer with verticallyFixed true");
  1880                                  double &value, QString &unit)
 const  1894     sv_frame_t left = (frame / resolution) * resolution;
  1895     sv_frame_t right = left + resolution;
  1898     case SnapLeft:  frame = left;  
break;
  1901         if (frame - left > right - frame) frame = right;
  1913     if (!renderer) 
return;
  1916     if (rect.isValid()) {
  1927                                       vector<QRect> &extents)
 const  1932 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"  1935     extents.push_back(vertical);
  1937     QRect horizontal(0, cursorPos.y(), cursorPos.x(), 1);
  1938     extents.push_back(horizontal);
  1942     QRect freq(sw, cursorPos.y() - paint.fontMetrics().ascent() - 2,
  1943                paint.fontMetrics().width(
"123456 Hz") + 2,
  1944                paint.fontMetrics().height());
  1945     extents.push_back(freq);
  1947     QRect pitch(sw, cursorPos.y() + 2,
  1948                 paint.fontMetrics().width(
"C#10+50c") + 2,
  1949                 paint.fontMetrics().height());
  1950     extents.push_back(pitch);
  1952     QRect rt(cursorPos.x(),
  1954              paint.fontMetrics().width(
"1234.567 s"),
  1955              paint.fontMetrics().height());
  1956     extents.push_back(rt);
  1958     int w(paint.fontMetrics().width(
"1234567890") + 2);
  1959     QRect frame(cursorPos.x() - w - 2,
  1962                 paint.fontMetrics().height());
  1963     extents.push_back(frame);
  1970                                   QPoint cursorPos)
 const  1972     auto model = ModelById::getAs<DenseTimeValueModel>(
m_model);
  1979     QFont fn = paint.font();
  1980     if (fn.pointSize() > 8) {
  1981         fn.setPointSize(fn.pointSize() - 1);
  1986     paint.drawLine(0, cursorPos.y(), cursorPos.x() - 1, cursorPos.y());
  1987     paint.drawLine(cursorPos.x(), 0, cursorPos.x(), v->
getPaintHeight());
  1995          QString(
"%1 Hz").arg(fundamental),
  1998     if (Pitch::isFrequencyInMidiRange(fundamental)) {
  1999         QString pitchLabel = Pitch::getPitchLabelForFrequency(fundamental);
  2003              cursorPos.y() + paint.fontMetrics().ascent() + 2,
  2009     RealTime rt = RealTime::frame2RealTime(frame, model->getSampleRate());
  2010     QString rtLabel = QString(
"%1 s").arg(rt.toText(
true).c_str());
  2011     QString frameLabel = QString(
"%1").arg(frame);
  2014          cursorPos.x() - paint.fontMetrics().width(frameLabel) - 2,
  2027     while (harmonic < 100) {
  2034         if (harmonic % 2 == 0) {
  2035             if (harmonic % 4 == 0) {
  2042         paint.drawLine(cursorPos.x() - len,
  2059     auto model = ModelById::getAs<DenseTimeValueModel>(
m_model);
  2060     if (!model || !model->isOK()) 
return "";
  2062     double magMin = 0, magMax = 0;
  2063     double phaseMin = 0, phaseMax = 0;
  2064     double freqMin = 0, freqMax = 0;
  2065     double adjFreqMin = 0, adjFreqMax = 0;
  2066     QString pitchMin, pitchMax;
  2067     RealTime rtMin, rtMax;
  2069     bool haveValues = 
false;
  2078     QString adjFreqText = 
"", adjPitchText = 
"";
  2083                                         adjFreqMin, adjFreqMax)) {
  2087         if (adjFreqMin != adjFreqMax) {
  2088             adjFreqText = tr(
"Peak Frequency:\t%1 - %2 Hz\n")
  2089                 .arg(adjFreqMin).arg(adjFreqMax);
  2091             adjFreqText = tr(
"Peak Frequency:\t%1 Hz\n")
  2095         QString pmin = Pitch::getPitchLabelForFrequency(adjFreqMin);
  2096         QString pmax = Pitch::getPitchLabelForFrequency(adjFreqMax);
  2099             adjPitchText = tr(
"Peak Pitch:\t%3 - %4\n").arg(pmin).arg(pmax);
  2101             adjPitchText = tr(
"Peak Pitch:\t%2\n").arg(pmin);
  2111     if (rtMin != rtMax) {
  2112         text += tr(
"Time:\t%1 - %2\n")
  2113             .arg(rtMin.toText(
true).c_str())
  2114             .arg(rtMax.toText(
true).c_str());
  2116         text += tr(
"Time:\t%1\n")
  2117             .arg(rtMin.toText(
true).c_str());
  2120     if (freqMin != freqMax) {
  2121         text += tr(
"%1Bin Frequency:\t%2 - %3 Hz\n%4Bin Pitch:\t%5 - %6\n")
  2126             .arg(Pitch::getPitchLabelForFrequency(freqMin))
  2127             .arg(Pitch::getPitchLabelForFrequency(freqMax));
  2129         text += tr(
"%1Bin Frequency:\t%2 Hz\n%3Bin Pitch:\t%4\n")
  2133             .arg(Pitch::getPitchLabelForFrequency(freqMin));
  2137         double dbMin = AudioLevel::multiplier_to_dB(magMin);
  2138         double dbMax = AudioLevel::multiplier_to_dB(magMax);
  2139         QString dbMinString;
  2140         QString dbMaxString;
  2141         if (dbMin == AudioLevel::DB_FLOOR) {
  2142             dbMinString = Strings::minus_infinity;
  2144             dbMinString = QString(
"%1").arg(lrint(dbMin));
  2146         if (dbMax == AudioLevel::DB_FLOOR) {
  2147             dbMaxString = Strings::minus_infinity;
  2149             dbMaxString = QString(
"%1").arg(lrint(dbMax));
  2151         if (lrint(dbMin) != lrint(dbMax)) {
  2152             text += tr(
"dB:\t%1 - %2").arg(dbMinString).arg(dbMaxString);
  2154             text += tr(
"dB:\t%1").arg(dbMinString);
  2156         if (phaseMin != phaseMax) {
  2157             text += tr(
"\nPhase:\t%1 - %2").arg(phaseMin).arg(phaseMax);
  2159             text += tr(
"\nPhase:\t%1").arg(phaseMin);
  2171     cw = paint.fontMetrics().width(
"-80dB");
  2179     auto model = ModelById::getAs<DenseTimeValueModel>(
m_model);
  2180     if (!model || !model->isOK()) 
return 0;
  2185     int tw = paint.fontMetrics().width(QString(
"%1")
  2188                                           model->getSampleRate() / 2));
  2190     int fw = paint.fontMetrics().width(tr(
"43Hz"));
  2191     if (tw < fw) tw = fw;
  2195     return cw + tickw + tw + 13;
  2200                                      QPainter &
paint, QRect rect)
 const  2202     auto model = ModelById::getAs<DenseTimeValueModel>(
m_model);
  2203     if (!model || !model->isOK()) {
  2207     Profiler profiler(
"SpectrogramLayer::paintVerticalScale");
  2211     int h = rect.height(), w = rect.width();
  2212     int textHeight = paint.fontMetrics().height();
  2214     if (detailed && (h > textHeight * 3 + 10)) {
  2223     sv_samplerate_t sr = model->getSampleRate();
  2234     int toff = -textHeight + paint.fontMetrics().ascent() + 2;
  2236     paint.drawLine(cw + 7, 0, cw + 7, h);
  2247         if (
int(q0) > bin) {
  2256         if (py >= 0 && (vy - py) < textHeight - 1) {
  2258                 paint.drawLine(w - tickw, h - vy, w, h - vy);
  2263         QString text = QString(
"%1").arg(freq);
  2264         if (bin == 1) text = tr(
"%1Hz").arg(freq); 
  2265         paint.drawLine(cw + 7, h - vy, w - pkw - 1, h - vy);
  2267         if (h - vy - textHeight >= -2) {
  2268             int tx = w - 3 - paint.fontMetrics().width(text) - max(tickw, pkw);
  2269             paint.drawText(tx, h - vy + toff, text);
  2280             (v, paint, QRect(w - pkw - 1, 0, pkw, h),
  2289                                      QPainter &
paint, QRect rect)
 const  2298     int h = rect.height();
  2299     int textHeight = paint.fontMetrics().height();
  2300     int toff = -textHeight + paint.fontMetrics().ascent() + 2;
  2303     int cbw = paint.fontMetrics().width(
"dB");
  2307     int ch = h - textHeight * (topLines + 1) - 8;
  2309     paint.drawRect(4 + cw - cbw, textHeight * topLines + 4, cbw - 1, ch + 1);
  2311     QString top, bottom;
  2316     if (max <= min) max = min + 0.1;
  2318     double dBmin = AudioLevel::multiplier_to_dB(min);
  2319     double dBmax = AudioLevel::multiplier_to_dB(max);
  2321 #ifdef DEBUG_SPECTROGRAM_REPAINT  2322     cerr << 
"paintVerticalScale: for view id " << v->
getId()
  2323          << 
": min = " << min << 
", max = " << max
  2324          << 
", dBmin = " << dBmin << 
", dBmax = " << dBmax << endl;
  2327     if (dBmax < -60.f) dBmax = -60.f;
  2328     else top = QString(
"%1").arg(lrint(dBmax));
  2330     if (dBmin < dBmax - 60.f) dBmin = dBmax - 60.f;
  2331     bottom = QString(
"%1").arg(lrint(dBmin));
  2333 #ifdef DEBUG_SPECTROGRAM_REPAINT  2334     cerr << 
"adjusted dB range to min = " << dBmin << 
", max = " << dBmax
  2338     paint.drawText((cw + 6 - paint.fontMetrics().width(
"dBFS")) / 2,
  2339                    2 + textHeight + toff, 
"dBFS");
  2341     paint.drawText(3 + cw - cbw - paint.fontMetrics().width(top),
  2342                    2 + textHeight * topLines + toff + textHeight/2, top);
  2344     paint.drawText(3 + cw - cbw - paint.fontMetrics().width(bottom),
  2345                    h + toff - 3 - textHeight/2, bottom);
  2348     paint.setBrush(Qt::NoBrush);
  2353     for (
int i = 0; i < ch; ++i) {
  2355         double dBval = dBmin + (((dBmax - dBmin) * i) / (ch - 1));
  2356         int idb = int(dBval);
  2358         double value = AudioLevel::dB_to_multiplier(dBval);
  2361         int y = textHeight * topLines + 4 + ch - i;
  2363         paint.drawLine(5 + cw - cbw, y, cw + 2, y);
  2368         } 
else if (i < ch - paint.fontMetrics().ascent() &&
  2370                    ((abs(y - lasty) > textHeight && 
  2372                     (abs(y - lasty) > paint.fontMetrics().ascent() && 
  2375             QString text = QString(
"%1").arg(idb);
  2376             paint.drawText(3 + cw - cbw - paint.fontMetrics().width(text),
  2377                            y + toff + textHeight/2, text);
  2378             paint.drawLine(5 + cw - cbw, y, 8 + cw - cbw, y);
  2388                                           QPainter &
paint, QRect rect)
 const  2392     int h = rect.height();
  2393     int textHeight = paint.fontMetrics().height();
  2394     int toff = -textHeight + paint.fontMetrics().ascent() + 2;
  2400     int cbw = paint.fontMetrics().width(
"dB");
  2404     int ch = h - textHeight * (topLines + 1) - 8;
  2405     paint.drawRect(4 + cw - cbw, textHeight * topLines + 4, cbw - 1, ch + 1);
  2407     QString top = Strings::pi, bottom = Strings::minus_pi, middle = 
"0";
  2412     paint.drawText(3 + cw - cbw - paint.fontMetrics().width(top),
  2413                    2 + textHeight * topLines + toff + textHeight/2, top);
  2415     paint.drawText(3 + cw - cbw - paint.fontMetrics().width(middle),
  2416                    2 + textHeight * topLines + ch/2 + toff + textHeight/2, middle);
  2418     paint.drawText(3 + cw - cbw - paint.fontMetrics().width(bottom),
  2419                    h + toff - 3 - textHeight/2, bottom);
  2422     paint.setBrush(Qt::NoBrush);
  2424     for (
int i = 0; i < ch; ++i) {
  2425         double val = min + (((max - min) * i) / (ch - 1));
  2427         int y = textHeight * topLines + 4 + ch - i;
  2428         paint.drawLine(5 + cw - cbw, y, cw + 2, y);
  2438         m_s2(sqrt(sqrt(2))) { }
  2443         double dist = m_dist;
  2447         while (dist > (value + 0.00001) && dist > 0.1) {
  2457         return getPositionForValue(value);
  2467         double dist = m_dist;
  2470         while (n < position) {
  2480         return getValueForPosition(position);
  2493     auto model = ModelById::getAs<DenseTimeValueModel>(
m_model);
  2494     if (!model) 
return 0;
  2496     sv_samplerate_t sr = model->getSampleRate();
  2505     if (initialMax == 0) initialMax = int(sr / 2);
  2511     return maxStep - minStep;
  2517     auto model = ModelById::getAs<DenseTimeValueModel>(
m_model);
  2518     if (!model) 
return 0;
  2532     auto model = ModelById::getAs<DenseTimeValueModel>(
m_model);
  2540     sv_samplerate_t sr = model->getSampleRate();
  2544     double newmin, newmax;
  2569         newmax = (newdist + sqrt(newdist*newdist + 4*dmin*dmax)) / 2;
  2570         newmin = newmax - newdist;
  2575         double dmid = (dmax + dmin) / 2;
  2576         newmin = dmid - newdist / 2;
  2577         newmax = dmid + newdist / 2;
  2582     mmax = double(sr) / 2;
  2584     if (newmin < mmin) {
  2585         newmax += (mmin - newmin);
  2588     if (newmax > mmax) {
  2601     auto model = ModelById::getAs<DenseTimeValueModel>(
m_model);
  2602     if (!model) 
return nullptr;
  2635                         QString indent, QString extraAttributes)
 const  2639     s += QString(
"channel=\"%1\" "  2640                  "windowSize=\"%2\" "  2641                  "windowHopLevel=\"%3\" "  2642                  "oversampling=\"%4\" "  2644                  "threshold=\"%6\" ")
  2652     s += QString(
"minFrequency=\"%1\" "  2653                  "maxFrequency=\"%2\" "  2654                  "colourScale=\"%3\" "  2655                  "colourRotation=\"%4\" "  2656                  "frequencyScale=\"%5\" "  2657                  "binDisplay=\"%6\" ")
  2668     s += QString(
"colourMap=\"%1\" ")
  2673     s += QString(
"colourScheme=\"%1\" ")
  2681     s += QString(
"columnNormalization=\"%1\" ")
  2691     s += QString(
"normalizeColumns=\"%1\" ")
  2692         .arg(
m_normalization == ColumnNormalization::Max1 ? 
"true" : 
"false");
  2696     s += QString(
"normalizeVisibleArea=\"%1\" ")
  2699     Layer::toXml(stream, indent, extraAttributes + 
" " + s);
  2707     int channel = attributes.value(
"channel").toInt(&ok);
  2710     int windowSize = attributes.value(
"windowSize").toUInt(&ok);
  2713     int windowHopLevel = attributes.value(
"windowHopLevel").toUInt(&ok);
  2716         int windowOverlap = attributes.value(
"windowOverlap").toUInt(&ok);
  2727     int oversampling = attributes.value(
"oversampling").toUInt(&ok);
  2730     float gain = attributes.value(
"gain").toFloat(&ok);
  2733     float threshold = attributes.value(
"threshold").toFloat(&ok);
  2736     int minFrequency = attributes.value(
"minFrequency").toUInt(&ok);
  2738         SVDEBUG << 
"SpectrogramLayer::setProperties: setting min freq to " << minFrequency << endl;
  2742     int maxFrequency = attributes.value(
"maxFrequency").toUInt(&ok);
  2744         SVDEBUG << 
"SpectrogramLayer::setProperties: setting max freq to " << maxFrequency << endl;
  2749         (attributes.value(
"colourScale").toInt(&ok));
  2755     QString colourMapId = attributes.value(
"colourMap");
  2757     if (colourMap >= 0) {
  2760         colourMap = attributes.value(
"colourScheme").toInt(&ok);
  2766     int colourRotation = attributes.value(
"colourRotation").toInt(&ok);
  2770         attributes.value(
"frequencyScale").toInt(&ok);
  2774         attributes.value(
"binDisplay").toInt(&ok);
  2777     bool haveNewStyleNormalization = 
false;
  2779     QString columnNormalization = attributes.value(
"columnNormalization");
  2781     if (columnNormalization != 
"") {
  2783         haveNewStyleNormalization = 
true;
  2785         if (columnNormalization == 
"peak") {
  2787         } 
else if (columnNormalization == 
"hybrid") {
  2789         } 
else if (columnNormalization == 
"none") {
  2792             SVCERR << 
"NOTE: Unknown or unsupported columnNormalization attribute \""  2793                  << columnNormalization << 
"\"" << endl;
  2797     if (!haveNewStyleNormalization) {
  2799         bool normalizeColumns =
  2800             (attributes.value(
"normalizeColumns").trimmed() == 
"true");
  2801         if (normalizeColumns) {
  2805         bool normalizeHybrid =
  2806             (attributes.value(
"normalizeHybrid").trimmed() == 
"true");
  2807         if (normalizeHybrid) {
  2812     bool normalizeVisibleArea =
  2813         (attributes.value(
"normalizeVisibleArea").trimmed() == 
"true");
  2816     if (!haveNewStyleNormalization && 
m_normalization == ColumnNormalization::Hybrid) {
 QString getPropertyValueLabel(const PropertyName &, int value) const override
void setChannel(int)
Specify the channel to use from the source model. 
void setColourRotation(int)
Specify the colourmap rotation for the colour scale. 
double threshold
Threshold below which every value is mapped to background pixel 0. 
virtual bool isLayerDormant(const LayerGeometryProvider *v) const 
Return whether the layer is dormant (i.e. 
RangeMapper * getNewVerticalZoomRangeMapper() const override
Create and return a range mapper for vertical zoom step values. 
void measureDoubleClick(LayerGeometryProvider *, QMouseEvent *) override
int getMaxFrequency() const 
bool getYScaleValue(const LayerGeometryProvider *, int, double &, QString &) const override
Return the value and unit at the given y coordinate in the given view. 
void setNormalizeVisibleArea(bool)
Specify whether to normalize the visible area. 
bool isLayerScrollable(const LayerGeometryProvider *) const override
This should return true if the layer can safely be scrolled automatically by a given view (simply cop...
void cacheInvalid(ModelId)
bool setDisplayExtents(double min, double max) override
Set the displayed minimum and maximum values for the y axis to the given range, if supported...
SpectrogramLayer(Configuration=FullRangeDb)
Construct a SpectrogramLayer with default parameters appropriate for the given configuration. 
ColumnNormalization normalization
Type of column normalization. 
virtual QColor getForeground() const =0
const LayerGeometryProvider * provider
ColourScale colourScale
A complete ColourScale object by value, used for colour map conversion. 
PropertyList getProperties() const override
double getYForBin(const LayerGeometryProvider *, double bin) const override
!! VerticalBinLayer methods. Note overlap with get*BinRange() 
double getFrequencyForY(const LayerGeometryProvider *v, int y) const 
void checkCacheSpace(int *suggestedPeakDivisor, bool *createWholeCache) const 
int m_lastEmittedZoomStep
int getWindowSize() const 
int getWindowIncrement() const 
virtual bool shouldIlluminateLocalFeatures(const Layer *, QPoint &) const =0
void toXml(QTextStream &stream, QString indent="", QString extraAttributes="") const override
Convert the layer's data (though not those of the model it refers to) into XML for file output...
static std::pair< ColourScaleType, double > convertToColourScale(int value)
void illuminateLocalFeatures(LayerGeometryProvider *v, QPainter &painter) const 
bool getDisplayExtents(double &min, double &max) const override
Return the minimum and maximum values within the visible area for the y axis of this layer...
double getValueForPositionUnclamped(int position) const override
virtual ZoomLevel getZoomLevel() const =0
Return the zoom level, i.e. 
RenderResult renderTimeConstrained(const LayerGeometryProvider *v, QPainter &paint, QRect rect)
Render the requested area using the given painter, obtaining geometry (e.g. 
void updateMeasureRectYCoords(LayerGeometryProvider *v, const MeasureRect &r) const override
ViewMagMap m_lastRenderedMags
int getPropertyRangeAndValue(const PropertyName &, int *min, int *max, int *deflt) const override
void setBinScale(BinScale)
Specify the scale for the y axis. 
bool getXBinSourceRange(LayerGeometryProvider *v, int x, RealTime &timeMin, RealTime &timeMax) const 
void paintWithRenderer(LayerGeometryProvider *v, QPainter &paint, QRect rect) const 
double getBinForY(const LayerGeometryProvider *, double y) const override
Return the bin number, possibly fractional, at the given y coordinate. 
int getColourScaleWidth(QPainter &) const 
void setMaxFrequency(int)
int getOversampling() const 
double scaleFactor
Initial scale factor (e.g. 
virtual double getFrequencyForY(double y, double minFreq, double maxFreq, bool logarithmic) const =0
Return the closest frequency to the given (maybe fractional) pixel y-coordinate, if the frequency ran...
Map values within a range onto a set of colours, with a given distribution (linear, log etc) and optional colourmap rotation. 
ViewRendererMap m_renderers
bool getYBinRange(LayerGeometryProvider *v, int y, double &freqBinMin, double &freqBinMax) const 
void setColourScaleMultiple(double)
Specify multiple factor for colour scale. 
void addCommand(Command *command)
Add a command to the command history. 
bool getXYBinSourceRange(LayerGeometryProvider *v, int x, int y, double &min, double &max, double &phaseMin, double &phaseMax) const 
bool m_normalizeVisibleArea
void setThreshold(float threshold)
Set the threshold for sample values to qualify for being shown in the FFT, in voltage units...
void setNormalization(ColumnNormalization)
Specify the normalization mode for individual columns. 
void setModel(ModelId model)
virtual void setLayerDormant(const LayerGeometryProvider *v, bool dormant)
Indicate that a layer is not currently visible in the given view and is not expected to become visibl...
BinDisplay binDisplay
Selection of bins to include in the export. 
int getMinFrequency() const 
void invalidateMagnitudes()
double gain
Gain that is applied before thresholding, in the display, matching the ColourScale object parameters...
virtual sv_frame_t getFrameForX(int x) const =0
Return the closest frame to the given pixel x-coordinate. 
bool geometryChanged(const LayerGeometryProvider *v)
Return true if the provider's geometry differs from the cache, or if we are not using a cache...
void setProperty(const PropertyName &, int value) override
double maxValue
Maximum value in source range. 
int colourMap
A colour map index as used by ColourMapper. 
static int getColourMapCount()
Return the number of known colour maps. 
void setVerticallyFixed()
Mark the spectrogram layer as having a fixed range in the vertical axis. 
void setWindowHopLevel(int level)
static std::pair< ColumnNormalization, bool > convertToColumnNorm(int value)
double getEffectiveMinFrequency() const 
void setColourMap(int map)
Specify the colour map. 
static int getBackwardCompatibilityColourMap(int n)
Older versions of colour-handling code save and reload colour maps by numerical index and can't prope...
bool snapToFeatureFrame(LayerGeometryProvider *v, sv_frame_t &frame, int &resolution, SnapType snap, int ycoord) const override
Adjust the given frame to snap to the nearest feature, if possible. 
void modelChanged(ModelId)
Interface for classes that provide geometry information (such as size, start frame, and a large number of other properties) about the disposition of a layer. 
static QString getColourMapLabel(int n)
Return a human-readable label for the colour map with the given index. 
int getVerticalScaleWidth(LayerGeometryProvider *v, bool detailed, QPainter &) const override
double getValueForPosition(int position) const override
void setVerticalZoomStep(int) override
Set the vertical zoom step. 
ColourScaleType getColourScale() const 
int colourRotation
Colourmap rotation, in the range 0-255. 
bool interpolate
Whether to apply smoothing when rendering cells at more than one pixel per cell. 
double gain
Gain to apply before thresholding, mapping, and clamping. 
QRect rendered
The rect that was actually rendered. 
double minValue
Minimum value in source range. 
void setMeasureRectYCoord(LayerGeometryProvider *v, MeasureRect &r, bool start, int y) const override
void setOversampling(int oversampling)
double threshold
Threshold below which every value is mapped to background pixel 0 in the display, matching the Colour...
ModelId getExportModel(LayerGeometryProvider *) const override
Return the ID of a model representing the contents of this layer in a form suitable for export to a t...
bool hasLightBackground() const 
Return true if the colour map is intended to be placed over a light background, false otherwise...
virtual double getYForFrequency(double frequency, double minFreq, double maxFreq, bool logarithmic) const =0
Return the (maybe fractional) pixel y-coordinate corresponding to a given frequency, if the frequency range is as specified. 
virtual QRect getPaintRect() const =0
To be called from a layer, to obtain the extent of the surface that the layer is currently painting t...
bool hasLightBackground() const override
static int getColourMapById(QString id)
Return the index for the colour map with the given machine-readable id string, or -1 if the id is not...
void paint(LayerGeometryProvider *v, QPainter &paint, QRect rect) const override
Paint the given rectangle of this layer onto the given view using the given painter, superimposing it on top of any existing material in that view. 
double getYForFrequency(const LayerGeometryProvider *v, double frequency) const 
void layerParametersChanged()
int getWindowHopLevel() const 
void setSynchronousPainting(bool synchronous) override
Enable or disable synchronous painting. 
void verticalZoomChanged()
ColumnNormalization m_normalization
RenderResult render(const LayerGeometryProvider *v, QPainter &paint, QRect rect)
Render the requested area using the given painter, obtaining geometry (e.g. 
void paintDetailedScale(LayerGeometryProvider *v, QPainter &paint, QRect rect) const 
QString getError(LayerGeometryProvider *v) const override
Return an error string if any errors have occurred while loading or processing data for the given vie...
void paintPianoVertical(LayerGeometryProvider *v, QPainter &paint, QRect rect, double minf, double maxf)
int getVerticalZoomSteps(int &defaultStep) const override
Get the number of vertical zoom steps available for this layer. 
bool getValueExtents(double &min, double &max, bool &logarithmic, QString &unit) const override
Return the minimum and maximum values for the y axis of the model in this layer, as well as whether t...
void preferenceChanged(PropertyContainer::PropertyName name)
QString getUnit() const override
std::vector< ModelId > m_exporters
A class for mapping intensity values onto various colour maps. 
bool alwaysOpaque
Whether cells should always be opaque. 
static CommandHistory * getInstance()
void connectSignals(ModelId)
virtual int getPaintHeight() const 
int m_initialMaxFrequency
int getPositionForValue(double value) const override
bool getYBinSourceRange(LayerGeometryProvider *v, int y, double &freqMin, double &freqMax) const 
void paintVerticalScale(LayerGeometryProvider *v, bool detailed, QPainter &paint, QRect rect) const override
ColourScaleType m_colourScale
static int convertFromColourScale(ColourScaleType type, double multiple)
ColourScaleType scaleType
Distribution for the scale. 
RangeMapper * getNewPropertyRangeMapper(const PropertyName &) const override
SpectrogramRangeMapper(sv_samplerate_t sr, int)
double scaleFactor
Initial scale factor (e.g. 
void paintDetailedScalePhase(LayerGeometryProvider *v, QPainter &paint, QRect rect) const 
void toXml(QTextStream &stream, QString indent="", QString extraAttributes="") const override
QString getPropertyIconName(const PropertyName &) const override
ColumnNormalization normalization
Type of column normalization. 
QString getPropertyGroupName(const PropertyName &) const override
bool invertVertical
Whether to render the whole caboodle upside-down. 
void setProperties(const QXmlAttributes &attributes) override
Set the particular properties of a layer (those specific to the subclass) from a set of XML attribute...
BinDisplay getBinDisplay() const 
void paintCrosshairs(LayerGeometryProvider *, QPainter &, QPoint) const override
double getEffectiveMaxFrequency() const 
virtual void updatePaintRect(QRect r)=0
Colour3DPlotRenderer * getRenderer(LayerGeometryProvider *) const 
BinScale getBinScale() const 
QString getPropertyValueIconName(const PropertyName &, int value) const override
ColumnNormalization getNormalization() const 
void setLayerDormant(const LayerGeometryProvider *v, bool dormant) override
Indicate that a layer is not currently visible in the given view and is not expected to become visibl...
void invalidateRenderers()
QRect getLargestUncachedRect(const LayerGeometryProvider *v)
Return the area of the largest rectangle within the entire area of the cache that is unavailable in t...
void setGain(float gain)
Set the gain multiplier for sample values in this view. 
virtual void setMeasureRectFromPixrect(LayerGeometryProvider *v, MeasureRect &r, QRect pixrect) const 
virtual int getId() const =0
Retrieve the id of this object. 
const VerticalBinLayer * verticalBinLayer
QString getFeatureDescription(LayerGeometryProvider *v, QPoint &) const override
void setColourScale(ColourScaleType)
Specify the scale for sample levels. 
static QString getColourMapId(int n)
Return a machine-readable id string for the colour map with the given index. 
QString getPropertyLabel(const PropertyName &) const override
int getCompletion(LayerGeometryProvider *v) const override
Return the proportion of background work complete in drawing this view, as a percentage – in most ca...
static void drawVisibleText(const LayerGeometryProvider *, QPainter &p, int x, int y, QString text, TextStyle style)
MagnitudeRange range
The magnitude range of the data in the rendered area, after initial scaling (parameters.scaleFactor) and normalisation, for use in displaying colour scale etc. 
int getPositionForValueUnclamped(double value) const override
void modelChangedWithin(ModelId, sv_frame_t startFrame, sv_frame_t endFrame)
ModelId getSliceableModel() const override
void setMinFrequency(int)
QColor getContrastingColour() const 
Return a colour that contrasts somewhat with the colours in the map, so as to be used for cursors etc...
double m_colourScaleMultiple
~SpectrogramRangeMapper() override
const VerticalBinLayer * verticalBinLayer
float getThreshold() const 
double getColourScaleMultiple() const 
bool getAdjustedYBinSourceRange(LayerGeometryProvider *v, int x, int y, double &freqMin, double &freqMax, double &adjFreqMin, double &adjFreqMax) const 
void setWindowType(WindowType type)
virtual int getXForFrame(sv_frame_t frame) const =0
Return the pixel x-coordinate corresponding to a given sample frame (which may be negative)...
bool getXBinRange(LayerGeometryProvider *v, int x, double &windowMin, double &windowMax) const 
std::vector< ModelId > peakCaches
int getCurrentVerticalZoomStep() const override
Get the current vertical zoom step. 
double multiple
Multiple to apply after thresholding and mapping. 
BinScale binScale
Scale for vertical bin spacing (linear or logarithmic). 
bool getCrosshairExtents(LayerGeometryProvider *, QPainter &, QPoint cursorPos, std::vector< QRect > &extents) const override
BinDisplay binDisplay
Selection of bins to display. 
void deleteDerivedModels()
bool getNormalizeVisibleArea() const 
void setBinDisplay(BinDisplay)
Specify the processing of frequency bins for the y axis. 
WindowType getWindowType() const 
QRect findSimilarRegionExtents(QPoint point) const 
Return the enclosing rectangle for the region of similar colour to the given point within the cache...
static int convertFromColumnNorm(ColumnNormalization norm, bool visible)
PropertyType getPropertyType(const PropertyName &) const override