annotate layer/SpectrogramLayer.h @ 162:f32212631b9c

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