annotate data/fft/FFTFileCache.cpp @ 392:183ee2a55fc7

* More work to abstract out interactive components used in the data library, so that it does not need to depend on QtGui.
author Chris Cannam
date Fri, 14 Mar 2008 17:14:21 +0000
parents 7cc6b7b0d819
children 115f60df1e4d
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@148 21
Chris@148 22 #include <iostream>
Chris@148 23
Chris@148 24 #include <QMutexLocker>
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@148 72 QMutexLocker locker(&m_writeMutex);
Chris@148 73
Chris@266 74 m_mfc->resize(width, height * 2 + m_factorSize);
Chris@148 75 if (m_readbuf) {
Chris@148 76 delete[] m_readbuf;
Chris@148 77 m_readbuf = 0;
Chris@148 78 }
Chris@148 79 if (m_writebuf) {
Chris@148 80 delete[] m_writebuf;
Chris@148 81 }
Chris@266 82 m_writebuf = new char[(height * 2 + m_factorSize) * m_mfc->getCellSize()];
Chris@148 83 }
Chris@148 84
Chris@148 85 void
Chris@148 86 FFTFileCache::reset()
Chris@148 87 {
Chris@148 88 m_mfc->reset();
Chris@148 89 }
Chris@148 90
Chris@148 91 float
Chris@148 92 FFTFileCache::getMagnitudeAt(size_t x, size_t y) const
Chris@148 93 {
Chris@183 94 Profiler profiler("FFTFileCache::getMagnitudeAt", false);
Chris@183 95
Chris@148 96 float value = 0.f;
Chris@148 97
Chris@148 98 switch (m_storageType) {
Chris@148 99
Chris@148 100 case Compact:
Chris@148 101 value = (getFromReadBufCompactUnsigned(x, y * 2) / 65535.0)
Chris@148 102 * getNormalizationFactor(x);
Chris@148 103 break;
Chris@148 104
Chris@148 105 case Rectangular:
Chris@148 106 {
Chris@148 107 float real, imag;
Chris@148 108 getValuesAt(x, y, real, imag);
Chris@148 109 value = sqrtf(real * real + imag * imag);
Chris@148 110 break;
Chris@148 111 }
Chris@148 112
Chris@148 113 case Polar:
Chris@148 114 value = getFromReadBufStandard(x, y * 2);
Chris@148 115 break;
Chris@148 116 }
Chris@148 117
Chris@148 118 return value;
Chris@148 119 }
Chris@148 120
Chris@148 121 float
Chris@148 122 FFTFileCache::getNormalizedMagnitudeAt(size_t x, size_t y) const
Chris@148 123 {
Chris@148 124 float value = 0.f;
Chris@148 125
Chris@148 126 switch (m_storageType) {
Chris@148 127
Chris@148 128 case Compact:
Chris@148 129 value = getFromReadBufCompactUnsigned(x, y * 2) / 65535.0;
Chris@148 130 break;
Chris@148 131
Chris@148 132 default:
Chris@148 133 {
Chris@148 134 float mag = getMagnitudeAt(x, y);
Chris@148 135 float factor = getNormalizationFactor(x);
Chris@148 136 if (factor != 0) value = mag / factor;
Chris@148 137 else value = 0.f;
Chris@148 138 break;
Chris@148 139 }
Chris@148 140 }
Chris@148 141
Chris@148 142 return value;
Chris@148 143 }
Chris@148 144
Chris@148 145 float
Chris@148 146 FFTFileCache::getMaximumMagnitudeAt(size_t x) const
Chris@148 147 {
Chris@148 148 return getNormalizationFactor(x);
Chris@148 149 }
Chris@148 150
Chris@148 151 float
Chris@148 152 FFTFileCache::getPhaseAt(size_t x, size_t y) const
Chris@148 153 {
Chris@148 154 float value = 0.f;
Chris@148 155
Chris@148 156 switch (m_storageType) {
Chris@148 157
Chris@148 158 case Compact:
Chris@148 159 value = (getFromReadBufCompactSigned(x, y * 2 + 1) / 32767.0) * M_PI;
Chris@148 160 break;
Chris@148 161
Chris@148 162 case Rectangular:
Chris@148 163 {
Chris@148 164 float real, imag;
Chris@148 165 getValuesAt(x, y, real, imag);
Chris@148 166 value = princargf(atan2f(imag, real));
Chris@148 167 break;
Chris@148 168 }
Chris@148 169
Chris@148 170 case Polar:
Chris@148 171 value = getFromReadBufStandard(x, y * 2 + 1);
Chris@148 172 break;
Chris@148 173 }
Chris@148 174
Chris@148 175 return value;
Chris@148 176 }
Chris@148 177
Chris@148 178 void
Chris@148 179 FFTFileCache::getValuesAt(size_t x, size_t y, float &real, float &imag) const
Chris@148 180 {
Chris@148 181 switch (m_storageType) {
Chris@148 182
Chris@148 183 case Rectangular:
Chris@148 184 real = getFromReadBufStandard(x, y * 2);
Chris@148 185 imag = getFromReadBufStandard(x, y * 2 + 1);
Chris@148 186 return;
Chris@148 187
Chris@148 188 default:
Chris@148 189 float mag = getMagnitudeAt(x, y);
Chris@148 190 float phase = getPhaseAt(x, y);
Chris@148 191 real = mag * cosf(phase);
Chris@148 192 imag = mag * sinf(phase);
Chris@148 193 return;
Chris@148 194 }
Chris@148 195 }
Chris@148 196
Chris@148 197 bool
Chris@148 198 FFTFileCache::haveSetColumnAt(size_t x) const
Chris@148 199 {
Chris@148 200 return m_mfc->haveSetColumnAt(x);
Chris@148 201 }
Chris@148 202
Chris@148 203 void
Chris@148 204 FFTFileCache::setColumnAt(size_t x, float *mags, float *phases, float factor)
Chris@148 205 {
Chris@148 206 QMutexLocker locker(&m_writeMutex);
Chris@148 207
Chris@148 208 size_t h = getHeight();
Chris@148 209
Chris@148 210 switch (m_storageType) {
Chris@148 211
Chris@148 212 case Compact:
Chris@148 213 for (size_t y = 0; y < h; ++y) {
Chris@148 214 ((uint16_t *)m_writebuf)[y * 2] = uint16_t((mags[y] / factor) * 65535.0);
Chris@148 215 ((uint16_t *)m_writebuf)[y * 2 + 1] = uint16_t(int16_t((phases[y] * 32767) / M_PI));
Chris@148 216 }
Chris@148 217 break;
Chris@148 218
Chris@148 219 case Rectangular:
Chris@148 220 for (size_t y = 0; y < h; ++y) {
Chris@148 221 ((float *)m_writebuf)[y * 2] = mags[y] * cosf(phases[y]);
Chris@148 222 ((float *)m_writebuf)[y * 2 + 1] = mags[y] * sinf(phases[y]);
Chris@148 223 }
Chris@148 224 break;
Chris@148 225
Chris@148 226 case Polar:
Chris@148 227 for (size_t y = 0; y < h; ++y) {
Chris@148 228 ((float *)m_writebuf)[y * 2] = mags[y];
Chris@148 229 ((float *)m_writebuf)[y * 2 + 1] = phases[y];
Chris@148 230 }
Chris@148 231 break;
Chris@148 232 }
Chris@148 233
Chris@266 234 // static float maxFactor = 0;
Chris@266 235 // if (factor > maxFactor) maxFactor = factor;
Chris@266 236 // std::cerr << "Column " << x << ": normalization factor: " << factor << ", max " << maxFactor << " (height " << getHeight() << ")" << std::endl;
Chris@148 237
Chris@266 238 setNormalizationFactorToWritebuf(factor);
Chris@266 239
Chris@148 240 m_mfc->setColumnAt(x, m_writebuf);
Chris@148 241 }
Chris@148 242
Chris@148 243 void
Chris@148 244 FFTFileCache::setColumnAt(size_t x, float *real, float *imag)
Chris@148 245 {
Chris@148 246 QMutexLocker locker(&m_writeMutex);
Chris@148 247
Chris@148 248 size_t h = getHeight();
Chris@148 249
Chris@266 250 float factor = 0.0f;
Chris@148 251
Chris@148 252 switch (m_storageType) {
Chris@148 253
Chris@148 254 case Compact:
Chris@148 255 for (size_t y = 0; y < h; ++y) {
Chris@148 256 float mag = sqrtf(real[y] * real[y] + imag[y] * imag[y]);
Chris@266 257 if (mag > factor) factor = mag;
Chris@148 258 }
Chris@148 259 for (size_t y = 0; y < h; ++y) {
Chris@148 260 float mag = sqrtf(real[y] * real[y] + imag[y] * imag[y]);
Chris@148 261 float phase = princargf(atan2f(imag[y], real[y]));
Chris@266 262 ((uint16_t *)m_writebuf)[y * 2] = uint16_t((mag / factor) * 65535.0);
Chris@148 263 ((uint16_t *)m_writebuf)[y * 2 + 1] = uint16_t(int16_t((phase * 32767) / M_PI));
Chris@148 264 }
Chris@148 265 break;
Chris@148 266
Chris@148 267 case Rectangular:
Chris@148 268 for (size_t y = 0; y < h; ++y) {
Chris@148 269 ((float *)m_writebuf)[y * 2] = real[y];
Chris@148 270 ((float *)m_writebuf)[y * 2 + 1] = imag[y];
Chris@148 271 float mag = sqrtf(real[y] * real[y] + imag[y] * imag[y]);
Chris@266 272 if (mag > factor) factor = mag;
Chris@148 273 }
Chris@148 274 break;
Chris@148 275
Chris@148 276 case Polar:
Chris@148 277 for (size_t y = 0; y < h; ++y) {
Chris@148 278 float mag = sqrtf(real[y] * real[y] + imag[y] * imag[y]);
Chris@266 279 if (mag > factor) factor = mag;
Chris@148 280 ((float *)m_writebuf)[y * 2] = mag;
Chris@290 281 float phase = princargf(atan2f(imag[y], real[y]));
Chris@290 282 ((float *)m_writebuf)[y * 2 + 1] = phase;
Chris@148 283 }
Chris@148 284 break;
Chris@148 285 }
Chris@148 286
Chris@266 287 // static float maxFactor = 0;
Chris@266 288 // if (factor > maxFactor) maxFactor = factor;
Chris@266 289 // std::cerr << "[RI] Column " << x << ": normalization factor: " << factor << ", max " << maxFactor << " (height " << getHeight() << ")" << std::endl;
Chris@266 290
Chris@266 291 setNormalizationFactorToWritebuf(factor);
Chris@266 292
Chris@148 293 m_mfc->setColumnAt(x, m_writebuf);
Chris@148 294 }
Chris@148 295
Chris@170 296 size_t
Chris@170 297 FFTFileCache::getCacheSize(size_t width, size_t height, StorageType type)
Chris@170 298 {
Chris@266 299 return (height * 2 + (type == Compact ? 2 : 1)) * width *
Chris@170 300 (type == Compact ? sizeof(uint16_t) : sizeof(float)) +
Chris@170 301 2 * sizeof(size_t); // matrix file header size
Chris@170 302 }
Chris@170 303
Chris@183 304 void
Chris@183 305 FFTFileCache::populateReadBuf(size_t x) const
Chris@183 306 {
Chris@183 307 Profiler profiler("FFTFileCache::populateReadBuf", false);
Chris@183 308
Chris@183 309 if (!m_readbuf) {
Chris@183 310 m_readbuf = new char[m_mfc->getHeight() * 2 * m_mfc->getCellSize()];
Chris@183 311 }
Chris@183 312 m_mfc->getColumnAt(x, m_readbuf);
Chris@183 313 if (m_mfc->haveSetColumnAt(x + 1)) {
Chris@183 314 m_mfc->getColumnAt
Chris@183 315 (x + 1, m_readbuf + m_mfc->getCellSize() * m_mfc->getHeight());
Chris@183 316 m_readbufWidth = 2;
Chris@183 317 } else {
Chris@183 318 m_readbufWidth = 1;
Chris@183 319 }
Chris@183 320 m_readbufCol = x;
Chris@183 321 }
Chris@183 322