comparison data/fft/FFTFileCache.cpp @ 0:fc9323a41f5a

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