annotate layer/SpectrogramLayer.h @ 1025:c02de0e34233 spectrogram-minor-refactor

Make paint method do its own timing and abandon if it's taking too long (still needs some work on queueing correct repaints of the remainder)
author Chris Cannam
date Mon, 25 Jan 2016 16:16:21 +0000
parents 3bce4c45b681
children 53110ace211f
rev   line source
Chris@58 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@0 2
Chris@0 3 /*
Chris@59 4 Sonic Visualiser
Chris@59 5 An audio file viewer and annotation editor.
Chris@59 6 Centre for Digital Music, Queen Mary, University of London.
Chris@182 7 This file copyright 2006 Chris Cannam and QMUL.
Chris@0 8
Chris@59 9 This program is free software; you can redistribute it and/or
Chris@59 10 modify it under the terms of the GNU General Public License as
Chris@59 11 published by the Free Software Foundation; either version 2 of the
Chris@59 12 License, or (at your option) any later version. See the file
Chris@59 13 COPYING included with this distribution for more information.
Chris@0 14 */
Chris@0 15
Chris@30 16 #ifndef _SPECTROGRAM_LAYER_H_
Chris@30 17 #define _SPECTROGRAM_LAYER_H_
Chris@0 18
Chris@193 19 #include "SliceableLayer.h"
Chris@0 20 #include "base/Window.h"
Chris@71 21 #include "base/RealTime.h"
Chris@92 22 #include "base/Thread.h"
Chris@122 23 #include "base/PropertyContainer.h"
Chris@128 24 #include "data/model/PowerOfSqrtTwoZoomConstraint.h"
Chris@128 25 #include "data/model/DenseTimeValueModel.h"
Chris@130 26 #include "data/model/FFTModel.h"
Chris@0 27
Chris@0 28 #include <QMutex>
Chris@0 29 #include <QWaitCondition>
Chris@95 30 #include <QImage>
Chris@95 31 #include <QPixmap>
Chris@0 32
Chris@0 33 class View;
Chris@0 34 class QPainter;
Chris@0 35 class QImage;
Chris@0 36 class QPixmap;
Chris@0 37 class QTimer;
Chris@130 38 class FFTModel;
Chris@484 39 class Dense3DModelPeakCache;
Chris@114 40
Chris@0 41
Chris@0 42 /**
Chris@0 43 * SpectrogramLayer represents waveform data (obtained from a
Chris@0 44 * DenseTimeValueModel) in spectrogram form.
Chris@0 45 */
Chris@0 46
Chris@193 47 class SpectrogramLayer : public SliceableLayer,
Chris@31 48 public PowerOfSqrtTwoZoomConstraint
Chris@0 49 {
Chris@0 50 Q_OBJECT
Chris@0 51
Chris@0 52 public:
Chris@37 53 enum Configuration { FullRangeDb, MelodicRange, MelodicPeaks };
Chris@0 54
Chris@44 55 SpectrogramLayer(Configuration = FullRangeDb);
Chris@0 56 ~SpectrogramLayer();
Chris@0 57
Chris@0 58 virtual const ZoomConstraint *getZoomConstraint() const { return this; }
Chris@0 59 virtual const Model *getModel() const { return m_model; }
Chris@916 60 virtual void paint(LayerGeometryProvider *v, QPainter &paint, QRect rect) const;
Chris@389 61 virtual void setSynchronousPainting(bool synchronous);
Chris@0 62
Chris@918 63 virtual int getVerticalScaleWidth(LayerGeometryProvider *v, bool detailed, QPainter &) const;
Chris@918 64 virtual void paintVerticalScale(LayerGeometryProvider *v, bool detailed, QPainter &paint, QRect rect) const;
Chris@0 65
Chris@918 66 virtual bool getCrosshairExtents(LayerGeometryProvider *, QPainter &, QPoint cursorPos,
Chris@77 67 std::vector<QRect> &extents) const;
Chris@918 68 virtual void paintCrosshairs(LayerGeometryProvider *, QPainter &, QPoint) const;
Chris@77 69
Chris@918 70 virtual QString getFeatureDescription(LayerGeometryProvider *v, QPoint &) const;
Chris@0 71
Chris@918 72 virtual bool snapToFeatureFrame(LayerGeometryProvider *v, sv_frame_t &frame,
Chris@805 73 int &resolution,
Chris@28 74 SnapType snap) const;
Chris@13 75
Chris@918 76 virtual void measureDoubleClick(LayerGeometryProvider *, QMouseEvent *);
Chris@283 77
Chris@224 78 virtual bool hasLightBackground() const;
Chris@224 79
Chris@0 80 void setModel(const DenseTimeValueModel *model);
Chris@0 81
Chris@0 82 virtual PropertyList getProperties() const;
Chris@87 83 virtual QString getPropertyLabel(const PropertyName &) const;
Chris@335 84 virtual QString getPropertyIconName(const PropertyName &) const;
Chris@0 85 virtual PropertyType getPropertyType(const PropertyName &) const;
Chris@0 86 virtual QString getPropertyGroupName(const PropertyName &) const;
Chris@0 87 virtual int getPropertyRangeAndValue(const PropertyName &,
Chris@216 88 int *min, int *max, int *deflt) const;
Chris@0 89 virtual QString getPropertyValueLabel(const PropertyName &,
Chris@0 90 int value) const;
Chris@862 91 virtual QString getPropertyValueIconName(const PropertyName &,
Chris@862 92 int value) const;
Chris@167 93 virtual RangeMapper *getNewPropertyRangeMapper(const PropertyName &) const;
Chris@0 94 virtual void setProperty(const PropertyName &, int value);
Chris@0 95
Chris@0 96 /**
Chris@0 97 * Specify the channel to use from the source model.
Chris@0 98 * A value of -1 means to mix all available channels.
Chris@0 99 * The default is channel 0.
Chris@0 100 */
Chris@0 101 void setChannel(int);
Chris@0 102 int getChannel() const;
Chris@0 103
Chris@805 104 void setWindowSize(int);
Chris@805 105 int getWindowSize() const;
Chris@0 106
Chris@805 107 void setWindowHopLevel(int level);
Chris@805 108 int getWindowHopLevel() const;
Chris@0 109
Chris@0 110 void setWindowType(WindowType type);
Chris@0 111 WindowType getWindowType() const;
Chris@0 112
Chris@805 113 void setZeroPadLevel(int level);
Chris@805 114 int getZeroPadLevel() const;
Chris@109 115
Chris@0 116 /**
Chris@110 117 * Set the gain multiplier for sample values in this view.
Chris@0 118 * The default is 1.0.
Chris@0 119 */
Chris@0 120 void setGain(float gain);
Chris@0 121 float getGain() const;
Chris@0 122
Chris@37 123 /**
Chris@110 124 * Set the threshold for sample values to qualify for being shown
Chris@110 125 * in the FFT, in voltage units.
Chris@37 126 *
Chris@37 127 * The default is 0.0.
Chris@37 128 */
Chris@37 129 void setThreshold(float threshold);
Chris@37 130 float getThreshold() const;
Chris@37 131
Chris@805 132 void setMinFrequency(int);
Chris@805 133 int getMinFrequency() const;
Chris@37 134
Chris@805 135 void setMaxFrequency(int); // 0 -> no maximum
Chris@805 136 int getMaxFrequency() const;
Chris@0 137
Chris@37 138 enum ColourScale {
Chris@37 139 LinearColourScale,
Chris@37 140 MeterColourScale,
Chris@215 141 dBSquaredColourScale,
Chris@37 142 dBColourScale,
Chris@37 143 PhaseColourScale
Chris@37 144 };
Chris@0 145
Chris@0 146 /**
Chris@0 147 * Specify the scale for sample levels. See WaveformLayer for
Chris@0 148 * details of meter and dB scaling. The default is dBColourScale.
Chris@0 149 */
Chris@0 150 void setColourScale(ColourScale);
Chris@0 151 ColourScale getColourScale() const;
Chris@0 152
Chris@35 153 enum FrequencyScale {
Chris@35 154 LinearFrequencyScale,
Chris@35 155 LogFrequencyScale
Chris@35 156 };
Chris@0 157
Chris@0 158 /**
Chris@0 159 * Specify the scale for the y axis.
Chris@0 160 */
Chris@0 161 void setFrequencyScale(FrequencyScale);
Chris@0 162 FrequencyScale getFrequencyScale() const;
Chris@0 163
Chris@37 164 enum BinDisplay {
Chris@37 165 AllBins,
Chris@37 166 PeakBins,
Chris@37 167 PeakFrequencies
Chris@35 168 };
Chris@35 169
Chris@35 170 /**
Chris@35 171 * Specify the processing of frequency bins for the y axis.
Chris@35 172 */
Chris@37 173 void setBinDisplay(BinDisplay);
Chris@37 174 BinDisplay getBinDisplay() const;
Chris@862 175
Chris@862 176 enum Normalization {
Chris@862 177 NoNormalization,
Chris@862 178 NormalizeColumns,
Chris@862 179 NormalizeVisibleArea,
Chris@862 180 NormalizeHybrid
Chris@862 181 };
Chris@36 182
Chris@719 183 /**
Chris@862 184 * Specify the normalization mode for bin values.
Chris@719 185 */
Chris@862 186 void setNormalization(Normalization);
Chris@862 187 Normalization getNormalization() const;
Chris@120 188
Chris@719 189 /**
Chris@862 190 * Specify the colour map. See ColourMapper for the colour map
Chris@862 191 * values.
Chris@719 192 */
Chris@197 193 void setColourMap(int map);
Chris@197 194 int getColourMap() const;
Chris@0 195
Chris@9 196 /**
Chris@9 197 * Specify the colourmap rotation for the colour scale.
Chris@9 198 */
Chris@9 199 void setColourRotation(int);
Chris@9 200 int getColourRotation() const;
Chris@9 201
Chris@0 202 virtual VerticalPosition getPreferredFrameCountPosition() const {
Chris@0 203 return PositionTop;
Chris@0 204 }
Chris@0 205
Chris@15 206 virtual bool isLayerOpaque() const { return true; }
Chris@287 207
Chris@287 208 virtual ColourSignificance getLayerColourSignificance() const {
Chris@287 209 return ColourHasMeaningfulValue;
Chris@287 210 }
Chris@15 211
Chris@918 212 double getYForFrequency(const LayerGeometryProvider *v, double frequency) const;
Chris@918 213 double getFrequencyForY(const LayerGeometryProvider *v, int y) const;
Chris@42 214
Chris@918 215 virtual int getCompletion(LayerGeometryProvider *v) const;
Chris@918 216 virtual QString getError(LayerGeometryProvider *v) const;
Chris@0 217
Chris@905 218 virtual bool getValueExtents(double &min, double &max,
Chris@101 219 bool &logarithmic, QString &unit) const;
Chris@101 220
Chris@905 221 virtual bool getDisplayExtents(double &min, double &max) const;
Chris@79 222
Chris@905 223 virtual bool setDisplayExtents(double min, double max);
Chris@120 224
Chris@918 225 virtual bool getYScaleValue(const LayerGeometryProvider *, int, double &, QString &) const;
Chris@261 226
Chris@316 227 virtual void toXml(QTextStream &stream, QString indent = "",
Chris@316 228 QString extraAttributes = "") const;
Chris@6 229
Chris@11 230 void setProperties(const QXmlAttributes &attributes);
Chris@11 231
Chris@918 232 virtual void setLayerDormant(const LayerGeometryProvider *v, bool dormant);
Chris@29 233
Chris@918 234 virtual bool isLayerScrollable(const LayerGeometryProvider *) const { return false; }
Chris@94 235
Chris@133 236 virtual int getVerticalZoomSteps(int &defaultStep) const;
Chris@133 237 virtual int getCurrentVerticalZoomStep() const;
Chris@133 238 virtual void setVerticalZoomStep(int);
Chris@187 239 virtual RangeMapper *getNewVerticalZoomRangeMapper() const;
Chris@133 240
Chris@193 241 virtual const Model *getSliceableModel() const;
Chris@193 242
Chris@0 243 protected slots:
Chris@0 244 void cacheInvalid();
Chris@906 245 void cacheInvalid(sv_frame_t startFrame, sv_frame_t endFrame);
Chris@122 246
Chris@122 247 void preferenceChanged(PropertyContainer::PropertyName name);
Chris@0 248
Chris@0 249 protected:
Chris@0 250 const DenseTimeValueModel *m_model; // I do not own this
Chris@484 251
Chris@35 252 int m_channel;
Chris@1023 253 int m_windowSize;
Chris@35 254 WindowType m_windowType;
Chris@1023 255 int m_windowHopLevel;
Chris@1023 256 int m_zeroPadLevel;
Chris@1023 257 int m_fftSize;
Chris@35 258 float m_gain;
Chris@215 259 float m_initialGain;
Chris@37 260 float m_threshold;
Chris@215 261 float m_initialThreshold;
Chris@35 262 int m_colourRotation;
Chris@215 263 int m_initialRotation;
Chris@1023 264 int m_minFrequency;
Chris@1023 265 int m_maxFrequency;
Chris@1023 266 int m_initialMaxFrequency;
Chris@35 267 ColourScale m_colourScale;
Chris@197 268 int m_colourMap;
Chris@77 269 QColor m_crosshairColour;
Chris@35 270 FrequencyScale m_frequencyScale;
Chris@37 271 BinDisplay m_binDisplay;
Chris@862 272 Normalization m_normalization;
Chris@133 273 int m_lastEmittedZoomStep;
Chris@389 274 bool m_synchronous;
Chris@0 275
Chris@608 276 mutable bool m_haveDetailedScale;
Chris@215 277
Chris@38 278 enum { NO_VALUE = 0 }; // colour index for unused pixels
Chris@38 279
Chris@197 280 class Palette
Chris@86 281 {
Chris@86 282 public:
Chris@86 283 QColor getColour(unsigned char index) const {
Chris@86 284 return m_colours[index];
Chris@86 285 }
Chris@86 286
Chris@86 287 void setColour(unsigned char index, QColor colour) {
Chris@86 288 m_colours[index] = colour;
Chris@86 289 }
Chris@86 290
Chris@86 291 private:
Chris@86 292 QColor m_colours[256];
Chris@86 293 };
Chris@86 294
Chris@197 295 Palette m_palette;
Chris@31 296
Chris@477 297 /**
Chris@478 298 * ImageCache covers the area of the view, at view resolution.
Chris@477 299 * Not all of it is necessarily valid at once (it is refreshed
Chris@477 300 * in parts when scrolling, for example).
Chris@477 301 */
Chris@478 302 struct ImageCache
Chris@95 303 {
Chris@478 304 QImage image;
Chris@95 305 QRect validArea;
Chris@907 306 sv_frame_t startFrame;
Chris@805 307 int zoomLevel;
Chris@95 308 };
Chris@478 309 typedef std::map<const View *, ImageCache> ViewImageCache;
Chris@478 310 void invalidateImageCaches();
Chris@906 311 void invalidateImageCaches(sv_frame_t startFrame, sv_frame_t endFrame);
Chris@478 312 mutable ViewImageCache m_imageCaches;
Chris@477 313
Chris@477 314 /**
Chris@477 315 * When painting, we draw directly onto the draw buffer and then
Chris@478 316 * copy this to the part of the image cache that needed refreshing
Chris@478 317 * before copying the image cache onto the window. (Remind me why
Chris@477 318 * we don't draw directly onto the cache?)
Chris@477 319 */
Chris@95 320 mutable QImage m_drawBuffer;
Chris@0 321
Chris@0 322 bool m_exiting;
Chris@0 323
Chris@197 324 void initialisePalette();
Chris@197 325 void rotatePalette(int distance);
Chris@0 326
Chris@918 327 unsigned char getDisplayValue(LayerGeometryProvider *v, double input) const;
Chris@40 328
Chris@40 329 int getColourScaleWidth(QPainter &) const;
Chris@40 330
Chris@918 331 void illuminateLocalFeatures(LayerGeometryProvider *v, QPainter &painter) const;
Chris@121 332
Chris@905 333 double getEffectiveMinFrequency() const;
Chris@905 334 double getEffectiveMaxFrequency() const;
Chris@38 335
Chris@486 336 // Note that the getYBin... methods return the nominal bin in the
Chris@486 337 // un-smoothed spectrogram. This is not necessarily the same bin
Chris@486 338 // as is pulled from the spectrogram and drawn at the given
Chris@486 339 // position, if the spectrogram has oversampling smoothing. Use
Chris@486 340 // getSmoothedYBinRange to obtain that.
Chris@486 341
Chris@918 342 bool getXBinRange(LayerGeometryProvider *v, int x, double &windowMin, double &windowMax) const;
Chris@918 343 bool getYBinRange(LayerGeometryProvider *v, int y, double &freqBinMin, double &freqBinMax) const;
Chris@918 344 bool getSmoothedYBinRange(LayerGeometryProvider *v, int y, double &freqBinMin, double &freqBinMax) const;
Chris@0 345
Chris@918 346 bool getYBinSourceRange(LayerGeometryProvider *v, int y, double &freqMin, double &freqMax) const;
Chris@918 347 bool getAdjustedYBinSourceRange(LayerGeometryProvider *v, int x, int y,
Chris@905 348 double &freqMin, double &freqMax,
Chris@905 349 double &adjFreqMin, double &adjFreqMax) const;
Chris@918 350 bool getXBinSourceRange(LayerGeometryProvider *v, int x, RealTime &timeMin, RealTime &timeMax) const;
Chris@918 351 bool getXYBinSourceRange(LayerGeometryProvider *v, int x, int y, double &min, double &max,
Chris@905 352 double &phaseMin, double &phaseMax) const;
Chris@0 353
Chris@805 354 int getWindowIncrement() const {
Chris@97 355 if (m_windowHopLevel == 0) return m_windowSize;
Chris@97 356 else if (m_windowHopLevel == 1) return (m_windowSize * 3) / 4;
Chris@97 357 else return m_windowSize / (1 << (m_windowHopLevel - 1));
Chris@0 358 }
Chris@113 359
Chris@918 360 int getZeroPadLevel(const LayerGeometryProvider *v) const;
Chris@918 361 int getFFTSize(const LayerGeometryProvider *v) const;
Chris@918 362 FFTModel *getFFTModel(const LayerGeometryProvider *v) const;
Chris@918 363 Dense3DModelPeakCache *getPeakCache(const LayerGeometryProvider *v) const;
Chris@130 364 void invalidateFFTModels();
Chris@115 365
Chris@985 366 typedef std::map<const View *, FFTModel *> ViewFFTMap;
Chris@484 367 typedef std::map<const View *, Dense3DModelPeakCache *> PeakCacheMap;
Chris@130 368 mutable ViewFFTMap m_fftModels;
Chris@484 369 mutable PeakCacheMap m_peakCaches;
Chris@193 370 mutable Model *m_sliceableModel;
Chris@119 371
Chris@119 372 class MagnitudeRange {
Chris@119 373 public:
Chris@119 374 MagnitudeRange() : m_min(0), m_max(0) { }
Chris@119 375 bool operator==(const MagnitudeRange &r) {
Chris@119 376 return r.m_min == m_min && r.m_max == m_max;
Chris@119 377 }
Chris@905 378 bool isSet() const { return (m_min != 0.f || m_max != 0.f); }
Chris@119 379 void set(float min, float max) {
Chris@905 380 m_min = min;
Chris@905 381 m_max = max;
Chris@119 382 if (m_max < m_min) m_max = m_min;
Chris@119 383 }
Chris@119 384 bool sample(float f) {
Chris@119 385 bool changed = false;
Chris@119 386 if (isSet()) {
Chris@905 387 if (f < m_min) { m_min = f; changed = true; }
Chris@905 388 if (f > m_max) { m_max = f; changed = true; }
Chris@119 389 } else {
Chris@905 390 m_max = m_min = f;
Chris@119 391 changed = true;
Chris@119 392 }
Chris@119 393 return changed;
Chris@119 394 }
Chris@119 395 bool sample(const MagnitudeRange &r) {
Chris@119 396 bool changed = false;
Chris@119 397 if (isSet()) {
Chris@119 398 if (r.m_min < m_min) { m_min = r.m_min; changed = true; }
Chris@119 399 if (r.m_max > m_max) { m_max = r.m_max; changed = true; }
Chris@119 400 } else {
Chris@119 401 m_min = r.m_min;
Chris@119 402 m_max = r.m_max;
Chris@119 403 changed = true;
Chris@119 404 }
Chris@119 405 return changed;
Chris@119 406 }
Chris@905 407 float getMin() const { return m_min; }
Chris@905 408 float getMax() const { return m_max; }
Chris@119 409 private:
Chris@905 410 float m_min;
Chris@905 411 float m_max;
Chris@119 412 };
Chris@119 413
Chris@918 414 typedef std::map<const LayerGeometryProvider *, MagnitudeRange> ViewMagMap;
Chris@119 415 mutable ViewMagMap m_viewMags;
Chris@119 416 mutable std::vector<MagnitudeRange> m_columnMags;
Chris@119 417 void invalidateMagnitudes();
Chris@918 418 bool updateViewMagnitudes(LayerGeometryProvider *v) const;
Chris@1024 419 int paintDrawBuffer(LayerGeometryProvider *v, int w, int h,
Chris@1024 420 const std::vector<int> &binforx,
Chris@1024 421 const std::vector<double> &binfory,
Chris@1024 422 bool usePeaksCache,
Chris@1024 423 MagnitudeRange &overallMag,
Chris@1024 424 bool &overallMagChanged) const;
Chris@1024 425 int paintDrawBufferPeakFrequencies(LayerGeometryProvider *v, int w, int h,
Chris@1024 426 const std::vector<int> &binforx,
Chris@1024 427 int minbin,
Chris@1024 428 int maxbin,
Chris@1024 429 double displayMinFreq,
Chris@1024 430 double displayMaxFreq,
Chris@1024 431 bool logarithmic,
Chris@1024 432 MagnitudeRange &overallMag,
Chris@1024 433 bool &overallMagChanged) const;
Chris@273 434
Chris@918 435 virtual void updateMeasureRectYCoords(LayerGeometryProvider *v, const MeasureRect &r) const;
Chris@918 436 virtual void setMeasureRectYCoord(LayerGeometryProvider *v, MeasureRect &r, bool start, int y) const;
Chris@0 437 };
Chris@0 438
Chris@0 439 #endif