annotate layer/SpectrogramLayer.h @ 473:4f4f943bfdfc

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