lbajardsilogic@0
|
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
lbajardsilogic@0
|
2
|
lbajardsilogic@0
|
3 /*
|
lbajardsilogic@0
|
4 Sonic Visualiser
|
lbajardsilogic@0
|
5 An audio file viewer and annotation editor.
|
lbajardsilogic@0
|
6 Centre for Digital Music, Queen Mary, University of London.
|
lbajardsilogic@0
|
7 This file copyright 2006 Chris Cannam and QMUL.
|
lbajardsilogic@0
|
8
|
lbajardsilogic@0
|
9 This program is free software; you can redistribute it and/or
|
lbajardsilogic@0
|
10 modify it under the terms of the GNU General Public License as
|
lbajardsilogic@0
|
11 published by the Free Software Foundation; either version 2 of the
|
lbajardsilogic@0
|
12 License, or (at your option) any later version. See the file
|
lbajardsilogic@0
|
13 COPYING included with this distribution for more information.
|
lbajardsilogic@0
|
14 */
|
lbajardsilogic@0
|
15
|
lbajardsilogic@0
|
16 #include <iostream>
|
lbajardsilogic@0
|
17
|
lbajardsilogic@0
|
18 #include <QMutexLocker>
|
lbajardsilogic@0
|
19
|
lbajardsilogic@191
|
20 #include "fileio/MatrixFile.h"
|
lbajardsilogic@191
|
21 #include "base/Profiler.h"
|
lbajardsilogic@191
|
22
|
lbajardsilogic@191
|
23 #include "FFTFileCache.h"
|
lbajardsilogic@191
|
24
|
lbajardsilogic@191
|
25
|
lbajardsilogic@191
|
26
|
lbajardsilogic@191
|
27
|
lbajardsilogic@0
|
28 // The underlying matrix has height (m_height * 2 + 1). In each
|
lbajardsilogic@0
|
29 // column we store magnitude at [0], [2] etc and phase at [1], [3]
|
lbajardsilogic@0
|
30 // etc, and then store the normalization factor (maximum magnitude) at
|
lbajardsilogic@0
|
31 // [m_height * 2].
|
lbajardsilogic@0
|
32
|
lbajardsilogic@0
|
33 FFTFileCache::FFTFileCache(QString fileBase, MatrixFile::Mode mode,
|
lbajardsilogic@0
|
34 StorageType storageType) :
|
lbajardsilogic@0
|
35 m_writebuf(0),
|
lbajardsilogic@0
|
36 m_readbuf(0),
|
lbajardsilogic@0
|
37 m_readbufCol(0),
|
lbajardsilogic@0
|
38 m_readbufWidth(0),
|
lbajardsilogic@0
|
39 m_mfc(new MatrixFile
|
lbajardsilogic@0
|
40 (fileBase, mode,
|
lbajardsilogic@0
|
41 storageType == Compact ? sizeof(uint16_t) : sizeof(float),
|
lbajardsilogic@0
|
42 mode == MatrixFile::ReadOnly)),
|
lbajardsilogic@0
|
43 m_storageType(storageType)
|
lbajardsilogic@0
|
44 {
|
lbajardsilogic@0
|
45 // std::cerr << "FFTFileCache: storage type is " << (storageType == Compact ? "Compact" : storageType == Polar ? "Polar" : "Rectangular") << std::endl;
|
lbajardsilogic@0
|
46 }
|
lbajardsilogic@0
|
47
|
lbajardsilogic@0
|
48 FFTFileCache::~FFTFileCache()
|
lbajardsilogic@0
|
49 {
|
lbajardsilogic@0
|
50 if (m_readbuf) delete[] m_readbuf;
|
lbajardsilogic@0
|
51 if (m_writebuf) delete[] m_writebuf;
|
lbajardsilogic@0
|
52 delete m_mfc;
|
lbajardsilogic@0
|
53 }
|
lbajardsilogic@0
|
54
|
lbajardsilogic@0
|
55 size_t
|
lbajardsilogic@0
|
56 FFTFileCache::getWidth() const
|
lbajardsilogic@0
|
57 {
|
lbajardsilogic@0
|
58 return m_mfc->getWidth();
|
lbajardsilogic@0
|
59 }
|
lbajardsilogic@0
|
60
|
lbajardsilogic@0
|
61 size_t
|
lbajardsilogic@0
|
62 FFTFileCache::getHeight() const
|
lbajardsilogic@0
|
63 {
|
lbajardsilogic@0
|
64 size_t mh = m_mfc->getHeight();
|
lbajardsilogic@0
|
65 if (mh > 0) return (mh - 1) / 2;
|
lbajardsilogic@0
|
66 else return 0;
|
lbajardsilogic@0
|
67 }
|
lbajardsilogic@0
|
68
|
lbajardsilogic@0
|
69 void
|
lbajardsilogic@0
|
70 FFTFileCache::resize(size_t width, size_t height)
|
lbajardsilogic@0
|
71 {
|
lbajardsilogic@0
|
72 QMutexLocker locker(&m_writeMutex);
|
lbajardsilogic@0
|
73
|
lbajardsilogic@0
|
74 m_mfc->resize(width, height * 2 + 1);
|
lbajardsilogic@0
|
75 if (m_readbuf) {
|
lbajardsilogic@0
|
76 delete[] m_readbuf;
|
lbajardsilogic@0
|
77 m_readbuf = 0;
|
lbajardsilogic@0
|
78 }
|
lbajardsilogic@0
|
79 if (m_writebuf) {
|
lbajardsilogic@0
|
80 delete[] m_writebuf;
|
lbajardsilogic@0
|
81 }
|
lbajardsilogic@0
|
82 m_writebuf = new char[(height * 2 + 1) * m_mfc->getCellSize()];
|
lbajardsilogic@0
|
83 }
|
lbajardsilogic@0
|
84
|
lbajardsilogic@0
|
85 void
|
lbajardsilogic@0
|
86 FFTFileCache::reset()
|
lbajardsilogic@0
|
87 {
|
lbajardsilogic@0
|
88 m_mfc->reset();
|
lbajardsilogic@0
|
89 }
|
lbajardsilogic@0
|
90
|
lbajardsilogic@0
|
91 float
|
lbajardsilogic@0
|
92 FFTFileCache::getMagnitudeAt(size_t x, size_t y) const
|
lbajardsilogic@0
|
93 {
|
lbajardsilogic@0
|
94 Profiler profiler("FFTFileCache::getMagnitudeAt", false);
|
lbajardsilogic@0
|
95
|
lbajardsilogic@0
|
96 float value = 0.f;
|
lbajardsilogic@0
|
97
|
lbajardsilogic@0
|
98 switch (m_storageType) {
|
lbajardsilogic@0
|
99
|
lbajardsilogic@0
|
100 case Compact:
|
lbajardsilogic@0
|
101 value = (getFromReadBufCompactUnsigned(x, y * 2) / 65535.0)
|
lbajardsilogic@0
|
102 * getNormalizationFactor(x);
|
lbajardsilogic@0
|
103 break;
|
lbajardsilogic@0
|
104
|
lbajardsilogic@0
|
105 case Rectangular:
|
lbajardsilogic@0
|
106 {
|
lbajardsilogic@0
|
107 float real, imag;
|
lbajardsilogic@0
|
108 getValuesAt(x, y, real, imag);
|
lbajardsilogic@0
|
109 value = sqrtf(real * real + imag * imag);
|
lbajardsilogic@0
|
110 break;
|
lbajardsilogic@0
|
111 }
|
lbajardsilogic@0
|
112
|
lbajardsilogic@0
|
113 case Polar:
|
lbajardsilogic@0
|
114 value = getFromReadBufStandard(x, y * 2);
|
lbajardsilogic@0
|
115 break;
|
lbajardsilogic@0
|
116 }
|
lbajardsilogic@0
|
117
|
lbajardsilogic@0
|
118 return value;
|
lbajardsilogic@0
|
119 }
|
lbajardsilogic@0
|
120
|
lbajardsilogic@0
|
121 float
|
lbajardsilogic@0
|
122 FFTFileCache::getNormalizedMagnitudeAt(size_t x, size_t y) const
|
lbajardsilogic@0
|
123 {
|
lbajardsilogic@0
|
124 float value = 0.f;
|
lbajardsilogic@0
|
125
|
lbajardsilogic@0
|
126 switch (m_storageType) {
|
lbajardsilogic@0
|
127
|
lbajardsilogic@0
|
128 case Compact:
|
lbajardsilogic@0
|
129 value = getFromReadBufCompactUnsigned(x, y * 2) / 65535.0;
|
lbajardsilogic@0
|
130 break;
|
lbajardsilogic@0
|
131
|
lbajardsilogic@0
|
132 default:
|
lbajardsilogic@0
|
133 {
|
lbajardsilogic@0
|
134 float mag = getMagnitudeAt(x, y);
|
lbajardsilogic@0
|
135 float factor = getNormalizationFactor(x);
|
lbajardsilogic@0
|
136 if (factor != 0) value = mag / factor;
|
lbajardsilogic@0
|
137 else value = 0.f;
|
lbajardsilogic@0
|
138 break;
|
lbajardsilogic@0
|
139 }
|
lbajardsilogic@0
|
140 }
|
lbajardsilogic@0
|
141
|
lbajardsilogic@0
|
142 return value;
|
lbajardsilogic@0
|
143 }
|
lbajardsilogic@0
|
144
|
lbajardsilogic@0
|
145 float
|
lbajardsilogic@0
|
146 FFTFileCache::getMaximumMagnitudeAt(size_t x) const
|
lbajardsilogic@0
|
147 {
|
lbajardsilogic@0
|
148 return getNormalizationFactor(x);
|
lbajardsilogic@0
|
149 }
|
lbajardsilogic@0
|
150
|
lbajardsilogic@0
|
151 float
|
lbajardsilogic@0
|
152 FFTFileCache::getPhaseAt(size_t x, size_t y) const
|
lbajardsilogic@0
|
153 {
|
lbajardsilogic@0
|
154 float value = 0.f;
|
lbajardsilogic@0
|
155
|
lbajardsilogic@0
|
156 switch (m_storageType) {
|
lbajardsilogic@0
|
157
|
lbajardsilogic@0
|
158 case Compact:
|
lbajardsilogic@0
|
159 value = (getFromReadBufCompactSigned(x, y * 2 + 1) / 32767.0) * M_PI;
|
lbajardsilogic@0
|
160 break;
|
lbajardsilogic@0
|
161
|
lbajardsilogic@0
|
162 case Rectangular:
|
lbajardsilogic@0
|
163 {
|
lbajardsilogic@0
|
164 float real, imag;
|
lbajardsilogic@0
|
165 getValuesAt(x, y, real, imag);
|
lbajardsilogic@0
|
166 value = princargf(atan2f(imag, real));
|
lbajardsilogic@0
|
167 break;
|
lbajardsilogic@0
|
168 }
|
lbajardsilogic@0
|
169
|
lbajardsilogic@0
|
170 case Polar:
|
lbajardsilogic@0
|
171 value = getFromReadBufStandard(x, y * 2 + 1);
|
lbajardsilogic@0
|
172 break;
|
lbajardsilogic@0
|
173 }
|
lbajardsilogic@0
|
174
|
lbajardsilogic@0
|
175 return value;
|
lbajardsilogic@0
|
176 }
|
lbajardsilogic@0
|
177
|
lbajardsilogic@0
|
178 void
|
lbajardsilogic@0
|
179 FFTFileCache::getValuesAt(size_t x, size_t y, float &real, float &imag) const
|
lbajardsilogic@0
|
180 {
|
lbajardsilogic@0
|
181 switch (m_storageType) {
|
lbajardsilogic@0
|
182
|
lbajardsilogic@0
|
183 case Rectangular:
|
lbajardsilogic@0
|
184 real = getFromReadBufStandard(x, y * 2);
|
lbajardsilogic@0
|
185 imag = getFromReadBufStandard(x, y * 2 + 1);
|
lbajardsilogic@0
|
186 return;
|
lbajardsilogic@0
|
187
|
lbajardsilogic@0
|
188 default:
|
lbajardsilogic@0
|
189 float mag = getMagnitudeAt(x, y);
|
lbajardsilogic@0
|
190 float phase = getPhaseAt(x, y);
|
lbajardsilogic@0
|
191 real = mag * cosf(phase);
|
lbajardsilogic@0
|
192 imag = mag * sinf(phase);
|
lbajardsilogic@0
|
193 return;
|
lbajardsilogic@0
|
194 }
|
lbajardsilogic@0
|
195 }
|
lbajardsilogic@0
|
196
|
lbajardsilogic@0
|
197 bool
|
lbajardsilogic@0
|
198 FFTFileCache::haveSetColumnAt(size_t x) const
|
lbajardsilogic@0
|
199 {
|
lbajardsilogic@0
|
200 return m_mfc->haveSetColumnAt(x);
|
lbajardsilogic@0
|
201 }
|
lbajardsilogic@0
|
202
|
lbajardsilogic@0
|
203 void
|
lbajardsilogic@0
|
204 FFTFileCache::setColumnAt(size_t x, float *mags, float *phases, float factor)
|
lbajardsilogic@0
|
205 {
|
lbajardsilogic@0
|
206 QMutexLocker locker(&m_writeMutex);
|
lbajardsilogic@0
|
207
|
lbajardsilogic@0
|
208 size_t h = getHeight();
|
lbajardsilogic@0
|
209
|
lbajardsilogic@0
|
210 switch (m_storageType) {
|
lbajardsilogic@0
|
211
|
lbajardsilogic@0
|
212 case Compact:
|
lbajardsilogic@0
|
213 for (size_t y = 0; y < h; ++y) {
|
lbajardsilogic@0
|
214 ((uint16_t *)m_writebuf)[y * 2] = uint16_t((mags[y] / factor) * 65535.0);
|
lbajardsilogic@0
|
215 ((uint16_t *)m_writebuf)[y * 2 + 1] = uint16_t(int16_t((phases[y] * 32767) / M_PI));
|
lbajardsilogic@0
|
216 }
|
lbajardsilogic@0
|
217 break;
|
lbajardsilogic@0
|
218
|
lbajardsilogic@0
|
219 case Rectangular:
|
lbajardsilogic@0
|
220 for (size_t y = 0; y < h; ++y) {
|
lbajardsilogic@0
|
221 ((float *)m_writebuf)[y * 2] = mags[y] * cosf(phases[y]);
|
lbajardsilogic@0
|
222 ((float *)m_writebuf)[y * 2 + 1] = mags[y] * sinf(phases[y]);
|
lbajardsilogic@0
|
223 }
|
lbajardsilogic@0
|
224 break;
|
lbajardsilogic@0
|
225
|
lbajardsilogic@0
|
226 case Polar:
|
lbajardsilogic@0
|
227 for (size_t y = 0; y < h; ++y) {
|
lbajardsilogic@0
|
228 ((float *)m_writebuf)[y * 2] = mags[y];
|
lbajardsilogic@0
|
229 ((float *)m_writebuf)[y * 2 + 1] = phases[y];
|
lbajardsilogic@0
|
230 }
|
lbajardsilogic@0
|
231 break;
|
lbajardsilogic@0
|
232 }
|
lbajardsilogic@0
|
233
|
lbajardsilogic@0
|
234 static float maxFactor = 0;
|
lbajardsilogic@0
|
235 if (factor > maxFactor) maxFactor = factor;
|
lbajardsilogic@0
|
236 // std::cerr << "Normalization factor: " << factor << ", max " << maxFactor << " (height " << getHeight() << ")" << std::endl;
|
lbajardsilogic@0
|
237
|
lbajardsilogic@0
|
238 if (m_storageType == Compact) {
|
lbajardsilogic@0
|
239 if (factor < 0.f || factor > 1.f) {
|
lbajardsilogic@0
|
240 std::cerr << "WARNING: FFTFileCache::setColumnAt: Normalization factor " << factor << " out of range" << std::endl;
|
lbajardsilogic@0
|
241 if (factor < 0.f) factor = 0.f;
|
lbajardsilogic@0
|
242 if (factor > 1.f) factor = 1.f;
|
lbajardsilogic@0
|
243 }
|
lbajardsilogic@0
|
244 ((uint16_t *)m_writebuf)[h * 2] = (uint16_t)(factor * 65535.0);
|
lbajardsilogic@0
|
245 } else {
|
lbajardsilogic@0
|
246 ((float *)m_writebuf)[h * 2] = factor;
|
lbajardsilogic@0
|
247 }
|
lbajardsilogic@0
|
248 m_mfc->setColumnAt(x, m_writebuf);
|
lbajardsilogic@0
|
249 }
|
lbajardsilogic@0
|
250
|
lbajardsilogic@0
|
251 void
|
lbajardsilogic@0
|
252 FFTFileCache::setColumnAt(size_t x, float *real, float *imag)
|
lbajardsilogic@0
|
253 {
|
lbajardsilogic@0
|
254 QMutexLocker locker(&m_writeMutex);
|
lbajardsilogic@0
|
255
|
lbajardsilogic@0
|
256 size_t h = getHeight();
|
lbajardsilogic@0
|
257
|
lbajardsilogic@0
|
258 float max = 0.0f;
|
lbajardsilogic@0
|
259
|
lbajardsilogic@0
|
260 switch (m_storageType) {
|
lbajardsilogic@0
|
261
|
lbajardsilogic@0
|
262 case Compact:
|
lbajardsilogic@0
|
263 for (size_t y = 0; y < h; ++y) {
|
lbajardsilogic@0
|
264 float mag = sqrtf(real[y] * real[y] + imag[y] * imag[y]);
|
lbajardsilogic@0
|
265 if (mag > max) max = mag;
|
lbajardsilogic@0
|
266 }
|
lbajardsilogic@0
|
267 for (size_t y = 0; y < h; ++y) {
|
lbajardsilogic@0
|
268 float mag = sqrtf(real[y] * real[y] + imag[y] * imag[y]);
|
lbajardsilogic@0
|
269 float phase = princargf(atan2f(imag[y], real[y]));
|
lbajardsilogic@0
|
270 ((uint16_t *)m_writebuf)[y * 2] = uint16_t((mag / max) * 65535.0);
|
lbajardsilogic@0
|
271 ((uint16_t *)m_writebuf)[y * 2 + 1] = uint16_t(int16_t((phase * 32767) / M_PI));
|
lbajardsilogic@0
|
272 }
|
lbajardsilogic@0
|
273 break;
|
lbajardsilogic@0
|
274
|
lbajardsilogic@0
|
275 case Rectangular:
|
lbajardsilogic@0
|
276 for (size_t y = 0; y < h; ++y) {
|
lbajardsilogic@0
|
277 ((float *)m_writebuf)[y * 2] = real[y];
|
lbajardsilogic@0
|
278 ((float *)m_writebuf)[y * 2 + 1] = imag[y];
|
lbajardsilogic@0
|
279 float mag = sqrtf(real[y] * real[y] + imag[y] * imag[y]);
|
lbajardsilogic@0
|
280 if (mag > max) max = mag;
|
lbajardsilogic@0
|
281 }
|
lbajardsilogic@0
|
282 break;
|
lbajardsilogic@0
|
283
|
lbajardsilogic@0
|
284 case Polar:
|
lbajardsilogic@0
|
285 for (size_t y = 0; y < h; ++y) {
|
lbajardsilogic@0
|
286 float mag = sqrtf(real[y] * real[y] + imag[y] * imag[y]);
|
lbajardsilogic@0
|
287 if (mag > max) max = mag;
|
lbajardsilogic@0
|
288 ((float *)m_writebuf)[y * 2] = mag;
|
lbajardsilogic@0
|
289 ((float *)m_writebuf)[y * 2 + 1] = princargf(atan2f(imag[y], real[y]));
|
lbajardsilogic@0
|
290 }
|
lbajardsilogic@0
|
291 break;
|
lbajardsilogic@0
|
292 }
|
lbajardsilogic@0
|
293
|
lbajardsilogic@0
|
294 ((float *)m_writebuf)[h * 2] = max;
|
lbajardsilogic@0
|
295 m_mfc->setColumnAt(x, m_writebuf);
|
lbajardsilogic@0
|
296 }
|
lbajardsilogic@0
|
297
|
lbajardsilogic@0
|
298 size_t
|
lbajardsilogic@0
|
299 FFTFileCache::getCacheSize(size_t width, size_t height, StorageType type)
|
lbajardsilogic@0
|
300 {
|
lbajardsilogic@0
|
301 return (height * 2 + 1) * width *
|
lbajardsilogic@0
|
302 (type == Compact ? sizeof(uint16_t) : sizeof(float)) +
|
lbajardsilogic@0
|
303 2 * sizeof(size_t); // matrix file header size
|
lbajardsilogic@0
|
304 }
|
lbajardsilogic@0
|
305
|
lbajardsilogic@0
|
306 void
|
lbajardsilogic@0
|
307 FFTFileCache::populateReadBuf(size_t x) const
|
lbajardsilogic@0
|
308 {
|
lbajardsilogic@0
|
309 Profiler profiler("FFTFileCache::populateReadBuf", false);
|
lbajardsilogic@0
|
310
|
lbajardsilogic@0
|
311 if (!m_readbuf) {
|
lbajardsilogic@0
|
312 m_readbuf = new char[m_mfc->getHeight() * 2 * m_mfc->getCellSize()];
|
lbajardsilogic@0
|
313 }
|
lbajardsilogic@0
|
314 m_mfc->getColumnAt(x, m_readbuf);
|
lbajardsilogic@0
|
315 if (m_mfc->haveSetColumnAt(x + 1)) {
|
lbajardsilogic@0
|
316 m_mfc->getColumnAt
|
lbajardsilogic@0
|
317 (x + 1, m_readbuf + m_mfc->getCellSize() * m_mfc->getHeight());
|
lbajardsilogic@0
|
318 m_readbufWidth = 2;
|
lbajardsilogic@0
|
319 } else {
|
lbajardsilogic@0
|
320 m_readbufWidth = 1;
|
lbajardsilogic@0
|
321 }
|
lbajardsilogic@0
|
322 m_readbufCol = x;
|
lbajardsilogic@0
|
323 }
|
lbajardsilogic@0
|
324
|