annotate layer/SpectrogramLayer.h @ 183:5f86ae638b04

* Omit translucent blue fill for selection rectangles that are superimposed over layers that use colours for meaningful purposes such as the spectrogram (CHARM change request)
author Chris Cannam
date Fri, 24 Nov 2006 16:56:15 +0000
parents 42118892f428
children e7cf6044c2a0
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@128 19 #include "Layer.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@0 46 class SpectrogramLayer : public Layer,
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@0 74 void setModel(const DenseTimeValueModel *model);
Chris@0 75
Chris@0 76 virtual PropertyList getProperties() const;
Chris@87 77 virtual QString getPropertyLabel(const PropertyName &) const;
Chris@0 78 virtual PropertyType getPropertyType(const PropertyName &) const;
Chris@0 79 virtual QString getPropertyGroupName(const PropertyName &) const;
Chris@0 80 virtual int getPropertyRangeAndValue(const PropertyName &,
Chris@0 81 int *min, int *max) const;
Chris@0 82 virtual QString getPropertyValueLabel(const PropertyName &,
Chris@0 83 int value) const;
Chris@167 84 virtual RangeMapper *getNewPropertyRangeMapper(const PropertyName &) const;
Chris@0 85 virtual void setProperty(const PropertyName &, int value);
Chris@0 86
Chris@0 87 /**
Chris@0 88 * Specify the channel to use from the source model.
Chris@0 89 * A value of -1 means to mix all available channels.
Chris@0 90 * The default is channel 0.
Chris@0 91 */
Chris@0 92 void setChannel(int);
Chris@0 93 int getChannel() const;
Chris@0 94
Chris@0 95 void setWindowSize(size_t);
Chris@0 96 size_t getWindowSize() const;
Chris@0 97
Chris@109 98 void setWindowHopLevel(size_t level);
Chris@97 99 size_t getWindowHopLevel() const;
Chris@0 100
Chris@0 101 void setWindowType(WindowType type);
Chris@0 102 WindowType getWindowType() const;
Chris@0 103
Chris@109 104 void setZeroPadLevel(size_t level);
Chris@109 105 size_t getZeroPadLevel() const;
Chris@109 106
Chris@0 107 /**
Chris@110 108 * Set the gain multiplier for sample values in this view.
Chris@0 109 * The default is 1.0.
Chris@0 110 */
Chris@0 111 void setGain(float gain);
Chris@0 112 float getGain() const;
Chris@0 113
Chris@37 114 /**
Chris@110 115 * Set the threshold for sample values to qualify for being shown
Chris@110 116 * in the FFT, in voltage units.
Chris@37 117 *
Chris@37 118 * The default is 0.0.
Chris@37 119 */
Chris@37 120 void setThreshold(float threshold);
Chris@37 121 float getThreshold() const;
Chris@37 122
Chris@37 123 void setMinFrequency(size_t);
Chris@37 124 size_t getMinFrequency() const;
Chris@37 125
Chris@0 126 void setMaxFrequency(size_t); // 0 -> no maximum
Chris@0 127 size_t getMaxFrequency() const;
Chris@0 128
Chris@37 129 enum ColourScale {
Chris@37 130 LinearColourScale,
Chris@37 131 MeterColourScale,
Chris@37 132 dBColourScale,
Chris@119 133 OtherColourScale,
Chris@37 134 PhaseColourScale
Chris@37 135 };
Chris@0 136
Chris@0 137 /**
Chris@0 138 * Specify the scale for sample levels. See WaveformLayer for
Chris@0 139 * details of meter and dB scaling. The default is dBColourScale.
Chris@0 140 */
Chris@0 141 void setColourScale(ColourScale);
Chris@0 142 ColourScale getColourScale() const;
Chris@0 143
Chris@35 144 enum FrequencyScale {
Chris@35 145 LinearFrequencyScale,
Chris@35 146 LogFrequencyScale
Chris@35 147 };
Chris@0 148
Chris@0 149 /**
Chris@0 150 * Specify the scale for the y axis.
Chris@0 151 */
Chris@0 152 void setFrequencyScale(FrequencyScale);
Chris@0 153 FrequencyScale getFrequencyScale() const;
Chris@0 154
Chris@37 155 enum BinDisplay {
Chris@37 156 AllBins,
Chris@37 157 PeakBins,
Chris@37 158 PeakFrequencies
Chris@35 159 };
Chris@35 160
Chris@35 161 /**
Chris@35 162 * Specify the processing of frequency bins for the y axis.
Chris@35 163 */
Chris@37 164 void setBinDisplay(BinDisplay);
Chris@37 165 BinDisplay getBinDisplay() const;
Chris@35 166
Chris@36 167 void setNormalizeColumns(bool n);
Chris@36 168 bool getNormalizeColumns() const;
Chris@36 169
Chris@120 170 void setNormalizeVisibleArea(bool n);
Chris@120 171 bool getNormalizeVisibleArea() const;
Chris@120 172
Chris@0 173 enum ColourScheme { DefaultColours, WhiteOnBlack, BlackOnWhite,
Chris@71 174 RedOnBlue, YellowOnBlack, BlueOnBlack, Rainbow };
Chris@0 175
Chris@0 176 void setColourScheme(ColourScheme scheme);
Chris@0 177 ColourScheme getColourScheme() const;
Chris@0 178
Chris@9 179 /**
Chris@9 180 * Specify the colourmap rotation for the colour scale.
Chris@9 181 */
Chris@9 182 void setColourRotation(int);
Chris@9 183 int getColourRotation() const;
Chris@9 184
Chris@0 185 virtual VerticalPosition getPreferredFrameCountPosition() const {
Chris@0 186 return PositionTop;
Chris@0 187 }
Chris@0 188
Chris@15 189 virtual bool isLayerOpaque() const { return true; }
Chris@183 190 virtual bool isLayerColourSignificant() const { return true; }
Chris@15 191
Chris@44 192 float getYForFrequency(View *v, float frequency) const;
Chris@44 193 float getFrequencyForY(View *v, int y) const;
Chris@42 194
Chris@115 195 virtual int getCompletion(View *v) const;
Chris@0 196
Chris@101 197 virtual bool getValueExtents(float &min, float &max,
Chris@101 198 bool &logarithmic, QString &unit) const;
Chris@101 199
Chris@101 200 virtual bool getDisplayExtents(float &min, float &max) const;
Chris@79 201
Chris@120 202 virtual bool setDisplayExtents(float min, float max);
Chris@120 203
Chris@6 204 virtual QString toXmlString(QString indent = "",
Chris@6 205 QString extraAttributes = "") const;
Chris@6 206
Chris@11 207 void setProperties(const QXmlAttributes &attributes);
Chris@11 208
Chris@47 209 virtual void setLayerDormant(const View *v, bool dormant);
Chris@29 210
Chris@94 211 virtual bool isLayerScrollable(const View *v) const { return false; }
Chris@94 212
Chris@133 213 virtual int getVerticalZoomSteps(int &defaultStep) const;
Chris@133 214 virtual int getCurrentVerticalZoomStep() const;
Chris@133 215 virtual void setVerticalZoomStep(int);
Chris@133 216
Chris@0 217 protected slots:
Chris@0 218 void cacheInvalid();
Chris@0 219 void cacheInvalid(size_t startFrame, size_t endFrame);
Chris@122 220
Chris@122 221 void preferenceChanged(PropertyContainer::PropertyName name);
Chris@0 222
Chris@0 223 void fillTimerTimedOut();
Chris@0 224
Chris@0 225 protected:
Chris@0 226 const DenseTimeValueModel *m_model; // I do not own this
Chris@0 227
Chris@35 228 int m_channel;
Chris@35 229 size_t m_windowSize;
Chris@35 230 WindowType m_windowType;
Chris@97 231 size_t m_windowHopLevel;
Chris@109 232 size_t m_zeroPadLevel;
Chris@107 233 size_t m_fftSize;
Chris@35 234 float m_gain;
Chris@37 235 float m_threshold;
Chris@35 236 int m_colourRotation;
Chris@37 237 size_t m_minFrequency;
Chris@35 238 size_t m_maxFrequency;
Chris@135 239 size_t m_initialMaxFrequency;
Chris@35 240 ColourScale m_colourScale;
Chris@35 241 ColourScheme m_colourScheme;
Chris@77 242 QColor m_crosshairColour;
Chris@35 243 FrequencyScale m_frequencyScale;
Chris@37 244 BinDisplay m_binDisplay;
Chris@36 245 bool m_normalizeColumns;
Chris@120 246 bool m_normalizeVisibleArea;
Chris@133 247 int m_lastEmittedZoomStep;
Chris@0 248
Chris@38 249 enum { NO_VALUE = 0 }; // colour index for unused pixels
Chris@38 250
Chris@86 251 class ColourMap
Chris@86 252 {
Chris@86 253 public:
Chris@86 254 QColor getColour(unsigned char index) const {
Chris@86 255 return m_colours[index];
Chris@86 256 }
Chris@86 257
Chris@86 258 void setColour(unsigned char index, QColor colour) {
Chris@86 259 m_colours[index] = colour;
Chris@86 260 }
Chris@86 261
Chris@86 262 private:
Chris@86 263 QColor m_colours[256];
Chris@86 264 };
Chris@86 265
Chris@86 266 ColourMap m_colourMap;
Chris@31 267
Chris@95 268 struct PixmapCache
Chris@95 269 {
Chris@95 270 QPixmap pixmap;
Chris@95 271 QRect validArea;
Chris@95 272 long startFrame;
Chris@95 273 size_t zoomLevel;
Chris@95 274 };
Chris@95 275 typedef std::map<const View *, PixmapCache> ViewPixmapCache;
Chris@95 276 void invalidatePixmapCaches();
Chris@95 277 void invalidatePixmapCaches(size_t startFrame, size_t endFrame);
Chris@95 278 mutable ViewPixmapCache m_pixmapCaches;
Chris@95 279 mutable QImage m_drawBuffer;
Chris@0 280
Chris@114 281 mutable QTimer *m_updateTimer;
Chris@110 282
Chris@44 283 mutable size_t m_candidateFillStartFrame;
Chris@0 284 bool m_exiting;
Chris@0 285
Chris@90 286 void setColourmap();
Chris@90 287 void rotateColourmap(int distance);
Chris@0 288
Chris@38 289 static float calculateFrequency(size_t bin,
Chris@38 290 size_t windowSize,
Chris@38 291 size_t windowIncrement,
Chris@38 292 size_t sampleRate,
Chris@38 293 float previousPhase,
Chris@38 294 float currentPhase,
Chris@38 295 bool &steadyState);
Chris@38 296
Chris@119 297 unsigned char getDisplayValue(View *v, float input) const;
Chris@40 298 float getInputForDisplayValue(unsigned char uc) const;
Chris@40 299
Chris@40 300 int getColourScaleWidth(QPainter &) const;
Chris@40 301
Chris@121 302 void illuminateLocalFeatures(View *v, QPainter &painter) const;
Chris@121 303
Chris@40 304 float getEffectiveMinFrequency() const;
Chris@40 305 float getEffectiveMaxFrequency() const;
Chris@38 306
Chris@0 307 struct LayerRange {
Chris@0 308 long startFrame;
Chris@0 309 int zoomLevel;
Chris@0 310 size_t modelStart;
Chris@0 311 size_t modelEnd;
Chris@0 312 };
Chris@44 313 bool getXBinRange(View *v, int x, float &windowMin, float &windowMax) const;
Chris@44 314 bool getYBinRange(View *v, int y, float &freqBinMin, float &freqBinMax) const;
Chris@0 315
Chris@44 316 bool getYBinSourceRange(View *v, int y, float &freqMin, float &freqMax) const;
Chris@44 317 bool getAdjustedYBinSourceRange(View *v, int x, int y,
Chris@35 318 float &freqMin, float &freqMax,
Chris@35 319 float &adjFreqMin, float &adjFreqMax) const;
Chris@44 320 bool getXBinSourceRange(View *v, int x, RealTime &timeMin, RealTime &timeMax) const;
Chris@44 321 bool getXYBinSourceRange(View *v, int x, int y, float &min, float &max,
Chris@38 322 float &phaseMin, float &phaseMax) const;
Chris@0 323
Chris@0 324 size_t getWindowIncrement() const {
Chris@97 325 if (m_windowHopLevel == 0) return m_windowSize;
Chris@97 326 else if (m_windowHopLevel == 1) return (m_windowSize * 3) / 4;
Chris@97 327 else return m_windowSize / (1 << (m_windowHopLevel - 1));
Chris@0 328 }
Chris@113 329
Chris@114 330 size_t getZeroPadLevel(const View *v) const;
Chris@114 331 size_t getFFTSize(const View *v) const;
Chris@130 332 FFTModel *getFFTModel(const View *v) const;
Chris@130 333 void invalidateFFTModels();
Chris@115 334
Chris@130 335 typedef std::pair<FFTModel *, int> FFTFillPair; // model, last fill
Chris@115 336 typedef std::map<const View *, FFTFillPair> ViewFFTMap;
Chris@119 337 typedef std::vector<float> FloatVector;
Chris@130 338 mutable ViewFFTMap m_fftModels;
Chris@119 339
Chris@119 340 class MagnitudeRange {
Chris@119 341 public:
Chris@119 342 MagnitudeRange() : m_min(0), m_max(0) { }
Chris@119 343 bool operator==(const MagnitudeRange &r) {
Chris@119 344 return r.m_min == m_min && r.m_max == m_max;
Chris@119 345 }
Chris@119 346 bool isSet() const { return (m_min != 0 || m_max != 0); }
Chris@119 347 void set(float min, float max) {
Chris@119 348 m_min = convert(min);
Chris@119 349 m_max = convert(max);
Chris@119 350 if (m_max < m_min) m_max = m_min;
Chris@119 351 }
Chris@119 352 bool sample(float f) {
Chris@119 353 unsigned int ui = convert(f);
Chris@119 354 bool changed = false;
Chris@119 355 if (isSet()) {
Chris@119 356 if (ui < m_min) { m_min = ui; changed = true; }
Chris@119 357 if (ui > m_max) { m_max = ui; changed = true; }
Chris@119 358 } else {
Chris@119 359 m_max = m_min = ui;
Chris@119 360 changed = true;
Chris@119 361 }
Chris@119 362 return changed;
Chris@119 363 }
Chris@119 364 bool sample(const MagnitudeRange &r) {
Chris@119 365 bool changed = false;
Chris@119 366 if (isSet()) {
Chris@119 367 if (r.m_min < m_min) { m_min = r.m_min; changed = true; }
Chris@119 368 if (r.m_max > m_max) { m_max = r.m_max; changed = true; }
Chris@119 369 } else {
Chris@119 370 m_min = r.m_min;
Chris@119 371 m_max = r.m_max;
Chris@119 372 changed = true;
Chris@119 373 }
Chris@119 374 return changed;
Chris@119 375 }
Chris@119 376 float getMin() const { return float(m_min) / UINT_MAX; }
Chris@119 377 float getMax() const { return float(m_max) / UINT_MAX; }
Chris@119 378 private:
Chris@119 379 unsigned int m_min;
Chris@119 380 unsigned int m_max;
Chris@119 381 unsigned int convert(float f) {
Chris@119 382 if (f < 0.f) f = 0.f;
Chris@119 383 if (f > 1.f) f = 1.f;
Chris@119 384 return (unsigned int)(f * UINT_MAX);
Chris@119 385 }
Chris@119 386 };
Chris@119 387
Chris@119 388 typedef std::map<const View *, MagnitudeRange> ViewMagMap;
Chris@119 389 mutable ViewMagMap m_viewMags;
Chris@119 390 mutable std::vector<MagnitudeRange> m_columnMags;
Chris@119 391 void invalidateMagnitudes();
Chris@119 392 bool updateViewMagnitudes(View *v) const;
Chris@0 393 };
Chris@0 394
Chris@0 395 #endif