annotate layer/SpectrogramLayer.h @ 101:0f36cdf407a6 sv1-v0.9rc1

* Make vertical scale alignment modes work in note layer as well as time-value layer, and several significant fixes to it * Make it possible to draw notes properly on the note layer * Show units (and frequencies etc in note layer's case) in the time-value and note layer description boxes * Minor fix to item edit dialog layout * Some minor menu rearrangement * Comment out a lot of debug output * Add SV website and reference URLs to Help menu, and add code to (attempt to) open them in the user's preferred browser
author Chris Cannam
date Fri, 12 May 2006 14:40:43 +0000
parents a0e7edf9703a
children 1348818e7be7
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@0 19 #include "base/Layer.h"
Chris@0 20 #include "base/Window.h"
Chris@71 21 #include "base/RealTime.h"
Chris@92 22 #include "base/Thread.h"
Chris@0 23 #include "model/PowerOfSqrtTwoZoomConstraint.h"
Chris@0 24 #include "model/DenseTimeValueModel.h"
Chris@0 25
Chris@0 26 #include <QMutex>
Chris@0 27 #include <QWaitCondition>
Chris@95 28 #include <QImage>
Chris@95 29 #include <QPixmap>
Chris@0 30
Chris@0 31 #include <fftw3.h>
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@85 38 class FFTCacheBase;
Chris@0 39
Chris@0 40 /**
Chris@0 41 * SpectrogramLayer represents waveform data (obtained from a
Chris@0 42 * DenseTimeValueModel) in spectrogram form.
Chris@0 43 */
Chris@0 44
Chris@0 45 class SpectrogramLayer : public Layer,
Chris@31 46 public PowerOfSqrtTwoZoomConstraint
Chris@0 47 {
Chris@0 48 Q_OBJECT
Chris@0 49
Chris@0 50 public:
Chris@37 51 enum Configuration { FullRangeDb, MelodicRange, MelodicPeaks };
Chris@0 52
Chris@44 53 SpectrogramLayer(Configuration = FullRangeDb);
Chris@0 54 ~SpectrogramLayer();
Chris@0 55
Chris@0 56 virtual const ZoomConstraint *getZoomConstraint() const { return this; }
Chris@0 57 virtual const Model *getModel() const { return m_model; }
Chris@44 58 virtual void paint(View *v, QPainter &paint, QRect rect) const;
Chris@0 59
Chris@44 60 virtual int getVerticalScaleWidth(View *v, QPainter &) const;
Chris@44 61 virtual void paintVerticalScale(View *v, QPainter &paint, QRect rect) const;
Chris@0 62
Chris@77 63 virtual bool getCrosshairExtents(View *, QPainter &, QPoint cursorPos,
Chris@77 64 std::vector<QRect> &extents) const;
Chris@77 65 virtual void paintCrosshairs(View *, QPainter &, QPoint) const;
Chris@77 66
Chris@44 67 virtual QString getFeatureDescription(View *v, QPoint &) const;
Chris@0 68
Chris@44 69 virtual bool snapToFeatureFrame(View *v, int &frame,
Chris@28 70 size_t &resolution,
Chris@28 71 SnapType snap) const;
Chris@13 72
Chris@0 73 void setModel(const DenseTimeValueModel *model);
Chris@0 74
Chris@0 75 virtual PropertyList getProperties() const;
Chris@87 76 virtual QString getPropertyLabel(const PropertyName &) const;
Chris@0 77 virtual PropertyType getPropertyType(const PropertyName &) const;
Chris@0 78 virtual QString getPropertyGroupName(const PropertyName &) const;
Chris@0 79 virtual int getPropertyRangeAndValue(const PropertyName &,
Chris@0 80 int *min, int *max) const;
Chris@0 81 virtual QString getPropertyValueLabel(const PropertyName &,
Chris@0 82 int value) const;
Chris@0 83 virtual void setProperty(const PropertyName &, int value);
Chris@0 84
Chris@0 85 /**
Chris@0 86 * Specify the channel to use from the source model.
Chris@0 87 * A value of -1 means to mix all available channels.
Chris@0 88 * The default is channel 0.
Chris@0 89 */
Chris@0 90 void setChannel(int);
Chris@0 91 int getChannel() const;
Chris@0 92
Chris@0 93 void setWindowSize(size_t);
Chris@0 94 size_t getWindowSize() const;
Chris@0 95
Chris@97 96 void setWindowHopLevel(size_t percent);
Chris@97 97 size_t getWindowHopLevel() const;
Chris@0 98
Chris@0 99 void setWindowType(WindowType type);
Chris@0 100 WindowType getWindowType() const;
Chris@0 101
Chris@0 102 /**
Chris@0 103 * Set the gain multiplier for sample values in this view prior to
Chris@0 104 * FFT calculation.
Chris@0 105 *
Chris@0 106 * The default is 1.0.
Chris@0 107 */
Chris@0 108 void setGain(float gain);
Chris@0 109 float getGain() const;
Chris@0 110
Chris@37 111 /**
Chris@37 112 * Set the threshold for sample values to be shown in the FFT,
Chris@37 113 * in voltage units.
Chris@37 114 *
Chris@37 115 * The default is 0.0.
Chris@37 116 */
Chris@37 117 void setThreshold(float threshold);
Chris@37 118 float getThreshold() const;
Chris@37 119
Chris@37 120 void setMinFrequency(size_t);
Chris@37 121 size_t getMinFrequency() const;
Chris@37 122
Chris@0 123 void setMaxFrequency(size_t); // 0 -> no maximum
Chris@0 124 size_t getMaxFrequency() const;
Chris@0 125
Chris@37 126 enum ColourScale {
Chris@37 127 LinearColourScale,
Chris@37 128 MeterColourScale,
Chris@37 129 dBColourScale,
Chris@37 130 PhaseColourScale
Chris@37 131 };
Chris@0 132
Chris@0 133 /**
Chris@0 134 * Specify the scale for sample levels. See WaveformLayer for
Chris@0 135 * details of meter and dB scaling. The default is dBColourScale.
Chris@0 136 */
Chris@0 137 void setColourScale(ColourScale);
Chris@0 138 ColourScale getColourScale() const;
Chris@0 139
Chris@35 140 enum FrequencyScale {
Chris@35 141 LinearFrequencyScale,
Chris@35 142 LogFrequencyScale
Chris@35 143 };
Chris@0 144
Chris@0 145 /**
Chris@0 146 * Specify the scale for the y axis.
Chris@0 147 */
Chris@0 148 void setFrequencyScale(FrequencyScale);
Chris@0 149 FrequencyScale getFrequencyScale() const;
Chris@0 150
Chris@37 151 enum BinDisplay {
Chris@37 152 AllBins,
Chris@37 153 PeakBins,
Chris@37 154 PeakFrequencies
Chris@35 155 };
Chris@35 156
Chris@35 157 /**
Chris@35 158 * Specify the processing of frequency bins for the y axis.
Chris@35 159 */
Chris@37 160 void setBinDisplay(BinDisplay);
Chris@37 161 BinDisplay getBinDisplay() const;
Chris@35 162
Chris@36 163 void setNormalizeColumns(bool n);
Chris@36 164 bool getNormalizeColumns() const;
Chris@36 165
Chris@0 166 enum ColourScheme { DefaultColours, WhiteOnBlack, BlackOnWhite,
Chris@71 167 RedOnBlue, YellowOnBlack, BlueOnBlack, Rainbow };
Chris@0 168
Chris@0 169 void setColourScheme(ColourScheme scheme);
Chris@0 170 ColourScheme getColourScheme() const;
Chris@0 171
Chris@9 172 /**
Chris@9 173 * Specify the colourmap rotation for the colour scale.
Chris@9 174 */
Chris@9 175 void setColourRotation(int);
Chris@9 176 int getColourRotation() const;
Chris@9 177
Chris@0 178 virtual VerticalPosition getPreferredFrameCountPosition() const {
Chris@0 179 return PositionTop;
Chris@0 180 }
Chris@0 181
Chris@15 182 virtual bool isLayerOpaque() const { return true; }
Chris@15 183
Chris@44 184 float getYForFrequency(View *v, float frequency) const;
Chris@44 185 float getFrequencyForY(View *v, int y) const;
Chris@42 186
Chris@0 187 virtual int getCompletion() const;
Chris@0 188
Chris@101 189 virtual bool getValueExtents(float &min, float &max,
Chris@101 190 bool &logarithmic, QString &unit) const;
Chris@101 191
Chris@101 192 virtual bool getDisplayExtents(float &min, float &max) const;
Chris@79 193
Chris@6 194 virtual QString toXmlString(QString indent = "",
Chris@6 195 QString extraAttributes = "") const;
Chris@6 196
Chris@11 197 void setProperties(const QXmlAttributes &attributes);
Chris@11 198
Chris@47 199 virtual void setLayerDormant(const View *v, bool dormant);
Chris@29 200
Chris@94 201 virtual bool isLayerScrollable(const View *v) const { return false; }
Chris@94 202
Chris@0 203 protected slots:
Chris@0 204 void cacheInvalid();
Chris@0 205 void cacheInvalid(size_t startFrame, size_t endFrame);
Chris@0 206
Chris@0 207 void fillTimerTimedOut();
Chris@0 208
Chris@0 209 protected:
Chris@0 210 const DenseTimeValueModel *m_model; // I do not own this
Chris@0 211
Chris@35 212 int m_channel;
Chris@35 213 size_t m_windowSize;
Chris@35 214 WindowType m_windowType;
Chris@97 215 size_t m_windowHopLevel;
Chris@35 216 float m_gain;
Chris@37 217 float m_threshold;
Chris@35 218 int m_colourRotation;
Chris@37 219 size_t m_minFrequency;
Chris@35 220 size_t m_maxFrequency;
Chris@35 221 ColourScale m_colourScale;
Chris@35 222 ColourScheme m_colourScheme;
Chris@77 223 QColor m_crosshairColour;
Chris@35 224 FrequencyScale m_frequencyScale;
Chris@37 225 BinDisplay m_binDisplay;
Chris@36 226 bool m_normalizeColumns;
Chris@0 227
Chris@38 228 enum { NO_VALUE = 0 }; // colour index for unused pixels
Chris@38 229
Chris@86 230 class ColourMap
Chris@86 231 {
Chris@86 232 public:
Chris@86 233 QColor getColour(unsigned char index) const {
Chris@86 234 return m_colours[index];
Chris@86 235 }
Chris@86 236
Chris@86 237 void setColour(unsigned char index, QColor colour) {
Chris@86 238 m_colours[index] = colour;
Chris@86 239 }
Chris@86 240
Chris@86 241 private:
Chris@86 242 QColor m_colours[256];
Chris@86 243 };
Chris@86 244
Chris@86 245 ColourMap m_colourMap;
Chris@85 246 FFTCacheBase *m_cache;
Chris@86 247 FFTCacheBase *m_writeCache;
Chris@31 248 bool m_cacheInvalid;
Chris@31 249
Chris@92 250 class CacheFillThread : public Thread
Chris@0 251 {
Chris@0 252 public:
Chris@0 253 CacheFillThread(SpectrogramLayer &layer) :
Chris@0 254 m_layer(layer), m_fillExtent(0) { }
Chris@0 255
Chris@0 256 size_t getFillExtent() const { return m_fillExtent; }
Chris@0 257 size_t getFillCompletion() const { return m_fillCompletion; }
Chris@0 258 virtual void run();
Chris@0 259
Chris@0 260 protected:
Chris@0 261 SpectrogramLayer &m_layer;
Chris@0 262 size_t m_fillExtent;
Chris@0 263 size_t m_fillCompletion;
Chris@0 264 };
Chris@0 265
Chris@0 266 void fillCache();
Chris@0 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@95 280
Chris@0 281 QWaitCondition m_condition;
Chris@0 282 mutable QMutex m_mutex;
Chris@0 283
Chris@0 284 CacheFillThread *m_fillThread;
Chris@0 285 QTimer *m_updateTimer;
Chris@44 286 mutable size_t m_candidateFillStartFrame;
Chris@0 287 size_t m_lastFillExtent;
Chris@0 288 bool m_exiting;
Chris@0 289
Chris@90 290 void setColourmap();
Chris@90 291 void rotateColourmap(int distance);
Chris@0 292
Chris@38 293 void fillCacheColumn(int column,
Chris@0 294 double *inputBuffer,
Chris@0 295 fftw_complex *outputBuffer,
Chris@0 296 fftw_plan plan,
Chris@9 297 size_t windowSize,
Chris@9 298 size_t windowIncrement,
Chris@86 299 float *workbuffer,
Chris@38 300 const Window<double> &windower)
Chris@0 301 const;
Chris@0 302
Chris@38 303 static float calculateFrequency(size_t bin,
Chris@38 304 size_t windowSize,
Chris@38 305 size_t windowIncrement,
Chris@38 306 size_t sampleRate,
Chris@38 307 float previousPhase,
Chris@38 308 float currentPhase,
Chris@38 309 bool &steadyState);
Chris@38 310
Chris@38 311 unsigned char getDisplayValue(float input) const;
Chris@40 312 float getInputForDisplayValue(unsigned char uc) const;
Chris@40 313
Chris@40 314 int getColourScaleWidth(QPainter &) const;
Chris@40 315
Chris@40 316 float getEffectiveMinFrequency() const;
Chris@40 317 float getEffectiveMaxFrequency() const;
Chris@38 318
Chris@0 319 struct LayerRange {
Chris@0 320 long startFrame;
Chris@0 321 int zoomLevel;
Chris@0 322 size_t modelStart;
Chris@0 323 size_t modelEnd;
Chris@0 324 };
Chris@44 325 bool getXBinRange(View *v, int x, float &windowMin, float &windowMax) const;
Chris@44 326 bool getYBinRange(View *v, int y, float &freqBinMin, float &freqBinMax) const;
Chris@0 327
Chris@44 328 bool getYBinSourceRange(View *v, int y, float &freqMin, float &freqMax) const;
Chris@44 329 bool getAdjustedYBinSourceRange(View *v, int x, int y,
Chris@35 330 float &freqMin, float &freqMax,
Chris@35 331 float &adjFreqMin, float &adjFreqMax) const;
Chris@44 332 bool getXBinSourceRange(View *v, int x, RealTime &timeMin, RealTime &timeMax) const;
Chris@44 333 bool getXYBinSourceRange(View *v, int x, int y, float &min, float &max,
Chris@38 334 float &phaseMin, float &phaseMax) const;
Chris@0 335
Chris@0 336 size_t getWindowIncrement() const {
Chris@97 337 if (m_windowHopLevel == 0) return m_windowSize;
Chris@97 338 else if (m_windowHopLevel == 1) return (m_windowSize * 3) / 4;
Chris@97 339 else return m_windowSize / (1 << (m_windowHopLevel - 1));
Chris@0 340 }
Chris@0 341 };
Chris@0 342
Chris@0 343 #endif