annotate data/fft/FFTMemoryCache.h @ 458:f60360209e5c

* Fix race condition in FFTFileCache when reading from the same FFT model from multiple threads (e.g. when applying more than one plugin at once)
author Chris Cannam
date Wed, 15 Oct 2008 12:08:02 +0000
parents 115f60df1e4d
children 6066bde1c126
rev   line source
Chris@159 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@159 2
Chris@159 3 /*
Chris@159 4 Sonic Visualiser
Chris@159 5 An audio file viewer and annotation editor.
Chris@159 6 Centre for Digital Music, Queen Mary, University of London.
Chris@159 7 This file copyright 2006 Chris Cannam.
Chris@159 8
Chris@159 9 This program is free software; you can redistribute it and/or
Chris@159 10 modify it under the terms of the GNU General Public License as
Chris@159 11 published by the Free Software Foundation; either version 2 of the
Chris@159 12 License, or (at your option) any later version. See the file
Chris@159 13 COPYING included with this distribution for more information.
Chris@159 14 */
Chris@159 15
Chris@159 16 #ifndef _FFT_MEMORY_CACHE_H_
Chris@159 17 #define _FFT_MEMORY_CACHE_H_
Chris@159 18
Chris@159 19 #include "FFTCache.h"
Chris@159 20
Chris@159 21 #include "base/ResizeableBitset.h"
Chris@408 22 #include "base/Profiler.h"
Chris@159 23
Chris@159 24 /**
Chris@253 25 * In-memory FFT cache. For this we want to cache magnitude with
Chris@159 26 * enough resolution to have gain applied afterwards and determine
Chris@159 27 * whether something is a peak or not, and also cache phase rather
Chris@159 28 * than only phase-adjusted frequency so that we don't have to
Chris@159 29 * recalculate if switching between phase and magnitude displays. At
Chris@159 30 * the same time, we don't want to take up too much memory. It's not
Chris@159 31 * expected to be accurate enough to be used as input for DSP or
Chris@159 32 * resynthesis code.
Chris@159 33 *
Chris@159 34 * This implies probably 16 bits for a normalized magnitude and at
Chris@159 35 * most 16 bits for phase.
Chris@159 36 *
Chris@159 37 * Each column's magnitudes are expected to be stored normalized
Chris@159 38 * to [0,1] with respect to the column, so the normalization
Chris@159 39 * factor should be calculated before all values in a column, and
Chris@159 40 * set appropriately.
Chris@159 41 */
Chris@159 42
Chris@159 43 class FFTMemoryCache : public FFTCache
Chris@159 44 {
Chris@159 45 public:
Chris@264 46 FFTMemoryCache(StorageType storageType); // of size zero, call resize() before using
Chris@159 47 virtual ~FFTMemoryCache();
Chris@159 48
Chris@159 49 virtual size_t getWidth() const { return m_width; }
Chris@159 50 virtual size_t getHeight() const { return m_height; }
Chris@159 51
Chris@159 52 virtual void resize(size_t width, size_t height);
Chris@159 53 virtual void reset(); // zero-fill or 1-fill as appropriate without changing size
Chris@159 54
Chris@159 55 virtual float getMagnitudeAt(size_t x, size_t y) const {
Chris@334 56 if (m_storageType == Rectangular) {
Chris@408 57 Profiler profiler("FFTMemoryCache::getMagnitudeAt: cart to polar");
Chris@334 58 return sqrt(m_freal[x][y] * m_freal[x][y] +
Chris@334 59 m_fimag[x][y] * m_fimag[x][y]);
Chris@334 60 } else {
Chris@334 61 return getNormalizedMagnitudeAt(x, y) * m_factor[x];
Chris@334 62 }
Chris@159 63 }
Chris@159 64
Chris@159 65 virtual float getNormalizedMagnitudeAt(size_t x, size_t y) const {
Chris@334 66 if (m_storageType == Rectangular) return getMagnitudeAt(x, y) / m_factor[x];
Chris@334 67 else if (m_storageType == Polar) return m_fmagnitude[x][y];
Chris@264 68 else return float(m_magnitude[x][y]) / 65535.0;
Chris@159 69 }
Chris@159 70
Chris@159 71 virtual float getMaximumMagnitudeAt(size_t x) const {
Chris@159 72 return m_factor[x];
Chris@159 73 }
Chris@159 74
Chris@159 75 virtual float getPhaseAt(size_t x, size_t y) const {
Chris@334 76 if (m_storageType == Rectangular) {
Chris@408 77 Profiler profiler("FFTMemoryCache::getValuesAt: cart to polar");
Chris@334 78 return atan2f(m_fimag[x][y], m_freal[x][y]);
Chris@334 79 } else if (m_storageType == Polar) {
Chris@334 80 return m_fphase[x][y];
Chris@334 81 } else {
Chris@334 82 int16_t i = (int16_t)m_phase[x][y];
Chris@334 83 return (float(i) / 32767.0) * M_PI;
Chris@334 84 }
Chris@159 85 }
Chris@159 86
Chris@159 87 virtual void getValuesAt(size_t x, size_t y, float &real, float &imag) const {
Chris@334 88 if (m_storageType == Rectangular) {
Chris@334 89 real = m_freal[x][y];
Chris@334 90 imag = m_fimag[x][y];
Chris@334 91 } else {
Chris@408 92 Profiler profiler("FFTMemoryCache::getValuesAt: polar to cart");
Chris@334 93 float mag = getMagnitudeAt(x, y);
Chris@334 94 float phase = getPhaseAt(x, y);
Chris@334 95 real = mag * cosf(phase);
Chris@334 96 imag = mag * sinf(phase);
Chris@334 97 }
Chris@159 98 }
Chris@159 99
Chris@334 100 virtual bool haveSetColumnAt(size_t x) const {
Chris@334 101 return m_colset.get(x);
Chris@334 102 }
Chris@334 103
Chris@334 104 virtual void setColumnAt(size_t x, float *mags, float *phases, float factor);
Chris@334 105
Chris@334 106 virtual void setColumnAt(size_t x, float *reals, float *imags);
Chris@334 107
Chris@334 108 static size_t getCacheSize(size_t width, size_t height, StorageType type);
Chris@334 109
Chris@408 110 virtual StorageType getStorageType() { return m_storageType; }
Chris@359 111 virtual Type getType() { return MemoryCache; }
Chris@359 112
Chris@334 113 private:
Chris@334 114 size_t m_width;
Chris@334 115 size_t m_height;
Chris@334 116 uint16_t **m_magnitude;
Chris@334 117 uint16_t **m_phase;
Chris@334 118 float **m_fmagnitude;
Chris@334 119 float **m_fphase;
Chris@334 120 float **m_freal;
Chris@334 121 float **m_fimag;
Chris@334 122 float *m_factor;
Chris@334 123 StorageType m_storageType;
Chris@334 124 ResizeableBitset m_colset;
Chris@334 125
Chris@159 126 virtual void setNormalizationFactor(size_t x, float factor) {
Chris@159 127 if (x < m_width) m_factor[x] = factor;
Chris@159 128 }
Chris@159 129
Chris@159 130 virtual void setMagnitudeAt(size_t x, size_t y, float mag) {
Chris@159 131 // norm factor must already be set
Chris@159 132 setNormalizedMagnitudeAt(x, y, mag / m_factor[x]);
Chris@159 133 }
Chris@159 134
Chris@159 135 virtual void setNormalizedMagnitudeAt(size_t x, size_t y, float norm) {
Chris@159 136 if (x < m_width && y < m_height) {
Chris@264 137 if (m_storageType == Polar) m_fmagnitude[x][y] = norm;
Chris@264 138 else m_magnitude[x][y] = uint16_t(norm * 65535.0);
Chris@159 139 }
Chris@159 140 }
Chris@159 141
Chris@159 142 virtual void setPhaseAt(size_t x, size_t y, float phase) {
Chris@159 143 // phase in range -pi -> pi
Chris@159 144 if (x < m_width && y < m_height) {
Chris@264 145 if (m_storageType == Polar) m_fphase[x][y] = phase;
Chris@264 146 else m_phase[x][y] = uint16_t(int16_t((phase * 32767) / M_PI));
Chris@159 147 }
Chris@159 148 }
Chris@159 149
Chris@159 150 void resize(uint16_t **&, size_t, size_t);
Chris@264 151 void resize(float **&, size_t, size_t);
Chris@159 152 };
Chris@159 153
Chris@159 154
Chris@159 155 #endif
Chris@159 156