annotate layer/SpectrogramLayer.h @ 37:21d061e66177

* Make the frequency estimation mode in the spectrogram layer actually useful, and make sure it gets mostly the right results... Still some tidying to do in here.
author Chris Cannam
date Wed, 22 Feb 2006 17:45:18 +0000
parents c28ebb4ba4de
children beb801473743
rev   line source
Chris@0 1 /* -*- c-basic-offset: 4 -*- vi:set ts=8 sts=4 sw=4: */
Chris@0 2
Chris@0 3 /*
Chris@0 4 A waveform viewer and audio annotation editor.
Chris@5 5 Chris Cannam, Queen Mary University of London, 2005-2006
Chris@0 6
Chris@0 7 This is experimental software. Not for distribution.
Chris@0 8 */
Chris@0 9
Chris@30 10 #ifndef _SPECTROGRAM_LAYER_H_
Chris@30 11 #define _SPECTROGRAM_LAYER_H_
Chris@0 12
Chris@0 13 #include "base/Layer.h"
Chris@0 14 #include "base/Window.h"
Chris@0 15 #include "model/PowerOfSqrtTwoZoomConstraint.h"
Chris@0 16 #include "model/DenseTimeValueModel.h"
Chris@0 17
Chris@0 18 #include <QThread>
Chris@0 19 #include <QMutex>
Chris@0 20 #include <QWaitCondition>
Chris@0 21
Chris@0 22 #include <fftw3.h>
Chris@0 23
Chris@0 24 class View;
Chris@0 25 class QPainter;
Chris@0 26 class QImage;
Chris@0 27 class QPixmap;
Chris@0 28 class QTimer;
Chris@0 29 class RealTime;
Chris@0 30
Chris@0 31 /**
Chris@0 32 * SpectrogramLayer represents waveform data (obtained from a
Chris@0 33 * DenseTimeValueModel) in spectrogram form.
Chris@0 34 */
Chris@0 35
Chris@0 36 class SpectrogramLayer : public Layer,
Chris@31 37 public PowerOfSqrtTwoZoomConstraint
Chris@0 38 {
Chris@0 39 Q_OBJECT
Chris@0 40
Chris@0 41 public:
Chris@37 42 enum Configuration { FullRangeDb, MelodicRange, MelodicPeaks };
Chris@0 43
Chris@0 44 SpectrogramLayer(View *w, Configuration = FullRangeDb);
Chris@0 45 ~SpectrogramLayer();
Chris@0 46
Chris@0 47 virtual const ZoomConstraint *getZoomConstraint() const { return this; }
Chris@0 48 virtual const Model *getModel() const { return m_model; }
Chris@0 49 virtual void paint(QPainter &paint, QRect rect) const;
Chris@0 50
Chris@0 51 virtual int getVerticalScaleWidth(QPainter &) const;
Chris@0 52 virtual void paintVerticalScale(QPainter &paint, QRect rect) const;
Chris@0 53
Chris@25 54 virtual QString getFeatureDescription(QPoint &) const;
Chris@0 55
Chris@28 56 virtual bool snapToFeatureFrame(int &frame,
Chris@28 57 size_t &resolution,
Chris@28 58 SnapType snap) const;
Chris@13 59
Chris@0 60 void setModel(const DenseTimeValueModel *model);
Chris@0 61
Chris@0 62 virtual PropertyList getProperties() const;
Chris@0 63 virtual PropertyType getPropertyType(const PropertyName &) const;
Chris@0 64 virtual QString getPropertyGroupName(const PropertyName &) const;
Chris@0 65 virtual int getPropertyRangeAndValue(const PropertyName &,
Chris@0 66 int *min, int *max) const;
Chris@0 67 virtual QString getPropertyValueLabel(const PropertyName &,
Chris@0 68 int value) const;
Chris@0 69 virtual void setProperty(const PropertyName &, int value);
Chris@0 70
Chris@0 71 /**
Chris@0 72 * Specify the channel to use from the source model.
Chris@0 73 * A value of -1 means to mix all available channels.
Chris@0 74 * The default is channel 0.
Chris@0 75 */
Chris@0 76 void setChannel(int);
Chris@0 77 int getChannel() const;
Chris@0 78
Chris@0 79 void setWindowSize(size_t);
Chris@0 80 size_t getWindowSize() const;
Chris@0 81
Chris@0 82 void setWindowOverlap(size_t percent);
Chris@0 83 size_t getWindowOverlap() const;
Chris@0 84
Chris@0 85 void setWindowType(WindowType type);
Chris@0 86 WindowType getWindowType() const;
Chris@0 87
Chris@0 88 /**
Chris@0 89 * Set the gain multiplier for sample values in this view prior to
Chris@0 90 * FFT calculation.
Chris@0 91 *
Chris@0 92 * The default is 1.0.
Chris@0 93 */
Chris@0 94 void setGain(float gain);
Chris@0 95 float getGain() const;
Chris@0 96
Chris@37 97 /**
Chris@37 98 * Set the threshold for sample values to be shown in the FFT,
Chris@37 99 * in voltage units.
Chris@37 100 *
Chris@37 101 * The default is 0.0.
Chris@37 102 */
Chris@37 103 void setThreshold(float threshold);
Chris@37 104 float getThreshold() const;
Chris@37 105
Chris@37 106 void setMinFrequency(size_t);
Chris@37 107 size_t getMinFrequency() const;
Chris@37 108
Chris@0 109 void setMaxFrequency(size_t); // 0 -> no maximum
Chris@0 110 size_t getMaxFrequency() const;
Chris@0 111
Chris@37 112 enum ColourScale {
Chris@37 113 LinearColourScale,
Chris@37 114 MeterColourScale,
Chris@37 115 dBColourScale,
Chris@37 116 PhaseColourScale
Chris@37 117 };
Chris@0 118
Chris@0 119 /**
Chris@0 120 * Specify the scale for sample levels. See WaveformLayer for
Chris@0 121 * details of meter and dB scaling. The default is dBColourScale.
Chris@0 122 */
Chris@0 123 void setColourScale(ColourScale);
Chris@0 124 ColourScale getColourScale() const;
Chris@0 125
Chris@35 126 enum FrequencyScale {
Chris@35 127 LinearFrequencyScale,
Chris@35 128 LogFrequencyScale
Chris@35 129 };
Chris@0 130
Chris@0 131 /**
Chris@0 132 * Specify the scale for the y axis.
Chris@0 133 */
Chris@0 134 void setFrequencyScale(FrequencyScale);
Chris@0 135 FrequencyScale getFrequencyScale() const;
Chris@0 136
Chris@37 137 enum BinDisplay {
Chris@37 138 AllBins,
Chris@37 139 PeakBins,
Chris@37 140 PeakFrequencies
Chris@35 141 };
Chris@35 142
Chris@35 143 /**
Chris@35 144 * Specify the processing of frequency bins for the y axis.
Chris@35 145 */
Chris@37 146 void setBinDisplay(BinDisplay);
Chris@37 147 BinDisplay getBinDisplay() const;
Chris@35 148
Chris@36 149 void setNormalizeColumns(bool n);
Chris@36 150 bool getNormalizeColumns() const;
Chris@36 151
Chris@0 152 enum ColourScheme { DefaultColours, WhiteOnBlack, BlackOnWhite,
Chris@0 153 RedOnBlue, YellowOnBlack, RedOnBlack };
Chris@0 154
Chris@0 155 void setColourScheme(ColourScheme scheme);
Chris@0 156 ColourScheme getColourScheme() const;
Chris@0 157
Chris@9 158 /**
Chris@9 159 * Specify the colourmap rotation for the colour scale.
Chris@9 160 */
Chris@9 161 void setColourRotation(int);
Chris@9 162 int getColourRotation() const;
Chris@9 163
Chris@0 164 virtual VerticalPosition getPreferredFrameCountPosition() const {
Chris@0 165 return PositionTop;
Chris@0 166 }
Chris@0 167
Chris@15 168 virtual bool isLayerOpaque() const { return true; }
Chris@15 169
Chris@0 170 virtual int getCompletion() const;
Chris@0 171
Chris@6 172 virtual QString toXmlString(QString indent = "",
Chris@6 173 QString extraAttributes = "") const;
Chris@6 174
Chris@11 175 void setProperties(const QXmlAttributes &attributes);
Chris@11 176
Chris@33 177 virtual void setLayerDormant(bool dormant);
Chris@29 178
Chris@0 179 protected slots:
Chris@0 180 void cacheInvalid();
Chris@0 181 void cacheInvalid(size_t startFrame, size_t endFrame);
Chris@0 182
Chris@0 183 void fillTimerTimedOut();
Chris@0 184
Chris@0 185 protected:
Chris@0 186 const DenseTimeValueModel *m_model; // I do not own this
Chris@0 187
Chris@35 188 int m_channel;
Chris@35 189 size_t m_windowSize;
Chris@35 190 WindowType m_windowType;
Chris@35 191 size_t m_windowOverlap;
Chris@35 192 float m_gain;
Chris@37 193 float m_threshold;
Chris@35 194 int m_colourRotation;
Chris@37 195 size_t m_minFrequency;
Chris@35 196 size_t m_maxFrequency;
Chris@35 197 ColourScale m_colourScale;
Chris@35 198 ColourScheme m_colourScheme;
Chris@35 199 FrequencyScale m_frequencyScale;
Chris@37 200 BinDisplay m_binDisplay;
Chris@36 201 bool m_normalizeColumns;
Chris@0 202
Chris@37 203 enum { NO_VALUE = 0 };
Chris@37 204
Chris@31 205 // A QImage would do just as well here, and we originally used
Chris@31 206 // one: the problem is that we want to munlock() the memory it
Chris@31 207 // uses, and it's much easier to do that if we control it. This
Chris@31 208 // cache is hardwired to an effective 8-bit colour mapped layout.
Chris@31 209 class Cache {
Chris@31 210 public:
Chris@31 211 Cache(size_t width, size_t height);
Chris@31 212 ~Cache();
Chris@31 213
Chris@31 214 size_t getWidth() const;
Chris@31 215 size_t getHeight() const;
Chris@35 216
Chris@35 217 void resize(size_t width, size_t height);
Chris@31 218
Chris@31 219 unsigned char getValueAt(size_t x, size_t y) const;
Chris@31 220 void setValueAt(size_t x, size_t y, unsigned char value);
Chris@31 221
Chris@31 222 QColor getColour(unsigned char index) const;
Chris@31 223 void setColour(unsigned char index, QColor colour);
Chris@31 224
Chris@31 225 void fill(unsigned char value);
Chris@31 226
Chris@31 227 protected:
Chris@31 228 size_t m_width;
Chris@31 229 size_t m_height;
Chris@31 230 unsigned char *m_values;
Chris@31 231 QColor m_colours[256];
Chris@31 232 };
Chris@31 233
Chris@31 234 Cache *m_cache;
Chris@35 235 Cache *m_phaseAdjustCache;
Chris@31 236 bool m_cacheInvalid;
Chris@31 237
Chris@0 238 class CacheFillThread : public QThread
Chris@0 239 {
Chris@0 240 public:
Chris@0 241 CacheFillThread(SpectrogramLayer &layer) :
Chris@0 242 m_layer(layer), m_fillExtent(0) { }
Chris@0 243
Chris@0 244 size_t getFillExtent() const { return m_fillExtent; }
Chris@0 245 size_t getFillCompletion() const { return m_fillCompletion; }
Chris@0 246 virtual void run();
Chris@0 247
Chris@0 248 protected:
Chris@0 249 SpectrogramLayer &m_layer;
Chris@0 250 size_t m_fillExtent;
Chris@0 251 size_t m_fillCompletion;
Chris@0 252 };
Chris@0 253
Chris@0 254 void fillCache();
Chris@0 255
Chris@0 256 mutable QPixmap *m_pixmapCache;
Chris@0 257 mutable bool m_pixmapCacheInvalid;
Chris@0 258 mutable long m_pixmapCacheStartFrame;
Chris@0 259 mutable size_t m_pixmapCacheZoomLevel;
Chris@0 260
Chris@0 261 QWaitCondition m_condition;
Chris@0 262 mutable QMutex m_mutex;
Chris@0 263
Chris@0 264 CacheFillThread *m_fillThread;
Chris@0 265 QTimer *m_updateTimer;
Chris@0 266 size_t m_lastFillExtent;
Chris@0 267 bool m_cachedInitialVisibleArea;
Chris@0 268 bool m_exiting;
Chris@0 269
Chris@0 270 void setCacheColourmap();
Chris@9 271 void rotateCacheColourmap(int distance);
Chris@0 272
Chris@0 273 bool fillCacheColumn(int column,
Chris@0 274 double *inputBuffer,
Chris@0 275 fftw_complex *outputBuffer,
Chris@0 276 fftw_plan plan,
Chris@9 277 size_t windowSize,
Chris@9 278 size_t windowIncrement,
Chris@0 279 const Window<double> &windower,
Chris@35 280 bool resetStoredPhase)
Chris@0 281 const;
Chris@0 282
Chris@0 283 bool getYBinRange(int y, float &freqBinMin, float &freqBinMax) const;
Chris@0 284
Chris@0 285 struct LayerRange {
Chris@0 286 long startFrame;
Chris@0 287 int zoomLevel;
Chris@0 288 size_t modelStart;
Chris@0 289 size_t modelEnd;
Chris@0 290 };
Chris@20 291 bool getXBinRange(int x, float &windowMin, float &windowMax) const;
Chris@0 292
Chris@0 293 bool getYBinSourceRange(int y, float &freqMin, float &freqMax) const;
Chris@35 294 bool getAdjustedYBinSourceRange(int x, int y,
Chris@35 295 float &freqMin, float &freqMax,
Chris@35 296 float &adjFreqMin, float &adjFreqMax) const;
Chris@0 297 bool getXBinSourceRange(int x, RealTime &timeMin, RealTime &timeMax) const;
Chris@0 298 bool getXYBinSourceRange(int x, int y, float &dbMin, float &dbMax) const;
Chris@0 299
Chris@0 300 size_t getWindowIncrement() const {
Chris@0 301 return m_windowSize - m_windowSize * m_windowOverlap / 100;
Chris@0 302 }
Chris@0 303 };
Chris@0 304
Chris@0 305 #endif