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@0
|
10 #ifndef _SPECTROGRAM_VIEW_H_
|
Chris@0
|
11 #define _SPECTROGRAM_VIEW_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@0
|
37 public PowerOfSqrtTwoZoomConstraint
|
Chris@0
|
38 {
|
Chris@0
|
39 Q_OBJECT
|
Chris@0
|
40
|
Chris@0
|
41 public:
|
Chris@0
|
42 enum Configuration { FullRangeDb, MelodicRange };
|
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@0
|
54 virtual QRect getFeatureDescriptionRect(QPainter &, QPoint) const;
|
Chris@0
|
55 virtual void paintLocalFeatureDescription(QPainter &, QRect, QPoint) const;
|
Chris@0
|
56
|
Chris@13
|
57 virtual int getNearestFeatureFrame(int frame,
|
Chris@13
|
58 size_t &resolution,
|
Chris@13
|
59 bool snapRight = true) const;
|
Chris@13
|
60
|
Chris@0
|
61 void setModel(const DenseTimeValueModel *model);
|
Chris@0
|
62
|
Chris@0
|
63 virtual PropertyList getProperties() const;
|
Chris@0
|
64 virtual PropertyType getPropertyType(const PropertyName &) const;
|
Chris@0
|
65 virtual QString getPropertyGroupName(const PropertyName &) const;
|
Chris@0
|
66 virtual int getPropertyRangeAndValue(const PropertyName &,
|
Chris@0
|
67 int *min, int *max) const;
|
Chris@0
|
68 virtual QString getPropertyValueLabel(const PropertyName &,
|
Chris@0
|
69 int value) const;
|
Chris@0
|
70 virtual void setProperty(const PropertyName &, int value);
|
Chris@0
|
71
|
Chris@0
|
72 /**
|
Chris@0
|
73 * Specify the channel to use from the source model.
|
Chris@0
|
74 * A value of -1 means to mix all available channels.
|
Chris@0
|
75 * The default is channel 0.
|
Chris@0
|
76 */
|
Chris@0
|
77 void setChannel(int);
|
Chris@0
|
78 int getChannel() const;
|
Chris@0
|
79
|
Chris@0
|
80 void setWindowSize(size_t);
|
Chris@0
|
81 size_t getWindowSize() const;
|
Chris@0
|
82
|
Chris@0
|
83 void setWindowOverlap(size_t percent);
|
Chris@0
|
84 size_t getWindowOverlap() const;
|
Chris@0
|
85
|
Chris@0
|
86 void setWindowType(WindowType type);
|
Chris@0
|
87 WindowType getWindowType() const;
|
Chris@0
|
88
|
Chris@0
|
89 /**
|
Chris@0
|
90 * Set the gain multiplier for sample values in this view prior to
|
Chris@0
|
91 * FFT calculation.
|
Chris@0
|
92 *
|
Chris@0
|
93 * The default is 1.0.
|
Chris@0
|
94 */
|
Chris@0
|
95 void setGain(float gain);
|
Chris@0
|
96 float getGain() const;
|
Chris@0
|
97
|
Chris@0
|
98 void setMaxFrequency(size_t); // 0 -> no maximum
|
Chris@0
|
99 size_t getMaxFrequency() const;
|
Chris@0
|
100
|
Chris@0
|
101 enum ColourScale { LinearColourScale, MeterColourScale, dBColourScale,
|
Chris@0
|
102 PhaseColourScale };
|
Chris@0
|
103
|
Chris@0
|
104 /**
|
Chris@0
|
105 * Specify the scale for sample levels. See WaveformLayer for
|
Chris@0
|
106 * details of meter and dB scaling. The default is dBColourScale.
|
Chris@0
|
107 */
|
Chris@0
|
108 void setColourScale(ColourScale);
|
Chris@0
|
109 ColourScale getColourScale() const;
|
Chris@0
|
110
|
Chris@0
|
111 enum FrequencyScale { LinearFrequencyScale, LogFrequencyScale };
|
Chris@0
|
112
|
Chris@0
|
113 /**
|
Chris@0
|
114 * Specify the scale for the y axis.
|
Chris@0
|
115 */
|
Chris@0
|
116 void setFrequencyScale(FrequencyScale);
|
Chris@0
|
117 FrequencyScale getFrequencyScale() const;
|
Chris@0
|
118
|
Chris@0
|
119 enum ColourScheme { DefaultColours, WhiteOnBlack, BlackOnWhite,
|
Chris@0
|
120 RedOnBlue, YellowOnBlack, RedOnBlack };
|
Chris@0
|
121
|
Chris@0
|
122 void setColourScheme(ColourScheme scheme);
|
Chris@0
|
123 ColourScheme getColourScheme() const;
|
Chris@0
|
124
|
Chris@9
|
125 /**
|
Chris@9
|
126 * Specify the colourmap rotation for the colour scale.
|
Chris@9
|
127 */
|
Chris@9
|
128 void setColourRotation(int);
|
Chris@9
|
129 int getColourRotation() const;
|
Chris@9
|
130
|
Chris@0
|
131 virtual VerticalPosition getPreferredFrameCountPosition() const {
|
Chris@0
|
132 return PositionTop;
|
Chris@0
|
133 }
|
Chris@0
|
134
|
Chris@15
|
135 virtual bool isLayerOpaque() const { return true; }
|
Chris@15
|
136
|
Chris@0
|
137 virtual int getCompletion() const;
|
Chris@0
|
138
|
Chris@0
|
139 virtual QString getPropertyContainerIconName() const { return "spectrogram"; }
|
Chris@0
|
140
|
Chris@6
|
141 virtual QString toXmlString(QString indent = "",
|
Chris@6
|
142 QString extraAttributes = "") const;
|
Chris@6
|
143
|
Chris@11
|
144 void setProperties(const QXmlAttributes &attributes);
|
Chris@11
|
145
|
Chris@0
|
146 protected slots:
|
Chris@0
|
147 void cacheInvalid();
|
Chris@0
|
148 void cacheInvalid(size_t startFrame, size_t endFrame);
|
Chris@0
|
149
|
Chris@0
|
150 void fillTimerTimedOut();
|
Chris@0
|
151
|
Chris@0
|
152 protected:
|
Chris@0
|
153 const DenseTimeValueModel *m_model; // I do not own this
|
Chris@0
|
154
|
Chris@6
|
155 int m_channel;
|
Chris@6
|
156 size_t m_windowSize;
|
Chris@6
|
157 WindowType m_windowType;
|
Chris@6
|
158 size_t m_windowOverlap;
|
Chris@6
|
159 float m_gain;
|
Chris@9
|
160 int m_colourRotation;
|
Chris@6
|
161 size_t m_maxFrequency;
|
Chris@6
|
162 ColourScale m_colourScale;
|
Chris@6
|
163 ColourScheme m_colourScheme;
|
Chris@0
|
164 FrequencyScale m_frequencyScale;
|
Chris@0
|
165
|
Chris@0
|
166 class CacheFillThread : public QThread
|
Chris@0
|
167 {
|
Chris@0
|
168 public:
|
Chris@0
|
169 CacheFillThread(SpectrogramLayer &layer) :
|
Chris@0
|
170 m_layer(layer), m_fillExtent(0) { }
|
Chris@0
|
171
|
Chris@0
|
172 size_t getFillExtent() const { return m_fillExtent; }
|
Chris@0
|
173 size_t getFillCompletion() const { return m_fillCompletion; }
|
Chris@0
|
174 virtual void run();
|
Chris@0
|
175
|
Chris@0
|
176 protected:
|
Chris@0
|
177 SpectrogramLayer &m_layer;
|
Chris@0
|
178 size_t m_fillExtent;
|
Chris@0
|
179 size_t m_fillCompletion;
|
Chris@0
|
180 };
|
Chris@0
|
181
|
Chris@0
|
182 void fillCache();
|
Chris@0
|
183
|
Chris@0
|
184 QImage *m_cache;
|
Chris@0
|
185 bool m_cacheInvalid;
|
Chris@0
|
186
|
Chris@0
|
187 mutable QPixmap *m_pixmapCache;
|
Chris@0
|
188 mutable bool m_pixmapCacheInvalid;
|
Chris@0
|
189 mutable long m_pixmapCacheStartFrame;
|
Chris@0
|
190 mutable size_t m_pixmapCacheZoomLevel;
|
Chris@0
|
191
|
Chris@0
|
192 QWaitCondition m_condition;
|
Chris@0
|
193 mutable QMutex m_mutex;
|
Chris@0
|
194
|
Chris@0
|
195 CacheFillThread *m_fillThread;
|
Chris@0
|
196 QTimer *m_updateTimer;
|
Chris@0
|
197 size_t m_lastFillExtent;
|
Chris@0
|
198 bool m_cachedInitialVisibleArea;
|
Chris@0
|
199 bool m_exiting;
|
Chris@0
|
200
|
Chris@0
|
201 void setCacheColourmap();
|
Chris@9
|
202 void rotateCacheColourmap(int distance);
|
Chris@0
|
203
|
Chris@0
|
204 bool fillCacheColumn(int column,
|
Chris@0
|
205 double *inputBuffer,
|
Chris@0
|
206 fftw_complex *outputBuffer,
|
Chris@0
|
207 fftw_plan plan,
|
Chris@9
|
208 size_t windowSize,
|
Chris@9
|
209 size_t windowIncrement,
|
Chris@0
|
210 const Window<double> &windower,
|
Chris@0
|
211 bool lock)
|
Chris@0
|
212 const;
|
Chris@0
|
213
|
Chris@0
|
214 bool getYBinRange(int y, float &freqBinMin, float &freqBinMax) const;
|
Chris@0
|
215
|
Chris@0
|
216 struct LayerRange {
|
Chris@0
|
217 long startFrame;
|
Chris@0
|
218 int zoomLevel;
|
Chris@0
|
219 size_t modelStart;
|
Chris@0
|
220 size_t modelEnd;
|
Chris@0
|
221 };
|
Chris@0
|
222 /// LayerRange is only passed in to save lookup time
|
Chris@0
|
223 bool getXBinRange(int x, float &windowMin, float &windowMax,
|
Chris@0
|
224 LayerRange *range = 0) const;
|
Chris@0
|
225
|
Chris@0
|
226 bool getYBinSourceRange(int y, float &freqMin, float &freqMax) const;
|
Chris@0
|
227 bool getXBinSourceRange(int x, RealTime &timeMin, RealTime &timeMax) const;
|
Chris@0
|
228 bool getXYBinSourceRange(int x, int y, float &dbMin, float &dbMax) const;
|
Chris@0
|
229
|
Chris@0
|
230 size_t getWindowIncrement() const {
|
Chris@0
|
231 return m_windowSize - m_windowSize * m_windowOverlap / 100;
|
Chris@0
|
232 }
|
Chris@0
|
233 };
|
Chris@0
|
234
|
Chris@0
|
235 #endif
|