annotate layer/SpectrogramLayer.h @ 789:9fd1bdf214dd tonioni

Play pointer: when user drags pane during playback such that the pointer is no longer visible, accept that and stop trying to track it until pointer naturally comes back within visible area
author Chris Cannam
date Thu, 12 Jun 2014 12:48:11 +0100
parents 67e6d518ac27
children 1d526ba11a24
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@719 173
Chris@719 174 /**
Chris@719 175 * Normalize each column to its maximum value, independent of its
Chris@719 176 * neighbours.
Chris@719 177 */
Chris@36 178 void setNormalizeColumns(bool n);
Chris@36 179 bool getNormalizeColumns() const;
Chris@36 180
Chris@719 181 /**
Chris@719 182 * Normalize each value against the maximum in the visible region.
Chris@719 183 */
Chris@120 184 void setNormalizeVisibleArea(bool n);
Chris@120 185 bool getNormalizeVisibleArea() const;
Chris@120 186
Chris@719 187 /**
Chris@719 188 * Normalize each column to its maximum value, and then scale by
Chris@719 189 * the log of the (absolute) maximum value.
Chris@719 190 */
Chris@719 191 void setNormalizeHybrid(bool n);
Chris@719 192 bool getNormalizeHybrid() const;
Chris@719 193
Chris@197 194 void setColourMap(int map);
Chris@197 195 int getColourMap() const;
Chris@0 196
Chris@9 197 /**
Chris@9 198 * Specify the colourmap rotation for the colour scale.
Chris@9 199 */
Chris@9 200 void setColourRotation(int);
Chris@9 201 int getColourRotation() const;
Chris@9 202
Chris@0 203 virtual VerticalPosition getPreferredFrameCountPosition() const {
Chris@0 204 return PositionTop;
Chris@0 205 }
Chris@0 206
Chris@15 207 virtual bool isLayerOpaque() const { return true; }
Chris@287 208
Chris@287 209 virtual ColourSignificance getLayerColourSignificance() const {
Chris@287 210 return ColourHasMeaningfulValue;
Chris@287 211 }
Chris@15 212
Chris@267 213 float getYForFrequency(const View *v, float frequency) const;
Chris@267 214 float getFrequencyForY(const View *v, int y) const;
Chris@42 215
Chris@115 216 virtual int getCompletion(View *v) const;
Chris@583 217 virtual QString getError(View *v) const;
Chris@0 218
Chris@101 219 virtual bool getValueExtents(float &min, float &max,
Chris@101 220 bool &logarithmic, QString &unit) const;
Chris@101 221
Chris@101 222 virtual bool getDisplayExtents(float &min, float &max) const;
Chris@79 223
Chris@120 224 virtual bool setDisplayExtents(float min, float max);
Chris@120 225
Chris@267 226 virtual bool getYScaleValue(const View *, int, float &, QString &) const;
Chris@261 227
Chris@316 228 virtual void toXml(QTextStream &stream, QString indent = "",
Chris@316 229 QString extraAttributes = "") const;
Chris@6 230
Chris@11 231 void setProperties(const QXmlAttributes &attributes);
Chris@11 232
Chris@47 233 virtual void setLayerDormant(const View *v, bool dormant);
Chris@29 234
Chris@248 235 virtual bool isLayerScrollable(const View *) const { return false; }
Chris@94 236
Chris@133 237 virtual int getVerticalZoomSteps(int &defaultStep) const;
Chris@133 238 virtual int getCurrentVerticalZoomStep() const;
Chris@133 239 virtual void setVerticalZoomStep(int);
Chris@187 240 virtual RangeMapper *getNewVerticalZoomRangeMapper() const;
Chris@133 241
Chris@193 242 virtual const Model *getSliceableModel() const;
Chris@193 243
Chris@0 244 protected slots:
Chris@0 245 void cacheInvalid();
Chris@0 246 void cacheInvalid(size_t startFrame, size_t endFrame);
Chris@122 247
Chris@122 248 void preferenceChanged(PropertyContainer::PropertyName name);
Chris@0 249
Chris@0 250 void fillTimerTimedOut();
Chris@0 251
Chris@0 252 protected:
Chris@0 253 const DenseTimeValueModel *m_model; // I do not own this
Chris@484 254
Chris@35 255 int m_channel;
Chris@35 256 size_t m_windowSize;
Chris@35 257 WindowType m_windowType;
Chris@97 258 size_t m_windowHopLevel;
Chris@109 259 size_t m_zeroPadLevel;
Chris@107 260 size_t m_fftSize;
Chris@35 261 float m_gain;
Chris@215 262 float m_initialGain;
Chris@37 263 float m_threshold;
Chris@215 264 float m_initialThreshold;
Chris@35 265 int m_colourRotation;
Chris@215 266 int m_initialRotation;
Chris@37 267 size_t m_minFrequency;
Chris@35 268 size_t m_maxFrequency;
Chris@135 269 size_t m_initialMaxFrequency;
Chris@35 270 ColourScale m_colourScale;
Chris@197 271 int m_colourMap;
Chris@77 272 QColor m_crosshairColour;
Chris@35 273 FrequencyScale m_frequencyScale;
Chris@37 274 BinDisplay m_binDisplay;
Chris@36 275 bool m_normalizeColumns;
Chris@120 276 bool m_normalizeVisibleArea;
Chris@719 277 bool m_normalizeHybrid;
Chris@133 278 int m_lastEmittedZoomStep;
Chris@389 279 bool m_synchronous;
Chris@0 280
Chris@608 281 mutable bool m_haveDetailedScale;
Chris@215 282 mutable int m_lastPaintBlockWidth;
Chris@215 283 mutable RealTime m_lastPaintTime;
Chris@215 284
Chris@38 285 enum { NO_VALUE = 0 }; // colour index for unused pixels
Chris@38 286
Chris@197 287 class Palette
Chris@86 288 {
Chris@86 289 public:
Chris@86 290 QColor getColour(unsigned char index) const {
Chris@86 291 return m_colours[index];
Chris@86 292 }
Chris@86 293
Chris@86 294 void setColour(unsigned char index, QColor colour) {
Chris@86 295 m_colours[index] = colour;
Chris@86 296 }
Chris@86 297
Chris@86 298 private:
Chris@86 299 QColor m_colours[256];
Chris@86 300 };
Chris@86 301
Chris@197 302 Palette m_palette;
Chris@31 303
Chris@477 304 /**
Chris@478 305 * ImageCache covers the area of the view, at view resolution.
Chris@477 306 * Not all of it is necessarily valid at once (it is refreshed
Chris@477 307 * in parts when scrolling, for example).
Chris@477 308 */
Chris@478 309 struct ImageCache
Chris@95 310 {
Chris@478 311 QImage image;
Chris@95 312 QRect validArea;
Chris@95 313 long startFrame;
Chris@95 314 size_t zoomLevel;
Chris@95 315 };
Chris@478 316 typedef std::map<const View *, ImageCache> ViewImageCache;
Chris@478 317 void invalidateImageCaches();
Chris@478 318 void invalidateImageCaches(size_t startFrame, size_t endFrame);
Chris@478 319 mutable ViewImageCache m_imageCaches;
Chris@477 320
Chris@477 321 /**
Chris@477 322 * When painting, we draw directly onto the draw buffer and then
Chris@478 323 * copy this to the part of the image cache that needed refreshing
Chris@478 324 * before copying the image cache onto the window. (Remind me why
Chris@477 325 * we don't draw directly onto the cache?)
Chris@477 326 */
Chris@95 327 mutable QImage m_drawBuffer;
Chris@0 328
Chris@114 329 mutable QTimer *m_updateTimer;
Chris@110 330
Chris@44 331 mutable size_t m_candidateFillStartFrame;
Chris@0 332 bool m_exiting;
Chris@0 333
Chris@197 334 void initialisePalette();
Chris@197 335 void rotatePalette(int distance);
Chris@0 336
Chris@119 337 unsigned char getDisplayValue(View *v, float input) const;
Chris@40 338
Chris@40 339 int getColourScaleWidth(QPainter &) const;
Chris@40 340
Chris@121 341 void illuminateLocalFeatures(View *v, QPainter &painter) const;
Chris@121 342
Chris@40 343 float getEffectiveMinFrequency() const;
Chris@40 344 float getEffectiveMaxFrequency() const;
Chris@38 345
Chris@0 346 struct LayerRange {
Chris@0 347 long startFrame;
Chris@0 348 int zoomLevel;
Chris@0 349 size_t modelStart;
Chris@0 350 size_t modelEnd;
Chris@0 351 };
Chris@486 352
Chris@486 353 // Note that the getYBin... methods return the nominal bin in the
Chris@486 354 // un-smoothed spectrogram. This is not necessarily the same bin
Chris@486 355 // as is pulled from the spectrogram and drawn at the given
Chris@486 356 // position, if the spectrogram has oversampling smoothing. Use
Chris@486 357 // getSmoothedYBinRange to obtain that.
Chris@486 358
Chris@44 359 bool getXBinRange(View *v, int x, float &windowMin, float &windowMax) const;
Chris@44 360 bool getYBinRange(View *v, int y, float &freqBinMin, float &freqBinMax) const;
Chris@486 361 bool getSmoothedYBinRange(View *v, int y, float &freqBinMin, float &freqBinMax) const;
Chris@0 362
Chris@44 363 bool getYBinSourceRange(View *v, int y, float &freqMin, float &freqMax) const;
Chris@44 364 bool getAdjustedYBinSourceRange(View *v, int x, int y,
Chris@35 365 float &freqMin, float &freqMax,
Chris@35 366 float &adjFreqMin, float &adjFreqMax) const;
Chris@44 367 bool getXBinSourceRange(View *v, int x, RealTime &timeMin, RealTime &timeMax) const;
Chris@44 368 bool getXYBinSourceRange(View *v, int x, int y, float &min, float &max,
Chris@38 369 float &phaseMin, float &phaseMax) const;
Chris@0 370
Chris@0 371 size_t getWindowIncrement() const {
Chris@97 372 if (m_windowHopLevel == 0) return m_windowSize;
Chris@97 373 else if (m_windowHopLevel == 1) return (m_windowSize * 3) / 4;
Chris@97 374 else return m_windowSize / (1 << (m_windowHopLevel - 1));
Chris@0 375 }
Chris@113 376
Chris@114 377 size_t getZeroPadLevel(const View *v) const;
Chris@114 378 size_t getFFTSize(const View *v) const;
Chris@130 379 FFTModel *getFFTModel(const View *v) const;
Chris@484 380 Dense3DModelPeakCache *getPeakCache(const View *v) const;
Chris@130 381 void invalidateFFTModels();
Chris@115 382
Chris@130 383 typedef std::pair<FFTModel *, int> FFTFillPair; // model, last fill
Chris@115 384 typedef std::map<const View *, FFTFillPair> ViewFFTMap;
Chris@484 385 typedef std::map<const View *, Dense3DModelPeakCache *> PeakCacheMap;
Chris@130 386 mutable ViewFFTMap m_fftModels;
Chris@484 387 mutable PeakCacheMap m_peakCaches;
Chris@193 388 mutable Model *m_sliceableModel;
Chris@119 389
Chris@119 390 class MagnitudeRange {
Chris@119 391 public:
Chris@119 392 MagnitudeRange() : m_min(0), m_max(0) { }
Chris@119 393 bool operator==(const MagnitudeRange &r) {
Chris@119 394 return r.m_min == m_min && r.m_max == m_max;
Chris@119 395 }
Chris@119 396 bool isSet() const { return (m_min != 0 || m_max != 0); }
Chris@119 397 void set(float min, float max) {
Chris@119 398 m_min = convert(min);
Chris@119 399 m_max = convert(max);
Chris@119 400 if (m_max < m_min) m_max = m_min;
Chris@119 401 }
Chris@119 402 bool sample(float f) {
Chris@119 403 unsigned int ui = convert(f);
Chris@119 404 bool changed = false;
Chris@119 405 if (isSet()) {
Chris@119 406 if (ui < m_min) { m_min = ui; changed = true; }
Chris@119 407 if (ui > m_max) { m_max = ui; changed = true; }
Chris@119 408 } else {
Chris@119 409 m_max = m_min = ui;
Chris@119 410 changed = true;
Chris@119 411 }
Chris@119 412 return changed;
Chris@119 413 }
Chris@119 414 bool sample(const MagnitudeRange &r) {
Chris@119 415 bool changed = false;
Chris@119 416 if (isSet()) {
Chris@119 417 if (r.m_min < m_min) { m_min = r.m_min; changed = true; }
Chris@119 418 if (r.m_max > m_max) { m_max = r.m_max; changed = true; }
Chris@119 419 } else {
Chris@119 420 m_min = r.m_min;
Chris@119 421 m_max = r.m_max;
Chris@119 422 changed = true;
Chris@119 423 }
Chris@119 424 return changed;
Chris@119 425 }
Chris@119 426 float getMin() const { return float(m_min) / UINT_MAX; }
Chris@119 427 float getMax() const { return float(m_max) / UINT_MAX; }
Chris@119 428 private:
Chris@119 429 unsigned int m_min;
Chris@119 430 unsigned int m_max;
Chris@119 431 unsigned int convert(float f) {
Chris@119 432 if (f < 0.f) f = 0.f;
Chris@119 433 if (f > 1.f) f = 1.f;
Chris@119 434 return (unsigned int)(f * UINT_MAX);
Chris@119 435 }
Chris@119 436 };
Chris@119 437
Chris@119 438 typedef std::map<const View *, MagnitudeRange> ViewMagMap;
Chris@119 439 mutable ViewMagMap m_viewMags;
Chris@119 440 mutable std::vector<MagnitudeRange> m_columnMags;
Chris@119 441 void invalidateMagnitudes();
Chris@119 442 bool updateViewMagnitudes(View *v) const;
Chris@484 443 bool paintDrawBuffer(View *v, int w, int h,
Chris@490 444 int *binforx, float *binfory,
Chris@491 445 bool usePeaksCache,
Chris@491 446 MagnitudeRange &overallMag,
Chris@491 447 bool &overallMagChanged) const;
Chris@488 448 bool paintDrawBufferPeakFrequencies(View *v, int w, int h,
Chris@488 449 int *binforx,
Chris@488 450 int minbin,
Chris@488 451 int maxbin,
Chris@488 452 float displayMinFreq,
Chris@488 453 float displayMaxFreq,
Chris@491 454 bool logarithmic,
Chris@491 455 MagnitudeRange &overallMag,
Chris@491 456 bool &overallMagChanged) const;
Chris@273 457
Chris@273 458 virtual void updateMeasureRectYCoords(View *v, const MeasureRect &r) const;
Chris@273 459 virtual void setMeasureRectYCoord(View *v, MeasureRect &r, bool start, int y) const;
Chris@0 460 };
Chris@0 461
Chris@0 462 #endif