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
|