Mercurial > hg > easaier-soundaccess
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 |