annotate layer/SpectrogramLayer.h @ 349:369a197737c7

* Various fixes to object lifetime management, particularly in the spectrum layer and for notification of main model deletion. The main purpose of this is to improve the behaviour of the spectrum, but I think it may also help with #1840922 Various crashes in Layer Summary window.
author Chris Cannam
date Wed, 23 Jan 2008 15:43:27 +0000
parents 2f83b6e3b8ca
children 2ed4e572d0d4
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@114 39
Chris@0 40
Chris@0 41 /**
Chris@0 42 * SpectrogramLayer represents waveform data (obtained from a
Chris@0 43 * DenseTimeValueModel) in spectrogram form.
Chris@0 44 */
Chris@0 45
Chris@193 46 class SpectrogramLayer : public SliceableLayer,
Chris@31 47 public PowerOfSqrtTwoZoomConstraint
Chris@0 48 {
Chris@0 49 Q_OBJECT
Chris@0 50
Chris@0 51 public:
Chris@37 52 enum Configuration { FullRangeDb, MelodicRange, MelodicPeaks };
Chris@0 53
Chris@44 54 SpectrogramLayer(Configuration = FullRangeDb);
Chris@0 55 ~SpectrogramLayer();
Chris@0 56
Chris@0 57 virtual const ZoomConstraint *getZoomConstraint() const { return this; }
Chris@0 58 virtual const Model *getModel() const { return m_model; }
Chris@44 59 virtual void paint(View *v, QPainter &paint, QRect rect) const;
Chris@0 60
Chris@44 61 virtual int getVerticalScaleWidth(View *v, QPainter &) const;
Chris@44 62 virtual void paintVerticalScale(View *v, QPainter &paint, QRect rect) const;
Chris@0 63
Chris@77 64 virtual bool getCrosshairExtents(View *, QPainter &, QPoint cursorPos,
Chris@77 65 std::vector<QRect> &extents) const;
Chris@77 66 virtual void paintCrosshairs(View *, QPainter &, QPoint) const;
Chris@77 67
Chris@44 68 virtual QString getFeatureDescription(View *v, QPoint &) const;
Chris@0 69
Chris@44 70 virtual bool snapToFeatureFrame(View *v, int &frame,
Chris@28 71 size_t &resolution,
Chris@28 72 SnapType snap) const;
Chris@13 73
Chris@283 74 virtual void measureDoubleClick(View *, QMouseEvent *);
Chris@283 75
Chris@224 76 virtual bool hasLightBackground() const;
Chris@224 77
Chris@0 78 void setModel(const DenseTimeValueModel *model);
Chris@0 79
Chris@0 80 virtual PropertyList getProperties() const;
Chris@87 81 virtual QString getPropertyLabel(const PropertyName &) const;
Chris@335 82 virtual QString getPropertyIconName(const PropertyName &) const;
Chris@0 83 virtual PropertyType getPropertyType(const PropertyName &) const;
Chris@0 84 virtual QString getPropertyGroupName(const PropertyName &) const;
Chris@0 85 virtual int getPropertyRangeAndValue(const PropertyName &,
Chris@216 86 int *min, int *max, int *deflt) const;
Chris@0 87 virtual QString getPropertyValueLabel(const PropertyName &,
Chris@0 88 int value) const;
Chris@167 89 virtual RangeMapper *getNewPropertyRangeMapper(const PropertyName &) const;
Chris@0 90 virtual void setProperty(const PropertyName &, int value);
Chris@0 91
Chris@0 92 /**
Chris@0 93 * Specify the channel to use from the source model.
Chris@0 94 * A value of -1 means to mix all available channels.
Chris@0 95 * The default is channel 0.
Chris@0 96 */
Chris@0 97 void setChannel(int);
Chris@0 98 int getChannel() const;
Chris@0 99
Chris@0 100 void setWindowSize(size_t);
Chris@0 101 size_t getWindowSize() const;
Chris@0 102
Chris@109 103 void setWindowHopLevel(size_t level);
Chris@97 104 size_t getWindowHopLevel() const;
Chris@0 105
Chris@0 106 void setWindowType(WindowType type);
Chris@0 107 WindowType getWindowType() const;
Chris@0 108
Chris@109 109 void setZeroPadLevel(size_t level);
Chris@109 110 size_t getZeroPadLevel() const;
Chris@109 111
Chris@0 112 /**
Chris@110 113 * Set the gain multiplier for sample values in this view.
Chris@0 114 * The default is 1.0.
Chris@0 115 */
Chris@0 116 void setGain(float gain);
Chris@0 117 float getGain() const;
Chris@0 118
Chris@37 119 /**
Chris@110 120 * Set the threshold for sample values to qualify for being shown
Chris@110 121 * in the FFT, in voltage units.
Chris@37 122 *
Chris@37 123 * The default is 0.0.
Chris@37 124 */
Chris@37 125 void setThreshold(float threshold);
Chris@37 126 float getThreshold() const;
Chris@37 127
Chris@37 128 void setMinFrequency(size_t);
Chris@37 129 size_t getMinFrequency() const;
Chris@37 130
Chris@0 131 void setMaxFrequency(size_t); // 0 -> no maximum
Chris@0 132 size_t getMaxFrequency() const;
Chris@0 133
Chris@37 134 enum ColourScale {
Chris@37 135 LinearColourScale,
Chris@37 136 MeterColourScale,
Chris@215 137 dBSquaredColourScale,
Chris@37 138 dBColourScale,
Chris@37 139 PhaseColourScale
Chris@37 140 };
Chris@0 141
Chris@0 142 /**
Chris@0 143 * Specify the scale for sample levels. See WaveformLayer for
Chris@0 144 * details of meter and dB scaling. The default is dBColourScale.
Chris@0 145 */
Chris@0 146 void setColourScale(ColourScale);
Chris@0 147 ColourScale getColourScale() const;
Chris@0 148
Chris@35 149 enum FrequencyScale {
Chris@35 150 LinearFrequencyScale,
Chris@35 151 LogFrequencyScale
Chris@35 152 };
Chris@0 153
Chris@0 154 /**
Chris@0 155 * Specify the scale for the y axis.
Chris@0 156 */
Chris@0 157 void setFrequencyScale(FrequencyScale);
Chris@0 158 FrequencyScale getFrequencyScale() const;
Chris@0 159
Chris@37 160 enum BinDisplay {
Chris@37 161 AllBins,
Chris@37 162 PeakBins,
Chris@37 163 PeakFrequencies
Chris@35 164 };
Chris@35 165
Chris@35 166 /**
Chris@35 167 * Specify the processing of frequency bins for the y axis.
Chris@35 168 */
Chris@37 169 void setBinDisplay(BinDisplay);
Chris@37 170 BinDisplay getBinDisplay() const;
Chris@35 171
Chris@36 172 void setNormalizeColumns(bool n);
Chris@36 173 bool getNormalizeColumns() const;
Chris@36 174
Chris@120 175 void setNormalizeVisibleArea(bool n);
Chris@120 176 bool getNormalizeVisibleArea() const;
Chris@120 177
Chris@197 178 void setColourMap(int map);
Chris@197 179 int getColourMap() const;
Chris@0 180
Chris@9 181 /**
Chris@9 182 * Specify the colourmap rotation for the colour scale.
Chris@9 183 */
Chris@9 184 void setColourRotation(int);
Chris@9 185 int getColourRotation() const;
Chris@9 186
Chris@0 187 virtual VerticalPosition getPreferredFrameCountPosition() const {
Chris@0 188 return PositionTop;
Chris@0 189 }
Chris@0 190
Chris@15 191 virtual bool isLayerOpaque() const { return true; }
Chris@287 192
Chris@287 193 virtual ColourSignificance getLayerColourSignificance() const {
Chris@287 194 return ColourHasMeaningfulValue;
Chris@287 195 }
Chris@15 196
Chris@267 197 float getYForFrequency(const View *v, float frequency) const;
Chris@267 198 float getFrequencyForY(const View *v, int y) const;
Chris@42 199
Chris@115 200 virtual int getCompletion(View *v) const;
Chris@0 201
Chris@101 202 virtual bool getValueExtents(float &min, float &max,
Chris@101 203 bool &logarithmic, QString &unit) const;
Chris@101 204
Chris@101 205 virtual bool getDisplayExtents(float &min, float &max) const;
Chris@79 206
Chris@120 207 virtual bool setDisplayExtents(float min, float max);
Chris@120 208
Chris@267 209 virtual bool getYScaleValue(const View *, int, float &, QString &) const;
Chris@261 210
Chris@316 211 virtual void toXml(QTextStream &stream, QString indent = "",
Chris@316 212 QString extraAttributes = "") const;
Chris@6 213
Chris@11 214 void setProperties(const QXmlAttributes &attributes);
Chris@11 215
Chris@47 216 virtual void setLayerDormant(const View *v, bool dormant);
Chris@29 217
Chris@248 218 virtual bool isLayerScrollable(const View *) const { return false; }
Chris@94 219
Chris@133 220 virtual int getVerticalZoomSteps(int &defaultStep) const;
Chris@133 221 virtual int getCurrentVerticalZoomStep() const;
Chris@133 222 virtual void setVerticalZoomStep(int);
Chris@187 223 virtual RangeMapper *getNewVerticalZoomRangeMapper() const;
Chris@133 224
Chris@193 225 virtual const Model *getSliceableModel() const;
Chris@193 226
Chris@0 227 protected slots:
Chris@0 228 void cacheInvalid();
Chris@0 229 void cacheInvalid(size_t startFrame, size_t endFrame);
Chris@122 230
Chris@122 231 void preferenceChanged(PropertyContainer::PropertyName name);
Chris@0 232
Chris@0 233 void fillTimerTimedOut();
Chris@0 234
Chris@0 235 protected:
Chris@0 236 const DenseTimeValueModel *m_model; // I do not own this
Chris@0 237
Chris@35 238 int m_channel;
Chris@35 239 size_t m_windowSize;
Chris@35 240 WindowType m_windowType;
Chris@97 241 size_t m_windowHopLevel;
Chris@109 242 size_t m_zeroPadLevel;
Chris@107 243 size_t m_fftSize;
Chris@35 244 float m_gain;
Chris@215 245 float m_initialGain;
Chris@37 246 float m_threshold;
Chris@215 247 float m_initialThreshold;
Chris@35 248 int m_colourRotation;
Chris@215 249 int m_initialRotation;
Chris@37 250 size_t m_minFrequency;
Chris@35 251 size_t m_maxFrequency;
Chris@135 252 size_t m_initialMaxFrequency;
Chris@35 253 ColourScale m_colourScale;
Chris@197 254 int m_colourMap;
Chris@77 255 QColor m_crosshairColour;
Chris@35 256 FrequencyScale m_frequencyScale;
Chris@37 257 BinDisplay m_binDisplay;
Chris@36 258 bool m_normalizeColumns;
Chris@120 259 bool m_normalizeVisibleArea;
Chris@133 260 int m_lastEmittedZoomStep;
Chris@0 261
Chris@215 262 mutable int m_lastPaintBlockWidth;
Chris@215 263 mutable RealTime m_lastPaintTime;
Chris@215 264
Chris@38 265 enum { NO_VALUE = 0 }; // colour index for unused pixels
Chris@38 266
Chris@197 267 class Palette
Chris@86 268 {
Chris@86 269 public:
Chris@86 270 QColor getColour(unsigned char index) const {
Chris@86 271 return m_colours[index];
Chris@86 272 }
Chris@86 273
Chris@86 274 void setColour(unsigned char index, QColor colour) {
Chris@86 275 m_colours[index] = colour;
Chris@86 276 }
Chris@86 277
Chris@86 278 private:
Chris@86 279 QColor m_colours[256];
Chris@86 280 };
Chris@86 281
Chris@197 282 Palette m_palette;
Chris@31 283
Chris@95 284 struct PixmapCache
Chris@95 285 {
Chris@95 286 QPixmap pixmap;
Chris@95 287 QRect validArea;
Chris@95 288 long startFrame;
Chris@95 289 size_t zoomLevel;
Chris@95 290 };
Chris@95 291 typedef std::map<const View *, PixmapCache> ViewPixmapCache;
Chris@95 292 void invalidatePixmapCaches();
Chris@95 293 void invalidatePixmapCaches(size_t startFrame, size_t endFrame);
Chris@95 294 mutable ViewPixmapCache m_pixmapCaches;
Chris@95 295 mutable QImage m_drawBuffer;
Chris@0 296
Chris@114 297 mutable QTimer *m_updateTimer;
Chris@110 298
Chris@44 299 mutable size_t m_candidateFillStartFrame;
Chris@0 300 bool m_exiting;
Chris@0 301
Chris@197 302 void initialisePalette();
Chris@197 303 void rotatePalette(int distance);
Chris@0 304
Chris@119 305 unsigned char getDisplayValue(View *v, float input) const;
Chris@40 306 float getInputForDisplayValue(unsigned char uc) const;
Chris@40 307
Chris@40 308 int getColourScaleWidth(QPainter &) const;
Chris@40 309
Chris@121 310 void illuminateLocalFeatures(View *v, QPainter &painter) const;
Chris@121 311
Chris@40 312 float getEffectiveMinFrequency() const;
Chris@40 313 float getEffectiveMaxFrequency() const;
Chris@38 314
Chris@0 315 struct LayerRange {
Chris@0 316 long startFrame;
Chris@0 317 int zoomLevel;
Chris@0 318 size_t modelStart;
Chris@0 319 size_t modelEnd;
Chris@0 320 };
Chris@44 321 bool getXBinRange(View *v, int x, float &windowMin, float &windowMax) const;
Chris@44 322 bool getYBinRange(View *v, int y, float &freqBinMin, float &freqBinMax) const;
Chris@0 323
Chris@44 324 bool getYBinSourceRange(View *v, int y, float &freqMin, float &freqMax) const;
Chris@44 325 bool getAdjustedYBinSourceRange(View *v, int x, int y,
Chris@35 326 float &freqMin, float &freqMax,
Chris@35 327 float &adjFreqMin, float &adjFreqMax) const;
Chris@44 328 bool getXBinSourceRange(View *v, int x, RealTime &timeMin, RealTime &timeMax) const;
Chris@44 329 bool getXYBinSourceRange(View *v, int x, int y, float &min, float &max,
Chris@38 330 float &phaseMin, float &phaseMax) const;
Chris@0 331
Chris@0 332 size_t getWindowIncrement() const {
Chris@97 333 if (m_windowHopLevel == 0) return m_windowSize;
Chris@97 334 else if (m_windowHopLevel == 1) return (m_windowSize * 3) / 4;
Chris@97 335 else return m_windowSize / (1 << (m_windowHopLevel - 1));
Chris@0 336 }
Chris@113 337
Chris@114 338 size_t getZeroPadLevel(const View *v) const;
Chris@114 339 size_t getFFTSize(const View *v) const;
Chris@130 340 FFTModel *getFFTModel(const View *v) const;
Chris@130 341 void invalidateFFTModels();
Chris@115 342
Chris@130 343 typedef std::pair<FFTModel *, int> FFTFillPair; // model, last fill
Chris@115 344 typedef std::map<const View *, FFTFillPair> ViewFFTMap;
Chris@119 345 typedef std::vector<float> FloatVector;
Chris@130 346 mutable ViewFFTMap m_fftModels;
Chris@193 347 mutable Model *m_sliceableModel;
Chris@119 348
Chris@119 349 class MagnitudeRange {
Chris@119 350 public:
Chris@119 351 MagnitudeRange() : m_min(0), m_max(0) { }
Chris@119 352 bool operator==(const MagnitudeRange &r) {
Chris@119 353 return r.m_min == m_min && r.m_max == m_max;
Chris@119 354 }
Chris@119 355 bool isSet() const { return (m_min != 0 || m_max != 0); }
Chris@119 356 void set(float min, float max) {
Chris@119 357 m_min = convert(min);
Chris@119 358 m_max = convert(max);
Chris@119 359 if (m_max < m_min) m_max = m_min;
Chris@119 360 }
Chris@119 361 bool sample(float f) {
Chris@119 362 unsigned int ui = convert(f);
Chris@119 363 bool changed = false;
Chris@119 364 if (isSet()) {
Chris@119 365 if (ui < m_min) { m_min = ui; changed = true; }
Chris@119 366 if (ui > m_max) { m_max = ui; changed = true; }
Chris@119 367 } else {
Chris@119 368 m_max = m_min = ui;
Chris@119 369 changed = true;
Chris@119 370 }
Chris@119 371 return changed;
Chris@119 372 }
Chris@119 373 bool sample(const MagnitudeRange &r) {
Chris@119 374 bool changed = false;
Chris@119 375 if (isSet()) {
Chris@119 376 if (r.m_min < m_min) { m_min = r.m_min; changed = true; }
Chris@119 377 if (r.m_max > m_max) { m_max = r.m_max; changed = true; }
Chris@119 378 } else {
Chris@119 379 m_min = r.m_min;
Chris@119 380 m_max = r.m_max;
Chris@119 381 changed = true;
Chris@119 382 }
Chris@119 383 return changed;
Chris@119 384 }
Chris@119 385 float getMin() const { return float(m_min) / UINT_MAX; }
Chris@119 386 float getMax() const { return float(m_max) / UINT_MAX; }
Chris@119 387 private:
Chris@119 388 unsigned int m_min;
Chris@119 389 unsigned int m_max;
Chris@119 390 unsigned int convert(float f) {
Chris@119 391 if (f < 0.f) f = 0.f;
Chris@119 392 if (f > 1.f) f = 1.f;
Chris@119 393 return (unsigned int)(f * UINT_MAX);
Chris@119 394 }
Chris@119 395 };
Chris@119 396
Chris@119 397 typedef std::map<const View *, MagnitudeRange> ViewMagMap;
Chris@119 398 mutable ViewMagMap m_viewMags;
Chris@119 399 mutable std::vector<MagnitudeRange> m_columnMags;
Chris@119 400 void invalidateMagnitudes();
Chris@119 401 bool updateViewMagnitudes(View *v) const;
Chris@273 402
Chris@273 403 virtual void updateMeasureRectYCoords(View *v, const MeasureRect &r) const;
Chris@273 404 virtual void setMeasureRectYCoord(View *v, MeasureRect &r, bool start, int y) const;
Chris@0 405 };
Chris@0 406
Chris@0 407 #endif