Mercurial > hg > svgui
comparison layer/SpectrogramLayer.h @ 85:d31c4f5230d7
* Start factoring out the spectrogram's FFT cache into a separate set of
classes that will permit a choice of disk or memory cache strategies
author | Chris Cannam |
---|---|
date | Tue, 02 May 2006 12:27:41 +0000 |
parents | c683705adcbf |
children | 93a7efc75fb7 |
comparison
equal
deleted
inserted
replaced
84:c683705adcbf | 85:d31c4f5230d7 |
---|---|
26 #include <QMutex> | 26 #include <QMutex> |
27 #include <QWaitCondition> | 27 #include <QWaitCondition> |
28 | 28 |
29 #include <fftw3.h> | 29 #include <fftw3.h> |
30 | 30 |
31 #include <stdint.h> | |
32 | |
33 class View; | 31 class View; |
34 class QPainter; | 32 class QPainter; |
35 class QImage; | 33 class QImage; |
36 class QPixmap; | 34 class QPixmap; |
37 class QTimer; | 35 class QTimer; |
36 class FFTCacheBase; | |
38 | 37 |
39 /** | 38 /** |
40 * SpectrogramLayer represents waveform data (obtained from a | 39 * SpectrogramLayer represents waveform data (obtained from a |
41 * DenseTimeValueModel) in spectrogram form. | 40 * DenseTimeValueModel) in spectrogram form. |
42 */ | 41 */ |
216 QColor m_crosshairColour; | 215 QColor m_crosshairColour; |
217 FrequencyScale m_frequencyScale; | 216 FrequencyScale m_frequencyScale; |
218 BinDisplay m_binDisplay; | 217 BinDisplay m_binDisplay; |
219 bool m_normalizeColumns; | 218 bool m_normalizeColumns; |
220 | 219 |
221 // We would like to cache magnitude in a way that can have gain | |
222 // applied afterwards and can determine whether something is a | |
223 // peak or not, and also cache phase rather than only | |
224 // phase-adjusted frequency so that we don't have to recalculate | |
225 // if switching between phase and magnitude displays. At the same | |
226 // time, we don't want to waste too much memory. | |
227 | |
228 // This implies probably 16 bits for a normalized magnitude (in | |
229 // dB?) and at most 16 bits for phase. | |
230 | |
231 // Each column's magnitudes are expected to be stored normalized | |
232 // to [0,1] with respect to the column, so the normalization | |
233 // factor should be calculated before all values in a column, and | |
234 // set appropriately. | |
235 | |
236 class Cache { | |
237 public: | |
238 Cache(); // of size zero, call resize() before using | |
239 ~Cache(); | |
240 | |
241 size_t getWidth() const { return m_width; } | |
242 size_t getHeight() const { return m_height; } | |
243 | |
244 void resize(size_t width, size_t height); | |
245 void reset(); // zero-fill or 1-fill as appropriate without changing size | |
246 | |
247 float getMagnitudeAt(size_t x, size_t y) const { | |
248 return getNormalizedMagnitudeAt(x, y) * m_factor[x]; | |
249 } | |
250 | |
251 float getNormalizedMagnitudeAt(size_t x, size_t y) const { | |
252 return float(m_magnitude[x][y]) / 65535.0; | |
253 } | |
254 | |
255 float getPhaseAt(size_t x, size_t y) const { | |
256 int16_t i = (int16_t)m_phase[x][y]; | |
257 return (float(i) / 32767.0) * M_PI; | |
258 } | |
259 | |
260 bool isLocalPeak(size_t x, size_t y) const { | |
261 if (y > 0 && m_magnitude[x][y] < m_magnitude[x][y-1]) return false; | |
262 if (y < m_height-1 && m_magnitude[x][y] < m_magnitude[x][y+1]) return false; | |
263 return true; | |
264 } | |
265 | |
266 bool isOverThreshold(size_t x, size_t y, float threshold) const { | |
267 if (threshold == 0.0) return true; | |
268 return getMagnitudeAt(x, y) > threshold; | |
269 } | |
270 | |
271 void setNormalizationFactor(size_t x, float factor) { | |
272 if (x < m_width) m_factor[x] = factor; | |
273 } | |
274 | |
275 void setMagnitudeAt(size_t x, size_t y, float mag) { | |
276 // norm factor must already be set | |
277 setNormalizedMagnitudeAt(x, y, mag / m_factor[x]); | |
278 } | |
279 | |
280 void setNormalizedMagnitudeAt(size_t x, size_t y, float norm) { | |
281 if (x < m_width && y < m_height) { | |
282 m_magnitude[x][y] = uint16_t(norm * 65535.0); | |
283 } | |
284 } | |
285 | |
286 void setPhaseAt(size_t x, size_t y, float phase) { | |
287 // phase in range -pi -> pi | |
288 if (x < m_width && y < m_height) { | |
289 m_phase[x][y] = uint16_t(int16_t((phase * 32767) / M_PI)); | |
290 } | |
291 } | |
292 | |
293 QColor getColour(unsigned char index) const { | |
294 return m_colours[index]; | |
295 } | |
296 | |
297 void setColour(unsigned char index, QColor colour) { | |
298 m_colours[index] = colour; | |
299 } | |
300 | |
301 private: | |
302 size_t m_width; | |
303 size_t m_height; | |
304 uint16_t **m_magnitude; | |
305 uint16_t **m_phase; | |
306 float *m_factor; | |
307 QColor m_colours[256]; | |
308 | |
309 void resize(uint16_t **&, size_t, size_t); | |
310 }; | |
311 | |
312 enum { NO_VALUE = 0 }; // colour index for unused pixels | 220 enum { NO_VALUE = 0 }; // colour index for unused pixels |
313 | 221 |
314 Cache *m_cache; | 222 FFTCacheBase *m_cache; |
315 bool m_cacheInvalid; | 223 bool m_cacheInvalid; |
316 | 224 |
317 class CacheFillThread : public QThread | 225 class CacheFillThread : public QThread |
318 { | 226 { |
319 public: | 227 public: |