annotate layer/SpectrogramLayer.h @ 590:241929c5d57c sonification

Check the scale width in the View (which has access to it); ask the layer to do something when the user clicks in the scale regardless of the edit mode, and continue with normal processing if the layer has nothing interesting to do
author Chris Cannam
date Fri, 24 Jun 2011 14:27:32 +0100
parents 7ebd5a21d74f
children
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@44 63 virtual int getVerticalScaleWidth(View *v, QPainter &) const;
Chris@44 64 virtual void paintVerticalScale(View *v, 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@590 230 virtual bool scaleClicked(const View *, QMouseEvent *);
mathieu@589 231
Chris@0 232 protected slots:
Chris@0 233 void cacheInvalid();
Chris@0 234 void cacheInvalid(size_t startFrame, size_t endFrame);
Chris@122 235
Chris@122 236 void preferenceChanged(PropertyContainer::PropertyName name);
Chris@0 237
Chris@0 238 void fillTimerTimedOut();
Chris@0 239
Chris@0 240 protected:
Chris@0 241 const DenseTimeValueModel *m_model; // I do not own this
Chris@484 242
Chris@35 243 int m_channel;
Chris@35 244 size_t m_windowSize;
Chris@35 245 WindowType m_windowType;
Chris@97 246 size_t m_windowHopLevel;
Chris@109 247 size_t m_zeroPadLevel;
Chris@107 248 size_t m_fftSize;
Chris@35 249 float m_gain;
Chris@215 250 float m_initialGain;
Chris@37 251 float m_threshold;
Chris@215 252 float m_initialThreshold;
Chris@35 253 int m_colourRotation;
Chris@215 254 int m_initialRotation;
Chris@37 255 size_t m_minFrequency;
Chris@35 256 size_t m_maxFrequency;
Chris@135 257 size_t m_initialMaxFrequency;
Chris@35 258 ColourScale m_colourScale;
Chris@197 259 int m_colourMap;
Chris@77 260 QColor m_crosshairColour;
Chris@35 261 FrequencyScale m_frequencyScale;
Chris@37 262 BinDisplay m_binDisplay;
Chris@36 263 bool m_normalizeColumns;
Chris@120 264 bool m_normalizeVisibleArea;
Chris@133 265 int m_lastEmittedZoomStep;
Chris@389 266 bool m_synchronous;
Chris@0 267
Chris@215 268 mutable int m_lastPaintBlockWidth;
Chris@215 269 mutable RealTime m_lastPaintTime;
Chris@215 270
Chris@38 271 enum { NO_VALUE = 0 }; // colour index for unused pixels
Chris@38 272
Chris@197 273 class Palette
Chris@86 274 {
Chris@86 275 public:
Chris@86 276 QColor getColour(unsigned char index) const {
Chris@86 277 return m_colours[index];
Chris@86 278 }
Chris@86 279
Chris@86 280 void setColour(unsigned char index, QColor colour) {
Chris@86 281 m_colours[index] = colour;
Chris@86 282 }
Chris@86 283
Chris@86 284 private:
Chris@86 285 QColor m_colours[256];
Chris@86 286 };
Chris@86 287
Chris@197 288 Palette m_palette;
Chris@31 289
Chris@477 290 /**
Chris@478 291 * ImageCache covers the area of the view, at view resolution.
Chris@477 292 * Not all of it is necessarily valid at once (it is refreshed
Chris@477 293 * in parts when scrolling, for example).
Chris@477 294 */
Chris@478 295 struct ImageCache
Chris@95 296 {
Chris@478 297 QImage image;
Chris@95 298 QRect validArea;
Chris@95 299 long startFrame;
Chris@95 300 size_t zoomLevel;
Chris@95 301 };
Chris@478 302 typedef std::map<const View *, ImageCache> ViewImageCache;
Chris@478 303 void invalidateImageCaches();
Chris@478 304 void invalidateImageCaches(size_t startFrame, size_t endFrame);
Chris@478 305 mutable ViewImageCache m_imageCaches;
Chris@477 306
Chris@477 307 /**
Chris@477 308 * When painting, we draw directly onto the draw buffer and then
Chris@478 309 * copy this to the part of the image cache that needed refreshing
Chris@478 310 * before copying the image cache onto the window. (Remind me why
Chris@477 311 * we don't draw directly onto the cache?)
Chris@477 312 */
Chris@95 313 mutable QImage m_drawBuffer;
Chris@0 314
Chris@114 315 mutable QTimer *m_updateTimer;
Chris@110 316
Chris@44 317 mutable size_t m_candidateFillStartFrame;
Chris@0 318 bool m_exiting;
Chris@0 319
Chris@197 320 void initialisePalette();
Chris@197 321 void rotatePalette(int distance);
Chris@0 322
Chris@119 323 unsigned char getDisplayValue(View *v, float input) const;
Chris@40 324 float getInputForDisplayValue(unsigned char uc) const;
Chris@40 325
Chris@40 326 int getColourScaleWidth(QPainter &) const;
Chris@40 327
Chris@121 328 void illuminateLocalFeatures(View *v, QPainter &painter) const;
Chris@121 329
Chris@40 330 float getEffectiveMinFrequency() const;
Chris@40 331 float getEffectiveMaxFrequency() const;
Chris@38 332
Chris@0 333 struct LayerRange {
Chris@0 334 long startFrame;
Chris@0 335 int zoomLevel;
Chris@0 336 size_t modelStart;
Chris@0 337 size_t modelEnd;
Chris@0 338 };
Chris@486 339
Chris@486 340 // Note that the getYBin... methods return the nominal bin in the
Chris@486 341 // un-smoothed spectrogram. This is not necessarily the same bin
Chris@486 342 // as is pulled from the spectrogram and drawn at the given
Chris@486 343 // position, if the spectrogram has oversampling smoothing. Use
Chris@486 344 // getSmoothedYBinRange to obtain that.
Chris@486 345
Chris@44 346 bool getXBinRange(View *v, int x, float &windowMin, float &windowMax) const;
Chris@44 347 bool getYBinRange(View *v, int y, float &freqBinMin, float &freqBinMax) const;
Chris@486 348 bool getSmoothedYBinRange(View *v, int y, float &freqBinMin, float &freqBinMax) const;
Chris@0 349
Chris@44 350 bool getYBinSourceRange(View *v, int y, float &freqMin, float &freqMax) const;
Chris@44 351 bool getAdjustedYBinSourceRange(View *v, int x, int y,
Chris@35 352 float &freqMin, float &freqMax,
Chris@35 353 float &adjFreqMin, float &adjFreqMax) const;
Chris@44 354 bool getXBinSourceRange(View *v, int x, RealTime &timeMin, RealTime &timeMax) const;
Chris@44 355 bool getXYBinSourceRange(View *v, int x, int y, float &min, float &max,
Chris@38 356 float &phaseMin, float &phaseMax) const;
Chris@0 357
Chris@0 358 size_t getWindowIncrement() const {
Chris@97 359 if (m_windowHopLevel == 0) return m_windowSize;
Chris@97 360 else if (m_windowHopLevel == 1) return (m_windowSize * 3) / 4;
Chris@97 361 else return m_windowSize / (1 << (m_windowHopLevel - 1));
Chris@0 362 }
Chris@113 363
Chris@114 364 size_t getZeroPadLevel(const View *v) const;
Chris@114 365 size_t getFFTSize(const View *v) const;
Chris@130 366 FFTModel *getFFTModel(const View *v) const;
Chris@484 367 Dense3DModelPeakCache *getPeakCache(const View *v) const;
Chris@130 368 void invalidateFFTModels();
Chris@115 369
Chris@130 370 typedef std::pair<FFTModel *, int> FFTFillPair; // model, last fill
Chris@115 371 typedef std::map<const View *, FFTFillPair> ViewFFTMap;
Chris@484 372 typedef std::map<const View *, Dense3DModelPeakCache *> PeakCacheMap;
Chris@130 373 mutable ViewFFTMap m_fftModels;
Chris@484 374 mutable PeakCacheMap m_peakCaches;
Chris@193 375 mutable Model *m_sliceableModel;
Chris@119 376
Chris@119 377 class MagnitudeRange {
Chris@119 378 public:
Chris@119 379 MagnitudeRange() : m_min(0), m_max(0) { }
Chris@119 380 bool operator==(const MagnitudeRange &r) {
Chris@119 381 return r.m_min == m_min && r.m_max == m_max;
Chris@119 382 }
Chris@119 383 bool isSet() const { return (m_min != 0 || m_max != 0); }
Chris@119 384 void set(float min, float max) {
Chris@119 385 m_min = convert(min);
Chris@119 386 m_max = convert(max);
Chris@119 387 if (m_max < m_min) m_max = m_min;
Chris@119 388 }
Chris@119 389 bool sample(float f) {
Chris@119 390 unsigned int ui = convert(f);
Chris@119 391 bool changed = false;
Chris@119 392 if (isSet()) {
Chris@119 393 if (ui < m_min) { m_min = ui; changed = true; }
Chris@119 394 if (ui > m_max) { m_max = ui; changed = true; }
Chris@119 395 } else {
Chris@119 396 m_max = m_min = ui;
Chris@119 397 changed = true;
Chris@119 398 }
Chris@119 399 return changed;
Chris@119 400 }
Chris@119 401 bool sample(const MagnitudeRange &r) {
Chris@119 402 bool changed = false;
Chris@119 403 if (isSet()) {
Chris@119 404 if (r.m_min < m_min) { m_min = r.m_min; changed = true; }
Chris@119 405 if (r.m_max > m_max) { m_max = r.m_max; changed = true; }
Chris@119 406 } else {
Chris@119 407 m_min = r.m_min;
Chris@119 408 m_max = r.m_max;
Chris@119 409 changed = true;
Chris@119 410 }
Chris@119 411 return changed;
Chris@119 412 }
Chris@119 413 float getMin() const { return float(m_min) / UINT_MAX; }
Chris@119 414 float getMax() const { return float(m_max) / UINT_MAX; }
Chris@119 415 private:
Chris@119 416 unsigned int m_min;
Chris@119 417 unsigned int m_max;
Chris@119 418 unsigned int convert(float f) {
Chris@119 419 if (f < 0.f) f = 0.f;
Chris@119 420 if (f > 1.f) f = 1.f;
Chris@119 421 return (unsigned int)(f * UINT_MAX);
Chris@119 422 }
Chris@119 423 };
Chris@119 424
Chris@119 425 typedef std::map<const View *, MagnitudeRange> ViewMagMap;
Chris@119 426 mutable ViewMagMap m_viewMags;
Chris@119 427 mutable std::vector<MagnitudeRange> m_columnMags;
Chris@119 428 void invalidateMagnitudes();
Chris@119 429 bool updateViewMagnitudes(View *v) const;
Chris@484 430 bool paintDrawBuffer(View *v, int w, int h,
Chris@490 431 int *binforx, float *binfory,
Chris@491 432 bool usePeaksCache,
Chris@491 433 MagnitudeRange &overallMag,
Chris@491 434 bool &overallMagChanged) const;
Chris@488 435 bool paintDrawBufferPeakFrequencies(View *v, int w, int h,
Chris@488 436 int *binforx,
Chris@488 437 int minbin,
Chris@488 438 int maxbin,
Chris@488 439 float displayMinFreq,
Chris@488 440 float displayMaxFreq,
Chris@491 441 bool logarithmic,
Chris@491 442 MagnitudeRange &overallMag,
Chris@491 443 bool &overallMagChanged) const;
Chris@273 444
Chris@273 445 virtual void updateMeasureRectYCoords(View *v, const MeasureRect &r) const;
Chris@273 446 virtual void setMeasureRectYCoord(View *v, MeasureRect &r, bool start, int y) const;
Chris@0 447 };
Chris@0 448
Chris@0 449 #endif