annotate layer/SpectrogramLayer.h @ 1024:3bce4c45b681 spectrogram-minor-refactor

Rearrange cache update calculations so as to use the actual painted width returned by paint functions (though they only ever return the same width as requested, at this point)
author Chris Cannam
date Mon, 25 Jan 2016 15:52:26 +0000
parents 74755fa6ea9e
children c02de0e34233
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 mutable int m_lastPaintBlockWidth;
Chris@1023 278 mutable double m_lastPaintTime; // seconds
Chris@215 279
Chris@38 280 enum { NO_VALUE = 0 }; // colour index for unused pixels
Chris@38 281
Chris@197 282 class Palette
Chris@86 283 {
Chris@86 284 public:
Chris@86 285 QColor getColour(unsigned char index) const {
Chris@86 286 return m_colours[index];
Chris@86 287 }
Chris@86 288
Chris@86 289 void setColour(unsigned char index, QColor colour) {
Chris@86 290 m_colours[index] = colour;
Chris@86 291 }
Chris@86 292
Chris@86 293 private:
Chris@86 294 QColor m_colours[256];
Chris@86 295 };
Chris@86 296
Chris@197 297 Palette m_palette;
Chris@31 298
Chris@477 299 /**
Chris@478 300 * ImageCache covers the area of the view, at view resolution.
Chris@477 301 * Not all of it is necessarily valid at once (it is refreshed
Chris@477 302 * in parts when scrolling, for example).
Chris@477 303 */
Chris@478 304 struct ImageCache
Chris@95 305 {
Chris@478 306 QImage image;
Chris@95 307 QRect validArea;
Chris@907 308 sv_frame_t startFrame;
Chris@805 309 int zoomLevel;
Chris@95 310 };
Chris@478 311 typedef std::map<const View *, ImageCache> ViewImageCache;
Chris@478 312 void invalidateImageCaches();
Chris@906 313 void invalidateImageCaches(sv_frame_t startFrame, sv_frame_t endFrame);
Chris@478 314 mutable ViewImageCache m_imageCaches;
Chris@477 315
Chris@477 316 /**
Chris@477 317 * When painting, we draw directly onto the draw buffer and then
Chris@478 318 * copy this to the part of the image cache that needed refreshing
Chris@478 319 * before copying the image cache onto the window. (Remind me why
Chris@477 320 * we don't draw directly onto the cache?)
Chris@477 321 */
Chris@95 322 mutable QImage m_drawBuffer;
Chris@0 323
Chris@0 324 bool m_exiting;
Chris@0 325
Chris@197 326 void initialisePalette();
Chris@197 327 void rotatePalette(int distance);
Chris@0 328
Chris@918 329 unsigned char getDisplayValue(LayerGeometryProvider *v, double input) const;
Chris@40 330
Chris@40 331 int getColourScaleWidth(QPainter &) const;
Chris@40 332
Chris@918 333 void illuminateLocalFeatures(LayerGeometryProvider *v, QPainter &painter) const;
Chris@121 334
Chris@905 335 double getEffectiveMinFrequency() const;
Chris@905 336 double getEffectiveMaxFrequency() const;
Chris@38 337
Chris@486 338 // Note that the getYBin... methods return the nominal bin in the
Chris@486 339 // un-smoothed spectrogram. This is not necessarily the same bin
Chris@486 340 // as is pulled from the spectrogram and drawn at the given
Chris@486 341 // position, if the spectrogram has oversampling smoothing. Use
Chris@486 342 // getSmoothedYBinRange to obtain that.
Chris@486 343
Chris@918 344 bool getXBinRange(LayerGeometryProvider *v, int x, double &windowMin, double &windowMax) const;
Chris@918 345 bool getYBinRange(LayerGeometryProvider *v, int y, double &freqBinMin, double &freqBinMax) const;
Chris@918 346 bool getSmoothedYBinRange(LayerGeometryProvider *v, int y, double &freqBinMin, double &freqBinMax) const;
Chris@0 347
Chris@918 348 bool getYBinSourceRange(LayerGeometryProvider *v, int y, double &freqMin, double &freqMax) const;
Chris@918 349 bool getAdjustedYBinSourceRange(LayerGeometryProvider *v, int x, int y,
Chris@905 350 double &freqMin, double &freqMax,
Chris@905 351 double &adjFreqMin, double &adjFreqMax) const;
Chris@918 352 bool getXBinSourceRange(LayerGeometryProvider *v, int x, RealTime &timeMin, RealTime &timeMax) const;
Chris@918 353 bool getXYBinSourceRange(LayerGeometryProvider *v, int x, int y, double &min, double &max,
Chris@905 354 double &phaseMin, double &phaseMax) const;
Chris@0 355
Chris@805 356 int getWindowIncrement() const {
Chris@97 357 if (m_windowHopLevel == 0) return m_windowSize;
Chris@97 358 else if (m_windowHopLevel == 1) return (m_windowSize * 3) / 4;
Chris@97 359 else return m_windowSize / (1 << (m_windowHopLevel - 1));
Chris@0 360 }
Chris@113 361
Chris@918 362 int getZeroPadLevel(const LayerGeometryProvider *v) const;
Chris@918 363 int getFFTSize(const LayerGeometryProvider *v) const;
Chris@918 364 FFTModel *getFFTModel(const LayerGeometryProvider *v) const;
Chris@918 365 Dense3DModelPeakCache *getPeakCache(const LayerGeometryProvider *v) const;
Chris@130 366 void invalidateFFTModels();
Chris@115 367
Chris@985 368 typedef std::map<const View *, FFTModel *> ViewFFTMap;
Chris@484 369 typedef std::map<const View *, Dense3DModelPeakCache *> PeakCacheMap;
Chris@130 370 mutable ViewFFTMap m_fftModels;
Chris@484 371 mutable PeakCacheMap m_peakCaches;
Chris@193 372 mutable Model *m_sliceableModel;
Chris@119 373
Chris@119 374 class MagnitudeRange {
Chris@119 375 public:
Chris@119 376 MagnitudeRange() : m_min(0), m_max(0) { }
Chris@119 377 bool operator==(const MagnitudeRange &r) {
Chris@119 378 return r.m_min == m_min && r.m_max == m_max;
Chris@119 379 }
Chris@905 380 bool isSet() const { return (m_min != 0.f || m_max != 0.f); }
Chris@119 381 void set(float min, float max) {
Chris@905 382 m_min = min;
Chris@905 383 m_max = max;
Chris@119 384 if (m_max < m_min) m_max = m_min;
Chris@119 385 }
Chris@119 386 bool sample(float f) {
Chris@119 387 bool changed = false;
Chris@119 388 if (isSet()) {
Chris@905 389 if (f < m_min) { m_min = f; changed = true; }
Chris@905 390 if (f > m_max) { m_max = f; changed = true; }
Chris@119 391 } else {
Chris@905 392 m_max = m_min = f;
Chris@119 393 changed = true;
Chris@119 394 }
Chris@119 395 return changed;
Chris@119 396 }
Chris@119 397 bool sample(const MagnitudeRange &r) {
Chris@119 398 bool changed = false;
Chris@119 399 if (isSet()) {
Chris@119 400 if (r.m_min < m_min) { m_min = r.m_min; changed = true; }
Chris@119 401 if (r.m_max > m_max) { m_max = r.m_max; changed = true; }
Chris@119 402 } else {
Chris@119 403 m_min = r.m_min;
Chris@119 404 m_max = r.m_max;
Chris@119 405 changed = true;
Chris@119 406 }
Chris@119 407 return changed;
Chris@119 408 }
Chris@905 409 float getMin() const { return m_min; }
Chris@905 410 float getMax() const { return m_max; }
Chris@119 411 private:
Chris@905 412 float m_min;
Chris@905 413 float m_max;
Chris@119 414 };
Chris@119 415
Chris@918 416 typedef std::map<const LayerGeometryProvider *, MagnitudeRange> ViewMagMap;
Chris@119 417 mutable ViewMagMap m_viewMags;
Chris@119 418 mutable std::vector<MagnitudeRange> m_columnMags;
Chris@119 419 void invalidateMagnitudes();
Chris@918 420 bool updateViewMagnitudes(LayerGeometryProvider *v) const;
Chris@1024 421 int paintDrawBuffer(LayerGeometryProvider *v, int w, int h,
Chris@1024 422 const std::vector<int> &binforx,
Chris@1024 423 const std::vector<double> &binfory,
Chris@1024 424 bool usePeaksCache,
Chris@1024 425 MagnitudeRange &overallMag,
Chris@1024 426 bool &overallMagChanged) const;
Chris@1024 427 int paintDrawBufferPeakFrequencies(LayerGeometryProvider *v, int w, int h,
Chris@1024 428 const std::vector<int> &binforx,
Chris@1024 429 int minbin,
Chris@1024 430 int maxbin,
Chris@1024 431 double displayMinFreq,
Chris@1024 432 double displayMaxFreq,
Chris@1024 433 bool logarithmic,
Chris@1024 434 MagnitudeRange &overallMag,
Chris@1024 435 bool &overallMagChanged) const;
Chris@273 436
Chris@918 437 virtual void updateMeasureRectYCoords(LayerGeometryProvider *v, const MeasureRect &r) const;
Chris@918 438 virtual void setMeasureRectYCoord(LayerGeometryProvider *v, MeasureRect &r, bool start, int y) const;
Chris@0 439 };
Chris@0 440
Chris@0 441 #endif