annotate data/fft/FFTMemoryCache.h @ 823:f0558e69a074

Rename Resampling- to DecodingWavFileReader, and use it whenever we have an audio file that is not quickly seekable using libsndfile. Avoids very slow performance when analysing ogg files.
author Chris Cannam
date Wed, 17 Jul 2013 15:40:01 +0100
parents 1469caaa8e67
children 59e7fe1b1003
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@537 19 #include "FFTCacheReader.h"
Chris@537 20 #include "FFTCacheWriter.h"
Chris@537 21 #include "FFTCacheStorageType.h"
Chris@159 22 #include "base/ResizeableBitset.h"
Chris@408 23 #include "base/Profiler.h"
Chris@159 24
Chris@548 25 #include <QReadWriteLock>
Chris@537 26
Chris@159 27 /**
Chris@253 28 * In-memory FFT cache. For this we want to cache magnitude with
Chris@159 29 * enough resolution to have gain applied afterwards and determine
Chris@159 30 * whether something is a peak or not, and also cache phase rather
Chris@159 31 * than only phase-adjusted frequency so that we don't have to
Chris@159 32 * recalculate if switching between phase and magnitude displays. At
Chris@159 33 * the same time, we don't want to take up too much memory. It's not
Chris@159 34 * expected to be accurate enough to be used as input for DSP or
Chris@159 35 * resynthesis code.
Chris@159 36 *
Chris@159 37 * This implies probably 16 bits for a normalized magnitude and at
Chris@159 38 * most 16 bits for phase.
Chris@159 39 *
Chris@159 40 * Each column's magnitudes are expected to be stored normalized
Chris@159 41 * to [0,1] with respect to the column, so the normalization
Chris@159 42 * factor should be calculated before all values in a column, and
Chris@159 43 * set appropriately.
Chris@159 44 */
Chris@159 45
Chris@537 46 class FFTMemoryCache : public FFTCacheReader, public FFTCacheWriter
Chris@159 47 {
Chris@159 48 public:
Chris@537 49 FFTMemoryCache(FFTCache::StorageType storageType,
Chris@537 50 size_t width, size_t height);
Chris@537 51 ~FFTMemoryCache();
Chris@159 52
Chris@537 53 size_t getWidth() const { return m_width; }
Chris@537 54 size_t getHeight() const { return m_height; }
Chris@159 55
Chris@537 56 float getMagnitudeAt(size_t x, size_t y) const {
Chris@537 57 if (m_storageType == FFTCache::Rectangular) {
Chris@408 58 Profiler profiler("FFTMemoryCache::getMagnitudeAt: cart to polar");
Chris@509 59 return sqrtf(m_freal[x][y] * m_freal[x][y] +
Chris@509 60 m_fimag[x][y] * m_fimag[x][y]);
Chris@334 61 } else {
Chris@334 62 return getNormalizedMagnitudeAt(x, y) * m_factor[x];
Chris@334 63 }
Chris@159 64 }
Chris@159 65
Chris@537 66 float getNormalizedMagnitudeAt(size_t x, size_t y) const {
Chris@537 67 if (m_storageType == FFTCache::Rectangular) return getMagnitudeAt(x, y) / m_factor[x];
Chris@537 68 else if (m_storageType == FFTCache::Polar) return m_fmagnitude[x][y];
Chris@264 69 else return float(m_magnitude[x][y]) / 65535.0;
Chris@159 70 }
Chris@159 71
Chris@537 72 float getMaximumMagnitudeAt(size_t x) const {
Chris@159 73 return m_factor[x];
Chris@159 74 }
Chris@159 75
Chris@537 76 float getPhaseAt(size_t x, size_t y) const {
Chris@537 77 if (m_storageType == FFTCache::Rectangular) {
Chris@408 78 Profiler profiler("FFTMemoryCache::getValuesAt: cart to polar");
Chris@334 79 return atan2f(m_fimag[x][y], m_freal[x][y]);
Chris@537 80 } else if (m_storageType == FFTCache::Polar) {
Chris@334 81 return m_fphase[x][y];
Chris@334 82 } else {
Chris@334 83 int16_t i = (int16_t)m_phase[x][y];
Chris@334 84 return (float(i) / 32767.0) * M_PI;
Chris@334 85 }
Chris@159 86 }
Chris@159 87
Chris@537 88 void getValuesAt(size_t x, size_t y, float &real, float &imag) const {
Chris@537 89 if (m_storageType == FFTCache::Rectangular) {
Chris@334 90 real = m_freal[x][y];
Chris@334 91 imag = m_fimag[x][y];
Chris@334 92 } else {
Chris@408 93 Profiler profiler("FFTMemoryCache::getValuesAt: polar to cart");
Chris@334 94 float mag = getMagnitudeAt(x, y);
Chris@334 95 float phase = getPhaseAt(x, y);
Chris@334 96 real = mag * cosf(phase);
Chris@334 97 imag = mag * sinf(phase);
Chris@334 98 }
Chris@159 99 }
Chris@159 100
Chris@537 101 void getMagnitudesAt(size_t x, float *values, size_t minbin, size_t count, size_t step) const
Chris@509 102 {
Chris@537 103 if (m_storageType == FFTCache::Rectangular) {
Chris@509 104 for (size_t i = 0; i < count; ++i) {
Chris@509 105 size_t y = i * step + minbin;
Chris@509 106 values[i] = sqrtf(m_freal[x][y] * m_freal[x][y] +
Chris@509 107 m_fimag[x][y] * m_fimag[x][y]);
Chris@509 108 }
Chris@537 109 } else if (m_storageType == FFTCache::Polar) {
Chris@509 110 for (size_t i = 0; i < count; ++i) {
Chris@509 111 size_t y = i * step + minbin;
Chris@509 112 values[i] = m_fmagnitude[x][y] * m_factor[x];
Chris@509 113 }
Chris@509 114 } else {
Chris@509 115 for (size_t i = 0; i < count; ++i) {
Chris@509 116 size_t y = i * step + minbin;
Chris@509 117 values[i] = (float(m_magnitude[x][y]) * m_factor[x]) / 65535.0;
Chris@509 118 }
Chris@509 119 }
Chris@509 120 }
Chris@509 121
Chris@537 122 bool haveSetColumnAt(size_t x) const {
Chris@548 123 m_colsetLock.lockForRead();
Chris@537 124 bool have = m_colset.get(x);
Chris@548 125 m_colsetLock.unlock();
Chris@537 126 return have;
Chris@334 127 }
Chris@334 128
Chris@537 129 void setColumnAt(size_t x, float *mags, float *phases, float factor);
Chris@334 130
Chris@537 131 void setColumnAt(size_t x, float *reals, float *imags);
Chris@334 132
Chris@537 133 void allColumnsWritten() { }
Chris@334 134
Chris@537 135 static size_t getCacheSize(size_t width, size_t height,
Chris@537 136 FFTCache::StorageType type);
Chris@537 137
Chris@537 138 FFTCache::StorageType getStorageType() const { return m_storageType; }
Chris@359 139
Chris@334 140 private:
Chris@334 141 size_t m_width;
Chris@334 142 size_t m_height;
Chris@334 143 uint16_t **m_magnitude;
Chris@334 144 uint16_t **m_phase;
Chris@334 145 float **m_fmagnitude;
Chris@334 146 float **m_fphase;
Chris@334 147 float **m_freal;
Chris@334 148 float **m_fimag;
Chris@334 149 float *m_factor;
Chris@537 150 FFTCache::StorageType m_storageType;
Chris@334 151 ResizeableBitset m_colset;
Chris@548 152 mutable QReadWriteLock m_colsetLock;
Chris@334 153
Chris@537 154 void initialise();
Chris@537 155
Chris@537 156 void setNormalizationFactor(size_t x, float factor) {
Chris@159 157 if (x < m_width) m_factor[x] = factor;
Chris@159 158 }
Chris@159 159
Chris@537 160 void setMagnitudeAt(size_t x, size_t y, float mag) {
Chris@159 161 // norm factor must already be set
Chris@159 162 setNormalizedMagnitudeAt(x, y, mag / m_factor[x]);
Chris@159 163 }
Chris@159 164
Chris@537 165 void setNormalizedMagnitudeAt(size_t x, size_t y, float norm) {
Chris@159 166 if (x < m_width && y < m_height) {
Chris@537 167 if (m_storageType == FFTCache::Polar) m_fmagnitude[x][y] = norm;
Chris@264 168 else m_magnitude[x][y] = uint16_t(norm * 65535.0);
Chris@159 169 }
Chris@159 170 }
Chris@159 171
Chris@537 172 void setPhaseAt(size_t x, size_t y, float phase) {
Chris@159 173 // phase in range -pi -> pi
Chris@159 174 if (x < m_width && y < m_height) {
Chris@537 175 if (m_storageType == FFTCache::Polar) m_fphase[x][y] = phase;
Chris@264 176 else m_phase[x][y] = uint16_t(int16_t((phase * 32767) / M_PI));
Chris@159 177 }
Chris@159 178 }
Chris@159 179
Chris@537 180 void initialise(uint16_t **&);
Chris@537 181 void initialise(float **&);
Chris@159 182 };
Chris@159 183
Chris@159 184
Chris@159 185 #endif
Chris@159 186