| 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 |