annotate layer/SpectrogramLayer.h @ 640:c6d705bf1672

Merge from branch "qt5". This revision actually builds with Qt4 (late releases) or Qt5, though it will warn on configure with Qt4.
author Chris Cannam
date Tue, 14 May 2013 12:36:43 +0100
parents 0dba6a391760
children 67e6d518ac27
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@44 60 virtual void paint(View *v, QPainter &paint, QRect rect) const;
Chris@389 61 virtual void setSynchronousPainting(bool synchronous);
Chris@0 62
Chris@607 63 virtual int getVerticalScaleWidth(View *v, bool detailed, QPainter &) const;
Chris@607 64 virtual void paintVerticalScale(View *v, bool detailed, QPainter &paint, QRect rect) const;
Chris@0 65
Chris@77 66 virtual bool getCrosshairExtents(View *, QPainter &, QPoint cursorPos,
Chris@77 67 std::vector<QRect> &extents) const;
Chris@77 68 virtual void paintCrosshairs(View *, QPainter &, QPoint) const;
Chris@77 69
Chris@44 70 virtual QString getFeatureDescription(View *v, QPoint &) const;
Chris@0 71
Chris@44 72 virtual bool snapToFeatureFrame(View *v, int &frame,
Chris@28 73 size_t &resolution,
Chris@28 74 SnapType snap) const;
Chris@13 75
Chris@283 76 virtual void measureDoubleClick(View *, 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@167 91 virtual RangeMapper *getNewPropertyRangeMapper(const PropertyName &) const;
Chris@0 92 virtual void setProperty(const PropertyName &, int value);
Chris@0 93
Chris@0 94 /**
Chris@0 95 * Specify the channel to use from the source model.
Chris@0 96 * A value of -1 means to mix all available channels.
Chris@0 97 * The default is channel 0.
Chris@0 98 */
Chris@0 99 void setChannel(int);
Chris@0 100 int getChannel() const;
Chris@0 101
Chris@0 102 void setWindowSize(size_t);
Chris@0 103 size_t getWindowSize() const;
Chris@0 104
Chris@109 105 void setWindowHopLevel(size_t level);
Chris@97 106 size_t getWindowHopLevel() const;
Chris@0 107
Chris@0 108 void setWindowType(WindowType type);
Chris@0 109 WindowType getWindowType() const;
Chris@0 110
Chris@109 111 void setZeroPadLevel(size_t level);
Chris@109 112 size_t getZeroPadLevel() const;
Chris@109 113
Chris@0 114 /**
Chris@110 115 * Set the gain multiplier for sample values in this view.
Chris@0 116 * The default is 1.0.
Chris@0 117 */
Chris@0 118 void setGain(float gain);
Chris@0 119 float getGain() const;
Chris@0 120
Chris@37 121 /**
Chris@110 122 * Set the threshold for sample values to qualify for being shown
Chris@110 123 * in the FFT, in voltage units.
Chris@37 124 *
Chris@37 125 * The default is 0.0.
Chris@37 126 */
Chris@37 127 void setThreshold(float threshold);
Chris@37 128 float getThreshold() const;
Chris@37 129
Chris@37 130 void setMinFrequency(size_t);
Chris@37 131 size_t getMinFrequency() const;
Chris@37 132
Chris@0 133 void setMaxFrequency(size_t); // 0 -> no maximum
Chris@0 134 size_t getMaxFrequency() const;
Chris@0 135
Chris@37 136 enum ColourScale {
Chris@37 137 LinearColourScale,
Chris@37 138 MeterColourScale,
Chris@215 139 dBSquaredColourScale,
Chris@37 140 dBColourScale,
Chris@37 141 PhaseColourScale
Chris@37 142 };
Chris@0 143
Chris@0 144 /**
Chris@0 145 * Specify the scale for sample levels. See WaveformLayer for
Chris@0 146 * details of meter and dB scaling. The default is dBColourScale.
Chris@0 147 */
Chris@0 148 void setColourScale(ColourScale);
Chris@0 149 ColourScale getColourScale() const;
Chris@0 150
Chris@35 151 enum FrequencyScale {
Chris@35 152 LinearFrequencyScale,
Chris@35 153 LogFrequencyScale
Chris@35 154 };
Chris@0 155
Chris@0 156 /**
Chris@0 157 * Specify the scale for the y axis.
Chris@0 158 */
Chris@0 159 void setFrequencyScale(FrequencyScale);
Chris@0 160 FrequencyScale getFrequencyScale() const;
Chris@0 161
Chris@37 162 enum BinDisplay {
Chris@37 163 AllBins,
Chris@37 164 PeakBins,
Chris@37 165 PeakFrequencies
Chris@35 166 };
Chris@35 167
Chris@35 168 /**
Chris@35 169 * Specify the processing of frequency bins for the y axis.
Chris@35 170 */
Chris@37 171 void setBinDisplay(BinDisplay);
Chris@37 172 BinDisplay getBinDisplay() const;
Chris@35 173
Chris@36 174 void setNormalizeColumns(bool n);
Chris@36 175 bool getNormalizeColumns() const;
Chris@36 176
Chris@120 177 void setNormalizeVisibleArea(bool n);
Chris@120 178 bool getNormalizeVisibleArea() const;
Chris@120 179
Chris@197 180 void setColourMap(int map);
Chris@197 181 int getColourMap() const;
Chris@0 182
Chris@9 183 /**
Chris@9 184 * Specify the colourmap rotation for the colour scale.
Chris@9 185 */
Chris@9 186 void setColourRotation(int);
Chris@9 187 int getColourRotation() const;
Chris@9 188
Chris@0 189 virtual VerticalPosition getPreferredFrameCountPosition() const {
Chris@0 190 return PositionTop;
Chris@0 191 }
Chris@0 192
Chris@15 193 virtual bool isLayerOpaque() const { return true; }
Chris@287 194
Chris@287 195 virtual ColourSignificance getLayerColourSignificance() const {
Chris@287 196 return ColourHasMeaningfulValue;
Chris@287 197 }
Chris@15 198
Chris@267 199 float getYForFrequency(const View *v, float frequency) const;
Chris@267 200 float getFrequencyForY(const View *v, int y) const;
Chris@42 201
Chris@115 202 virtual int getCompletion(View *v) const;
Chris@583 203 virtual QString getError(View *v) const;
Chris@0 204
Chris@101 205 virtual bool getValueExtents(float &min, float &max,
Chris@101 206 bool &logarithmic, QString &unit) const;
Chris@101 207
Chris@101 208 virtual bool getDisplayExtents(float &min, float &max) const;
Chris@79 209
Chris@120 210 virtual bool setDisplayExtents(float min, float max);
Chris@120 211
Chris@267 212 virtual bool getYScaleValue(const View *, int, float &, QString &) const;
Chris@261 213
Chris@316 214 virtual void toXml(QTextStream &stream, QString indent = "",
Chris@316 215 QString extraAttributes = "") const;
Chris@6 216
Chris@11 217 void setProperties(const QXmlAttributes &attributes);
Chris@11 218
Chris@47 219 virtual void setLayerDormant(const View *v, bool dormant);
Chris@29 220
Chris@248 221 virtual bool isLayerScrollable(const View *) const { return false; }
Chris@94 222
Chris@133 223 virtual int getVerticalZoomSteps(int &defaultStep) const;
Chris@133 224 virtual int getCurrentVerticalZoomStep() const;
Chris@133 225 virtual void setVerticalZoomStep(int);
Chris@187 226 virtual RangeMapper *getNewVerticalZoomRangeMapper() const;
Chris@133 227
Chris@193 228 virtual const Model *getSliceableModel() const;
Chris@193 229
Chris@0 230 protected slots:
Chris@0 231 void cacheInvalid();
Chris@0 232 void cacheInvalid(size_t startFrame, size_t endFrame);
Chris@122 233
Chris@122 234 void preferenceChanged(PropertyContainer::PropertyName name);
Chris@0 235
Chris@0 236 void fillTimerTimedOut();
Chris@0 237
Chris@0 238 protected:
Chris@0 239 const DenseTimeValueModel *m_model; // I do not own this
Chris@484 240
Chris@35 241 int m_channel;
Chris@35 242 size_t m_windowSize;
Chris@35 243 WindowType m_windowType;
Chris@97 244 size_t m_windowHopLevel;
Chris@109 245 size_t m_zeroPadLevel;
Chris@107 246 size_t m_fftSize;
Chris@35 247 float m_gain;
Chris@215 248 float m_initialGain;
Chris@37 249 float m_threshold;
Chris@215 250 float m_initialThreshold;
Chris@35 251 int m_colourRotation;
Chris@215 252 int m_initialRotation;
Chris@37 253 size_t m_minFrequency;
Chris@35 254 size_t m_maxFrequency;
Chris@135 255 size_t m_initialMaxFrequency;
Chris@35 256 ColourScale m_colourScale;
Chris@197 257 int m_colourMap;
Chris@77 258 QColor m_crosshairColour;
Chris@35 259 FrequencyScale m_frequencyScale;
Chris@37 260 BinDisplay m_binDisplay;
Chris@36 261 bool m_normalizeColumns;
Chris@120 262 bool m_normalizeVisibleArea;
Chris@133 263 int m_lastEmittedZoomStep;
Chris@389 264 bool m_synchronous;
Chris@0 265
Chris@608 266 mutable bool m_haveDetailedScale;
Chris@215 267 mutable int m_lastPaintBlockWidth;
Chris@215 268 mutable RealTime m_lastPaintTime;
Chris@215 269
Chris@38 270 enum { NO_VALUE = 0 }; // colour index for unused pixels
Chris@38 271
Chris@197 272 class Palette
Chris@86 273 {
Chris@86 274 public:
Chris@86 275 QColor getColour(unsigned char index) const {
Chris@86 276 return m_colours[index];
Chris@86 277 }
Chris@86 278
Chris@86 279 void setColour(unsigned char index, QColor colour) {
Chris@86 280 m_colours[index] = colour;
Chris@86 281 }
Chris@86 282
Chris@86 283 private:
Chris@86 284 QColor m_colours[256];
Chris@86 285 };
Chris@86 286
Chris@197 287 Palette m_palette;
Chris@31 288
Chris@477 289 /**
Chris@478 290 * ImageCache covers the area of the view, at view resolution.
Chris@477 291 * Not all of it is necessarily valid at once (it is refreshed
Chris@477 292 * in parts when scrolling, for example).
Chris@477 293 */
Chris@478 294 struct ImageCache
Chris@95 295 {
Chris@478 296 QImage image;
Chris@95 297 QRect validArea;
Chris@95 298 long startFrame;
Chris@95 299 size_t zoomLevel;
Chris@95 300 };
Chris@478 301 typedef std::map<const View *, ImageCache> ViewImageCache;
Chris@478 302 void invalidateImageCaches();
Chris@478 303 void invalidateImageCaches(size_t startFrame, size_t endFrame);
Chris@478 304 mutable ViewImageCache m_imageCaches;
Chris@477 305
Chris@477 306 /**
Chris@477 307 * When painting, we draw directly onto the draw buffer and then
Chris@478 308 * copy this to the part of the image cache that needed refreshing
Chris@478 309 * before copying the image cache onto the window. (Remind me why
Chris@477 310 * we don't draw directly onto the cache?)
Chris@477 311 */
Chris@95 312 mutable QImage m_drawBuffer;
Chris@0 313
Chris@114 314 mutable QTimer *m_updateTimer;
Chris@110 315
Chris@44 316 mutable size_t m_candidateFillStartFrame;
Chris@0 317 bool m_exiting;
Chris@0 318
Chris@197 319 void initialisePalette();
Chris@197 320 void rotatePalette(int distance);
Chris@0 321
Chris@119 322 unsigned char getDisplayValue(View *v, float input) const;
Chris@40 323 float getInputForDisplayValue(unsigned char uc) const;
Chris@40 324
Chris@40 325 int getColourScaleWidth(QPainter &) const;
Chris@40 326
Chris@121 327 void illuminateLocalFeatures(View *v, QPainter &painter) const;
Chris@121 328
Chris@40 329 float getEffectiveMinFrequency() const;
Chris@40 330 float getEffectiveMaxFrequency() const;
Chris@38 331
Chris@0 332 struct LayerRange {
Chris@0 333 long startFrame;
Chris@0 334 int zoomLevel;
Chris@0 335 size_t modelStart;
Chris@0 336 size_t modelEnd;
Chris@0 337 };
Chris@486 338
Chris@486 339 // Note that the getYBin... methods return the nominal bin in the
Chris@486 340 // un-smoothed spectrogram. This is not necessarily the same bin
Chris@486 341 // as is pulled from the spectrogram and drawn at the given
Chris@486 342 // position, if the spectrogram has oversampling smoothing. Use
Chris@486 343 // getSmoothedYBinRange to obtain that.
Chris@486 344
Chris@44 345 bool getXBinRange(View *v, int x, float &windowMin, float &windowMax) const;
Chris@44 346 bool getYBinRange(View *v, int y, float &freqBinMin, float &freqBinMax) const;
Chris@486 347 bool getSmoothedYBinRange(View *v, int y, float &freqBinMin, float &freqBinMax) const;
Chris@0 348
Chris@44 349 bool getYBinSourceRange(View *v, int y, float &freqMin, float &freqMax) const;
Chris@44 350 bool getAdjustedYBinSourceRange(View *v, int x, int y,
Chris@35 351 float &freqMin, float &freqMax,
Chris@35 352 float &adjFreqMin, float &adjFreqMax) const;
Chris@44 353 bool getXBinSourceRange(View *v, int x, RealTime &timeMin, RealTime &timeMax) const;
Chris@44 354 bool getXYBinSourceRange(View *v, int x, int y, float &min, float &max,
Chris@38 355 float &phaseMin, float &phaseMax) const;
Chris@0 356
Chris@0 357 size_t getWindowIncrement() const {
Chris@97 358 if (m_windowHopLevel == 0) return m_windowSize;
Chris@97 359 else if (m_windowHopLevel == 1) return (m_windowSize * 3) / 4;
Chris@97 360 else return m_windowSize / (1 << (m_windowHopLevel - 1));
Chris@0 361 }
Chris@113 362
Chris@114 363 size_t getZeroPadLevel(const View *v) const;
Chris@114 364 size_t getFFTSize(const View *v) const;
Chris@130 365 FFTModel *getFFTModel(const View *v) const;
Chris@484 366 Dense3DModelPeakCache *getPeakCache(const View *v) const;
Chris@130 367 void invalidateFFTModels();
Chris@115 368
Chris@130 369 typedef std::pair<FFTModel *, int> FFTFillPair; // model, last fill
Chris@115 370 typedef std::map<const View *, FFTFillPair> ViewFFTMap;
Chris@484 371 typedef std::map<const View *, Dense3DModelPeakCache *> PeakCacheMap;
Chris@130 372 mutable ViewFFTMap m_fftModels;
Chris@484 373 mutable PeakCacheMap m_peakCaches;
Chris@193 374 mutable Model *m_sliceableModel;
Chris@119 375
Chris@119 376 class MagnitudeRange {
Chris@119 377 public:
Chris@119 378 MagnitudeRange() : m_min(0), m_max(0) { }
Chris@119 379 bool operator==(const MagnitudeRange &r) {
Chris@119 380 return r.m_min == m_min && r.m_max == m_max;
Chris@119 381 }
Chris@119 382 bool isSet() const { return (m_min != 0 || m_max != 0); }
Chris@119 383 void set(float min, float max) {
Chris@119 384 m_min = convert(min);
Chris@119 385 m_max = convert(max);
Chris@119 386 if (m_max < m_min) m_max = m_min;
Chris@119 387 }
Chris@119 388 bool sample(float f) {
Chris@119 389 unsigned int ui = convert(f);
Chris@119 390 bool changed = false;
Chris@119 391 if (isSet()) {
Chris@119 392 if (ui < m_min) { m_min = ui; changed = true; }
Chris@119 393 if (ui > m_max) { m_max = ui; changed = true; }
Chris@119 394 } else {
Chris@119 395 m_max = m_min = ui;
Chris@119 396 changed = true;
Chris@119 397 }
Chris@119 398 return changed;
Chris@119 399 }
Chris@119 400 bool sample(const MagnitudeRange &r) {
Chris@119 401 bool changed = false;
Chris@119 402 if (isSet()) {
Chris@119 403 if (r.m_min < m_min) { m_min = r.m_min; changed = true; }
Chris@119 404 if (r.m_max > m_max) { m_max = r.m_max; changed = true; }
Chris@119 405 } else {
Chris@119 406 m_min = r.m_min;
Chris@119 407 m_max = r.m_max;
Chris@119 408 changed = true;
Chris@119 409 }
Chris@119 410 return changed;
Chris@119 411 }
Chris@119 412 float getMin() const { return float(m_min) / UINT_MAX; }
Chris@119 413 float getMax() const { return float(m_max) / UINT_MAX; }
Chris@119 414 private:
Chris@119 415 unsigned int m_min;
Chris@119 416 unsigned int m_max;
Chris@119 417 unsigned int convert(float f) {
Chris@119 418 if (f < 0.f) f = 0.f;
Chris@119 419 if (f > 1.f) f = 1.f;
Chris@119 420 return (unsigned int)(f * UINT_MAX);
Chris@119 421 }
Chris@119 422 };
Chris@119 423
Chris@119 424 typedef std::map<const View *, MagnitudeRange> ViewMagMap;
Chris@119 425 mutable ViewMagMap m_viewMags;
Chris@119 426 mutable std::vector<MagnitudeRange> m_columnMags;
Chris@119 427 void invalidateMagnitudes();
Chris@119 428 bool updateViewMagnitudes(View *v) const;
Chris@484 429 bool paintDrawBuffer(View *v, int w, int h,
Chris@490 430 int *binforx, float *binfory,
Chris@491 431 bool usePeaksCache,
Chris@491 432 MagnitudeRange &overallMag,
Chris@491 433 bool &overallMagChanged) const;
Chris@488 434 bool paintDrawBufferPeakFrequencies(View *v, int w, int h,
Chris@488 435 int *binforx,
Chris@488 436 int minbin,
Chris@488 437 int maxbin,
Chris@488 438 float displayMinFreq,
Chris@488 439 float displayMaxFreq,
Chris@491 440 bool logarithmic,
Chris@491 441 MagnitudeRange &overallMag,
Chris@491 442 bool &overallMagChanged) const;
Chris@273 443
Chris@273 444 virtual void updateMeasureRectYCoords(View *v, const MeasureRect &r) const;
Chris@273 445 virtual void setMeasureRectYCoord(View *v, MeasureRect &r, bool start, int y) const;
Chris@0 446 };
Chris@0 447
Chris@0 448 #endif