annotate data/fft/FFTFileCache.cpp @ 532:59dd6d1bcfb0

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